Branch data Line data Source code
1 : : #pragma once 2 : : 3 : : #include <cstddef> // size_t 4 : : #include <iterator> // input_iterator_tag 5 : : #include <string> // string, to_string 6 : : #include <tuple> // tuple_size, get, tuple_element 7 : : 8 : : #include <nlohmann/detail/meta/type_traits.hpp> 9 : : #include <nlohmann/detail/value_t.hpp> 10 : : 11 : : namespace nlohmann 12 : : { 13 : : namespace detail 14 : : { 15 : 0 : template <typename IteratorType> class iteration_proxy_value 16 : : { 17 : : public: 18 : : using difference_type = std::ptrdiff_t; 19 : : using value_type = iteration_proxy_value; 20 : : using pointer = value_type * ; 21 : : using reference = value_type & ; 22 : : using iterator_category = std::input_iterator_tag; 23 : : 24 : : private: 25 : : /// the iterator 26 : : IteratorType anchor; 27 : : /// an index for arrays (used to create key names) 28 : 0 : std::size_t array_index = 0; 29 : : /// last stringified array index 30 : 0 : mutable std::size_t array_index_last = 0; 31 : : /// a string representation of the array index 32 : 0 : mutable std::string array_index_str = "0"; 33 : : /// an empty string (to return a reference for primitive values) 34 : 0 : const std::string empty_str = ""; 35 : : 36 : : public: 37 : 0 : explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} 38 : : 39 : : /// dereference operator (needed for range-based for) 40 : 0 : iteration_proxy_value& operator*() 41 : : { 42 : 0 : return *this; 43 : : } 44 : : 45 : : /// increment operator (needed for range-based for) 46 : 0 : iteration_proxy_value& operator++() 47 : : { 48 : 0 : ++anchor; 49 : 0 : ++array_index; 50 : : 51 : 0 : return *this; 52 : : } 53 : : 54 : : /// equality operator (needed for InputIterator) 55 : : bool operator==(const iteration_proxy_value& o) const 56 : : { 57 : : return anchor == o.anchor; 58 : : } 59 : : 60 : : /// inequality operator (needed for range-based for) 61 : 0 : bool operator!=(const iteration_proxy_value& o) const 62 : : { 63 : 0 : return anchor != o.anchor; 64 : : } 65 : : 66 : : /// return key of the iterator 67 : 0 : const std::string& key() const 68 : : { 69 : 0 : assert(anchor.m_object != nullptr); 70 : : 71 : 0 : switch (anchor.m_object->type()) 72 : : { 73 : : // use integer array index as key 74 : : case value_t::array: 75 : : { 76 : 0 : if (array_index != array_index_last) 77 : : { 78 : 0 : array_index_str = std::to_string(array_index); 79 : 0 : array_index_last = array_index; 80 : 0 : } 81 : 0 : return array_index_str; 82 : : } 83 : : 84 : : // use key from the object 85 : : case value_t::object: 86 : 0 : return anchor.key(); 87 : : 88 : : // use an empty key for all primitive types 89 : : default: 90 : 0 : return empty_str; 91 : : } 92 : 0 : } 93 : : 94 : : /// return value of the iterator 95 : 0 : typename IteratorType::reference value() const 96 : : { 97 : 0 : return anchor.value(); 98 : : } 99 : : }; 100 : : 101 : : /// proxy class for the items() function 102 : : template<typename IteratorType> class iteration_proxy 103 : : { 104 : : private: 105 : : /// the container to iterate 106 : : typename IteratorType::reference container; 107 : : 108 : : public: 109 : : /// construct iteration proxy from a container 110 : 0 : explicit iteration_proxy(typename IteratorType::reference cont) noexcept 111 : 0 : : container(cont) {} 112 : : 113 : : /// return iterator begin (needed for range-based for) 114 : 0 : iteration_proxy_value<IteratorType> begin() noexcept 115 : : { 116 : 0 : return iteration_proxy_value<IteratorType>(container.begin()); 117 : : } 118 : : 119 : : /// return iterator end (needed for range-based for) 120 : 0 : iteration_proxy_value<IteratorType> end() noexcept 121 : : { 122 : 0 : return iteration_proxy_value<IteratorType>(container.end()); 123 : : } 124 : : }; 125 : : // Structured Bindings Support 126 : : // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 127 : : // And see https://github.com/nlohmann/json/pull/1391 128 : : template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0> 129 : : auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key()) 130 : : { 131 : : return i.key(); 132 : : } 133 : : // Structured Bindings Support 134 : : // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 135 : : // And see https://github.com/nlohmann/json/pull/1391 136 : : template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0> 137 : : auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value()) 138 : : { 139 : : return i.value(); 140 : : } 141 : : } // namespace detail 142 : : } // namespace nlohmann 143 : : 144 : : // The Addition to the STD Namespace is required to add 145 : : // Structured Bindings Support to the iteration_proxy_value class 146 : : // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 147 : : // And see https://github.com/nlohmann/json/pull/1391 148 : : namespace std 149 : : { 150 : : #if defined(__clang__) 151 : : // Fix: https://github.com/nlohmann/json/issues/1401 152 : : #pragma clang diagnostic push 153 : : #pragma clang diagnostic ignored "-Wmismatched-tags" 154 : : #endif 155 : : template <typename IteratorType> 156 : : class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> 157 : : : public std::integral_constant<std::size_t, 2> {}; 158 : : 159 : : template <std::size_t N, typename IteratorType> 160 : : class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> 161 : : { 162 : : public: 163 : : using type = decltype( 164 : : get<N>(std::declval < 165 : : ::nlohmann::detail::iteration_proxy_value<IteratorType >> ())); 166 : : }; 167 : : #if defined(__clang__) 168 : : #pragma clang diagnostic pop 169 : : #endif 170 : : } // namespace std