A toolkit for working with phylogenetic data.
v0.24.0
json/document.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2019 Lucas Czech and HITS gGmbH
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 #include <array>
74 
75 namespace genesis {
76 namespace utils {
77 
78 // =================================================================================================
79 // Constructors and Rule of Five
80 // =================================================================================================
81 
82 // ---------------------------------------------------------------------
83 // Initializer List Constructor
84 // ---------------------------------------------------------------------
85 
87  std::initializer_list<JsonDocument> init,
88  bool type_deduction,
89  ValueType manual_type
90 ) {
91 
92  // Check if each element is an array with two elements, whose first element is a string
93  bool is_an_object = std::all_of(
94  init.begin(),
95  init.end(),
96  []( JsonDocument const& element ) {
97  return element.is_array() and element.size() == 2 and element[0].is_string();
98  }
99  );
100 
101  // Adjust type if type deduction is not wanted
102  if( not type_deduction ) {
103  // if array is wanted, do not create an object though possible
104  if( manual_type == ValueType::kArray ) {
105  is_an_object = false;
106  }
107 
108  // if object is wanted but impossible, throw an exception
109  if( manual_type == ValueType::kObject and not is_an_object ) {
110  throw std::domain_error( "Invalid initializer list for creating Json object ." );
111  }
112  }
113 
114  if( is_an_object ) {
115  // the initializer list is a list of pairs -> create object
116  type_ = ValueType::kObject;
117  value_ = ValueType::kObject;
118 
119  std::for_each(
120  init.begin(),
121  init.end(),
122  [this] ( JsonDocument const& element ) {
123  value_.object->emplace( *(element[0].value_.string), element[1] );
124  }
125  );
126 
127  } else {
128  // the initializer list describes an array -> create array
129  type_ = ValueType::kArray;
130  value_.array = create<ArrayType>( init );
131  }
132 
133  assert_invariant();
134 }
135 
136 // ---------------------------------------------------------------------
137 // Copy Constructor
138 // ---------------------------------------------------------------------
139 
141  : type_( other.type_ )
142 {
143  // Check that the passed value is valid
144  other.assert_invariant();
145 
146  switch ( type_ ) {
147  case ValueType::kObject: {
148  value_ = *other.value_.object;
149  break;
150  }
151  case ValueType::kArray: {
152  value_ = *other.value_.array;
153  break;
154  }
155  case ValueType::kString: {
156  value_ = *other.value_.string;
157  break;
158  }
159  case ValueType::kBoolean: {
160  value_ = other.value_.boolean;
161  break;
162  }
164  value_ = other.value_.number_float;
165  break;
166  }
168  value_ = other.value_.number_signed;
169  break;
170  }
172  value_ = other.value_.number_unsigned;
173  break;
174  }
175  default: {
176  break;
177  }
178  }
179 
180  assert_invariant();
181 }
182 
183 // ---------------------------------------------------------------------
184 // Move Constructor
185 // ---------------------------------------------------------------------
186 
188  : type_( std::move( other.type_ ))
189  , value_( std::move( other.value_ ))
190 {
191  // Check that passed value is valid
192  other.assert_invariant();
193 
194  // Invalidate payload
195  other.type_ = ValueType::kNull;
196  other.value_ = {};
197 
198  assert_invariant();
199 }
200 
201 // ---------------------------------------------------------------------
202 // Copy Assignment
203 // ---------------------------------------------------------------------
204 
206 {
207  // check that passed value is valid
208  other.assert_invariant();
209 
210  // Use copy swap idion (with copy being done in the signature).
211  using std::swap;
212  swap( type_, other.type_ );
213  swap( value_, other.value_ );
214 
215  assert_invariant();
216  return *this;
217 }
218 
219 // ---------------------------------------------------------------------
220 // Destructor
221 // ---------------------------------------------------------------------
222 
224 {
225  assert_invariant();
226 
227  switch( type_ ) {
228  case ValueType::kArray: {
229  destroy<ArrayType>( value_.array );
230  break;
231  }
232  case ValueType::kObject: {
233  destroy<ObjectType>( value_.object );
234  break;
235  }
236  case ValueType::kString: {
237  destroy<StringType>( value_.string );
238  break;
239  }
240  default: {
241  // Nothing to do for other types.
242  break;
243  }
244  }
245 }
246 
247 // =================================================================================================
248 // Capacity
249 // =================================================================================================
250 
252 {
253  switch( type_ ) {
254  case ValueType::kNull: {
255  // null values are empty
256  return true;
257  }
258  case ValueType::kArray: {
259  // delegate call to ArrayType::empty()
260  return value_.array->empty();
261  }
262  case ValueType::kObject: {
263  // delegate call to ObjectType::empty()
264  return value_.object->empty();
265  }
266  default: {
267  // all other types are nonempty
268  return false;
269  }
270  }
271 }
272 
273 size_t JsonDocument::size() const
274 {
275  switch( type_ ) {
276  case ValueType::kNull: {
277  // null values are empty
278  return 0;
279  }
280  case ValueType::kArray: {
281  // delegate call to ArrayType::size()
282  return value_.array->size();
283  }
284  case ValueType::kObject: {
285  // delegate call to ObjectType::size()
286  return value_.object->size();
287  }
288  default: {
289  // all other types have size 1
290  return 1;
291  }
292  }
293 }
294 
296 {
297  switch( type_ ) {
298  case ValueType::kArray: {
299  // delegate call to ArrayType::max_size()
300  return value_.array->max_size();
301  }
302  case ValueType::kObject: {
303  // delegate call to ObjectType::max_size()
304  return value_.object->max_size();
305  }
306  default: {
307  // all other types have max_size() == size()
308  return size();
309  }
310  }
311 }
312 
313 // =================================================================================================
314 // Value Access
315 // =================================================================================================
316 
318 {
319  if( not is_array() ) {
320  throw std::domain_error( "Cannot use get_array() with " + type_name() + "." );
321  }
322  return *value_.array;
323 }
324 
326 {
327  if( not is_array() ) {
328  throw std::domain_error( "Cannot use get_array() with " + type_name() + "." );
329  }
330  return *value_.array;
331 }
332 
334 {
335  if( not is_object() ) {
336  throw std::domain_error( "Cannot use get_object() with " + type_name() + "." );
337  }
338  return *value_.object;
339 }
340 
342 {
343  if( not is_object() ) {
344  throw std::domain_error( "Cannot use get_object() with " + type_name() + "." );
345  }
346  return *value_.object;
347 }
348 
350 {
351  if( not is_string() ) {
352  throw std::domain_error( "Cannot use get_string() with " + type_name() + "." );
353  }
354  return *value_.string;
355 }
356 
358 {
359  if( not is_string() ) {
360  throw std::domain_error( "Cannot use get_string() with " + type_name() + "." );
361  }
362  return *value_.string;
363 }
364 
366 {
367  if( not is_boolean() ) {
368  throw std::domain_error( "Cannot use get_boolean() with " + type_name() + "." );
369  }
370  return value_.boolean;
371 }
372 
374 {
375  if( not is_boolean() ) {
376  throw std::domain_error( "Cannot use get_boolean() with " + type_name() + "." );
377  }
378  return value_.boolean;
379 }
380 
382 {
383  if( not is_number_float() ) {
384  throw std::domain_error( "Cannot use get_number_float() with " + type_name() + "." );
385  }
386  return value_.number_float;
387 }
388 
390 {
391  if( not is_number_float() ) {
392  throw std::domain_error( "Cannot use get_number_float() with " + type_name() + "." );
393  }
394  return value_.number_float;
395 }
396 
398 {
399  if( not is_number_signed() ) {
400  throw std::domain_error( "Cannot use get_number_signed() with " + type_name() + "." );
401  }
402  return value_.number_signed;
403 }
404 
406 {
407  if( not is_number_signed() ) {
408  throw std::domain_error( "Cannot use get_number_signed() with " + type_name() + "." );
409  }
410  return value_.number_signed;
411 }
412 
414 {
415  if( not is_number_unsigned() ) {
416  throw std::domain_error( "Cannot use get_number_unsigned() with " + type_name() + "." );
417  }
418  return value_.number_unsigned;
419 }
420 
422 {
423  if( not is_number_unsigned() ) {
424  throw std::domain_error( "Cannot use get_number_unsigned() with " + type_name() + "." );
425  }
426  return value_.number_unsigned;
427 }
428 
429 // =================================================================================================
430 // Element Access
431 // =================================================================================================
432 
434 {
435  // This code is also copied to the const version of the function.
436  if( is_array() ) {
437  try{
438  return value_.array->at( index );
439  } catch( ... ) {
440  throw std::out_of_range(
441  "Array index " + std::to_string( index ) + " is out of range."
442  );
443  }
444  } else {
445  throw std::domain_error( "Cannot use at() with " + type_name() );
446  }
447 }
448 
449 JsonDocument const& JsonDocument::at( size_t index ) const
450 {
451  // Copied from non-const version of the function.
452  if( is_array() ) {
453  try{
454  return value_.array->at( index );
455  } catch( ... ) {
456  throw std::out_of_range(
457  "Array index " + std::to_string( index ) + " is out of range."
458  );
459  }
460  } else {
461  throw std::domain_error( "Cannot use at() with " + type_name() );
462  }
463 }
464 
465 JsonDocument& JsonDocument::at( typename ObjectType::key_type const& key )
466 {
467  // This code is also copied to the const version of the function.
468  if( is_object() ) {
469  try{
470  return value_.object->at( key );
471  } catch( ... ) {
472  throw std::out_of_range(
473  "Invalid key '" + key + "' for object access."
474  );
475  }
476  } else {
477  throw std::domain_error( "Cannot use at() with " + type_name() );
478  }
479 }
480 
481 JsonDocument const& JsonDocument::at( typename ObjectType::key_type const& key ) const
482 {
483  // Copied from non-const version of the function.
484  if( is_object() ) {
485  try{
486  return value_.object->at( key );
487  } catch( ... ) {
488  throw std::out_of_range(
489  "Invalid key '" + key + "' for object access."
490  );
491  }
492  } else {
493  throw std::domain_error( "Cannot use at() with " + type_name() );
494  }
495 }
496 
498 {
499  // Implicitly convert null value to an empty array
500  if( is_null( )) {
501  type_ = ValueType::kArray;
502  value_.array = create<ArrayType>();
503  assert_invariant();
504  }
505 
506  if( is_array() ) {
507  // fill up array with null values if given idx is outside range
508  if( index >= value_.array->size() ) {
509  value_.array->insert(
510  value_.array->end(),
511  index - value_.array->size() + 1,
512  JsonDocument()
513  );
514  }
515 
516  return value_.array->operator[]( index );
517  } else {
518  throw std::domain_error( "Cannot use operator[] with " + type_name() );
519  }
520 }
521 
522 JsonDocument const& JsonDocument::operator [] ( size_t index ) const
523 {
524  if( is_array() ) {
525  return value_.array->operator[]( index );
526  } else {
527  throw std::domain_error( "Cannot use operator[] with " + type_name() );
528  }
529 }
530 
531 JsonDocument& JsonDocument::operator [] ( typename ObjectType::key_type const& key )
532 {
533  // implicitly convert null value to an empty object
534  if( is_null() ) {
535  type_ = ValueType::kObject;
536  value_.object = create<ObjectType>();
537  assert_invariant();
538  }
539 
540  // operator[] only works for objects
541  if( is_object() ) {
542  return value_.object->operator[]( key );
543  } else {
544  throw std::domain_error( "Cannot use operator[] with " + type_name() );
545  }
546 }
547 
548 JsonDocument const& JsonDocument::operator [] ( typename ObjectType::key_type const& key ) const
549 {
550  // const operator[] only works for objects
551  if( is_object() ) {
552  assert(value_.object->find(key) != value_.object->end());
553  return value_.object->find(key)->second;
554  } else {
555  throw std::domain_error( "Cannot use operator[] with " + type_name() );
556  }
557 }
558 
559 // =================================================================================================
560 // Lookup
561 // =================================================================================================
562 
563 JsonDocument::iterator JsonDocument::find( typename JsonDocument::ObjectType::key_type key )
564 {
565  auto result = end();
566  if( is_object() ) {
567  result.iterator_.object_iterator = value_.object->find(key);
568  }
569  return result;
570 }
571 
572 JsonDocument::const_iterator JsonDocument::find(typename JsonDocument::ObjectType::key_type key) const
573 {
574  auto result = cend();
575  if( is_object() ) {
576  result.iterator_.object_iterator = value_.object->find(key);
577  }
578  return result;
579 }
580 
581 JsonDocument::size_type JsonDocument::count(typename JsonDocument::ObjectType::key_type key) const
582 {
583  // return 0 for all nonobject types
584  return is_object() ? value_.object->count(key) : 0;
585 }
586 
587 // =================================================================================================
588 // Iterators
589 // =================================================================================================
590 
592 {
593  iterator result(this);
594  result.set_begin();
595  return result;
596 }
597 
599 {
600  return cbegin();
601 }
602 
604 {
605  const_iterator result(this);
606  result.set_begin();
607  return result;
608 }
609 
611 {
612  iterator result(this);
613  result.set_end();
614  return result;
615 }
616 
618 {
619  return cend();
620 }
621 
623 {
624  const_iterator result(this);
625  result.set_end();
626  return result;
627 }
628 
629 // =================================================================================================
630 // Modifiers
631 // =================================================================================================
632 
634 {
635  switch( type_ ) {
637  value_.number_signed = 0;
638  break;
639  }
641  value_.number_unsigned = 0;
642  break;
643  }
645  value_.number_float = 0.0;
646  break;
647  }
648  case ValueType::kBoolean: {
649  value_.boolean = false;
650  break;
651  }
652  case ValueType::kString: {
653  value_.string->clear();
654  break;
655  }
656  case ValueType::kArray: {
657  value_.array->clear();
658  break;
659  }
660  case ValueType::kObject: {
661  value_.object->clear();
662  break;
663  }
664  default: {
665  break;
666  }
667  }
668 }
669 
671 {
672  // push_back only works for null objects or arrays
673  if( not(is_null() or is_array()) ) {
674  throw std::domain_error("Cannot use push_back() with " + type_name());
675  }
676 
677  // transform null object into an array
678  if( is_null() ) {
679  type_ = ValueType::kArray;
680  value_ = ValueType::kArray;
681  assert_invariant();
682  }
683 
684  // add element to array (move semantics)
685  value_.array->push_back(std::move(val));
686  // invalidate object
687  val.type_ = ValueType::kNull;
688 }
689 
691 {
692  // push_back only works for null objects or arrays
693  if( not(is_null() or is_array()) ) {
694  throw std::domain_error("cannot use push_back() with " + type_name());
695  }
696 
697  // transform null object into an array
698  if( is_null() ) {
699  type_ = ValueType::kArray;
700  value_ = ValueType::kArray;
701  assert_invariant();
702  }
703 
704  // add element to array
705  value_.array->push_back(val);
706 }
707 
708 void JsonDocument::push_back( typename ObjectType::value_type const& val )
709 {
710  // push_back only works for null objects or objects
711  if( not(is_null() or is_object()) ) {
712  throw std::domain_error("Cannot use push_back() with " + type_name());
713  }
714 
715  // transform null object into an object
716  if( is_null() ) {
717  type_ = ValueType::kObject;
718  value_ = ValueType::kObject;
719  assert_invariant();
720  }
721 
722  // add element to array
723  value_.object->insert(val);
724 }
725 
726 // =================================================================================================
727 // Lexicographical Comparison Operators
728 // =================================================================================================
729 
731 {
732  const auto lhs_type = lhs.type();
733  const auto rhs_type = rhs.type();
734 
735  // Shorthands
739 
740  if( lhs_type == rhs_type ) {
741  switch( lhs_type ) {
742  case ValueType::kArray: {
743  return *lhs.value_.array == *rhs.value_.array;
744  }
745  case ValueType::kObject: {
746  return *lhs.value_.object == *rhs.value_.object;
747  }
748  case ValueType::kNull: {
749  return true;
750  }
751  case ValueType::kString: {
752  return *lhs.value_.string == *rhs.value_.string;
753  }
754  case ValueType::kBoolean: {
755  return lhs.value_.boolean == rhs.value_.boolean;
756  }
758  return lhs.value_.number_signed == rhs.value_.number_signed;
759  }
761  return lhs.value_.number_unsigned == rhs.value_.number_unsigned;
762  }
764  return lhs.value_.number_float == rhs.value_.number_float;
765  }
766  default: {
767  return false;
768  }
769  }
770  }
771  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberFloat ) {
772  return static_cast<NumberFloatType>(lhs.value_.number_signed) == rhs.value_.number_float;
773  }
774  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberSigned ) {
775  return lhs.value_.number_float == static_cast<NumberFloatType>(rhs.value_.number_signed);
776  }
777  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberFloat ) {
778  return static_cast<NumberFloatType>(lhs.value_.number_unsigned) == rhs.value_.number_float;
779  }
780  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberUnsigned ) {
781  return lhs.value_.number_float == static_cast<NumberFloatType>(rhs.value_.number_unsigned);
782  }
783  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberSigned ) {
784  return static_cast<NumberSignedType>(lhs.value_.number_unsigned) == rhs.value_.number_signed;
785  }
786  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberUnsigned ) {
787  return lhs.value_.number_signed == static_cast<NumberSignedType>(rhs.value_.number_unsigned);
788  }
789 
790  return false;
791 }
792 
794 {
795  const auto lhs_type = lhs.type();
796  const auto rhs_type = rhs.type();
797 
798  // Shorthands
802 
803  if( lhs_type == rhs_type ) {
804  switch( lhs_type ) {
805  case ValueType::kArray: {
806  return *lhs.value_.array < *rhs.value_.array;
807  }
808  case ValueType::kObject: {
809  return *lhs.value_.object < *rhs.value_.object;
810  }
811  case ValueType::kNull: {
812  return false;
813  }
814  case ValueType::kString: {
815  return *lhs.value_.string < *rhs.value_.string;
816  }
817  case ValueType::kBoolean: {
818  return lhs.value_.boolean < rhs.value_.boolean;
819  }
821  return lhs.value_.number_signed < rhs.value_.number_signed;
822  }
824  return lhs.value_.number_unsigned < rhs.value_.number_unsigned;
825  }
827  return lhs.value_.number_float < rhs.value_.number_float;
828  }
829  default: {
830  return false;
831  }
832  }
833  }
834  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberFloat ) {
835  return static_cast<NumberFloatType>(lhs.value_.number_signed) < rhs.value_.number_float;
836  }
837  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberSigned ) {
838  return lhs.value_.number_float < static_cast<NumberFloatType>(rhs.value_.number_signed);
839  }
840  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberFloat ) {
841  return static_cast<NumberFloatType>(lhs.value_.number_unsigned) < rhs.value_.number_float;
842  }
843  else if( lhs_type == ValueType::kNumberFloat and rhs_type == ValueType::kNumberUnsigned ) {
844  return lhs.value_.number_float < static_cast<NumberFloatType>(rhs.value_.number_unsigned);
845  }
846  else if( lhs_type == ValueType::kNumberSigned and rhs_type == ValueType::kNumberUnsigned ) {
847  return lhs.value_.number_signed < static_cast<NumberSignedType>(rhs.value_.number_unsigned);
848  }
849  else if( lhs_type == ValueType::kNumberUnsigned and rhs_type == ValueType::kNumberSigned ) {
850  return static_cast<NumberSignedType>(lhs.value_.number_unsigned) < rhs.value_.number_signed;
851  }
852 
853  // We only reach this line if we cannot compare values. In that case,
854  // we compare types. Note we have to call the operator explicitly,
855  // because MSVC has problems otherwise.
856  return operator<(lhs_type, rhs_type);
857 }
858 
860 {
861  // Use the order of the ValueType enum!
862  static std::array<uint8_t, 8> order = {{
863  0, // null
864  4, // array
865  3, // object
866  5, // string
867  1, // boolean
868  2, // float
869  2, // signed
870  2, // unsigned
871  }
872  };
873  return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)];
874 }
875 
876 // =================================================================================================
877 // Convenience Functions
878 // =================================================================================================
879 
880 std::string JsonDocument::type_name() const
881 {
882  switch( type_ ) {
883  case ValueType::kNull: {
884  return "null";
885  }
886  case ValueType::kArray: {
887  return "array";
888  }
889  case ValueType::kObject: {
890  return "object";
891  }
892  case ValueType::kString: {
893  return "string";
894  }
895  case ValueType::kBoolean: {
896  return "boolean";
897  }
899  return "float";
900  }
902  return "signed integer";
903  }
905  return "unsigned integer";
906  }
907  default: {
908  // Can only happen if we misuse the type somewhere.
909  // Make gcc happy by returning something here.
910  assert( false );
911  return "invalid type";
912  }
913  };
914 }
915 
916 } // namespace utils
917 } // namespace genesis
bool is_boolean() const
Return true iff the JSON value is a boolean.
void push_back(JsonDocument &&val)
Add a Json value to an array.
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)
bool is_number_signed() const
Return true iff the JSON value is a signed integer number.
JsonDocument & operator[](size_t index)
void swap(SequenceSet &lhs, SequenceSet &rhs)
bool is_string() const
Return true iff the JSON value is a string.
const_iterator cend() const
Return a const iterator to one past the last element.
STL namespace.
JsonDocument & operator=(JsonDocument other)
Copy assignment.
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
std::map< std::string, JsonDocument > ObjectType
bool is_object() const
Return true iff the JSON value is an object.
friend bool operator<(const_reference lhs, const_reference rhs)
Compare less than.
void swap(NexusTaxa &lhs, NexusTaxa &rhs)
Definition: taxa.hpp:209
NumberFloatType & get_number_float()
iterator begin()
Return an iterator to the first element.
const_iterator cbegin() const
Return a const iterator to the first element.
NumberUnsignedType & get_number_unsigned()
size_type count(typename ObjectType::key_type key) const
Return the number of occurrences of a key in a JSON object.
friend bool operator==(const_reference lhs, const_reference rhs)
Compare equal.
JsonDocument(std::nullptr_t=nullptr)
Create a null object.
iterator find(typename JsonDocument::ObjectType::key_type key)
Find an element in a JSON object.
Provides easy and fast logging functionality.
iterator end()
Return an iterator to one past the last element.
Store a Json value of any kind.
std::vector< JsonDocument > ArrayType
Template for a random access iterator for the JsonDocument class.
NumberSignedType & get_number_signed()
std::shared_ptr< BaseOutputTarget > to_string(std::string &target_string)
Obtain an output target for writing to a string.
bool is_number_unsigned() const
Return true iff the JSON value is an unsigned integer number.
bool is_null() const
Return true iff the JSON value is null.
std::string type_name() const
bool is_number_float() const
Return true iff the JSON value is a float number.
JsonDocument const & const_reference
bool is_array() const
Return true iff the JSON value is an array.