Unverified Commit 85849940 by Niels Lohmann Committed by GitHub

Merge pull request #1391 from pratikpc/develop

Added Support for Structured Bindings
parents 4f270e38 ebd3f458
...@@ -22,3 +22,4 @@ benchmarks/files/numbers/*.json ...@@ -22,3 +22,4 @@ benchmarks/files/numbers/*.json
cmake-build-debug cmake-build-debug
test/test-* test/test-*
/.vs
...@@ -290,9 +290,9 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) ...@@ -290,9 +290,9 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
template < template <
typename BasicJsonType, typename T, std::size_t N, typename BasicJsonType, typename T, std::size_t N,
enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
const T (&)[N]>::value, const T(&)[N]>::value,
int> = 0 > int> = 0 >
void to_json(BasicJsonType& j, const T (&arr)[N]) void to_json(BasicJsonType& j, const T(&arr)[N])
{ {
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
} }
...@@ -300,21 +300,21 @@ void to_json(BasicJsonType& j, const T (&arr)[N]) ...@@ -300,21 +300,21 @@ void to_json(BasicJsonType& j, const T (&arr)[N])
template<typename BasicJsonType, typename... Args> template<typename BasicJsonType, typename... Args>
void to_json(BasicJsonType& j, const std::pair<Args...>& p) void to_json(BasicJsonType& j, const std::pair<Args...>& p)
{ {
j = {p.first, p.second}; j = { p.first, p.second };
} }
// for https://github.com/nlohmann/json/pull/1134 // for https://github.com/nlohmann/json/pull/1134
template<typename BasicJsonType, typename T, template < typename BasicJsonType, typename T,
enable_if_t<std::is_same<T, typename iteration_proxy<typename BasicJsonType::iterator>::iteration_proxy_internal>::value, int> = 0> enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
void to_json(BasicJsonType& j, const T& b) void to_json(BasicJsonType& j, const T& b)
{ {
j = {{b.key(), b.value()}}; j = { {b.key(), b.value()} };
} }
template<typename BasicJsonType, typename Tuple, std::size_t... Idx> template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/) void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
{ {
j = {std::get<Idx>(t)...}; j = { std::get<Idx>(t)... };
} }
template<typename BasicJsonType, typename... Args> template<typename BasicJsonType, typename... Args>
......
...@@ -17,24 +17,21 @@ namespace detail ...@@ -17,24 +17,21 @@ namespace detail
{ {
// forward declare, to be able to friend it later on // forward declare, to be able to friend it later on
template<typename IteratorType> class iteration_proxy; 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 @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 This class implements a both iterators (iterator and const_iterator) for the
@ref basic_json class. @ref basic_json class.
@note An iterator is called *initialized* when a pointer to a JSON value has @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 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. default-constructed, it is *uninitialized* and most methods are undefined.
**The library uses assertions to detect calls on uninitialized iterators.** **The library uses assertions to detect calls on uninitialized iterators.**
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- -
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
The iterator that can be moved can be moved in both directions (i.e. The iterator that can be moved can be moved in both directions (i.e.
incremented and decremented). incremented and decremented).
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional @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) iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
*/ */
...@@ -45,6 +42,7 @@ class iter_impl ...@@ -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 iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
friend BasicJsonType; friend BasicJsonType;
friend iteration_proxy<iter_impl>; friend iteration_proxy<iter_impl>;
friend iteration_proxy_value<iter_impl>;
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
using array_t = typename BasicJsonType::array_t; using array_t = typename BasicJsonType::array_t;
...@@ -611,4 +609,4 @@ class iter_impl ...@@ -611,4 +609,4 @@ class iter_impl
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it; internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it;
}; };
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann
\ No newline at end of file
...@@ -3,104 +3,105 @@ ...@@ -3,104 +3,105 @@
#include <cstddef> // size_t #include <cstddef> // size_t
#include <string> // string, to_string #include <string> // string, to_string
#include <iterator> // input_iterator_tag #include <iterator> // input_iterator_tag
#include <tuple> // tuple_size, get, tuple_element
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
{ {
/// proxy class for the items() function template <typename IteratorType> class iteration_proxy_value
template<typename IteratorType> class iteration_proxy
{ {
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: private:
/// helper class for iteration /// the iterator
class iteration_proxy_internal 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*()
{ {
public: return *this;
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) /// increment operator (needed for range-based for)
iteration_proxy_internal& operator++() iteration_proxy_value& operator++()
{ {
++anchor; ++anchor;
++array_index; ++array_index;
return *this; return *this;
} }
/// equality operator (needed for InputIterator) /// equality operator (needed for InputIterator)
bool operator==(const iteration_proxy_internal& o) const noexcept bool operator==(const iteration_proxy_value& o) const noexcept
{ {
return anchor == o.anchor; return anchor == o.anchor;
} }
/// inequality operator (needed for range-based for) /// inequality operator (needed for range-based for)
bool operator!=(const iteration_proxy_internal& o) const noexcept bool operator!=(const iteration_proxy_value& o) const noexcept
{ {
return anchor != o.anchor; return anchor != o.anchor;
} }
/// return key of the iterator /// return key of the iterator
const std::string& key() const const std::string& key() const
{ {
assert(anchor.m_object != nullptr); assert(anchor.m_object != nullptr);
switch (anchor.m_object->type()) switch (anchor.m_object->type())
{
// use integer array index as key
case value_t::array:
{ {
// use integer array index as key if (array_index != array_index_last)
case value_t::array:
{ {
if (array_index != array_index_last) array_index_str = std::to_string(array_index);
{ array_index_last = array_index;
array_index_str = std::to_string(array_index);
array_index_last = array_index;
}
return array_index_str;
} }
return array_index_str;
}
// use key from the object // use key from the object
case value_t::object: case value_t::object:
return anchor.key(); return anchor.key();
// use an empty key for all primitive types // use an empty key for all primitive types
default: default:
return empty_str; return empty_str;
}
} }
}
/// return value of the iterator /// return value of the iterator
typename IteratorType::reference value() const typename IteratorType::reference value() const
{ {
return anchor.value(); return anchor.value();
} }
}; };
/// proxy class for the items() function
template<typename IteratorType> class iteration_proxy
{
private:
/// the container to iterate /// the container to iterate
typename IteratorType::reference container; typename IteratorType::reference container;
...@@ -110,16 +111,52 @@ template<typename IteratorType> class iteration_proxy ...@@ -110,16 +111,52 @@ template<typename IteratorType> class iteration_proxy
: container(cont) {} : container(cont) {}
/// return iterator begin (needed for range-based for) /// 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) /// 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 detail
} // namespace nlohmann } // 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 >> ()));
};
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment