A toolkit for working with phylogenetic data.
v0.18.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
json/document.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
24 /*
25  The code in this and the following source files is a heavily altered adaption of the excellent
26  "JSON for Modern C++" library by Niels Lohmann, see https://github.com/nlohmann/json
27 
28  * lib/utils/formats/json/document.hpp
29  * lib/utils/formats/json/document.cpp
30  * lib/utils/formats/json/iterator.hpp
31 
32  We adapted the original code by splitting it into different classes, using our naming convention
33  and name spaces, removed not needed functionality and wrote our own reading/parsing routines.
34 
35  For the files listed above, we need to include the following original license:
36 
37  MIT License
38 
39  Copyright (c) 2013-2017 Niels Lohmann
40 
41  Permission is hereby granted, free of charge, to any person obtaining a copy
42  of this software and associated documentation files (the "Software"), to deal
43  in the Software without restriction, including without limitation the rights
44  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45  copies of the Software, and to permit persons to whom the Software is
46  furnished to do so, subject to the following conditions:
47 
48  The above copyright notice and this permission notice shall be included in all
49  copies or substantial portions of the Software.
50 
51  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
54  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
57  SOFTWARE.
58  */
59 
68 
71 
72 #include<algorithm>
73 
74 namespace genesis {
75 namespace utils {
76 
77 // =================================================================================================
78 // Constructors and Rule of Five
79 // =================================================================================================
80 
81 // ---------------------------------------------------------------------
82 // Initializer List Constructor
83 // ---------------------------------------------------------------------
84 
86  std::initializer_list<JsonDocument> init,
87  bool type_deduction,
88  ValueType manual_type
89 ) {
90 
91  // Check if each element is an array with two elements, whose first element is a string
92  bool is_an_object = std::all_of(
93  init.begin(),
94  init.end(),
95  []( JsonDocument const& element ) {
96  return element.is_array() and element.size() == 2 and element[0].is_string();
97  }
98  );
99 
100  // Adjust type if type deduction is not wanted
101  if( not type_deduction ) {
102  // if array is wanted, do not create an object though possible
103  if( manual_type == ValueType::kArray ) {
104  is_an_object = false;
105  }
106 
107  // if object is wanted but impossible, throw an exception
108  if( manual_type == ValueType::kObject and not is_an_object ) {
109  throw std::domain_error( "Invalid initializer list for creating Json object ." );
110  }
111  }
112 
113  if( is_an_object ) {
114  // the initializer list is a list of pairs -> create object
115  type_ = ValueType::kObject;
116  value_ = ValueType::kObject;
117 
118  std::for_each(
119  init.begin(),
120  init.end(),
121  [this] ( JsonDocument const& element ) {
122  value_.object->emplace( *(element[0].value_.string), element[1] );
123  }
124  );
125 
126  } else {
127  // the initializer list describes an array -> create array
128  type_ = ValueType::kArray;
129  value_.array = create<ArrayType>( init );
130  }
131 
132  assert_invariant();
133 }
134 
135 // ---------------------------------------------------------------------
136 // Copy Constructor
137 // ---------------------------------------------------------------------
138 
140  : type_( other.type_ )
141 {
142  // Check that the passed value is valid
143  other.assert_invariant();
144 
145  switch ( type_ ) {
146  case ValueType::kObject: {
147  value_ = *other.value_.object;
148  break;
149  }
150  case ValueType::kArray: {
151  value_ = *other.value_.array;
152  break;
153  }
154  case ValueType::kString: {
155  value_ = *other.value_.string;
156  break;
157  }
158  case ValueType::kBoolean: {
159  value_ = other.value_.boolean;
160  break;
161  }
163  value_ = other.value_.number_float;
164  break;
165  }
167  value_ = other.value_.number_signed;
168  break;
169  }
171  value_ = other.value_.number_unsigned;
172  break;
173  }
174  default: {
175  break;
176  }
177  }
178 
179  assert_invariant();
180 }
181 
182 // ---------------------------------------------------------------------
183 // Move Constructor
184 // ---------------------------------------------------------------------
185 
187  : type_( std::move( other.type_ ))
188  , value_( std::move( other.value_ ))
189 {
190  // Check that passed value is valid
191  other.assert_invariant();
192 
193  // Invalidate payload
194  other.type_ = ValueType::kNull;
195  other.value_ = {};
196 
197  assert_invariant();
198 }
199 
200 // ---------------------------------------------------------------------
201 // Copy Assignment
202 // ---------------------------------------------------------------------
203 
205 {
206  // check that passed value is valid
207  other.assert_invariant();
208 
209  // Use copy swap idion (with copy being done in the signature).
210  using std::swap;
211  swap( type_, other.type_ );
212  swap( value_, other.value_ );
213 
214  assert_invariant();
215  return *this;
216 }
217 
218 // ---------------------------------------------------------------------
219 // Destructor
220 // ---------------------------------------------------------------------
221 
223 {
224  assert_invariant();
225 
226  switch( type_ ) {
227  case ValueType::kArray: {
228  destroy<ArrayType>( value_.array );
229  break;
230  }
231  case ValueType::kObject: {
232  destroy<ObjectType>( value_.object );
233  break;
234  }
235  case ValueType::kString: {
236  destroy<StringType>( value_.string );
237  break;
238  }
239  default: {
240  // Nothing to do for other types.
241  break;
242  }
243  }
244 }
245 
246 // =================================================================================================
247 // Capacity
248 // =================================================================================================
249 
251 {
252  switch( type_ ) {
253  case ValueType::kNull: {
254  // null values are empty
255  return true;
256  }
257  case ValueType::kArray: {
258  // delegate call to ArrayType::empty()
259  return value_.array->empty();
260  }
261  case ValueType::kObject: {
262  // delegate call to ObjectType::empty()
263  return value_.object->empty();
264  }
265  default: {
266  // all other types are nonempty
267  return false;
268  }
269  }
270 }
271 
272 size_t JsonDocument::size() const
273 {
274  switch( type_ ) {
275  case ValueType::kNull: {
276  // null values are empty
277  return 0;
278  }
279  case ValueType::kArray: {
280  // delegate call to ArrayType::size()
281  return value_.array->size();
282  }
283  case ValueType::kObject: {
284  // delegate call to ObjectType::size()
285  return value_.object->size();
286  }
287  default: {
288  // all other types have size 1
289  return 1;
290  }
291  }
292 }
293 
295 {
296  switch( type_ ) {
297  case ValueType::kArray: {
298  // delegate call to ArrayType::max_size()
299  return value_.array->max_size();
300  }
301  case ValueType::kObject: {
302  // delegate call to ObjectType::max_size()
303  return value_.object->max_size();
304  }
305  default: {
306  // all other types have max_size() == size()
307  return size();
308  }
309  }
310 }
311 
312 // =================================================================================================
313 // Value Access
314 // =================================================================================================
315 
317 {
318  if( not is_array() ) {
319  throw std::domain_error( "Cannot use get_array() with " + type_name() + "." );
320  }
321  return *value_.array;
322 }
323 
325 {
326  if( not is_array() ) {
327  throw std::domain_error( "Cannot use get_array() with " + type_name() + "." );
328  }
329  return *value_.array;
330 }
331 
333 {
334  if( not is_object() ) {
335  throw std::domain_error( "Cannot use get_object() with " + type_name() + "." );
336  }
337  return *value_.object;
338 }
339 
341 {
342  if( not is_object() ) {
343  throw std::domain_error( "Cannot use get_object() with " + type_name() + "." );
344  }
345  return *value_.object;
346 }
347 
349 {
350  if( not is_string() ) {
351  throw std::domain_error( "Cannot use get_string() with " + type_name() + "." );
352  }
353  return *value_.string;
354 }
355 
357 {
358  if( not is_string() ) {
359  throw std::domain_error( "Cannot use get_string() with " + type_name() + "." );
360  }
361  return *value_.string;
362 }
363 
365 {
366  if( not is_boolean() ) {
367  throw std::domain_error( "Cannot use get_boolean() with " + type_name() + "." );
368  }
369  return value_.boolean;
370 }
371 
373 {
374  if( not is_boolean() ) {
375  throw std::domain_error( "Cannot use get_boolean() with " + type_name() + "." );
376  }
377  return value_.boolean;
378 }
379 
381 {
382  if( not is_number_float() ) {
383  throw std::domain_error( "Cannot use get_number_float() with " + type_name() + "." );
384  }
385  return value_.number_float;
386 }
387 
389 {
390  if( not is_number_float() ) {
391  throw std::domain_error( "Cannot use get_number_float() with " + type_name() + "." );
392  }
393  return value_.number_float;
394 }
395 
397 {
398  if( not is_number_signed() ) {
399  throw std::domain_error( "Cannot use get_number_signed() with " + type_name() + "." );
400  }
401  return value_.number_signed;
402 }
403 
405 {
406  if( not is_number_signed() ) {
407  throw std::domain_error( "Cannot use get_number_signed() with " + type_name() + "." );
408  }
409  return value_.number_signed;
410 }
411 
413 {
414  if( not is_number_unsigned() ) {
415  throw std::domain_error( "Cannot use get_number_unsigned() with " + type_name() + "." );
416  }
417  return value_.number_unsigned;
418 }
419 
421 {
422  if( not is_number_unsigned() ) {
423  throw std::domain_error( "Cannot use get_number_unsigned() with " + type_name() + "." );
424  }
425  return value_.number_unsigned;
426 }
427 
428 // =================================================================================================
429 // Element Access
430 // =================================================================================================
431 
433 {
434  // This code is also copied to the const version of the function.
435  if( is_array() ) {
436  try{
437  return value_.array->at( index );
438  } catch( ... ) {
439  throw std::out_of_range(
440  "Array index " + std::to_string( index ) + " is out of range."
441  );
442  }
443  } else {
444  throw std::domain_error( "Cannot use at() with " + type_name() );
445  }
446 }
447 
448 JsonDocument const& JsonDocument::at( size_t index ) const
449 {
450  // Copied from non-const version of the function.
451  if( is_array() ) {
452  try{
453  return value_.array->at( index );
454  } catch( ... ) {
455  throw std::out_of_range(
456  "Array index " + std::to_string( index ) + " is out of range."
457  );
458  }
459  } else {
460  throw std::domain_error( "Cannot use at() with " + type_name() );
461  }
462 }
463 
464 JsonDocument& JsonDocument::at( typename ObjectType::key_type const& key )
465 {
466  // This code is also copied to the const version of the function.
467  if( is_object() ) {
468  try{
469  return value_.object->at( key );
470  } catch( ... ) {
471  throw std::out_of_range(
472  "Invalid key '" + key + "' for object access."
473  );
474  }
475  } else {
476  throw std::domain_error( "Cannot use at() with " + type_name() );
477  }
478 }
479 
480 JsonDocument const& JsonDocument::at( typename ObjectType::key_type const& key ) const
481 {
482  // Copied from non-const version of the function.
483  if( is_object() ) {
484  try{
485  return value_.object->at( key );
486  } catch( ... ) {
487  throw std::out_of_range(
488  "Invalid key '" + key + "' for object access."
489  );
490  }
491  } else {
492  throw std::domain_error( "Cannot use at() with " + type_name() );
493  }
494 }
495 
497 {
498  // Implicitly convert null value to an empty array
499  if( is_null( )) {
500  type_ = ValueType::kArray;
501  value_.array = create<ArrayType>();
502  assert_invariant();
503  }
504 
505  if( is_array() ) {
506  // fill up array with null values if given idx is outside range
507  if( index >= value_.array->size() ) {
508  value_.array->insert(
509  value_.array->end(),
510  index - value_.array->size() + 1,
511  JsonDocument()
512  );
513  }
514 
515  return value_.array->operator[]( index );
516  } else {
517  throw std::domain_error( "Cannot use operator[] with " + type_name() );
518  }
519 }
520 
521 JsonDocument const& JsonDocument::operator [] ( size_t index ) const
522 {
523  if( is_array() ) {
524  return value_.array->operator[]( index );
525  } else {
526  throw std::domain_error( "Cannot use operator[] with " + type_name() );
527  }
528 }
529 
530 JsonDocument& JsonDocument::operator [] ( typename ObjectType::key_type const& key )
531 {
532  // implicitly convert null value to an empty object
533  if( is_null() ) {
534  type_ = ValueType::kObject;
535  value_.object = create<ObjectType>();
536  assert_invariant();
537  }
538 
539  // operator[] only works for objects
540  if( is_object() ) {
541  return value_.object->operator[]( key );
542  } else {
543  throw std::domain_error( "Cannot use operator[] with " + type_name() );
544  }
545 }
546 
547 JsonDocument const& JsonDocument::operator [] ( typename ObjectType::key_type const& key ) const
548 {
549  // const operator[] only works for objects
550  if( is_object() ) {
551  assert(value_.object->find(key) != value_.object->end());
552  return value_.object->find(key)->second;
553  } else {
554  throw std::domain_error( "Cannot use operator[] with " + type_name() );
555  }
556 }
557 
558 // =================================================================================================
559 // Lookup
560 // =================================================================================================
561 
562 JsonDocument::iterator JsonDocument::find( typename JsonDocument::ObjectType::key_type key )
563 {
564  auto result = end();
565  if( is_object() ) {
566  result.iterator_.object_iterator = value_.object->find(key);
567  }
568  return result;
569 }
570 
571 JsonDocument::const_iterator JsonDocument::find(typename JsonDocument::ObjectType::key_type key) const
572 {
573  auto result = cend();
574  if( is_object() ) {
575  result.iterator_.object_iterator = value_.object->find(key);
576  }
577  return result;
578 }
579 
580 JsonDocument::size_type JsonDocument::count(typename JsonDocument::ObjectType::key_type key) const
581 {
582  // return 0 for all nonobject types
583  return is_object() ? value_.object->count(key) : 0;
584 }
585 
586 // =================================================================================================
587 // Iterators
588 // =================================================================================================
589 
591 {
592  iterator result(this);
593  result.set_begin();
594  return result;
595 }
596 
598 {
599  return cbegin();
600 }
601 
603 {
604  const_iterator result(this);
605  result.set_begin();
606  return result;
607 }
608 
610 {
611  iterator result(this);
612  result.set_end();
613  return result;
614 }
615 
617 {
618  return cend();
619 }
620 
622 {
623  const_iterator result(this);
624  result.set_end();
625  return result;
626 }
627 
628 // =================================================================================================
629 // Modifiers
630 // =================================================================================================
631 
633 {
634  switch( type_ ) {
636  value_.number_signed = 0;
637  break;
638  }
640  value_.number_unsigned = 0;
641  break;
642  }
644  value_.number_float = 0.0;
645  break;
646  }
647  case ValueType::kBoolean: {
648  value_.boolean = false;
649  break;
650  }
651  case ValueType::kString: {
652  value_.string->clear();
653  break;
654  }
655  case ValueType::kArray: {
656  value_.array->clear();
657  break;
658  }
659  case ValueType::kObject: {
660  value_.object->clear();
661  break;
662  }
663  default: {
664  break;
665  }
666  }
667 }
668 
670 {
671  // push_back only works for null objects or arrays
672  if( not(is_null() or is_array()) ) {
673  throw std::domain_error("Cannot use push_back() with " + type_name());
674  }
675 
676  // transform null object into an array
677  if( is_null() ) {
678  type_ = ValueType::kArray;
679  value_ = ValueType::kArray;
680  assert_invariant();
681  }
682 
683  // add element to array (move semantics)
684  value_.array->push_back(std::move(val));
685  // invalidate object
686  val.type_ = ValueType::kNull;
687 }
688 
690 {
691  // push_back only works for null objects or arrays
692  if( not(is_null() or is_array()) ) {
693  throw std::domain_error("cannot use push_back() with " + type_name());
694  }
695 
696  // transform null object into an array
697  if( is_null() ) {
698  type_ = ValueType::kArray;
699  value_ = ValueType::kArray;
700  assert_invariant();
701  }
702 
703  // add element to array
704  value_.array->push_back(val);
705 }
706 
707 void JsonDocument::push_back( typename ObjectType::value_type const& val )
708 {
709  // push_back only works for null objects or objects
710  if( not(is_null() or is_object()) ) {
711  throw std::domain_error("Cannot use push_back() with " + type_name());
712  }
713 
714  // transform null object into an object
715  if( is_null() ) {
716  type_ = ValueType::kObject;
717  value_ = ValueType::kObject;
718  assert_invariant();
719  }
720 
721  // add element to array
722  value_.object->insert(val);
723 }
724 
725 // =================================================================================================
726 // Lexicographical Comparison Operators
727 // =================================================================================================
728 
730 {
731  const auto lhs_type = lhs.type();
732  const auto rhs_type = rhs.type();
733 
734  // Shorthands
735  using ValueType = JsonDocument::ValueType;
736  using NumberFloatType = JsonDocument::NumberFloatType;
737  using NumberSignedType = JsonDocument::NumberSignedType;
738 
739  if( lhs_type == rhs_type ) {
740  switch( lhs_type ) {
741  case ValueType::kArray: {
742  return *lhs.value_.array == *rhs.value_.array;
743  }
744  case ValueType::kObject: {
745  return *lhs.value_.object == *rhs.value_.object;
746  }
747  case ValueType::kNull: {
748  return true;
749  }
750  case ValueType::kString: {
751  return *lhs.value_.string == *rhs.value_.string;
752  }
753  case ValueType::kBoolean: {
754  return lhs.value_.boolean == rhs.value_.boolean;
755  }
756  case ValueType::kNumberSigned: {
757  return lhs.value_.number_signed == rhs.value_.number_signed;
758  }
759  case ValueType::kNumberUnsigned: {
760  return lhs.value_.number_unsigned == rhs.value_.number_unsigned;
761  }
762  case ValueType::kNumberFloat: {
763  return lhs.value_.number_float == rhs.value_.number_float;
764  }
765  default: {
766  return false;
767  }
768  }
769  }
770  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberFloat ) {
771  return static_cast<NumberFloatType>(lhs.value_.number_signed) == rhs.value_.number_float;
772  }
773  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberSigned ) {
774  return lhs.value_.number_float == static_cast<NumberFloatType>(rhs.value_.number_signed);
775  }
776  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberFloat ) {
777  return static_cast<NumberFloatType>(lhs.value_.number_unsigned) == rhs.value_.number_float;
778  }
779  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberUnsigned ) {
780  return lhs.value_.number_float == static_cast<NumberFloatType>(rhs.value_.number_unsigned);
781  }
782  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberSigned ) {
783  return static_cast<NumberSignedType>(lhs.value_.number_unsigned) == rhs.value_.number_signed;
784  }
785  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberUnsigned ) {
786  return lhs.value_.number_signed == static_cast<NumberSignedType>(rhs.value_.number_unsigned);
787  }
788 
789  return false;
790 }
791 
793 {
794  const auto lhs_type = lhs.type();
795  const auto rhs_type = rhs.type();
796 
797  // Shorthands
798  using ValueType = JsonDocument::ValueType;
799  using NumberFloatType = JsonDocument::NumberFloatType;
800  using NumberSignedType = JsonDocument::NumberSignedType;
801 
802  if( lhs_type == rhs_type ) {
803  switch( lhs_type ) {
804  case ValueType::kArray: {
805  return *lhs.value_.array < *rhs.value_.array;
806  }
807  case ValueType::kObject: {
808  return *lhs.value_.object < *rhs.value_.object;
809  }
810  case ValueType::kNull: {
811  return false;
812  }
813  case ValueType::kString: {
814  return *lhs.value_.string < *rhs.value_.string;
815  }
816  case ValueType::kBoolean: {
817  return lhs.value_.boolean < rhs.value_.boolean;
818  }
819  case ValueType::kNumberSigned: {
820  return lhs.value_.number_signed < rhs.value_.number_signed;
821  }
822  case ValueType::kNumberUnsigned: {
823  return lhs.value_.number_unsigned < rhs.value_.number_unsigned;
824  }
825  case ValueType::kNumberFloat: {
826  return lhs.value_.number_float < rhs.value_.number_float;
827  }
828  default: {
829  return false;
830  }
831  }
832  }
833  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberFloat ) {
834  return static_cast<NumberFloatType>(lhs.value_.number_signed) < rhs.value_.number_float;
835  }
836  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberSigned ) {
837  return lhs.value_.number_float < static_cast<NumberFloatType>(rhs.value_.number_signed);
838  }
839  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberFloat ) {
840  return static_cast<NumberFloatType>(lhs.value_.number_unsigned) < rhs.value_.number_float;
841  }
842  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberUnsigned ) {
843  return lhs.value_.number_float < static_cast<NumberFloatType>(rhs.value_.number_unsigned);
844  }
845  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberUnsigned ) {
846  return lhs.value_.number_signed < static_cast<NumberSignedType>(rhs.value_.number_unsigned);
847  }
848  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberSigned ) {
849  return static_cast<NumberSignedType>(lhs.value_.number_unsigned) < rhs.value_.number_signed;
850  }
851 
852  // We only reach this line if we cannot compare values. In that case,
853  // we compare types. Note we have to call the operator explicitly,
854  // because MSVC has problems otherwise.
855  return operator<(lhs_type, rhs_type);
856 }
857 
858 bool operator<(const JsonDocument::ValueType lhs, const JsonDocument::ValueType rhs) noexcept
859 {
860  // Use the order of the ValueType enum!
861  static constexpr std::array<uint8_t, 8> order = {{
862  0, // null
863  4, // array
864  3, // object
865  5, // string
866  1, // boolean
867  2, // float
868  2, // signed
869  2, // unsigned
870  }
871  };
872  return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)];
873 }
874 
875 // =================================================================================================
876 // Convenience Functions
877 // =================================================================================================
878 
879 std::string JsonDocument::type_name() const
880 {
881  switch( type_ ) {
882  case ValueType::kNull: {
883  return "null";
884  }
885  case ValueType::kArray: {
886  return "array";
887  }
888  case ValueType::kObject: {
889  return "object";
890  }
891  case ValueType::kString: {
892  return "string";
893  }
894  case ValueType::kBoolean: {
895  return "boolean";
896  }
898  return "float";
899  }
901  return "signed integer";
902  }
904  return "unsigned integer";
905  }
906  default: {
907  // Can only happen if we misuse the type somewhere.
908  // Make gcc happy by returning something here.
909  assert( false );
910  return "invalid type";
911  }
912  };
913 }
914 
915 } // namespace utils
916 } // namespace genesis
bool is_number_float() const
Return true iff the JSON value is a float number.
iterator end() noexcept
Return an iterator to one past the last element.
void push_back(JsonDocument &&val)
Add a Json value to an array.
std::string type_name() const
void clear()
Clears the content of a JSON value and resets it to the default value as if JsonDocument(ValueType) w...
JsonDocument & at(size_t index)
const_iterator cend() const noexcept
Return a const iterator to one past the last element.
JsonDocument & operator[](size_t index)
bool is_array() const
Return true iff the JSON value is an array.
void swap(SequenceSet &lhs, SequenceSet &rhs)
bool is_boolean() const
Return true iff the JSON value is a boolean.
bool operator<(JsonDocument::const_reference lhs, JsonDocument::const_reference rhs) noexcept
iterator begin() noexcept
Return an iterator to the first element.
JsonDocument & operator=(JsonDocument other)
Copy assignment.
std::string to_string(T const &v)
Return a string representation of a given value.
Definition: string.hpp:300
bool is_null() const
Return true iff the JSON value is null.
std::map< std::string, JsonDocument > ObjectType
bool is_number_unsigned() const
Return true iff the JSON value is an unsigned integer number.
void swap(NexusTaxa &lhs, NexusTaxa &rhs)
Definition: taxa.hpp:207
bool is_string() const
Return true iff the JSON value is a string.
NumberFloatType & get_number_float()
size_type count(typename ObjectType::key_type key) const
Return the number of occurrences of a key in a JSON object.
NumberUnsignedType & get_number_unsigned()
JsonDocument(std::nullptr_t=nullptr)
Create a null object.
bool is_number_signed() const
Return true iff the JSON value is a signed integer number.
const_iterator cbegin() const noexcept
Return a const iterator to the first element.
iterator find(typename JsonDocument::ObjectType::key_type key)
Find an element in a JSON object.
Provides easy and fast logging functionality.
Store a Json value of any kind.
std::vector< JsonDocument > ArrayType
bool operator==(SortedVector< T > const &lhs, SortedVector< T > const &rhs)
Template for a random access iterator for the JsonDocument class.
NumberSignedType & get_number_signed()
bool is_object() const
Return true iff the JSON value is an object.
JsonDocument const & const_reference