mirror of https://gitlab.com/cppit/jucipp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
5.4 KiB
181 lines
5.4 KiB
#pragma once |
|
|
|
#include <cstddef> // size_t |
|
#include <iterator> // input_iterator_tag |
|
#include <string> // string, to_string |
|
#include <tuple> // tuple_size, get, tuple_element |
|
#include <utility> // move |
|
|
|
#include <nlohmann/detail/meta/type_traits.hpp> |
|
#include <nlohmann/detail/value_t.hpp> |
|
|
|
namespace nlohmann |
|
{ |
|
namespace detail |
|
{ |
|
template<typename string_type> |
|
void int_to_string( string_type& target, std::size_t value ) |
|
{ |
|
// For ADL |
|
using std::to_string; |
|
target = to_string(value); |
|
} |
|
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; |
|
using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type; |
|
|
|
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 string_type array_index_str = "0"; |
|
/// an empty string (to return a reference for primitive values) |
|
const string_type empty_str{}; |
|
|
|
public: |
|
explicit iteration_proxy_value(IteratorType it) noexcept |
|
: anchor(std::move(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 |
|
{ |
|
return anchor == o.anchor; |
|
} |
|
|
|
/// inequality operator (needed for range-based for) |
|
bool operator!=(const iteration_proxy_value& o) const |
|
{ |
|
return anchor != o.anchor; |
|
} |
|
|
|
/// return key of the iterator |
|
const string_type& key() const |
|
{ |
|
JSON_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) |
|
{ |
|
int_to_string( array_index_str, 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: |
|
/// the container to iterate |
|
typename IteratorType::reference container; |
|
|
|
public: |
|
/// construct iteration proxy from a container |
|
explicit iteration_proxy(typename IteratorType::reference cont) noexcept |
|
: container(cont) {} |
|
|
|
/// return iterator begin (needed for range-based for) |
|
iteration_proxy_value<IteratorType> begin() noexcept |
|
{ |
|
return iteration_proxy_value<IteratorType>(container.begin()); |
|
} |
|
|
|
/// return iterator end (needed for range-based for) |
|
iteration_proxy_value<IteratorType> end() noexcept |
|
{ |
|
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 |
|
{ |
|
#if defined(__clang__) |
|
// Fix: https://github.com/nlohmann/json/issues/1401 |
|
#pragma clang diagnostic push |
|
#pragma clang diagnostic ignored "-Wmismatched-tags" |
|
#endif |
|
template<typename IteratorType> |
|
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> |
|
: public std::integral_constant<std::size_t, 2> {}; |
|
|
|
template<std::size_t N, typename IteratorType> |
|
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> |
|
{ |
|
public: |
|
using type = decltype( |
|
get<N>(std::declval < |
|
::nlohmann::detail::iteration_proxy_value<IteratorType >> ())); |
|
}; |
|
#if defined(__clang__) |
|
#pragma clang diagnostic pop |
|
#endif |
|
} // namespace std
|
|
|