A library for working with phylogenetic and population genetic data.
v0.27.0
formats/json/iterator.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_FORMATS_JSON_ITERATOR_H_
2 #define GENESIS_UTILS_FORMATS_JSON_ITERATOR_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2017 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@h-its.org>
23  Exelixis Lab, Heidelberg Institute for Theoretical Studies
24  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
25 */
26 
27 /*
28  The code in this and the following source files is a heavily altered adaption of the excellent
29  "JSON for Modern C++" library by Niels Lohmann, see https://github.com/nlohmann/json
30 
31  * lib/utils/formats/json/document.hpp
32  * lib/utils/formats/json/document.cpp
33  * lib/utils/formats/json/iterator.hpp
34 
35  We adapted the original code by splitting it into different classes, using our naming convention
36  and name spaces, removed not needed functionality and wrote our own reading/parsing routines.
37 
38  For the files listed above, we need to include the following original license:
39 
40  MIT License
41 
42  Copyright (c) 2013-2017 Niels Lohmann
43 
44  Permission is hereby granted, free of charge, to any person obtaining a copy
45  of this software and associated documentation files (the "Software"), to deal
46  in the Software without restriction, including without limitation the rights
47  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48  copies of the Software, and to permit persons to whom the Software is
49  furnished to do so, subject to the following conditions:
50 
51  The above copyright notice and this permission notice shall be included in all
52  copies or substantial portions of the Software.
53 
54  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
60  SOFTWARE.
61  */
62 
71 
72 #include <cassert>
73 #include <stdexcept>
74 
75 namespace genesis {
76 namespace utils {
77 
78 // =================================================================================================
79 // Json Iterator
80 // =================================================================================================
81 
101 template<typename U>
102 class JsonIterator : public std::iterator<std::random_access_iterator_tag, U>
103 {
104  // -------------------------------------------------------------------------
105  // Friends and Asserts
106  // -------------------------------------------------------------------------
107 
108  // Allow JsonDocument to access private members
109  friend class JsonDocument;
110 
111  // make sure U is JsonDocument or const JsonDocument
112  static_assert(
113  std::is_same<U, JsonDocument>::value or
114  std::is_same<U, const JsonDocument>::value,
115  "JsonIterator only accepts (const) JsonDocument."
116  );
117 
118  // -------------------------------------------------------------------------
119  // Typedefs and Enums
120  // -------------------------------------------------------------------------
121 
122 public:
123 
126 
127  using pointer = typename std::conditional<std::is_const<U>::value,
129  typename JsonDocument::pointer
130  >::type;
131  using reference = typename std::conditional<std::is_const<U>::value,
133  typename JsonDocument::reference
134  >::type;
135 
136  using iterator_category = std::bidirectional_iterator_tag;
137 
138  // -------------------------------------------------------------------------
139  // Primitive Iterator
140  // -------------------------------------------------------------------------
141 
151  {
152  public:
153 
154  // set iterator to a defined beginning
155  void set_begin() noexcept
156  {
157  iterator_ = begin_value;
158  }
159 
160  // set iterator to a defined past the end
161  void set_end() noexcept
162  {
163  iterator_ = end_value;
164  }
165 
166  // return whether the iterator can be dereferenced
167  constexpr bool is_begin() const noexcept
168  {
169  return (iterator_ == begin_value);
170  }
171 
172  // return whether the iterator is at end
173  constexpr bool is_end() const noexcept
174  {
175  return (iterator_ == end_value);
176  }
177 
178  // return reference to the value to change and compare
179  operator difference_type& () noexcept
180  {
181  return iterator_;
182  }
183 
184  // return value to compare
185  constexpr operator difference_type () const noexcept
186  {
187  return iterator_;
188  }
189 
190  private:
191 
192  static constexpr difference_type begin_value = 0;
193  static constexpr difference_type end_value = begin_value + 1;
194 
195  // iterator as signed integer type
196  difference_type iterator_ = std::numeric_limits<std::ptrdiff_t>::denorm_min();
197  };
198 
199  // -------------------------------------------------------------------------
200  // Internal Iterator
201  // -------------------------------------------------------------------------
202 
210  {
211  // iterator for JSON objects
212  typename JsonDocument::ObjectType::iterator object_iterator;
213 
214  // iterator for JSON arrays
215  typename JsonDocument::ArrayType::iterator array_iterator;
216 
217  // generic iterator for all other types
219 
220  // create an uninitialized InternalIterator
221  InternalIterator() noexcept
222  : object_iterator()
223  , array_iterator()
225  {}
226  };
227 
228  // -------------------------------------------------------------------------
229  // Constructors and Rule of Five
230  // -------------------------------------------------------------------------
231 
232 public:
233 
234  JsonIterator() = default;
235 
239  explicit JsonIterator( pointer object )
240  : object_(object)
241  {
242  assert(object_ != nullptr);
243 
244  switch( object_->type_ ) {
246  iterator_.object_iterator = typename JsonDocument::ObjectType::iterator();
247  break;
248  }
249 
251  iterator_.array_iterator = typename JsonDocument::ArrayType::iterator();
252  break;
253  }
254 
255  default: {
257  break;
258  }
259  }
260  }
261 
265  JsonIterator(const JsonIterator& other) noexcept
266  : object_(other.object_)
267  , iterator_(other.iterator_)
268  {}
269 
274  std::is_nothrow_move_constructible<pointer>::value and
275  std::is_nothrow_move_assignable<pointer>::value and
276  std::is_nothrow_move_constructible<InternalIterator>::value and
277  std::is_nothrow_move_assignable<InternalIterator>::value
278  ) {
279  std::swap(object_, other.object_);
280  std::swap(iterator_, other.iterator_);
281  return *this;
282  }
283 
284  // -------------------------------------------------------------------------
285  // Operators
286  // -------------------------------------------------------------------------
287 
288 public:
289 
295  {
296  assert(object_ != nullptr);
297 
298  switch( object_->type_ ) {
300  assert(iterator_.object_iterator != object_->value_.object->end());
301  return iterator_.object_iterator->second;
302  }
304  assert(iterator_.array_iterator != object_->value_.array->end());
305  return *iterator_.array_iterator;
306  }
308  throw std::out_of_range("Cannot get value from Json Iterator.");
309  }
310  default: {
311  if( iterator_.primitive_iterator.is_begin() ) {
312  return *object_;
313  }
314 
315  throw std::out_of_range("Cannot get value from Json Iterator.");
316  }
317  }
318  }
319 
325  {
326  assert(object_ != nullptr);
327 
328  switch( object_->type_ ) {
330  assert(iterator_.object_iterator != object_->value_.object->end());
331  return &(iterator_.object_iterator->second);
332  }
334  assert(iterator_.array_iterator != object_->value_.array->end());
335  return &*iterator_.array_iterator;
336  }
337  default: {
338  if( iterator_.primitive_iterator.is_begin() ) {
339  return object_;
340  }
341 
342  throw std::out_of_range("cannot get value");
343  }
344  }
345  }
346 
352  {
353  auto result = *this;
354  ++(*this);
355  return result;
356  }
357 
363  {
364  assert(object_ != nullptr);
365 
366  switch( object_->type_ ) {
368  std::advance(iterator_.object_iterator, 1);
369  break;
370  }
372  std::advance(iterator_.array_iterator, 1);
373  break;
374  }
375  default: {
376  ++iterator_.primitive_iterator;
377  break;
378  }
379  }
380 
381  return *this;
382  }
383 
389  {
390  auto result = *this;
391  --(*this);
392  return result;
393  }
394 
400  {
401  assert(object_ != nullptr);
402 
403  switch( object_->type_ ) {
405  std::advance(iterator_.object_iterator, -1);
406  break;
407  }
409  std::advance(iterator_.array_iterator, -1);
410  break;
411  }
412  default: {
413  --iterator_.primitive_iterator;
414  break;
415  }
416  }
417 
418  return *this;
419  }
420 
425  bool operator==(const JsonIterator& other) const
426  {
427  // if objects are not the same, the comparison is undefined
428  if( object_ != other.object_ ) {
429  throw std::domain_error("Cannot compare Json Iterators of different containers.");
430  }
431 
432  assert(object_ != nullptr);
433 
434  switch( object_->type_ ) {
436  return (iterator_.object_iterator == other.iterator_.object_iterator);
437  }
439  return (iterator_.array_iterator == other.iterator_.array_iterator);
440  }
441  default: {
442  return (iterator_.primitive_iterator == other.iterator_.primitive_iterator);
443  }
444  }
445  }
446 
451  bool operator!=(const JsonIterator& other) const
452  {
453  return not operator==(other);
454  }
455 
460  bool operator<(const JsonIterator& other) const
461  {
462  // if objects are not the same, the comparison is undefined
463  if( object_ != other.object_ ) {
464  throw std::domain_error("Cannot compare Json Iterators of different containers.");
465  }
466 
467  assert(object_ != nullptr);
468 
469  switch( object_->type_ ) {
471  throw std::domain_error("Cannot compare order of Json object iterators.");
472  }
474  return (iterator_.array_iterator < other.iterator_.array_iterator);
475  }
476  default: {
477  return (iterator_.primitive_iterator < other.iterator_.primitive_iterator);
478  }
479  }
480  }
481 
486  bool operator<=(const JsonIterator& other) const
487  {
488  return not other.operator < (*this);
489  }
490 
495  bool operator>(const JsonIterator& other) const
496  {
497  return not operator<=(other);
498  }
499 
504  bool operator>=(const JsonIterator& other) const
505  {
506  return not operator<(other);
507  }
508 
514  {
515  assert(object_ != nullptr);
516 
517  switch( object_->type_ ) {
519  throw std::domain_error("Cannot use offsets with Json object iterators.");
520  }
522  std::advance(iterator_.array_iterator, i);
523  break;
524  }
525  default: {
526  iterator_.primitive_iterator += i;
527  break;
528  }
529  }
530 
531  return *this;
532  }
533 
539  {
540  return operator+=(-i);
541  }
542 
548  {
549  auto result = *this;
550  result += i;
551  return result;
552  }
553 
559  {
560  auto result = *this;
561  result -= i;
562  return result;
563  }
564 
570  {
571  assert(object_ != nullptr);
572 
573  switch( object_->type_ ) {
575  throw std::domain_error("Cannot use offsets with Json object iterators.");
576  }
577 
579  return iterator_.array_iterator - other.iterator_.array_iterator;
580  }
581 
582  default: {
583  return iterator_.primitive_iterator - other.iterator_.primitive_iterator;
584  }
585  }
586  }
587 
593  {
594  assert(object_ != nullptr);
595 
596  switch( object_->type_ ) {
598  throw std::domain_error("Cannot use operator[] for Json object iterators.");
599  }
600 
602  return *std::next(iterator_.array_iterator, n);
603  }
604 
606  throw std::out_of_range("Cannot get value from Json Iterator.");
607  }
608 
609  default: {
610  if( iterator_.primitive_iterator == -n ) {
611  return *object_;
612  }
613 
614  throw std::out_of_range("Cannot get value from Json Iterator.");
615  }
616  }
617  }
618 
619  // -------------------------------------------------------------------------
620  // Key Value Access for Objects
621  // -------------------------------------------------------------------------
622 
627  typename JsonDocument::ObjectType::key_type key() const
628  {
629  assert(object_ != nullptr);
630 
631  if( object_->is_object() ) {
632  return iterator_.object_iterator->first;
633  }
634 
635  throw std::domain_error("Cannot use key() for non-object Json Iterators.");
636  }
637 
642  reference value() const
643  {
644  return operator*();
645  }
646 
647  // -------------------------------------------------------------------------
648  // Internal Helpers
649  // -------------------------------------------------------------------------
650 
651 private:
652 
657  void set_begin() noexcept
658  {
659  assert(object_ != nullptr);
660 
661  switch( object_->type_ ) {
663  iterator_.object_iterator = object_->value_.object->begin();
664  break;
665  }
667  iterator_.array_iterator = object_->value_.array->begin();
668  break;
669  }
671  // set to end so begin()==end() is true: null is empty
672  iterator_.primitive_iterator.set_end();
673  break;
674  }
675  default: {
676  iterator_.primitive_iterator.set_begin();
677  break;
678  }
679  }
680  }
681 
686  void set_end() noexcept
687  {
688  assert(object_ != nullptr);
689 
690  switch( object_->type_ ) {
692  iterator_.object_iterator = object_->value_.object->end();
693  break;
694  }
696  iterator_.array_iterator = object_->value_.array->end();
697  break;
698  }
699  default: {
700  iterator_.primitive_iterator.set_end();
701  break;
702  }
703  }
704  }
705 
706  // -------------------------------------------------------------------------
707  // Member Data
708  // -------------------------------------------------------------------------
709 
710 private:
711  pointer object_ = nullptr;
712  InternalIterator iterator_ = InternalIterator();
713 
714 };
715 
716 } // namespace utils
717 } // namespace genesis
718 
719 #endif // include guard
genesis::utils::JsonIterator::operator++
JsonIterator & operator++()
Pre-increment (++it).
Definition: formats/json/iterator.hpp:362
genesis::placement::swap
void swap(Sample &lhs, Sample &rhs)
Definition: sample.cpp:104
genesis::utils::JsonIterator::PrimitiveIterator
an iterator for primitive JSON types
Definition: formats/json/iterator.hpp:150
genesis::utils::JsonIterator::operator>
bool operator>(const JsonIterator &other) const
comparison: greater than
Definition: formats/json/iterator.hpp:495
genesis::utils::JsonIterator::operator[]
reference operator[](difference_type n) const
access to successor
Definition: formats/json/iterator.hpp:592
genesis::utils::JsonDocument::value_type
JsonDocument value_type
Definition: json/document.hpp:129
genesis::utils::JsonIterator::PrimitiveIterator::set_end
void set_end() noexcept
Definition: formats/json/iterator.hpp:161
genesis::utils::JsonIterator::operator+=
JsonIterator & operator+=(difference_type i)
add to iterator
Definition: formats/json/iterator.hpp:513
genesis::utils::JsonDocument::ValueType::kNull
@ kNull
genesis::utils::JsonIterator::operator==
bool operator==(const JsonIterator &other) const
comparison: equal
Definition: formats/json/iterator.hpp:425
genesis::utils::JsonIterator::value
reference value() const
return the value of an iterator
Definition: formats/json/iterator.hpp:642
genesis::utils::JsonIterator::operator*
reference operator*() const
Return a reference to the value pointed to by the iterator.
Definition: formats/json/iterator.hpp:294
genesis::utils::JsonIterator::InternalIterator::primitive_iterator
PrimitiveIterator primitive_iterator
Definition: formats/json/iterator.hpp:218
genesis::utils::JsonIterator::pointer
typename std::conditional< std::is_const< U >::value, typename JsonDocument::const_pointer, typename JsonDocument::pointer >::type pointer
Definition: formats/json/iterator.hpp:130
genesis::utils::JsonDocument
Store a Json value of any kind.
Definition: json/document.hpp:114
genesis::utils::JsonDocument::difference_type
std::ptrdiff_t difference_type
Definition: json/document.hpp:139
genesis::utils::JsonIterator::key
JsonDocument::ObjectType::key_type key() const
return the key of an object iterator
Definition: formats/json/iterator.hpp:627
genesis::utils::JsonIterator::reference
typename std::conditional< std::is_const< U >::value, typename JsonDocument::const_reference, typename JsonDocument::reference >::type reference
Definition: formats/json/iterator.hpp:134
genesis::utils::JsonIterator::PrimitiveIterator::is_end
constexpr bool is_end() const noexcept
Definition: formats/json/iterator.hpp:173
genesis::utils::JsonIterator::operator<
bool operator<(const JsonIterator &other) const
comparison: smaller
Definition: formats/json/iterator.hpp:460
genesis::utils::JsonIterator::PrimitiveIterator::is_begin
constexpr bool is_begin() const noexcept
Definition: formats/json/iterator.hpp:167
genesis::utils::JsonIterator::operator++
JsonIterator operator++(int)
Post-increment (it++).
Definition: formats/json/iterator.hpp:351
genesis::utils::JsonIterator::JsonIterator
JsonIterator()=default
genesis::utils::JsonIterator::PrimitiveIterator::set_begin
void set_begin() noexcept
Definition: formats/json/iterator.hpp:155
genesis::utils::JsonIterator::operator->
pointer operator->() const
Dereference the Iterator.
Definition: formats/json/iterator.hpp:324
genesis::utils::JsonIterator::operator=
JsonIterator & operator=(JsonIterator other) noexcept(std::is_nothrow_move_constructible< pointer >::value and std::is_nothrow_move_assignable< pointer >::value and std::is_nothrow_move_constructible< InternalIterator >::value and std::is_nothrow_move_assignable< InternalIterator >::value)
Copy assignment.
Definition: formats/json/iterator.hpp:273
genesis::utils::JsonDocument::ValueType::kObject
@ kObject
genesis::utils::JsonDocument::const_reference
JsonDocument const & const_reference
Definition: json/document.hpp:131
document.hpp
genesis::utils::JsonIterator::operator--
JsonIterator & operator--()
pre-decrement (–it)
Definition: formats/json/iterator.hpp:399
genesis::utils::JsonIterator::iterator_category
std::bidirectional_iterator_tag iterator_category
Definition: formats/json/iterator.hpp:136
genesis::utils::JsonIterator::InternalIterator::InternalIterator
InternalIterator() noexcept
Definition: formats/json/iterator.hpp:221
genesis::utils::JsonIterator::InternalIterator::array_iterator
JsonDocument::ArrayType::iterator array_iterator
Definition: formats/json/iterator.hpp:215
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::JsonIterator::operator<=
bool operator<=(const JsonIterator &other) const
comparison: less than or equal
Definition: formats/json/iterator.hpp:486
genesis::utils::JsonIterator::JsonIterator
JsonIterator(pointer object)
Constructor for a given JSON instance.
Definition: formats/json/iterator.hpp:239
genesis::utils::JsonIterator::operator>=
bool operator>=(const JsonIterator &other) const
comparison: greater than or equal
Definition: formats/json/iterator.hpp:504
genesis::utils::JsonDocument::const_pointer
JsonDocument const * const_pointer
Definition: json/document.hpp:134
genesis::utils::JsonIterator::JsonIterator
JsonIterator(const JsonIterator &other) noexcept
Copy constructor.
Definition: formats/json/iterator.hpp:265
genesis::utils::JsonIterator::InternalIterator
an iterator value
Definition: formats/json/iterator.hpp:209
genesis::utils::JsonIterator::operator--
JsonIterator operator--(int)
Post-decrement (it–).
Definition: formats/json/iterator.hpp:388
genesis::utils::JsonDocument::ValueType::kArray
@ kArray
genesis::utils::JsonIterator::InternalIterator::object_iterator
JsonDocument::ObjectType::iterator object_iterator
Definition: formats/json/iterator.hpp:212
genesis::utils::JsonIterator::operator!=
bool operator!=(const JsonIterator &other) const
comparison: not equal
Definition: formats/json/iterator.hpp:451
genesis::utils::JsonIterator::operator-=
JsonIterator & operator-=(difference_type i)
subtract from iterator
Definition: formats/json/iterator.hpp:538
genesis::utils::JsonIterator::difference_type
typename JsonDocument::difference_type difference_type
Definition: formats/json/iterator.hpp:125
genesis::utils::JsonIterator::value_type
typename JsonDocument::value_type value_type
Definition: formats/json/iterator.hpp:124
genesis::utils::JsonIterator::operator-
JsonIterator operator-(difference_type i)
subtract from iterator
Definition: formats/json/iterator.hpp:558
genesis::utils::JsonIterator::operator+
JsonIterator operator+(difference_type i)
add to iterator
Definition: formats/json/iterator.hpp:547
genesis::utils::JsonIterator::operator-
difference_type operator-(const JsonIterator &other) const
return difference
Definition: formats/json/iterator.hpp:569
genesis::utils::JsonIterator
Template for a random access iterator for the JsonDocument class.
Definition: json/document.hpp:88