Merge pull request #1391 from pratikpc/develop
Added Support for Structured Bindings
This commit is contained in:
		
						commit
						85849940ba
					
				
					 6 changed files with 337 additions and 248 deletions
				
			
		|  | @ -17,24 +17,21 @@ namespace detail | |||
| { | ||||
| // forward declare, to be able to friend it later on
 | ||||
| template<typename IteratorType> class iteration_proxy; | ||||
| template<typename IteratorType> class iteration_proxy_value; | ||||
| 
 | ||||
| /*!
 | ||||
| @brief a template for a bidirectional iterator for the @ref basic_json class | ||||
| 
 | ||||
| This class implements a both iterators (iterator and const_iterator) for the | ||||
| @ref basic_json class. | ||||
| 
 | ||||
| @note An iterator is called *initialized* when a pointer to a JSON value has | ||||
|       been set (e.g., by a constructor or a copy assignment). If the iterator is | ||||
|       default-constructed, it is *uninitialized* and most methods are undefined. | ||||
|       **The library uses assertions to detect calls on uninitialized iterators.** | ||||
| 
 | ||||
| @requirement The class satisfies the following concept requirements: | ||||
| - | ||||
| [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
 | ||||
|   The iterator that can be moved can be moved in both directions (i.e. | ||||
|   incremented and decremented). | ||||
| 
 | ||||
| @since version 1.0.0, simplified in version 2.0.9, change to bidirectional | ||||
|        iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
 | ||||
| */ | ||||
|  | @ -45,6 +42,7 @@ class iter_impl | |||
|     friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>; | ||||
|     friend BasicJsonType; | ||||
|     friend iteration_proxy<iter_impl>; | ||||
|     friend iteration_proxy_value<iter_impl>; | ||||
| 
 | ||||
|     using object_t = typename BasicJsonType::object_t; | ||||
|     using array_t = typename BasicJsonType::array_t; | ||||
|  | @ -611,4 +609,4 @@ class iter_impl | |||
|     internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it; | ||||
| }; | ||||
| }  // namespace detail
 | ||||
| }  // namespace nlohmann
 | ||||
| } // namespace nlohmann
 | ||||
|  | @ -3,104 +3,105 @@ | |||
| #include <cstddef> // size_t
 | ||||
| #include <string> // string, to_string
 | ||||
| #include <iterator> // input_iterator_tag
 | ||||
| #include <tuple> // tuple_size, get, tuple_element
 | ||||
| 
 | ||||
| #include <nlohmann/detail/value_t.hpp> | ||||
| #include <nlohmann/detail/meta/type_traits.hpp> | ||||
| 
 | ||||
| namespace nlohmann | ||||
| { | ||||
| namespace detail | ||||
| { | ||||
| template <typename IteratorType> class iteration_proxy_value | ||||
| { | ||||
|   public: | ||||
|     using difference_type = std::ptrdiff_t; | ||||
|     using value_type = iteration_proxy_value; | ||||
|     using pointer = value_type * ; | ||||
|     using reference = value_type & ; | ||||
|     using iterator_category = std::input_iterator_tag; | ||||
| 
 | ||||
|   private: | ||||
|     /// the iterator
 | ||||
|     IteratorType anchor; | ||||
|     /// an index for arrays (used to create key names)
 | ||||
|     std::size_t array_index = 0; | ||||
|     /// last stringified array index
 | ||||
|     mutable std::size_t array_index_last = 0; | ||||
|     /// a string representation of the array index
 | ||||
|     mutable std::string array_index_str = "0"; | ||||
|     /// an empty string (to return a reference for primitive values)
 | ||||
|     const std::string empty_str = ""; | ||||
| 
 | ||||
|   public: | ||||
|     explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} | ||||
| 
 | ||||
|     /// dereference operator (needed for range-based for)
 | ||||
|     iteration_proxy_value& operator*() | ||||
|     { | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     /// increment operator (needed for range-based for)
 | ||||
|     iteration_proxy_value& operator++() | ||||
|     { | ||||
|         ++anchor; | ||||
|         ++array_index; | ||||
| 
 | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     /// equality operator (needed for InputIterator)
 | ||||
|     bool operator==(const iteration_proxy_value& o) const noexcept | ||||
|     { | ||||
|         return anchor == o.anchor; | ||||
|     } | ||||
| 
 | ||||
|     /// inequality operator (needed for range-based for)
 | ||||
|     bool operator!=(const iteration_proxy_value& o) const noexcept | ||||
|     { | ||||
|         return anchor != o.anchor; | ||||
|     } | ||||
| 
 | ||||
|     /// return key of the iterator
 | ||||
|     const std::string& key() const | ||||
|     { | ||||
|         assert(anchor.m_object != nullptr); | ||||
| 
 | ||||
|         switch (anchor.m_object->type()) | ||||
|         { | ||||
|             // use integer array index as key
 | ||||
|             case value_t::array: | ||||
|             { | ||||
|                 if (array_index != array_index_last) | ||||
|                 { | ||||
|                     array_index_str = std::to_string(array_index); | ||||
|                     array_index_last = array_index; | ||||
|                 } | ||||
|                 return array_index_str; | ||||
|             } | ||||
| 
 | ||||
|             // use key from the object
 | ||||
|             case value_t::object: | ||||
|                 return anchor.key(); | ||||
| 
 | ||||
|             // use an empty key for all primitive types
 | ||||
|             default: | ||||
|                 return empty_str; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// return value of the iterator
 | ||||
|     typename IteratorType::reference value() const | ||||
|     { | ||||
|         return anchor.value(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// proxy class for the items() function
 | ||||
| template<typename IteratorType> class iteration_proxy | ||||
| { | ||||
|   private: | ||||
|     /// helper class for iteration
 | ||||
|     class iteration_proxy_internal | ||||
|     { | ||||
|       public: | ||||
|         using difference_type = std::ptrdiff_t; | ||||
|         using value_type = iteration_proxy_internal; | ||||
|         using pointer = iteration_proxy_internal*; | ||||
|         using reference = iteration_proxy_internal&; | ||||
|         using iterator_category = std::input_iterator_tag; | ||||
| 
 | ||||
|       private: | ||||
|         /// the iterator
 | ||||
|         IteratorType anchor; | ||||
|         /// an index for arrays (used to create key names)
 | ||||
|         std::size_t array_index = 0; | ||||
|         /// last stringified array index
 | ||||
|         mutable std::size_t array_index_last = 0; | ||||
|         /// a string representation of the array index
 | ||||
|         mutable std::string array_index_str = "0"; | ||||
|         /// an empty string (to return a reference for primitive values)
 | ||||
|         const std::string empty_str = ""; | ||||
| 
 | ||||
|       public: | ||||
|         explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} | ||||
| 
 | ||||
|         /// dereference operator (needed for range-based for)
 | ||||
|         iteration_proxy_internal& operator*() | ||||
|         { | ||||
|             return *this; | ||||
|         } | ||||
| 
 | ||||
|         /// increment operator (needed for range-based for)
 | ||||
|         iteration_proxy_internal& operator++() | ||||
|         { | ||||
|             ++anchor; | ||||
|             ++array_index; | ||||
| 
 | ||||
|             return *this; | ||||
|         } | ||||
| 
 | ||||
|         /// equality operator (needed for InputIterator)
 | ||||
|         bool operator==(const iteration_proxy_internal& o) const noexcept | ||||
|         { | ||||
|             return anchor == o.anchor; | ||||
|         } | ||||
| 
 | ||||
|         /// inequality operator (needed for range-based for)
 | ||||
|         bool operator!=(const iteration_proxy_internal& o) const noexcept | ||||
|         { | ||||
|             return anchor != o.anchor; | ||||
|         } | ||||
| 
 | ||||
|         /// return key of the iterator
 | ||||
|         const std::string& key() const | ||||
|         { | ||||
|             assert(anchor.m_object != nullptr); | ||||
| 
 | ||||
|             switch (anchor.m_object->type()) | ||||
|             { | ||||
|                 // use integer array index as key
 | ||||
|                 case value_t::array: | ||||
|                 { | ||||
|                     if (array_index != array_index_last) | ||||
|                     { | ||||
|                         array_index_str = std::to_string(array_index); | ||||
|                         array_index_last = array_index; | ||||
|                     } | ||||
|                     return array_index_str; | ||||
|                 } | ||||
| 
 | ||||
|                 // use key from the object
 | ||||
|                 case value_t::object: | ||||
|                     return anchor.key(); | ||||
| 
 | ||||
|                 // use an empty key for all primitive types
 | ||||
|                 default: | ||||
|                     return empty_str; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// return value of the iterator
 | ||||
|         typename IteratorType::reference value() const | ||||
|         { | ||||
|             return anchor.value(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /// the container to iterate
 | ||||
|     typename IteratorType::reference container; | ||||
| 
 | ||||
|  | @ -110,16 +111,52 @@ template<typename IteratorType> class iteration_proxy | |||
|         : container(cont) {} | ||||
| 
 | ||||
|     /// return iterator begin (needed for range-based for)
 | ||||
|     iteration_proxy_internal begin() noexcept | ||||
|     iteration_proxy_value<IteratorType> begin() noexcept | ||||
|     { | ||||
|         return iteration_proxy_internal(container.begin()); | ||||
|         return iteration_proxy_value<IteratorType>(container.begin()); | ||||
|     } | ||||
| 
 | ||||
|     /// return iterator end (needed for range-based for)
 | ||||
|     iteration_proxy_internal end() noexcept | ||||
|     iteration_proxy_value<IteratorType> end() noexcept | ||||
|     { | ||||
|         return iteration_proxy_internal(container.end()); | ||||
|         return iteration_proxy_value<IteratorType>(container.end()); | ||||
|     } | ||||
| }; | ||||
| // Structured Bindings Support
 | ||||
| // For further reference see https://blog.tartanllama.xyz/structured-bindings/
 | ||||
| // And see https://github.com/nlohmann/json/pull/1391
 | ||||
| template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0> | ||||
| auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key()) | ||||
| { | ||||
|     return i.key(); | ||||
| } | ||||
| // Structured Bindings Support
 | ||||
| // For further reference see https://blog.tartanllama.xyz/structured-bindings/
 | ||||
| // And see https://github.com/nlohmann/json/pull/1391
 | ||||
| template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0> | ||||
| auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value()) | ||||
| { | ||||
|     return i.value(); | ||||
| } | ||||
| }  // namespace detail
 | ||||
| }  // namespace nlohmann
 | ||||
| 
 | ||||
| // The Addition to the STD Namespace is required to add
 | ||||
| // Structured Bindings Support to the iteration_proxy_value class
 | ||||
| // For further reference see https://blog.tartanllama.xyz/structured-bindings/
 | ||||
| // And see https://github.com/nlohmann/json/pull/1391
 | ||||
| namespace std | ||||
| { | ||||
| template <typename IteratorType> | ||||
| struct tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> | ||||
|             : std::integral_constant<std::size_t, 2> {}; | ||||
| 
 | ||||
| template <std::size_t N, typename IteratorType> | ||||
| struct tuple_element < | ||||
|     N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> | ||||
| { | ||||
|     using type = decltype( | ||||
|                      get<N>(std::declval < | ||||
|                             ::nlohmann::detail::iteration_proxy_value<IteratorType >> ())); | ||||
| }; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue