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