libfly  6.2.2
C++20 utility library for Linux, macOS, and Windows
json_iterator.hpp
1 #pragma once
2 
3 #include "fly/concepts/concepts.hpp"
4 #include "fly/types/json/concepts.hpp"
5 #include "fly/types/json/json_exception.hpp"
6 #include "fly/types/string/string.hpp"
7 
8 #include <cmath>
9 #include <cstdint>
10 #include <iterator>
11 #include <type_traits>
12 #include <variant>
13 
14 namespace fly {
15 class Json;
16 } // namespace fly
17 
18 namespace fly::detail {
19 
20 template <typename JsonIterator>
21 class JsonReverseIterator;
22 
56 template <fly::SameAs<Json> JsonType>
58 {
59  static constexpr bool is_const_iterator = std::is_const_v<JsonType>;
60 
64  using object_iterator_type = std::conditional_t<
65  is_const_iterator,
66  json_object_type::const_iterator,
67  json_object_type::iterator>;
68 
72  using array_iterator_type = std::conditional_t<
73  is_const_iterator,
74  json_array_type::const_iterator,
75  json_array_type::iterator>;
76 
80  using iterator_type = std::variant<object_iterator_type, array_iterator_type>;
81 
86 
91 
92 public:
96  using iterator_category = std::bidirectional_iterator_tag;
97  using value_type = JsonType;
98  using difference_type = typename JsonType::difference_type;
99  using reference = std::conditional_t<
100  is_const_iterator,
101  typename JsonType::const_reference,
102  typename JsonType::reference>;
103  using pointer = std::conditional_t<
104  is_const_iterator,
105  typename JsonType::const_pointer,
106  typename JsonType::pointer>;
107 
111  enum class Position : std::uint8_t
112  {
113  Begin,
114  End,
115  };
116 
120  JsonIterator() = default;
121 
131  JsonIterator(pointer json, Position position) noexcept(false);
132 
139  JsonIterator(const NonConstJsonIterator &iterator) noexcept;
140 
149  JsonIterator &operator=(const NonConstJsonIterator &iterator) noexcept;
150 
158  reference operator*() const;
159 
167  pointer operator->() const;
168 
183  reference operator[](difference_type offset) const;
184 
195  bool operator==(const JsonIterator &iterator) const;
196 
207  bool operator!=(const JsonIterator &iterator) const;
208 
220  bool operator<(const JsonIterator &iterator) const;
221 
234  bool operator<=(const JsonIterator &iterator) const;
235 
247  bool operator>(const JsonIterator &iterator) const;
248 
261  bool operator>=(const JsonIterator &iterator) const;
262 
273 
284 
296 
308 
322  JsonIterator &operator+=(difference_type offset);
323 
337  JsonIterator &operator-=(difference_type offset);
338 
352  JsonIterator operator+(difference_type offset) const;
353 
367  template <typename J>
368  friend JsonIterator<J>
369  operator+(typename JsonIterator<J>::difference_type offset, const JsonIterator<J> &iterator);
370 
384  JsonIterator operator-(difference_type offset) const;
385 
398  difference_type operator-(const JsonIterator &iterator) const;
399 
409  const typename json_object_type::key_type &key() const;
410 
418  reference value() const;
419 
420 private:
421  friend std::conditional_t<is_const_iterator, NonConstJsonIterator, ConstJsonIterator>;
423  friend fly::Json;
424 
428  template <typename... Ts>
429  static constexpr inline bool is_object_iterator = fly::SameAsAll<object_iterator_type, Ts...>;
430 
434  template <typename... Ts>
435  static constexpr inline bool is_array_iterator = fly::SameAsAll<array_iterator_type, Ts...>;
436 
442  void validate_iterator() const;
443 
452  void validate_iterator(const JsonIterator &iterator) const;
453 
466  template <typename T>
467  void validate_offset(const T &it, difference_type offset) const;
468 
478  template <typename T>
479  void validate_dereference(const T &it) const;
480 
481  pointer m_json {nullptr};
482  iterator_type m_iterator;
483 };
484 
485 //==================================================================================================
486 template <fly::SameAs<Json> JsonType>
487 JsonIterator<JsonType>::JsonIterator(pointer json, Position position) noexcept(false) : m_json(json)
488 {
489  auto visitor = [this, &position](auto &value) noexcept(JsonIterable<decltype(value)>) {
490  if constexpr (JsonIterable<decltype(value)>)
491  {
492  switch (position)
493  {
494  case Position::Begin:
495  m_iterator = value.begin();
496  break;
497  case Position::End:
498  m_iterator = value.end();
499  break;
500  }
501  }
502  else
503  {
504  throw JsonIteratorException(*m_json, "JSON type invalid for iteration");
505  }
506  };
507 
508  if (m_json != nullptr)
509  {
510  std::visit(std::move(visitor), m_json->m_value);
511  }
512 }
513 
514 //==================================================================================================
515 template <fly::SameAs<Json> JsonType>
517  m_json(iterator.m_json)
518 {
519  auto visitor = [this](const auto &it) noexcept {
520  m_iterator = it;
521  };
522 
523  std::visit(std::move(visitor), iterator.m_iterator);
524 }
525 
526 //==================================================================================================
527 template <fly::SameAs<Json> JsonType>
530 {
531  m_json = iterator.m_json;
532 
533  auto visitor = [this](const auto &it) noexcept {
534  m_iterator = it;
535  };
536 
537  std::visit(std::move(visitor), iterator.m_iterator);
538  return *this;
539 }
540 
541 //==================================================================================================
542 template <fly::SameAs<Json> JsonType>
543 auto JsonIterator<JsonType>::operator*() const -> reference
544 {
545  validate_iterator();
546 
547  auto visitor = [this](const auto &it) -> reference {
548  this->validate_dereference(it);
549 
550  if constexpr (is_object_iterator<decltype(it)>)
551  {
552  return it->second;
553  }
554  else if constexpr (is_array_iterator<decltype(it)>)
555  {
556  return *it;
557  }
558  };
559 
560  return std::visit(std::move(visitor), m_iterator);
561 }
562 
563 //==================================================================================================
564 template <fly::SameAs<Json> JsonType>
565 auto JsonIterator<JsonType>::operator->() const -> pointer
566 {
567  validate_iterator();
568 
569  auto visitor = [this](const auto &it) -> pointer {
570  this->validate_dereference(it);
571 
572  if constexpr (is_object_iterator<decltype(it)>)
573  {
574  return &(it->second);
575  }
576  else if constexpr (is_array_iterator<decltype(it)>)
577  {
578  return &(*it);
579  }
580  };
581 
582  return std::visit(std::move(visitor), m_iterator);
583 }
584 
585 //==================================================================================================
586 template <fly::SameAs<Json> JsonType>
587 auto JsonIterator<JsonType>::operator[](difference_type offset) const -> reference
588 {
589  validate_iterator();
590 
591  auto visitor = [&](const auto &it) -> reference {
592  if constexpr (is_array_iterator<decltype(it)>)
593  {
594  validate_offset(it, offset);
595 
596  auto next = std::next(it, offset);
597  validate_dereference(next);
598 
599  return *next;
600  }
601  else
602  {
603  throw JsonIteratorException(*m_json, "JSON type invalid for offset operator");
604  }
605  };
606 
607  return std::visit(std::move(visitor), m_iterator);
608 }
609 
610 //==================================================================================================
611 template <fly::SameAs<Json> JsonType>
613 {
614  validate_iterator(iterator);
615  return m_iterator == iterator.m_iterator;
616 }
617 
618 //==================================================================================================
619 template <fly::SameAs<Json> JsonType>
621 {
622  return !(*this == iterator);
623 }
624 
625 //==================================================================================================
626 template <fly::SameAs<Json> JsonType>
628 {
629  validate_iterator(iterator);
630 
631  auto visitor = [this](const auto &it1, const auto &it2) -> bool {
632  if constexpr (is_array_iterator<decltype(it1), decltype(it2)>)
633  {
634  return it1 < it2;
635  }
636  else
637  {
638  throw JsonIteratorException(*m_json, "JSON type invalid for comparison operator");
639  }
640  };
641 
642  return std::visit(std::move(visitor), m_iterator, iterator.m_iterator);
643 }
644 
645 //==================================================================================================
646 template <fly::SameAs<Json> JsonType>
648 {
649  return !(iterator < *this);
650 }
651 
652 //==================================================================================================
653 template <fly::SameAs<Json> JsonType>
655 {
656  return !(*this <= iterator);
657 }
658 
659 //==================================================================================================
660 template <fly::SameAs<Json> JsonType>
662 {
663  return !(*this < iterator);
664 }
665 
666 //==================================================================================================
667 template <fly::SameAs<Json> JsonType>
669 {
670  auto result = *this;
671  ++(*this);
672 
673  return result;
674 }
675 
676 //==================================================================================================
677 template <fly::SameAs<Json> JsonType>
679 {
680  validate_iterator();
681 
682  auto visitor = [this](auto &it) -> JsonIterator & {
683  validate_offset(it, 1);
684  std::advance(it, 1);
685 
686  return *this;
687  };
688 
689  return std::visit(std::move(visitor), m_iterator);
690 }
691 
692 //==================================================================================================
693 template <fly::SameAs<Json> JsonType>
695 {
696  auto result = *this;
697  --(*this);
698 
699  return result;
700 }
701 
702 //==================================================================================================
703 template <fly::SameAs<Json> JsonType>
705 {
706  validate_iterator();
707 
708  auto visitor = [this](auto &it) -> JsonIterator & {
709  validate_offset(it, -1);
710  std::advance(it, -1);
711 
712  return *this;
713  };
714 
715  return std::visit(std::move(visitor), m_iterator);
716 }
717 
718 //==================================================================================================
719 template <fly::SameAs<Json> JsonType>
720 auto JsonIterator<JsonType>::operator+=(difference_type offset) -> JsonIterator &
721 {
722  validate_iterator();
723 
724  auto visitor = [this, &offset](auto &it) {
725  if constexpr (is_array_iterator<decltype(it)>)
726  {
727  validate_offset(it, offset);
728  std::advance(it, offset);
729  }
730  else
731  {
732  throw JsonIteratorException(*m_json, "JSON type invalid for iterator offset");
733  }
734  };
735 
736  std::visit(std::move(visitor), m_iterator);
737  return *this;
738 }
739 
740 //==================================================================================================
741 template <fly::SameAs<Json> JsonType>
742 auto JsonIterator<JsonType>::operator-=(difference_type offset) -> JsonIterator &
743 {
744  return *this += -offset;
745 }
746 
747 //==================================================================================================
748 template <fly::SameAs<Json> JsonType>
749 auto JsonIterator<JsonType>::operator+(difference_type offset) const -> JsonIterator
750 {
751  auto result = *this;
752  result += offset;
753 
754  return result;
755 }
756 
757 //==================================================================================================
758 template <fly::SameAs<Json> JsonType>
759 JsonIterator<JsonType> operator+(
760  typename JsonIterator<JsonType>::difference_type offset,
761  const JsonIterator<JsonType> &iterator)
762 {
763  auto result = iterator;
764  result += offset;
765 
766  return result;
767 }
768 
769 //==================================================================================================
770 template <fly::SameAs<Json> JsonType>
771 auto JsonIterator<JsonType>::operator-(difference_type offset) const -> JsonIterator
772 {
773  auto result = *this;
774  result -= offset;
775 
776  return result;
777 }
778 
779 //==================================================================================================
780 template <fly::SameAs<Json> JsonType>
781 auto JsonIterator<JsonType>::operator-(const JsonIterator &iterator) const -> difference_type
782 {
783  validate_iterator(iterator);
784 
785  auto visitor = [this](const auto &it1, const auto &it2) -> difference_type {
786  if constexpr (is_array_iterator<decltype(it1), decltype(it2)>)
787  {
788  return std::distance(it2, it1);
789  }
790  else
791  {
792  throw JsonIteratorException(*m_json, "JSON type invalid for iterator difference");
793  }
794  };
795 
796  return std::visit(std::move(visitor), m_iterator, iterator.m_iterator);
797 }
798 
799 //==================================================================================================
800 template <fly::SameAs<Json> JsonType>
801 const typename json_object_type::key_type &JsonIterator<JsonType>::key() const
802 {
803  validate_iterator();
804 
805  auto visitor = [this](const auto &it) -> const typename json_object_type::key_type & {
806  if constexpr (is_object_iterator<decltype(it)>)
807  {
808  validate_dereference(it);
809  return it->first;
810  }
811  else
812  {
813  throw JsonIteratorException(*m_json, "JSON type is not keyed");
814  }
815  };
816 
817  return std::visit(std::move(visitor), m_iterator);
818 }
819 
820 //==================================================================================================
821 template <fly::SameAs<Json> JsonType>
822 auto JsonIterator<JsonType>::value() const -> reference
823 {
824  return *(*this);
825 }
826 
827 //==================================================================================================
828 template <fly::SameAs<Json> JsonType>
830 {
831  if (m_json == nullptr)
832  {
833  throw NullJsonException();
834  }
835 }
836 
837 //==================================================================================================
838 template <fly::SameAs<Json> JsonType>
839 void JsonIterator<JsonType>::validate_iterator(const JsonIterator &iterator) const
840 {
841  validate_iterator();
842  iterator.validate_iterator();
843 
844  if (m_json != iterator.m_json)
845  {
846  throw BadJsonComparisonException(*m_json, *iterator.m_json);
847  }
848 }
849 
850 //==================================================================================================
851 template <fly::SameAs<Json> JsonType>
852 template <typename T>
853 void JsonIterator<JsonType>::validate_offset(const T &it, difference_type offset) const
854 
855 {
856  difference_type distance = 0;
857 
858  if (offset >= 0)
859  {
860  const JsonIterator end = m_json->end();
861  distance = std::distance(it, std::get<T>(end.m_iterator));
862  }
863  else
864  {
865  const JsonIterator begin = m_json->begin();
866  distance = std::distance(std::get<T>(begin.m_iterator), it);
867  }
868 
869  if (std::abs(offset) > distance)
870  {
871  throw OutOfRangeJsonException(*m_json, offset);
872  }
873 }
874 
875 //==================================================================================================
876 template <fly::SameAs<Json> JsonType>
877 template <typename T>
878 void JsonIterator<JsonType>::validate_dereference(const T &it) const
879 {
880  const JsonIterator end = m_json->end();
881 
882  if (it == std::get<T>(end.m_iterator))
883  {
884  throw NullJsonException(*m_json);
885  }
886 }
887 
888 } // namespace fly::detail
Definition: json.hpp:162
Definition: json_exception.hpp:58
Definition: json_exception.hpp:88
Definition: json_iterator.hpp:58
bool operator==(const JsonIterator &iterator) const
Definition: json_iterator.hpp:612
const json_object_type::key_type & key() const
Definition: json_iterator.hpp:801
std::bidirectional_iterator_tag iterator_category
Definition: json_iterator.hpp:96
bool operator<=(const JsonIterator &iterator) const
Definition: json_iterator.hpp:647
bool operator>=(const JsonIterator &iterator) const
Definition: json_iterator.hpp:661
reference operator[](difference_type offset) const
Definition: json_iterator.hpp:587
bool operator!=(const JsonIterator &iterator) const
Definition: json_iterator.hpp:620
bool operator>(const JsonIterator &iterator) const
Definition: json_iterator.hpp:654
JsonIterator & operator+=(difference_type offset)
Definition: json_iterator.hpp:720
reference operator*() const
Definition: json_iterator.hpp:543
reference value() const
Definition: json_iterator.hpp:822
JsonIterator & operator++()
Definition: json_iterator.hpp:678
JsonIterator operator+(difference_type offset) const
Definition: json_iterator.hpp:749
JsonIterator & operator--()
Definition: json_iterator.hpp:704
Position
Definition: json_iterator.hpp:112
JsonIterator operator-(difference_type offset) const
Definition: json_iterator.hpp:771
bool operator<(const JsonIterator &iterator) const
Definition: json_iterator.hpp:627
JsonIterator & operator-=(difference_type offset)
Definition: json_iterator.hpp:742
pointer operator->() const
Definition: json_iterator.hpp:565
JsonIterator & operator=(const NonConstJsonIterator &iterator) noexcept
Definition: json_iterator.hpp:529
friend JsonIterator< J > operator+(typename JsonIterator< J >::difference_type offset, const JsonIterator< J > &iterator)
Definition: json_reverse_iterator.hpp:22