CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
jsonParser.cc
Go to the documentation of this file.
2 #include "casm/misc/CASM_math.hh"
3 
4 namespace CASM {
5 
7 
8  jsonParser &to_json(bool value, jsonParser &json) {
9  *((json_spirit::mValue *) &json) = json_spirit::mValue(value);
10  return json;
11  }
12 
13  jsonParser &to_json(int value, jsonParser &json) {
14  *((json_spirit::mValue *) &json) = json_spirit::mValue(value);
15  return json;
16  }
17 
18  jsonParser &to_json(unsigned int value, jsonParser &json) {
19  *((json_spirit::mValue *) &json) = json_spirit::mValue(boost::uint64_t(value));
20  return json;
21  }
22 
23  jsonParser &to_json(const long int value, jsonParser &json) {
24  *((json_spirit::mValue *) &json) = json_spirit::mValue(boost::int64_t(value));
25  return json;
26  }
27 
28  jsonParser &to_json(const unsigned long int value, jsonParser &json) {
29  *((json_spirit::mValue *) &json) = json_spirit::mValue(boost::uint64_t(value));
30  return json;
31  }
32 
33  jsonParser &to_json(double value, jsonParser &json) {
34  if(value != value) {
35  return to_json("nan", json);
36  }
37  else if(value == 1.0 / 0.0) {
38  return to_json("inf", json);
39  }
40  else if(value == -1.0 / 0.0) {
41  return to_json("-inf", json);
42  }
43  else {
44  *((json_spirit::mValue *) &json) = json_spirit::mValue(value);
45  return json;
46  }
47 
48  }
49 
50  jsonParser &to_json(const std::string &value, jsonParser &json) {
51  *((json_spirit::mValue *) &json) = json_spirit::mValue(value);
52  return json;
53  }
54 
55  jsonParser &to_json(const char *value, jsonParser &json) {
56  *((json_spirit::mValue *) &json) = json_spirit::mValue(value);
57  return json;
58  }
59 
60  jsonParser &to_json(const jsonParser &value, jsonParser &json) {
61  return json = value;
62  }
63 
64 
65  template<>
66  bool from_json<bool>(const jsonParser &json) {
67  return json.get_bool();
68  }
69 
70  template<>
71  int from_json<int>(const jsonParser &json) {
72  return json.get_int();
73  }
74 
75  template<>
76  unsigned int from_json<unsigned int>(const jsonParser &json) {
77  return (unsigned int) json.get_int();
78  }
79 
80  template<>
81  long int from_json<long int>(const jsonParser &json) {
82  return (long int) json.get_int64();
83  }
84 
85  template<>
86  unsigned long int from_json<unsigned long int>(const jsonParser &json) {
87  return (unsigned long int) json.get_uint64();
88  }
89 
90  template<>
91  double from_json<double>(const jsonParser &json) {
92  double d;
93  from_json(d, json);
94  return d;
95  }
96 
97  template<>
98  std::string from_json<std::string>(const jsonParser &json) {
99  return json.get_str();
100  }
101 
102  template<>
104  return json;
105  }
106 
107 
108  void from_json(bool &value, const jsonParser &json) {
109  value = json.get_bool();
110  }
111 
112  void from_json(int &value, const jsonParser &json) {
113  value = json.get_int();
114  }
115 
116  void from_json(unsigned int &value, const jsonParser &json) {
117  value = json.get_int();
118  }
119 
120  void from_json(long int &value, const jsonParser &json) {
121  value = json.get_int64();
122  }
123 
124  void from_json(unsigned long int &value, const jsonParser &json) {
125  value = json.get_uint64();
126  }
127 
128  void from_json(double &value, const jsonParser &json) {
129  if(json.is_string()) {
130  std::string str = json.get_str();
131  if(str == "nan") {
132  value = sqrt(-1.0);
133  }
134  else if(str == "inf") {
135  value = 1.0 / 0.0;
136  }
137  else if(str == "-inf") {
138  value = -1.0 / 0.0;
139  }
140  else {
141  throw std::runtime_error("Expected json real, received string other than 'nan', 'inf', or '-inf': '" + str + "'");
142  }
143  }
144  else {
145  value = json.get_real();
146  }
147  }
148 
149  void from_json(std::string &value, const jsonParser &json) {
150  value = json.get_str();
151  }
152 
153  void from_json(jsonParser &value, const jsonParser &json) {
154  value = json;
155  }
156 
157  void from_json(fs::path &value, const jsonParser &json) {
158  value = fs::path(json.get_str());
159  }
160 
161 
162 
163  // ---- Read/Print JSON ----------------------------------
164 
165  bool jsonParser::read(std::istream &stream) {
166  return json_spirit::read_stream(stream, (json_spirit::mValue &) * this);
167  }
168 
169  bool jsonParser::read(const boost::filesystem::path &file_path) {
170  boost::filesystem::ifstream stream(file_path);
171  return read(stream);
172  }
173 
174  std::istream &operator>>(std::istream &stream, jsonParser &json) {
175  if(!json.read(stream)) {
176  std::cerr << "ERROR: Unable to successfully parse JSON file. File parsed as:\n"
177  << json
178  << "\nPlease correct input file and try again. Exiting...\n";
179  exit(1);
180  }
181  return stream;
182  }
183 
185  void jsonParser::print(std::ostream &stream, unsigned int indent, unsigned int prec) const {
186  json_spirit::write_stream((json_spirit::mValue &) *this, stream, indent, prec,
187  json_spirit::pretty_print | json_spirit::single_line_arrays);
188  };
189 
191  void jsonParser::write(const std::string &file_name, unsigned int indent, unsigned int prec) const {
192  std::ofstream file(file_name.c_str());
193  print(file, indent, prec);
194  file.close();
195  return;
196  }
197 
199  void jsonParser::write(const boost::filesystem::path &file_path, unsigned int indent, unsigned int prec) const {
200  boost::filesystem::ofstream file(file_path);
201  print(file, indent, prec);
202  file.close();
203  return;
204  }
205 
206  std::ostream &operator<< (std::ostream &stream, const jsonParser &json) {
207  json.print(stream);
208  return stream;
209  }
210 
211  bool jsonParser::almost_equal(const jsonParser &B, double tol) const {
212  if(type() != B.type()) {
213  return false;
214  }
215 
216  if(is_array()) {
217  auto f = [ = ](const jsonParser & _A, const jsonParser & _B) {
218  return _A.almost_equal(_B, tol);
219  };
220  bool res = (size() == B.size() && std::equal(begin(), end(), B.begin(), f));
221  return res;
222  }
223  else if(is_obj()) {
224  if(size() != B.size()) {
225  return false;
226  }
227  auto A_it = begin();
228  auto A_end = end();
229  auto B_it = B.begin();
230  for(; A_it != A_end; ++A_it, ++B_it) {
231  if(A_it.name() != B_it.name() || !A_it->almost_equal(*B_it, tol)) {
232  return false;
233  }
234  }
235  return true;
236  }
237  else if(is_number()) {
238  bool res = CASM::almost_equal(this->get<double>(), B.get<double>(), tol);
239  return res;
240  }
241  else {
242  bool res = (*this == B);
243  return res;
244  }
245  }
246 
247 
248  // ------ Type Checking Methods ------------------------------------
249 
251  bool jsonParser::is_null() const {
252  return type() == json_spirit::null_type;
253  }
254 
256  bool jsonParser::is_bool() const {
257  return type() == json_spirit::bool_type;
258  }
259 
261  bool jsonParser::is_int() const {
262  return type() == json_spirit::int_type;
263  }
264 
266  bool jsonParser::is_number() const {
267  return type() == json_spirit::real_type;
268  }
269 
271  bool jsonParser::is_string() const {
272  return type() == json_spirit::str_type;
273  }
274 
276  bool jsonParser::is_obj() const {
277  return type() == json_spirit::obj_type;
278  }
279 
281  bool jsonParser::is_array() const {
282  return type() == json_spirit::array_type;
283  }
284 
285 
286  // ---- Navigate the JSON data: ----------------------------
287 
290  jsonParser &jsonParser::operator[](const std::string &name) {
291 
292  json_spirit::mObject &obj = get_obj();
293  json_spirit::mObject::iterator it = obj.find(name);
294 
295  // if 'name' not found, add it and with value 'null'
296  if(it == obj.end()) {
297  obj[name] = json_spirit::mValue(json_spirit::mObject());
298  }
299  return (jsonParser &) obj[name];
300  }
301 
304  const jsonParser &jsonParser::operator[](const std::string &name) const {
305 
306  const json_spirit::mObject &obj = get_obj();
307  json_spirit::mObject::const_iterator it = obj.find(name);
308 
309  // if 'name' not found, add it and with value 'null'
310  if(it == obj.end()) {
311  throw std::runtime_error("Const operator[] access, but " + name + " does not exist");
312  }
313  return (const jsonParser &) it->second;
314  }
315 
322  return const_cast<jsonParser &>(static_cast<const jsonParser *>(this)->at(path));
323  }
324 
330  const jsonParser &jsonParser::at(const fs::path &path) const {
331  if(!path.is_relative()) {
332  throw std::invalid_argument(
333  "Error in jsonParser::operator[](const fs::path &path): path must be relative");
334  }
335  const jsonParser *curr = this;
336  for(auto it = path.begin(); it != path.end(); ++it) {
337  if(curr->is_array()) {
338  int index = std::stoi(it->string());
339  if(curr->size() > index) {
340  curr = &((*curr)[index]);
341  }
342  else {
343  std::string msg = "Error in jsonParser::at: attempted to access element outside of array range";
344  std::cerr << "path: " << path << std::endl;
345  std::cerr << "index: " << index << std::endl;
346  std::cerr << "curr->size(): " << curr->size() << std::endl;
347  throw std::invalid_argument(msg);
348  }
349  }
350  else {
351  auto res = curr->find(it->string());
352  if(res != curr->end()) {
353  curr = &((*curr)[it->string()]);
354  }
355  else {
356  std::string msg = "Error in jsonParser::at: key not found";
357  std::cerr << "path: " << path << std::endl;
358  std::cerr << "key: " << it->string() << std::endl;
359  throw std::invalid_argument(msg);
360  }
361  }
362  }
363 
364  return *curr;
365  }
366 
368  jsonParser &jsonParser::operator[](const int &element) {
369 
370  return (jsonParser &) get_array()[element];
371  }
372 
374  const jsonParser &jsonParser::operator[](const int &element) const {
375 
376  return (const jsonParser &) get_array()[element];
377  }
378 
381  auto A_it = A.cbegin();
382  auto B_it = B.cbegin();
383  while(A_it != A.cend()) {
384  if(*A_it != *B_it) {
385  if(A.is_obj() && B.is_obj()) {
386  return find_diff(*A_it, *B_it, diff / A_it.name());
387  }
388  else if(A.is_array() && B.is_array()) {
389  std::stringstream ss;
390  ss << std::distance(A.cbegin(), A_it);
391  return find_diff(*A_it, *B_it, diff / ss.str());
392  }
393  return diff;
394  }
395  ++A_it;
396  ++B_it;
397  }
398  return diff;
399  }
400 
403  auto A_it = A.cbegin();
404  auto B_it = B.cbegin();
405  while(A_it != A.cend()) {
406  if(!A_it->almost_equal(*B_it, tol)) {
407  if(A.is_obj() && B.is_obj()) {
408  if(A.size() != B.size()) {
409  return diff;
410  }
411  return find_diff(*A_it, *B_it, tol, diff / A_it.name());
412  }
413  else if(A.is_array() && B.is_array()) {
414  if(A.size() != B.size()) {
415  return diff;
416  }
417  std::stringstream ss;
418  ss << std::distance(A.cbegin(), A_it);
419  return find_diff(*A_it, *B_it, tol, diff / ss.str());
420  }
421  return diff;
422  }
423  ++A_it;
424  ++B_it;
425  }
426  return diff;
427  }
428 
431  if(is_obj())
432  return get_obj().size();
433  else if(is_array())
434  return get_array().size();
435  else
436  return 1;
437  }
438 
441  if(is_obj())
442  return iterator(this, get_obj().begin());
443  else if(is_array())
444  return iterator(this, get_array().begin());
445  else
446  return iterator(this, 0);
447  }
448 
451  return cbegin();
452  }
453 
456  if(is_obj())
457  return const_iterator(this, get_obj().cbegin());
458  else if(is_array())
459  return const_iterator(this, get_array().cbegin());
460  else
461  return const_iterator(this, 0);
462  }
463 
466  if(is_obj())
467  return iterator(this, get_obj().end());
468  else if(is_array())
469  return iterator(this, get_array().end());
470  else
471  return iterator(this, 0);
472  }
473 
476  return cend();
477  }
478 
481  if(is_obj())
482  return const_iterator(this, get_obj().cend());
483  else if(is_array())
484  return const_iterator(this, get_array().cend());
485  else
486  return const_iterator(this, 0);
487  }
488 
490  jsonParser::iterator jsonParser::find(const std::string &name) {
491  return iterator(this, get_obj().find(name));
492  }
493 
495  jsonParser::const_iterator jsonParser::find(const std::string &name) const {
496  return const_iterator(this, get_obj().find(name));
497  }
498 
500  bool jsonParser::contains(const std::string &name) const {
501  return find(name) != cend();
502  }
503 
506  json_spirit::mObject::size_type jsonParser::erase(const std::string &name) {
507  return get_obj().erase(name);
508  }
509 
510 }
511 
jsonParser & operator[](const std::string &name)
Definition: jsonParser.cc:290
size_type size() const
Returns array size if *this is a JSON array, object size if *this is a JSON object, 1 otherwise.
Definition: jsonParser.cc:430
bool is_int() const
Check if int type.
Definition: jsonParser.cc:261
void from_json(ClexDescription &desc, const jsonParser &json)
iterator end()
Returns iterator to end of JSON object or JSON array.
Definition: jsonParser.cc:465
boost::filesystem::path find_diff(const jsonParser &A, const jsonParser &B, boost::filesystem::path diff=boost::filesystem::path())
Return the location at which jsonParser 'A' != 'B' as a boost::filesystem::path.
Definition: jsonParser.cc:380
void write(const std::string &file_name, unsigned int indent=2, unsigned int prec=12) const
Write json to file.
Definition: jsonParser.cc:191
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
jsonParserIterator< true > const_iterator
Definition: jsonParser.hh:84
jsonParser & at(const fs::path &path)
Definition: jsonParser.cc:321
bool read(std::istream &stream)
Reads json from the stream.
Definition: jsonParser.cc:165
Main CASM namespace.
Definition: complete.cpp:8
iterator begin()
Returns const_iterator to beginning of JSON object or JSON array.
Definition: jsonParser.cc:440
const_iterator cend() const
Returns const_iterator to end of JSON object or JSON array.
Definition: jsonParser.cc:480
T get(Args...args) const
Get data from json, using one of several alternatives.
Definition: jsonParser.hh:729
bool is_obj() const
Check if object type.
Definition: jsonParser.cc:276
void print(std::ostream &stream, unsigned int indent=2, unsigned int prec=12) const
Print json to stream.
Definition: jsonParser.cc:185
double tol
long int from_json< long int >(const jsonParser &json)
Definition: jsonParser.cc:81
unsigned int from_json< unsigned int >(const jsonParser &json)
Definition: jsonParser.cc:76
bool is_null() const
Check if null type.
Definition: jsonParser.cc:251
size_type erase(const std::string &name)
Erase key:value pair from an object.
Definition: jsonParser.cc:506
std::ostream & operator<<(std::ostream &_stream, const FormattedPrintable &_formatted)
json_spirit::mObject::size_type size_type
Definition: jsonParser.hh:82
bool is_string() const
Check if string.
Definition: jsonParser.cc:271
bool is_bool() const
Check if bool type.
Definition: jsonParser.cc:256
std::istream & operator>>(std::istream &_in, std::vector< T > &vec)
int from_json< int >(const jsonParser &json)
Definition: jsonParser.cc:71
iterator find(const std::string &name)
Return iterator to JSON object value with 'name'.
Definition: jsonParser.cc:490
jsonParserIterator< false > iterator
Definition: jsonParser.hh:83
double from_json< double >(const jsonParser &json)
Definition: jsonParser.cc:91
bool is_number() const
Check if number type (not including int)
Definition: jsonParser.cc:266
bool almost_equal(const jsonParser &B, double tol) const
Definition: jsonParser.cc:211
bool contains(const std::string &name) const
Return true if JSON object contains 'name'.
Definition: jsonParser.cc:500
bool is_array() const
Check if array type.
Definition: jsonParser.cc:281
const_iterator cbegin() const
Returns const_iterator to beginning of JSON object or JSON array.
Definition: jsonParser.cc:455
jsonParser from_json< jsonParser >(const jsonParser &json)
Definition: jsonParser.cc:103
bool from_json< bool >(const jsonParser &json)
Definition: jsonParser.cc:66
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
unsigned long int from_json< unsigned long int >(const jsonParser &json)
Definition: jsonParser.cc:86