Classdesc 3.44
xml_pack_base.h
Go to the documentation of this file.
1/*
2 @copyright Russell Standish 2000-2013
3 @author Russell Standish
4 This file is part of Classdesc
5
6 Open source licensed under the MIT license. See LICENSE for details.
7*/
8
12
13#ifndef CLASSDESC_XML_PACK_BASE_H
14#define CLASSDESC_XML_PACK_BASE_H
15#include <cmath>
16#include <iostream>
17#include <iomanip>
18#include <sstream>
19#include <string>
20#include <assert.h>
21#include <stdarg.h>
22
23#include <classdesc.h>
24#include <classdesc_access.h>
25#include <xml_common.h>
26#include <stdexcept>
27
28namespace classdesc
29{
30 inline std::string xml_quote(char c)
31 {
32 switch (c)
33 {
34 case '&': return "&amp;";
35 case '<': return "&lt;";
36 case '>': return "&gt;";
37 case '\'': return "&apos;";
38 case '"': return "&quot;";
39 }
40 if (!isgraph(c))
41 {
42 std::ostringstream s;
43 s<<"&#"<<std::setfill('0')<<std::setw(4)<<int(c)<<";";
44 return s.str();
45 }
46 return std::string(1,c);
47 }
48
49 inline std::ostream& operator<<(std::ostream& o, const CDATA& x)
50 {return o<<"<![CDATA["<<static_cast<const std::string&>(x)<<"]]>";}
51
55 class xml_pack_t
56 {
57 std::ostream* o; // weak reference, allows for assignability
58 int taglevel;
59 // count number of ids separated by '.'s in a string
60 int level(const string& xx) {
61 const char* x=xx.c_str();
62 int l;
63 if (*x=='\0') return 0;
64 for (l=1; *x!='\0'; x++) if (*x=='.') l++;
65 return l;
66 }
67
68 void pretty(const string& d) {if (prettyPrint) *o << std::setw(level(d)) <<"";}
69 void endpretty() {if (prettyPrint) *o<<std::endl;}
70
75 bool tag(const string& d) {
76 int l=level(d);
77 bool ret = taglevel < l; //return true if tag created
78 if (ret)
79 {
80 pretty(d);
81 *o<<"<"<<tail(d);
82 if (l==1 && !schema.empty())
83 *o<<" xmlns=\""<<schema<<"\"";
84 *o<<">";
85 endpretty();
86 taglevel=l;
87 }
88 return ret;
89 }
91 void endtag(const string& d) {
92 taglevel--;
93 pretty(d);
94 *o<<"</"<<tail(d)<<">";
95 endpretty();
96 }
97
98 friend class Tag;
99 CLASSDESC_ACCESS(xml_pack_t);
100 public:
101 string schema;
102 bool prettyPrint;
103 volatile bool abort;
104 struct PackAborted: public std::exception {};
105
106 xml_pack_t(std::ostream& o, const string& schema=""):
107 o(&o), taglevel(0), schema(schema), prettyPrint(false), abort(false) {}
108
109 class Tag
110 {
111 xml_pack_t* t;
112 string d;
113 public:
114 Tag(xml_pack_t& t, const string& d): t(t.tag(d)? &t: 0), d(d) {}
115 ~Tag() {if (t) t->endtag(d);}
116 };
117
118 // handle peculiar case sensitivity of floating point special values in XML
119 template <class T>
120 typename enable_if<is_floating_point<T>, std::ostream&>::T
121 put(std::ostream& o, T x)
122 {
123 if (std::isnan(x))
124 return o<<"NaN";
125 else if (std::isinf(x))
126 if (x<0)
127 return o<<"-INF";
128 else
129 return o<<"INF";
130 else
131 return o<<x;
132 }
133
134 template <class T>
135 typename enable_if<Not<is_floating_point<T> >, std::ostream&>::T
136 put(std::ostream& o, const T& x)
137 {
138 return o<<x;
139 }
140
141
145 template <class T>
146 void pack(const string& d, const T&x)
147 {
148 if (abort) throw PackAborted();
149 std::string tag=tail(d);
150 pretty(d);
151 *o << "<"<<tag<<">";
152 put(*o,x) << "</"<<tag<<">";
153 endpretty();
154 if (!*o) throw std::runtime_error("failed to serialise");
155 }
156
160 template <class T>
161 void pack_notag(const string& d, const T&x) {
162 if (abort) throw PackAborted();
163 *o<<x;
164 if (!*o) throw std::runtime_error("failed to serialise");
165 }
166
167 };
168
169 template <class T>
170 typename enable_if<is_fundamental<T>, void>::T
171 xml_packp(xml_pack_t& x,const string& d,T& a)
172 {x.pack(d,a);}
173
174 template <> inline void xml_packp(xml_pack_t& x,const string& d, bool& a)
175 {x.pack(d, a? "true": "false");}
176
177 template <> inline void xml_packp(xml_pack_t& x,const string& d, char& a)
178 {x.pack(d,classdesc::xml_quote(a));}
179
183
184 template <class T>
185 typename enable_if<is_enum<T>, void>::T
186 xml_packp(xml_pack_t& x, const string& d, T& arg)
187 {x.pack(d,string(Enum_handle<T>(arg)));}
188
189
190
191 template <class T> void xml_pack(xml_pack_t&,const string&, const T&);
192
193 template <class T> void xml_pack(xml_pack_t&,const string&, T&);
194
195 template <class T> xml_pack_t& operator<<(xml_pack_t& t, const T& a);
196
197 inline void xml_pack(xml_pack_t& x,const string& d, std::string& a)
198 {
199 std::string tmp;
200 for (std::string::size_type i=0; i<a.length() && !x.abort; i++) tmp+=classdesc::xml_quote(a[i]);
201 x.pack(d,tmp);
202 }
203
204 inline void xml_pack(xml_pack_t& x,const string& d, const std::string& a)
205 {xml_pack(x,d,const_cast<std::string&>(a));}
206
207 /* now define the array version */
208 template <class T> void xml_pack(xml_pack_t& x,const string& d,is_array ia,
209 T& a, int dims,size_t ncopies,...)
210 {
211 va_list ap;
212 va_start(ap,ncopies);
213 for (int i=1; i<dims; i++) ncopies*=va_arg(ap,int); //assume that 2 and higher D arrays dimensions are int
214 va_end(ap);
215 xml_pack_t::Tag tag(x,d);
216
217 // element name is given by the type name
218 string eName=typeName<T>().c_str();
219 // strip leading namespace and qualifiers
220 const char *e=eName.c_str()+eName.length();
221 while (e!=eName.c_str() && *(e-1)!=' ' && *(e-1)!=':') e--;
222
223 for (size_t i=0; i<ncopies; i++) xml_pack(x,d+"."+e,(&a)[i]);
224 }
225
226 template <class T1, class T2>
227 void xml_pack(xml_pack_t& x, const string& d, const std::pair<T1,T2>& arg)
228 {
229 xml_pack_t::Tag t(x,d);
230 xml_pack(x,d+".first",arg.first);
231 xml_pack(x,d+".second",arg.second);
232 }
233
234 template <class T> typename
236 xml_packp(xml_pack_t& x, const string& d, T& arg, dummy<1> dum=0)
237 {
238 xml_pack_t::Tag tag(x,d);
239 // element name is given by the type name
240 string eName=typeName<typename T::value_type>().c_str();
241 eName=eName.substr(0,eName.find('<')); //trim off any template args
242 // strip leading namespace and qualifiers
243 const char *e=eName.c_str()+eName.length();
244 while (e!=eName.c_str() && *(e-1)!=' ' && *(e-1)!=':') e--;
245
246 for (typename T::const_iterator i=arg.begin(); i!=arg.end(); ++i)
247 xml_pack(x,d+"."+e,*i);
248 }
249
250 template <class T>
251 void xml_pack_onbase(xml_pack_t& x,const string& d,T& a)
252 {xml_pack(x,d+basename<T>(),a);}
253
254 /* const static members */
255 template<class T>
256 void//typename enable_if<Not<is_pointer<T> >,void>::T
257 xml_pack(xml_pack_t& targ, const string& desc, is_const_static i, T arg)
258 {}
259
260 template<class T>
261 void xml_pack(xml_pack_t& targ, const string& desc, Exclude<T>&) {}
262
263 // special handling of shared pointers to avoid a double wrapping problem
264 template<class T>
265 void xml_pack(xml_pack_t& x, const string& d, shared_ptr<T>& a);
266
267 template<class T>
268 void xml_pack(xml_pack_t& targ, const string& desc, is_graphnode, T&)
269 {
270 throw exception("xml_pack of arbitrary graphs not supported");
271 }
272
273}
274
275#include "use_mbr_pointers.h"
276CLASSDESC_USE_OLDSTYLE_MEMBER_OBJECTS(xml_pack)
277CLASSDESC_FUNCTION_NOP(xml_pack)
278
279using classdesc::xml_pack;
280using classdesc::xml_pack_onbase;
281
282#endif
Definition classdesc.h:868
Definition classdesc.h:920
Definition classdesc.h:923
Definition classdesc.h:931
<utility structure for handling tag/endtag
Definition xml_pack_base.h:110
Definition xml_pack_base.h:56
void pack_notag(const string &d, const T &x)
Definition xml_pack_base.h:161
volatile bool abort
if true, the layout XML in more human friendly form
Definition xml_pack_base.h:103
void pack(const string &d, const T &x)
Definition xml_pack_base.h:146
descriptor access to a class's privates
#define CLASSDESC_ACCESS(type)
add friend statements for each accessor function
Definition classdesc_access.h:36
Contains definitions related to classdesc functionality.
string basename()
returns a valid identifier to append to the descriptor of a base class
Definition classdesc.h:1127
used to transfer contents of CDATA sections.
Definition xml_common.h:23
Definition classdesc.h:1012
Definition classdesc.h:299
controlled template specialisation: stolen from boost::enable_if.
Definition classdesc.h:282
base class for exceptions thrown by classdesc
Definition classdesc.h:546
determines if T is a standard associative container
Definition classdesc.h:321
set to true to cancel packing from another thread
Definition xml_pack_base.h:104