Classdesc  3.D29
json_unpack_base.h
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 
9 #ifndef JSON_PACK_BASE_H
10 #define JSON_PACK_BASE_H
11 #include "classdesc.h"
12 #include <json_spirit.h>
13 #include <stdio.h>
14 #include <stdarg.h>
15 #include <vector>
16 #include <map>
17 
18 namespace classdesc
19 {
20  class json_pack_error : public exception
21  {
22  static const int maxchars=200; /* I hope this will always be large enough */
23  char errstring[maxchars];
24  public:
25  json_pack_error(const char *fmt,...)
26  {
27  va_list args;
28  va_start(args, fmt);
29  vsnprintf(errstring,maxchars,fmt,args);
30  va_end(args);
31  }
32  virtual ~json_pack_error() throw() {}
33  virtual const char* what() const throw() {return errstring;}
34  };
35 
36  // these are classes, not typedefs to avoid adding properties to mValue
37  class json_pack_t: public json_spirit::mValue
38  {
39  public:
40  bool throw_on_error;
41  json_pack_t(): json_spirit::mValue(json_spirit::mObject()),
42  throw_on_error(false) {}
43  json_pack_t(const json_spirit::mValue& x): json_spirit::mValue(x),
44  throw_on_error(false) {}
45  };
46 
47 
48  typedef json_pack_t json_unpack_t;
49 
51  template <class T> void json_pack(json_pack_t& o, const string& d, T& a);
52 
53  template <class T> void json_pack(json_pack_t& o, const string& d, const T& a)
54  {json_pack(o,d,const_cast<T&>(a));}
55 
56  template <class T> void json_unpack(json_unpack_t& o, const string& d, T& a);
57 
58  template <class T> json_pack_t& operator<<(json_pack_t& j, const T& a)
59  {json_pack(j,"",a); return j;}
60 
61  template <class T> const json_unpack_t& operator>>(const json_unpack_t& j, T& a)
62  {json_unpack(const_cast<json_unpack_t&>(j),"",a); return j;}
63 
65  inline json_spirit::mValue&
66  json_find(json_spirit::mValue& x, std::string name)
67  {
68  if (name.size()==0) return x;
69  if (name[0]=='.') name.erase(0,1); //remove leading '.'
70  std::string::size_type p=name.find('.');
71  if (x.type()==json_spirit::obj_type)
72  {
73  json_spirit::mObject& xo=x.get_obj();
74  json_spirit::mObject::iterator i=xo.find(name.substr(0,p));
75  if (i==xo.end())
76  throw json_pack_error("json object %s not found", name.substr(0,p).c_str());
77  else if (p==std::string::npos)
78  return i->second;
79  else
80  return json_find(i->second,name.substr(p,std::string::npos));
81  }
82  else
83  throw json_pack_error("%s is not a json object",name.c_str());
84  }
85 
86  //json_spirit::mValue does not provide constructors for everything. Oh well..
87  template <class T> json_spirit::mValue valueof(T a)
88  {return json_spirit::mValue(a);}
89  template <class T> T getValue(const json_spirit::mValue& x)
90  {return x.get_value<T>();}
91 
92  inline json_spirit::mValue valueof(unsigned char a)
93  {return json_spirit::mValue(int(a));}
94  template <> inline unsigned char getValue(const json_spirit::mValue& x)
95  {return x.get_value<int>();}
96 
97  inline json_spirit::mValue valueof(signed char a)
98  {return json_spirit::mValue(int(a));}
99  template <> inline signed char getValue(const json_spirit::mValue& x)
100  {return x.get_value<int>();}
101 
102  inline json_spirit::mValue valueof(char a)
103  {return json_spirit::mValue(int(a));}
104  template <> inline char getValue(const json_spirit::mValue& x)
105  {return x.get_value<int>();}
106 
107  inline json_spirit::mValue valueof(unsigned short a)
108  {return json_spirit::mValue(int(a));}
109  template <> inline unsigned short getValue(const json_spirit::mValue& x)
110  {return x.get_value<int>();}
111 
112  inline json_spirit::mValue valueof(signed short a)
113  {return json_spirit::mValue(int(a));}
114  template <> inline signed short getValue(const json_spirit::mValue& x)
115  {return x.get_value<int>();}
116 
117  inline json_spirit::mValue valueof(unsigned int a)
118  {return json_spirit::mValue(boost::uint64_t(a));}
119  template <> inline unsigned getValue(const json_spirit::mValue& x)
120  {return x.get_value<boost::uint64_t>();}
121 
122  inline json_spirit::mValue valueof(unsigned long a)
123  {return json_spirit::mValue(boost::uint64_t(a));}
124  template <> inline unsigned long getValue(const json_spirit::mValue& x)
125  {return x.get_value<boost::uint64_t>();}
126 
127  inline json_spirit::mValue valueof(long a)
128  {return json_spirit::mValue(boost::int64_t(a));}
129  template <> inline long getValue(const json_spirit::mValue& x)
130  {return x.get_value<boost::int64_t>();}
131 
132 #ifdef HAVE_LONGLONG
133  inline json_spirit::mValue valueof(unsigned long long a)
134  {return json_spirit::mValue(boost::uint64_t(a));}
135  template <> inline unsigned long long getValue(const json_spirit::mValue& x)
136  {return x.get_value<boost::uint64_t>();}
137 
138  inline json_spirit::mValue valueof(long long a)
139  {return json_spirit::mValue(boost::int64_t(a));}
140  template <> inline long long getValue(const json_spirit::mValue& x)
141  {return x.get_value<boost::int64_t>();}
142 #endif
143 
144  inline json_spirit::mValue valueof(float a)
145  {return json_spirit::mValue(double(a));}
146  template <> inline float getValue(const json_spirit::mValue& x)
147  {return x.get_value<double>();}
148 
149  // basic types
150  template <class T> typename
151  enable_if<Or<is_fundamental<T>,is_string<T> >, void>::T
152  json_packp(json_unpack_t& o, const string& d, const T& a, dummy<0> dum=0)
153  {
154  using namespace json_spirit;
155  if (d=="")
156  o=valueof(a);
157  else
158  {
159  try
160  {
161  json_spirit::mValue& parent=json_find(o,head(d));
162  if (parent.type()==obj_type)
163  parent.get_obj()[tail(d)]=valueof(a);
164  else
165  throw json_pack_error("cannot add to a basic type");
166  }
167  catch (json_pack_error&)
168  {
169  // only throw if this flag is set
170  if (o.throw_on_error) throw;
171  }
172  }
173  }
174 
175  // basic types
176  template <class T> typename
177  enable_if<Or<is_fundamental<T>,is_string<T> >, void>::T
178  json_unpackp(json_unpack_t& o, string d, T& a, dummy<0> dum=0)
179  {
180  try
181  {
182  a=getValue<T>(json_find(o,d));
183  }
184  catch (const json_pack_error&)
185  {
186  // only throw if this flag is set
187  if (o.throw_on_error) throw;
188  }
189  }
190 
191  template <class T> void json_pack_isarray
192  (json_spirit::mValue& jval, const T& val, std::vector<size_t> dims)
193  {
194  if (dims.empty())
195  {
196  json_pack_t j;
197  json_pack(j,"",val);
198  jval=j;
199  }
200  else
201  {
202  size_t s=dims.back();
203  jval=json_spirit::mArray(s);
204  dims.pop_back();
205  size_t stride=1;
206  for (size_t i=0; i<dims.size(); ++i) stride*=dims[i];
207  for (size_t i=0; i<s; ++i)
208  json_pack_isarray(jval.get_array()[i],(&val)[i*stride], dims);
209  }
210  }
211 
212  // array handling
213  template <class T>
214  void json_pack(json_pack_t& o, const string& d, is_array ia, const T& a,
215  int ndims,size_t ncopies,...)
216  {
217  va_list ap;
218  va_start(ap,ncopies);
219  std::vector<size_t> dims(ndims);
220  dims[ndims-1]=ncopies;
221  for (int i=ndims-2; i>=0; --i) dims[i]=va_arg(ap,size_t);
222  va_end(ap);
223  try
224  {
225  json_spirit::mValue& parent=json_find(o,head(d));
226  if (parent.type()!=json_spirit::obj_type)
227  throw json_pack_error("attempt to pack an array member into a non-object");
228  else
229  json_pack_isarray(parent.get_obj()[tail(d)],a,dims);
230  }
231  catch (json_pack_error&)
232  {
233  // only throw if this flag is set
234  if (o.throw_on_error) throw;
235  }
236  }
237 
238  template <class T> void json_unpack_isarray
239  (const json_spirit::mValue& jval, T& val, std::vector<size_t> dims)
240  {
241  if (dims.empty())
242  {
243  json_unpack_t j(jval);
244  json_unpack(j,"",val);
245  }
246  else
247  {
248  size_t s=dims.back();
249  dims.pop_back();
250  size_t stride=1;
251  for (size_t i=0; i<dims.size(); ++i) stride*=dims[i];
252  for (size_t i=0; i<s; ++i)
253  json_unpack_isarray(jval.get_array()[i],(&val)[i*stride], dims);
254  }
255  }
256 
257  template <class T>
258  void json_unpack(json_unpack_t& o, const string& d, is_array ia, T& a,
259  int ndims,size_t ncopies,...)
260  {
261  va_list ap;
262  va_start(ap,ncopies);
263  std::vector<size_t> dims(ndims);
264  dims[ndims-1]=ncopies;
265  for (int i=ndims-2; i>=0; --i) dims[i]=va_arg(ap,size_t);
266  va_end(ap);
267  try
268  {
269  const json_spirit::mValue& v=json_find(o,d);
270  if (v.type()!=json_spirit::array_type)
271  throw json_pack_error
272  ("attempt to unpack an array member from a non-object");
273  else
274  json_unpack_isarray(v,a,dims);
275  }
276  catch (json_pack_error&)
277  {
278  // only throw if this flag is set
279  if (o.throw_on_error) throw;
280  }
281 
282  }
283 
284 
289  template <class T> void json_pack(json_pack_t& x, const string& d,
290  Enum_handle<T> arg)
291  {
292  string tmp(static_cast<string>(arg));
293  json_pack(x,d,tmp);
294  }
295 
296  //Enum_handles have reference semantics
297  template <class T> void json_unpack(json_unpack_t& x, const string& d,
298  Enum_handle<T> arg)
299  {
300  std::string tmp;
301  json_unpack(x,d,tmp);
302  // remove extraneous white space
303  int (*isspace)(int)=std::isspace;
304  std::string::iterator end=std::remove_if(tmp.begin(),tmp.end(),isspace);
305  arg=tmp.substr(0,end-tmp.begin());
306  }
307 
309  template <class T> typename
310  enable_if<is_sequence<T>, void>::T
311  json_unpackp(json_unpack_t& o, const string& d, T& a, dummy<1> dum=0)
312  {
313  try
314  {
315  const json_spirit::mValue& val=json_find(o,d);
316  if (val.type()!=json_spirit::array_type)
317  throw json_pack_error("%s is not an array",d.c_str());
318  else
319  {
320  const json_spirit::mArray& arr=val.get_array();
321  for (size_t i=0; i<arr.size(); ++i)
322  {
323  typename T::value_type v;
324  json_unpack_t j(arr[i]);
325  json_unpack(j,"",v);
326  a.push_back(v);
327  }
328  }
329  }
330  catch (json_pack_error&)
331  {
332  if (o.throw_on_error) throw;
333  }
334  }
335 
336  template <class T1, class T2>
337  void json_pack(json_pack_t& o, const string& d, std::pair<T1,T2>& a)
338  {
339  json_pack(o,d+".first",a.first);
340  json_pack(o,d+".second",a.second);
341  }
342 
343  template <class T1, class T2>
344  void json_unpackp(json_unpack_t& o, const string& d, std::pair<T1,T2>& a)
345  {
346  json_unpack(o,d+".first",a.first);
347  json_unpack(o,d+".second",a.second);
348  }
349 
350  template <class T> typename
351  enable_if<Or<is_sequence<T>,is_associative_container<T> >, void>::T
352  json_packp(json_pack_t& o, const string& d, const T& a, dummy<1> dum=0)
353  {
354  try
355  {
356  json_spirit::mValue& parent=json_find(o,head(d));
357  if (parent.type()!=json_spirit::obj_type)
358  throw json_pack_error("attempt to pack an array member into a non-object");
359  else
360  {
361  json_spirit::mValue* v;
362  if (d.empty())
363  v=&parent;
364  else
365  v=&parent.get_obj()[tail(d)];
366 
367  json_spirit::mArray& arr=
368  (*v=json_spirit::mArray(a.size())).get_array();
369  typename T::const_iterator i=a.begin();
370  for (size_t k=0; i!=a.end(); ++i, ++k)
371  {
372  json_pack_t j;
373  json_pack(j,"",*i);
374  arr[k]=j;
375  }
376  }
377  }
378  catch (json_pack_error&)
379  {
380  if (o.throw_on_error) throw;
381  }
382  }
383 
384  template <class T> typename
385  enable_if<is_associative_container<T>, void>::T
386  json_unpackp(json_unpack_t& o, const string& d, T& a, dummy<2> dum=0)
387  {
388  try
389  {
390  const json_spirit::mValue& val=json_find(o,d);
391  if (val.type()!=json_spirit::array_type)
392  throw json_pack_error("%s is not an array",d.c_str());
393  else
394  {
395  const json_spirit::mArray& arr=val.get_array();
396  for (size_t i=0; i<arr.size(); ++i)
397  {
398  typename NonConstKeyValueType<typename T::value_type>::T v;
399  json_unpack_t j(arr[i]);
400  json_unpack(j,"",v);
401  a.insert(v);
402  }
403  }
404  }
405  catch (json_pack_error&)
406  {
407  if (o.throw_on_error) throw;
408  }
409  }
410 
411  /*
412  Method pointer serialisation (do nothing)
413  */
414  template <class C, class T>
415  void json_pack(json_pack_t& targ, const string& desc, C& c, T arg) {}
416 
417  template <class C, class T>
418  void json_unpack(json_unpack_t& targ, const string& desc, C& c, T arg) {}
419 
420  /*
421  const static support
422  */
423  template <class T>
424  void json_pack(json_pack_t& targ, const string& desc, is_const_static i, T arg)
425  {}
426 
427  template <class T>
428  void json_unpack(json_unpack_t& targ, const string& desc, is_const_static i, T arg)
429  {}
430 
431  // static methods
432  template <class T, class U>
433  void json_pack(json_pack_t&, const string&, is_const_static, const T&, U) {}
434 
435  // static methods
436  template <class T, class U>
437  void json_unpack(json_unpack_t&, const string&, is_const_static, const T&, U) {}
438 
439  template <class T>
440  void json_unpack(json_unpack_t& targ, const string& desc, const T& arg) {}
441 
442  template <class T>
443  void json_pack(json_pack_t& targ, const string& desc, Exclude<T>& arg) {}
444 
445  template <class T>
446  void json_unpack(json_unpack_t& targ, const string& desc, Exclude<T>& arg) {}
447 
449  template <class T> string json(const T& x)
450  {
451  json_pack_t j;
452  json_pack(j,"",x);
453  return write(j);
454  }
455  template <class T> void json(const T& x, const string& s)
456  {
457  json_pack_t j;
458  read(s, j);
459  json_unpack(j,"",x);
460  }
461 
462  template <class T>
463  void json_pack_onbase(json_pack_t& x,const string& d,T& a)
464  {json_pack(x,d+basename<T>(),a);}
465 
466  template <class T>
467  void json_unpack_onbase(json_unpack_t& x,const string& d,T& a)
468  {json_unpack(x,d+basename<T>(),a);}
469 
470 
471 }
472 
473 namespace classdesc_access
474 {
475  template <class T> struct access_json_pack;
476  template <class T> struct access_json_unpack;
477 }
478 
479 using classdesc::json_pack_onbase;
480 using classdesc::json_unpack_onbase;
481 
483 using classdesc::json_unpack;
484 #endif
bool throw_on_error
enable exceptions on error conditions
Definition: json_pack_base.h:40
string json(const T &x)
produce json string equivalent of object x
Definition: json_pack_base.h:449
void json_pack(json_pack_t &o, const string &d, T &a)
forward declare generic json operations
Definition: json_pack_epilogue.h:53
json_spirit::mValue & json_find(json_spirit::mValue &x, std::string name)
find an object named by name within the json object x
Definition: json_pack_base.h:66