From 40483ddadb86fe5865145af4c6fa7fda243ab2e5 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 19 Aug 2021 16:08:05 +0200 Subject: [PATCH] :sparkles: allow std::unordered_map as ObjectType --- include/nlohmann/detail/meta/type_traits.hpp | 18 +++++++++ include/nlohmann/json.hpp | 21 ++++++++--- single_include/nlohmann/json.hpp | 39 +++++++++++++++++--- test/src/unit-regression2.cpp | 12 ++++++ 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index ee028b5d2..cd31259fb 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -449,5 +449,23 @@ T conditional_static_cast(U value) return value; } +// helper to check if a type has bucket_count function (and hence can tell a std::map and a std::unordered_map apart) +template +class has_bucket_count +{ + typedef char one; + + struct two + { + char x[2]; + }; + + template static one test( decltype(&C::bucket_count) ) ; + template static two test(...); + + public: + enum { value = sizeof(test(0)) == sizeof(char) }; +}; + } // namespace detail } // namespace nlohmann diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index b679febe6..15480c7d1 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -507,11 +507,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. */ - using object_t = ObjectType>>; + using object_t = typename std::conditional < + detail::has_bucket_count>::value, + + std::unordered_map, + std::equal_to, + AllocatorType>>, + + std::map>> + >::type; /*! @brief a type for an array diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 9858388b5..5d6c8dd8e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3858,6 +3858,24 @@ T conditional_static_cast(U value) return value; } +// helper to check if a type has bucket_count function (and hence can tell a std::map and a std::unordered_map apart) +template +class has_bucket_count +{ + typedef char one; + + struct two + { + char x[2]; + }; + + template static one test( decltype(&C::bucket_count) ) ; + template static two test(...); + + public: + enum { value = sizeof(test(0)) == sizeof(char) }; +}; + } // namespace detail } // namespace nlohmann @@ -17890,11 +17908,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. */ - using object_t = ObjectType>>; + using object_t = typename std::conditional < + detail::has_bucket_count>::value, + + std::unordered_map, + std::equal_to, + AllocatorType>>, + + std::map>> + >::type; /*! @brief a type for an array diff --git a/test/src/unit-regression2.cpp b/test/src/unit-regression2.cpp index 179f2b45b..b991724ff 100644 --- a/test/src/unit-regression2.cpp +++ b/test/src/unit-regression2.cpp @@ -659,6 +659,18 @@ TEST_CASE("regression tests 2") { static_assert(std::is_copy_assignable::value, ""); } + + SECTION("issue #2932 - Support for unordered_map as object_t") + { + using ujson = nlohmann::basic_json; + ujson j; + j["a"] = 1; + j["b"] = 2; + CHECK(j.size() == 2); + + // check that object_t is really a std::unordered_map + CHECK(ujson::object_t::hasher()("foo") == std::hash()("foo")); + } } DOCTEST_CLANG_SUPPRESS_WARNING_POP