From f665a9233062397c9e713bbac1ff63f5f0a6fe45 Mon Sep 17 00:00:00 2001 From: David Avedissian <git@dga.me.uk> Date: Wed, 7 Nov 2018 18:39:25 +0000 Subject: [PATCH 1/3] Implement SFINAE friendly iterator_traits and use that instead. --- .../nlohmann/detail/input/input_adapters.hpp | 6 +- .../detail/iterators/iterator_traits.hpp | 47 ++++++++++++ include/nlohmann/detail/meta/type_traits.hpp | 9 ++- include/nlohmann/json.hpp | 2 +- single_include/nlohmann/json.hpp | 76 ++++++++++++++++--- 5 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 include/nlohmann/detail/iterators/iterator_traits.hpp diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 79a19c17..1d549ecc 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -331,7 +331,7 @@ class input_adapter /// input adapter for iterator range with contiguous storage template<class IteratorType, typename std::enable_if< - std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, + std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, int>::type = 0> input_adapter(IteratorType first, IteratorType last) { @@ -350,7 +350,7 @@ class input_adapter // assertion to check that each element is 1 byte long static_assert( - sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1, + sizeof(typename iterator_traits<IteratorType>::value_type) == 1, "each element in the iterator range must have the size of 1 byte"); const auto len = static_cast<size_t>(std::distance(first, last)); @@ -374,7 +374,7 @@ class input_adapter /// input adapter for contiguous container template<class ContiguousContainer, typename std::enable_if<not std::is_pointer<ContiguousContainer>::value and - std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value, + std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value, int>::type = 0> input_adapter(const ContiguousContainer& c) : input_adapter(std::begin(c), std::end(c)) {} diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp new file mode 100644 index 00000000..43603988 --- /dev/null +++ b/include/nlohmann/detail/iterators/iterator_traits.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include <iterator> // random_access_iterator_tag + +#include <nlohmann/detail/meta/void_t.hpp> + +namespace nlohmann +{ +namespace detail +{ +template <class It, class = void> +struct _iterator_types {}; + +template <class It> +struct _iterator_types< + It, + void_t<typename It::difference_type, typename It::value_type, typename It::pointer, + typename It::reference, typename It::iterator_category>> { + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +template <class Iter> +struct iterator_traits : _iterator_types<Iter> {}; + +template <class T> +struct iterator_traits<T*> { + typedef std::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; +}; + +template <class T> +struct iterator_traits<const T*> { + typedef std::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const T* pointer; + typedef const T& reference; +}; +} +} \ No newline at end of file diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index d901f1e0..ee04da22 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -6,6 +6,7 @@ #include <utility> // declval #include <nlohmann/json_fwd.hpp> +#include <nlohmann/detail/iterators/iterator_traits.hpp> #include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/macro_scope.hpp> @@ -131,10 +132,10 @@ template <typename T, typename = void> struct is_iterator_traits : std::false_type {}; template <typename T> -struct is_iterator_traits<std::iterator_traits<T>> +struct is_iterator_traits<iterator_traits<T>> { private: - using traits = std::iterator_traits<T>; + using traits = iterator_traits<T>; public: static constexpr auto value = @@ -251,7 +252,7 @@ struct is_compatible_array_type_impl < // Therefore it is detected as a CompatibleArrayType. // The real fix would be to have an Iterable concept. not is_iterator_traits< - std::iterator_traits<CompatibleArrayType>>::value >> + iterator_traits<CompatibleArrayType>>::value >> { static constexpr bool value = std::is_constructible<BasicJsonType, @@ -288,7 +289,7 @@ struct is_constructible_array_type_impl < // Therefore it is detected as a ConstructibleArrayType. // The real fix would be to have an Iterable concept. not is_iterator_traits < - std::iterator_traits<ConstructibleArrayType >>::value and + iterator_traits<ConstructibleArrayType >>::value and (std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or has_from_json<BasicJsonType, diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 30e69895..cbb00e03 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -41,7 +41,7 @@ SOFTWARE. #include <functional> // hash, less #include <initializer_list> // initializer_list #include <iosfwd> // istream, ostream -#include <iterator> // iterator_traits, random_access_iterator_tag +#include <iterator> // random_access_iterator_tag #include <numeric> // accumulate #include <string> // string, stoi, to_string #include <utility> // declval, forward, move, pair, swap diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 1e7cf51e..8ef906d6 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -41,7 +41,7 @@ SOFTWARE. #include <functional> // hash, less #include <initializer_list> // initializer_list #include <iosfwd> // istream, ostream -#include <iterator> // iterator_traits, random_access_iterator_tag +#include <iterator> // random_access_iterator_tag #include <numeric> // accumulate #include <string> // string, stoi, to_string #include <utility> // declval, forward, move, pair, swap @@ -324,12 +324,10 @@ constexpr T static_const<T>::value; // #include <nlohmann/json_fwd.hpp> -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/detected.hpp> +// #include <nlohmann/detail/iterators/iterator_traits.hpp> -#include <type_traits> +#include <iterator> // random_access_iterator_tag // #include <nlohmann/detail/meta/void_t.hpp> @@ -347,6 +345,60 @@ template <typename ...Ts> using void_t = typename make_void<Ts...>::type; } // namespace nlohmann +namespace nlohmann +{ +namespace detail +{ +template <class It, class = void> +struct _iterator_types {}; + +template <class It> +struct _iterator_types < + It, + void_t<typename It::difference_type, typename It::value_type, typename It::pointer, + typename It::reference, typename It::iterator_category >> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +template <class Iter> +struct iterator_traits : _iterator_types<Iter> {}; + +template <class T> +struct iterator_traits<T*> +{ + typedef std::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; +}; + +template <class T> +struct iterator_traits<const T*> +{ + typedef std::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const T* pointer; + typedef const T& reference; +}; +} +} +// #include <nlohmann/detail/meta/cpp_future.hpp> + +// #include <nlohmann/detail/meta/detected.hpp> + + +#include <type_traits> + +// #include <nlohmann/detail/meta/void_t.hpp> + + // http://en.cppreference.com/w/cpp/experimental/is_detected namespace nlohmann { @@ -522,10 +574,10 @@ template <typename T, typename = void> struct is_iterator_traits : std::false_type {}; template <typename T> -struct is_iterator_traits<std::iterator_traits<T>> +struct is_iterator_traits<iterator_traits<T>> { private: - using traits = std::iterator_traits<T>; + using traits = iterator_traits<T>; public: static constexpr auto value = @@ -642,7 +694,7 @@ struct is_compatible_array_type_impl < // Therefore it is detected as a CompatibleArrayType. // The real fix would be to have an Iterable concept. not is_iterator_traits< - std::iterator_traits<CompatibleArrayType>>::value >> + iterator_traits<CompatibleArrayType>>::value >> { static constexpr bool value = std::is_constructible<BasicJsonType, @@ -679,7 +731,7 @@ struct is_constructible_array_type_impl < // Therefore it is detected as a ConstructibleArrayType. // The real fix would be to have an Iterable concept. not is_iterator_traits < - std::iterator_traits<ConstructibleArrayType >>::value and + iterator_traits<ConstructibleArrayType >>::value and (std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or has_from_json<BasicJsonType, @@ -2380,7 +2432,7 @@ class input_adapter /// input adapter for iterator range with contiguous storage template<class IteratorType, typename std::enable_if< - std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, + std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, int>::type = 0> input_adapter(IteratorType first, IteratorType last) { @@ -2399,7 +2451,7 @@ class input_adapter // assertion to check that each element is 1 byte long static_assert( - sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1, + sizeof(typename iterator_traits<IteratorType>::value_type) == 1, "each element in the iterator range must have the size of 1 byte"); const auto len = static_cast<size_t>(std::distance(first, last)); @@ -2423,7 +2475,7 @@ class input_adapter /// input adapter for contiguous container template<class ContiguousContainer, typename std::enable_if<not std::is_pointer<ContiguousContainer>::value and - std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value, + std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value, int>::type = 0> input_adapter(const ContiguousContainer& c) : input_adapter(std::begin(c), std::end(c)) {} From 2c23f0a34600ce54a1687004b9557079046e5b6e Mon Sep 17 00:00:00 2001 From: David Avedissian <git@dga.me.uk> Date: Sat, 8 Dec 2018 15:46:33 +0000 Subject: [PATCH 2/3] Changes requested from code review. --- .../detail/iterators/iterator_traits.hpp | 36 +++++++++--------- single_include/nlohmann/json.hpp | 38 ++++++++++--------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp index 43603988..607dd49a 100644 --- a/include/nlohmann/detail/iterators/iterator_traits.hpp +++ b/include/nlohmann/detail/iterators/iterator_traits.hpp @@ -3,16 +3,17 @@ #include <iterator> // random_access_iterator_tag #include <nlohmann/detail/meta/void_t.hpp> +#include <nlohmann/detail/meta/cpp_future.hpp> namespace nlohmann { namespace detail { -template <class It, class = void> -struct _iterator_types {}; +template <typename It, typename = void> +struct iterator_types {}; -template <class It> -struct _iterator_types< +template <typename It> +struct iterator_types< It, void_t<typename It::difference_type, typename It::value_type, typename It::pointer, typename It::reference, typename It::iterator_category>> { @@ -23,25 +24,26 @@ struct _iterator_types< using iterator_category = typename It::iterator_category; }; -template <class Iter> -struct iterator_traits : _iterator_types<Iter> {}; +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template <typename T, typename = void> +struct iterator_traits +{ +}; -template <class T> -struct iterator_traits<T*> { +template <typename T> +struct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>> + : iterator_types<T> +{ +}; + +template <typename T> +struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> { typedef std::random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; }; - -template <class T> -struct iterator_traits<const T*> { - typedef std::random_access_iterator_tag iterator_category; - typedef T value_type; - typedef ptrdiff_t difference_type; - typedef const T* pointer; - typedef const T& reference; -}; } } \ No newline at end of file diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 8ef906d6..24ff17b8 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -344,16 +344,18 @@ template <typename ...Ts> using void_t = typename make_void<Ts...>::type; } // namespace detail } // namespace nlohmann +// #include <nlohmann/detail/meta/cpp_future.hpp> + namespace nlohmann { namespace detail { -template <class It, class = void> -struct _iterator_types {}; +template <typename It, typename = void> +struct iterator_types {}; -template <class It> -struct _iterator_types < +template <typename It> +struct iterator_types < It, void_t<typename It::difference_type, typename It::value_type, typename It::pointer, typename It::reference, typename It::iterator_category >> @@ -365,11 +367,21 @@ struct _iterator_types < using iterator_category = typename It::iterator_category; }; -template <class Iter> -struct iterator_traits : _iterator_types<Iter> {}; +// This is required due to https://github.com/nlohmann/json/issues/1341 - where some +// compilers implement std::iterator_traits in a way that doesn't work with SFINAE. +template <typename T, typename = void> +struct iterator_traits +{ +}; -template <class T> -struct iterator_traits<T*> +template <typename T> +struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >> + : iterator_types<T> +{ +}; + +template <typename T> +struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> { typedef std::random_access_iterator_tag iterator_category; typedef T value_type; @@ -377,16 +389,6 @@ struct iterator_traits<T*> typedef T* pointer; typedef T& reference; }; - -template <class T> -struct iterator_traits<const T*> -{ - typedef std::random_access_iterator_tag iterator_category; - typedef T value_type; - typedef ptrdiff_t difference_type; - typedef const T* pointer; - typedef const T& reference; -}; } } // #include <nlohmann/detail/meta/cpp_future.hpp> From f1080d7c396d692067384257f87c9feee98a6a98 Mon Sep 17 00:00:00 2001 From: David Avedissian <git@dga.me.uk> Date: Tue, 18 Dec 2018 20:44:37 +0000 Subject: [PATCH 3/3] Code review. --- .../nlohmann/detail/iterators/iterator_traits.hpp | 12 ++++++------ single_include/nlohmann/json.hpp | 15 ++++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp index 607dd49a..35ea81fb 100644 --- a/include/nlohmann/detail/iterators/iterator_traits.hpp +++ b/include/nlohmann/detail/iterators/iterator_traits.hpp @@ -39,11 +39,11 @@ struct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>> template <typename T> struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> { - typedef std::random_access_iterator_tag iterator_category; - typedef T value_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef T& reference; + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; }; } -} \ No newline at end of file +} diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 24ff17b8..2d7e1ddd 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -367,8 +367,8 @@ struct iterator_types < using iterator_category = typename It::iterator_category; }; -// This is required due to https://github.com/nlohmann/json/issues/1341 - where some -// compilers implement std::iterator_traits in a way that doesn't work with SFINAE. +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. template <typename T, typename = void> struct iterator_traits { @@ -383,14 +383,15 @@ struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >> template <typename T> struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> { - typedef std::random_access_iterator_tag iterator_category; - typedef T value_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef T& reference; + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; }; } } + // #include <nlohmann/detail/meta/cpp_future.hpp> // #include <nlohmann/detail/meta/detected.hpp>