From 4fd0d02b6f19d986694006e136c94c9fb820c9fb Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 19 Jun 2020 15:27:05 +0200 Subject: [PATCH 01/25] :construction: toward an ordered_json type --- include/nlohmann/json.hpp | 1 + include/nlohmann/json_fwd.hpp | 13 ++++++ include/nlohmann/ordered_map.hpp | 62 +++++++++++++++++++++++++++ single_include/nlohmann/json.hpp | 73 ++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/src/unit-ordered_json.cpp | 61 ++++++++++++++++++++++++++ 6 files changed, 211 insertions(+) create mode 100644 include/nlohmann/ordered_map.hpp create mode 100644 test/src/unit-ordered_json.cpp diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 409a6e7993..15921726eb 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -72,6 +72,7 @@ SOFTWARE. #include #include #include +#include /*! @brief namespace for Niels Lohmann diff --git a/include/nlohmann/json_fwd.hpp b/include/nlohmann/json_fwd.hpp index 824e86a1f6..d9e5428d9e 100644 --- a/include/nlohmann/json_fwd.hpp +++ b/include/nlohmann/json_fwd.hpp @@ -60,6 +60,19 @@ uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; + +template +struct ordered_map; + +/*! +@brief ordered JSON class + +This type preserves the insertion order of object keys. + +@since version 3.9.0 +*/ +using ordered_json = basic_json; + } // namespace nlohmann #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp new file mode 100644 index 0000000000..744541f3ab --- /dev/null +++ b/include/nlohmann/ordered_map.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include // less +#include // allocator +#include // pair +#include // vector + +namespace nlohmann +{ + +/// ordered_map: a minimal map-like container that preserves insertion order +/// for use within nlohmann::basic_json +template, + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> +struct ordered_map : Container +{ + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using Container::Container; + + std::pair emplace(key_type&& key, T&& t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return {it, false}; + } + } + + this->emplace_back(key, t); + return {--this->end(), true}; + } + + std::size_t erase(const key_type& key) + { + std::size_t result = 0; + for (auto it = this->begin(); it != this->end();) + { + if (it->first == key) + { + ++result; + it = Container::erase(it); + } + else + { + ++it; + } + } + + return result; + } + + T& operator[](key_type&& key) + { + return emplace(std::move(key), T{}).first->second; + } +}; + +} // namespace nlohmann diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index cc822a543b..f7f1664ecc 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2772,6 +2772,15 @@ uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; + +template +struct ordered_map; + +/*! +@since version 3.9.0 +*/ +using ordered_json = basic_json; + } // namespace nlohmann #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ @@ -15853,6 +15862,70 @@ class serializer // #include +// #include + + +#include // less +#include // allocator +#include // pair +#include // vector + +namespace nlohmann +{ + +/// ordered_map: a minimal map-like container that preserves insertion order +/// for use within nlohmann::basic_json +template, + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> +struct ordered_map : Container +{ + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using Container::Container; + + std::pair emplace(Key&& key, T&& t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return {it, false}; + } + } + + this->emplace_back(key, t); + return {--this->end(), true}; + } + + std::size_t erase(const Key& key) + { + std::size_t result = 0; + for (auto it = this->begin(); it != this->end(); ) + { + if (it->first == key) + { + ++result; + it = Container::erase(it); + } + else + { + ++it; + } + } + + return result; + } + + T& operator[]( Key&& key ) + { + return emplace(std::move(key), T{}).first->second; + } +}; + +} // namespace nlohmann + /*! @brief namespace for Niels Lohmann diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fdf5ac5b39..8e663f4977 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -123,6 +123,7 @@ set(files src/unit-modifiers.cpp src/unit-msgpack.cpp src/unit-noexcept.cpp + src/unit-ordered_json.cpp src/unit-pointer_access.cpp src/unit-readme.cpp src/unit-reference_access.cpp diff --git a/test/src/unit-ordered_json.cpp b/test/src/unit-ordered_json.cpp new file mode 100644 index 0000000000..1a97ece64f --- /dev/null +++ b/test/src/unit-ordered_json.cpp @@ -0,0 +1,61 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.8.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "doctest_compatibility.h" + +#include +using nlohmann::json; +using nlohmann::ordered_json; + + +TEST_CASE("ordered_json") +{ + json j; + ordered_json oj; + + j["element3"] = 3; + j["element1"] = 1; + j["element2"] = 2; + + oj["element3"] = 3; + oj["element1"] = 1; + oj["element2"] = 2; + + CHECK(j.dump() == "{\"element1\":1,\"element2\":2,\"element3\":3}"); + CHECK(oj.dump() == "{\"element3\":3,\"element1\":1,\"element2\":2}"); + + CHECK(j == json(oj)); + CHECK(ordered_json(json(oj)) == ordered_json(j)); + + j.erase("element1"); + oj.erase("element1"); + + CHECK(j.dump() == "{\"element2\":2,\"element3\":3}"); + CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}"); +} From 6ee9e5f40287202852b3b73fbaca97be9338328d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 20 Jun 2020 13:23:44 +0200 Subject: [PATCH 02/25] :alembic: remove const from value type --- include/nlohmann/ordered_map.hpp | 38 ++++++++++++--------------- single_include/nlohmann/json.hpp | 44 +++++++++++++++----------------- 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 744541f3ab..2cf33c425c 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -10,14 +10,15 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json -template, - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> +template , + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> struct ordered_map : Container { using key_type = Key; using mapped_type = T; - using value_type = std::pair; + using value_type = typename Container::value_type; + using size_type = typename Container::size_type; using Container::Container; std::pair emplace(key_type&& key, T&& t) @@ -29,33 +30,26 @@ struct ordered_map : Container return {it, false}; } } - - this->emplace_back(key, t); + Container::emplace_back(key, t); return {--this->end(), true}; } - std::size_t erase(const key_type& key) + T& operator[](Key&& key) { - std::size_t result = 0; - for (auto it = this->begin(); it != this->end();) + return emplace(std::move(key), T{}).first->second; + } + + size_type erase(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { - ++result; - it = Container::erase(it); - } - else - { - ++it; + Container::erase(it); + return 1; } } - - return result; - } - - T& operator[](key_type&& key) - { - return emplace(std::move(key), T{}).first->second; + return 0; } }; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index f7f1664ecc..c8cabbbf07 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2777,6 +2777,10 @@ template; @@ -15875,17 +15879,18 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json -template, - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> +template , + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> struct ordered_map : Container { using key_type = Key; using mapped_type = T; - using value_type = std::pair; + using value_type = typename Container::value_type; + using size_type = typename Container::size_type; using Container::Container; - std::pair emplace(Key&& key, T&& t) + std::pair emplace(key_type&& key, T&& t) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -15894,33 +15899,26 @@ struct ordered_map : Container return {it, false}; } } - - this->emplace_back(key, t); + Container::emplace_back(key, t); return {--this->end(), true}; } - std::size_t erase(const Key& key) + T& operator[](Key&& key) { - std::size_t result = 0; - for (auto it = this->begin(); it != this->end(); ) + return emplace(std::move(key), T{}).first->second; + } + + size_type erase(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { - ++result; - it = Container::erase(it); - } - else - { - ++it; + Container::erase(it); + return 1; } } - - return result; - } - - T& operator[]( Key&& key ) - { - return emplace(std::move(key), T{}).first->second; + return 0; } }; From 27aaf6f84598c98d92d4c1e96b31ab9833e79730 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Sun, 21 Jun 2020 22:28:03 +0100 Subject: [PATCH 03/25] Clean-up ordered_map declarations --- .gitignore | 2 ++ include/nlohmann/ordered_map.hpp | 7 ++++--- single_include/nlohmann/json.hpp | 7 ++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index bec7f59820..9d4fcb370e 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,9 @@ benchmarks/files/numbers/*.json cmake-build-debug test/test-* +test/test_data.hpp /.vs +.vscode doc/mkdocs/venv/ doc/mkdocs/docs/images diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 2cf33c425c..756b586a0c 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -17,11 +17,12 @@ struct ordered_map : Container { using key_type = Key; using mapped_type = T; - using value_type = typename Container::value_type; - using size_type = typename Container::size_type; + using typename Container::iterator; + using typename Container::value_type; + using typename Container::size_type; using Container::Container; - std::pair emplace(key_type&& key, T&& t) + std::pair emplace(key_type&& key, T&& t) { for (auto it = this->begin(); it != this->end(); ++it) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c8cabbbf07..b524fe6981 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15886,11 +15886,12 @@ struct ordered_map : Container { using key_type = Key; using mapped_type = T; - using value_type = typename Container::value_type; - using size_type = typename Container::size_type; + using typename Container::iterator; + using typename Container::value_type; + using typename Container::size_type; using Container::Container; - std::pair emplace(key_type&& key, T&& t) + std::pair emplace(key_type&& key, T&& t) { for (auto it = this->begin(); it != this->end(); ++it) { From 15337b2cc3c911efdb3d98bfbc50bc8d513bc8bb Mon Sep 17 00:00:00 2001 From: gatopeich Date: Mon, 22 Jun 2020 00:03:48 +0100 Subject: [PATCH 04/25] Ignore allocator hardcoded to match std::map --- include/nlohmann/json.hpp | 1 + include/nlohmann/ordered_map.hpp | 4 ++-- single_include/nlohmann/json.hpp | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 15921726eb..5e53e4f9f2 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,6 +496,7 @@ class basic_json using object_t = ObjectType AllocatorType>>; diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 756b586a0c..2fa00c0d4d 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -11,8 +11,8 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> + class IgnoredAllocator = std::allocator>, + class Container = std::vector>> struct ordered_map : Container { using key_type = Key; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b524fe6981..43da17f562 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15880,8 +15880,8 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> + class IgnoredAllocator = std::allocator>, + class Container = std::vector>> struct ordered_map : Container { using key_type = Key; @@ -16348,6 +16348,7 @@ class basic_json using object_t = ObjectType AllocatorType>>; From ddf0a45abbbb348142919adf3d9d8212ee998f53 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Mon, 22 Jun 2020 18:35:46 +0100 Subject: [PATCH 05/25] Use AllocatorType, instead of hard-coding it for std::map's value_type --- .gitignore | 2 ++ README.md | 2 +- doc/mkdocs/docs/features/types.md | 2 +- include/nlohmann/json.hpp | 4 +--- include/nlohmann/ordered_map.hpp | 4 ++-- single_include/nlohmann/json.hpp | 8 +++----- 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 9d4fcb370e..4a39c8747b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,8 @@ cmake-build-debug test/test-* test/test_data.hpp +Temporary + /.vs .vscode diff --git a/README.md b/README.md index d7492da34f..972d857f5e 100644 --- a/README.md +++ b/README.md @@ -1527,7 +1527,7 @@ This library will not support comments in the future. If you wish to use comment ### Order of object keys -By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). +By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can try the new [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179) specialization, or use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). ### Memory Release diff --git a/doc/mkdocs/docs/features/types.md b/doc/mkdocs/docs/features/types.md index 94e40cbaf3..7754bbca14 100644 --- a/doc/mkdocs/docs/features/types.md +++ b/doc/mkdocs/docs/features/types.md @@ -89,7 +89,7 @@ From the template arguments, the following types are derived: ```cpp using object_comparator_t = std::less<>; using object_t = ObjectType>>; + AllocatorType::value_type>>; using array_t = ArrayType>; diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 5e53e4f9f2..dc44c12c0a 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,9 +496,7 @@ class basic_json using object_t = ObjectType - AllocatorType>>; + AllocatorType::value_type>>; /*! @brief a type for an array diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 2fa00c0d4d..756b586a0c 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -11,8 +11,8 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class IgnoredAllocator = std::allocator>, - class Container = std::vector>> + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> struct ordered_map : Container { using key_type = Key; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 43da17f562..2d3d31a0e6 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15880,8 +15880,8 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class IgnoredAllocator = std::allocator>, - class Container = std::vector>> + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> struct ordered_map : Container { using key_type = Key; @@ -16348,9 +16348,7 @@ class basic_json using object_t = ObjectType - AllocatorType>>; + AllocatorType::value_type>>; /*! @brief a type for an array From 064a9c92126822d246b2e08c28b57d0fc2c44c29 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Mon, 22 Jun 2020 18:59:19 +0100 Subject: [PATCH 06/25] Fix regression test --- include/nlohmann/json.hpp | 4 +++- single_include/nlohmann/json.hpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index dc44c12c0a..69afaf0532 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,7 +496,9 @@ class basic_json using object_t = ObjectType::value_type>>; + // Note: instantiating ObjectType with dummy allocator to extract ::value_type + AllocatorType + >::value_type>>; /*! @brief a type for an array diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2d3d31a0e6..e6d87b31e1 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16348,7 +16348,9 @@ class basic_json using object_t = ObjectType::value_type>>; + // Note: instantiating ObjectType with dummy allocator to extract ::value_type + AllocatorType + >::value_type>>; /*! @brief a type for an array From 5fe3d3929a523eef4c64f0893db0969a12d3704e Mon Sep 17 00:00:00 2001 From: gatopeich Date: Mon, 22 Jun 2020 19:10:35 +0100 Subject: [PATCH 07/25] Using ordered_json instead of fifo_map in test-regression This is more comprehensive and the "my_workaround_fifo_map" wrapper does not allow to infer value type as required in this branch. This reverts commit 064a9c92126822d246b2e08c28b57d0fc2c44c29. --- include/nlohmann/json.hpp | 4 +--- single_include/nlohmann/json.hpp | 4 +--- test/src/unit-regression.cpp | 6 +----- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 69afaf0532..dc44c12c0a 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,9 +496,7 @@ class basic_json using object_t = ObjectType - >::value_type>>; + AllocatorType::value_type>>; /*! @brief a type for an array diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index e6d87b31e1..2d3d31a0e6 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16348,9 +16348,7 @@ class basic_json using object_t = ObjectType - >::value_type>>; + AllocatorType::value_type>>; /*! @brief a type for an array diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index e5cd0337b3..143508a631 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -52,15 +52,11 @@ using nlohmann::json; #include #endif -#include "fifo_map.hpp" - ///////////////////////////////////////////////////////////////////// // for #972 ///////////////////////////////////////////////////////////////////// -template -using my_workaround_fifo_map = nlohmann::fifo_map, A>; -using my_json = nlohmann::basic_json; +using my_json = nlohmann::ordered_json; ///////////////////////////////////////////////////////////////////// // for #977 From 49623a75ee670332f8b86cc37fa941542584dcfc Mon Sep 17 00:00:00 2001 From: gatopeich Date: Tue, 23 Jun 2020 11:30:52 +0100 Subject: [PATCH 08/25] Revert "Using ordered_json instead of fifo_map in test-regression" This reverts commit 5fe3d3929a523eef4c64f0893db0969a12d3704e. --- include/nlohmann/json.hpp | 4 +++- single_include/nlohmann/json.hpp | 4 +++- test/src/unit-regression.cpp | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index dc44c12c0a..69afaf0532 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,7 +496,9 @@ class basic_json using object_t = ObjectType::value_type>>; + // Note: instantiating ObjectType with dummy allocator to extract ::value_type + AllocatorType + >::value_type>>; /*! @brief a type for an array diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2d3d31a0e6..e6d87b31e1 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16348,7 +16348,9 @@ class basic_json using object_t = ObjectType::value_type>>; + // Note: instantiating ObjectType with dummy allocator to extract ::value_type + AllocatorType + >::value_type>>; /*! @brief a type for an array diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 143508a631..e5cd0337b3 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -52,11 +52,15 @@ using nlohmann::json; #include #endif +#include "fifo_map.hpp" + ///////////////////////////////////////////////////////////////////// // for #972 ///////////////////////////////////////////////////////////////////// -using my_json = nlohmann::ordered_json; +template +using my_workaround_fifo_map = nlohmann::fifo_map, A>; +using my_json = nlohmann::basic_json; ///////////////////////////////////////////////////////////////////// // for #977 From acd748e16f0462f73274fe02d37e157f808318ff Mon Sep 17 00:00:00 2001 From: gatopeich Date: Tue, 23 Jun 2020 12:03:21 +0100 Subject: [PATCH 09/25] Use std::map default allocator as a placeholder to extract the actual ObjectType::value_type Still fails on older compilers (GCC <= 5.5) --- include/nlohmann/json.hpp | 9 ++++++--- single_include/nlohmann/json.hpp | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 69afaf0532..31944e32d2 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,9 +496,12 @@ class basic_json using object_t = ObjectType - >::value_type>>; + // Note the use of std::map default allocator as a placeholder + // to extract the actual ObjectType::value_type + AllocatorType> + >::value_type>>; /*! @brief a type for an array diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index e6d87b31e1..76ee276432 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16348,9 +16348,12 @@ class basic_json using object_t = ObjectType - >::value_type>>; + // Note the use of std::map default allocator as a placeholder + // to extract the actual ObjectType::value_type + AllocatorType> + >::value_type>>; /*! @brief a type for an array From fb8c11f25cb6ff4abc305d988a609751726e674e Mon Sep 17 00:00:00 2001 From: gatopeich Date: Tue, 23 Jun 2020 15:01:20 +0100 Subject: [PATCH 10/25] Re-implement ordered_map::erase, so that it can handle pair --- include/nlohmann/json.hpp | 6 +++--- include/nlohmann/ordered_map.hpp | 9 ++++++++- single_include/nlohmann/json.hpp | 15 +++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 31944e32d2..2aef23b343 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -499,9 +499,9 @@ class basic_json // Note the use of std::map default allocator as a placeholder // to extract the actual ObjectType::value_type AllocatorType> - >::value_type>>; + ObjectType> + >::value_type>>; /*! @brief a type for an array diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 756b586a0c..bb5dfe4e6c 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -46,7 +46,14 @@ struct ordered_map : Container { if (it->first == key) { - Container::erase(it); + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + // *it = std::move(*next); // deleted + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); return 1; } } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 76ee276432..3cf133d541 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15915,7 +15915,14 @@ struct ordered_map : Container { if (it->first == key) { - Container::erase(it); + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + // *it = std::move(*next); // deleted + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); return 1; } } @@ -16351,9 +16358,9 @@ class basic_json // Note the use of std::map default allocator as a placeholder // to extract the actual ObjectType::value_type AllocatorType> - >::value_type>>; + ObjectType> + >::value_type>>; /*! @brief a type for an array From 5e7bdf1cab080543a8a3b428f18b2be854aa2007 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Tue, 23 Jun 2020 15:39:00 +0100 Subject: [PATCH 11/25] Roll-back to hard-coded object_t::value_type --- include/nlohmann/json.hpp | 8 ++------ single_include/nlohmann/json.hpp | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 2aef23b343..c85147b3c9 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,12 +496,8 @@ class basic_json using object_t = ObjectType> - >::value_type>>; + // Note: this forces object_t::value_type to match std::map's + AllocatorType>>; /*! @brief a type for an array diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 3cf133d541..18cd4a3809 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16355,12 +16355,8 @@ class basic_json using object_t = ObjectType> - >::value_type>>; + // Note: this forces object_t::value_type to match std::map's + AllocatorType>>; /*! @brief a type for an array From d08fca2bb95a3c6deccd2aa7fa9d86303d9a8d74 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Tue, 23 Jun 2020 15:44:46 +0100 Subject: [PATCH 12/25] Use const Key in ordered map (forgotten in previous commit!) --- include/nlohmann/ordered_map.hpp | 4 ++-- single_include/nlohmann/json.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index bb5dfe4e6c..58c5484566 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -11,8 +11,8 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> struct ordered_map : Container { using key_type = Key; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 18cd4a3809..937d5b0e39 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15880,8 +15880,8 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> struct ordered_map : Container { using key_type = Key; From 08963d6826997261682320971be1a6c3ca93f8c3 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Tue, 23 Jun 2020 15:48:02 +0100 Subject: [PATCH 13/25] Revert types.md --- doc/mkdocs/docs/features/types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mkdocs/docs/features/types.md b/doc/mkdocs/docs/features/types.md index 7754bbca14..211595e58b 100644 --- a/doc/mkdocs/docs/features/types.md +++ b/doc/mkdocs/docs/features/types.md @@ -89,7 +89,7 @@ From the template arguments, the following types are derived: ```cpp using object_comparator_t = std::less<>; using object_t = ObjectType::value_type>>; + AllocatorType>>; using array_t = ArrayType>; From cf18ba2394f7813ebaf8dbc94598db859e5916bf Mon Sep 17 00:00:00 2001 From: gatopeich Date: Tue, 23 Jun 2020 17:50:51 +0100 Subject: [PATCH 14/25] Test initialization with dup keys --- test/src/unit-ordered_json.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/src/unit-ordered_json.cpp b/test/src/unit-ordered_json.cpp index 1a97ece64f..e4ffd68ac2 100644 --- a/test/src/unit-ordered_json.cpp +++ b/test/src/unit-ordered_json.cpp @@ -58,4 +58,15 @@ TEST_CASE("ordered_json") CHECK(j.dump() == "{\"element2\":2,\"element3\":3}"); CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}"); + + // There are no dup keys cause constructor calls emplace... + json multi {{"z", 1}, {"m", 2}, {"m", 3}, {"y", 4}, {"m", 5}}; + CHECK(multi.size() == 3); + CHECK(multi.dump() == "{\"m\":2,\"y\":4,\"z\":1}"); + + ordered_json multi_ordered {{"z", 1}, {"m", 2}, {"m", 3}, {"y", 4}, {"m", 5}}; + CHECK(multi_ordered.size() == 3); + CHECK(multi_ordered.dump() == "{\"z\":1,\"m\":2,\"y\":4}"); + CHECK(multi_ordered.erase("m") == 1); + CHECK(multi_ordered.dump() == "{\"z\":1,\"y\":4}"); } From 49f26a02509d70a6f3cda614f4b0a272e7011978 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Mon, 29 Jun 2020 17:32:55 +0100 Subject: [PATCH 15/25] Have 4 template parameters for ordered_map --- include/nlohmann/ordered_map.hpp | 6 +++--- single_include/nlohmann/json.hpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 58c5484566..672eb31e59 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -11,10 +11,10 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> -struct ordered_map : Container + class Allocator = std::allocator>> +struct ordered_map : std::vector { + using Container = std::vector; using key_type = Key; using mapped_type = T; using typename Container::iterator; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 937d5b0e39..0f8d48bd00 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2773,7 +2773,7 @@ uses the standard template types. */ using json = basic_json<>; -template +template struct ordered_map; /*! @@ -15880,10 +15880,10 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> -struct ordered_map : Container + class Allocator = std::allocator>> +struct ordered_map : std::vector { + using Container = std::vector; using key_type = Key; using mapped_type = T; using typename Container::iterator; From 0fc261f0f2be664f61d90499b662d35a7727f426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20F=2E=20Pozuelo?= Date: Fri, 3 Jul 2020 00:33:31 +0100 Subject: [PATCH 16/25] Make ordered_map compatible with GCC 5.5 --- include/nlohmann/ordered_map.hpp | 16 +++++++++++----- single_include/nlohmann/json.hpp | 18 ++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 672eb31e59..a6e006e622 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -11,16 +11,22 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>> -struct ordered_map : std::vector + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> +struct ordered_map : Container { - using Container = std::vector; using key_type = Key; using mapped_type = T; using typename Container::iterator; - using typename Container::value_type; using typename Container::size_type; - using Container::Container; + using typename Container::value_type; + + // Explicit constructors instead of `using Container::Container` + // otherwise older compilers like GCC 5.5 choke on it + ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + template + ordered_map(It first, It last, const Allocator& alloc = Allocator()) + : Container{first, last, alloc} {} std::pair emplace(key_type&& key, T&& t) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0f8d48bd00..50e173e2b0 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2773,7 +2773,7 @@ uses the standard template types. */ using json = basic_json<>; -template +template struct ordered_map; /*! @@ -15880,16 +15880,22 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>> -struct ordered_map : std::vector + class Allocator = std::allocator>, + class Container = std::vector, Allocator>> +struct ordered_map : Container { - using Container = std::vector; using key_type = Key; using mapped_type = T; using typename Container::iterator; - using typename Container::value_type; using typename Container::size_type; - using Container::Container; + using typename Container::value_type; + + // Explicit constructors instead of `using Container::Container` + // otherwise older compilers like GCC 5.5 choke on it + ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + template + ordered_map(It first, It last, const Allocator& alloc = Allocator()) + : Container{first, last, alloc} {} std::pair emplace(key_type&& key, T&& t) { From 93770467a17773dcdd10885285ce6714f0ae3dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20F=2E=20Pozuelo?= Date: Fri, 3 Jul 2020 01:28:54 +0100 Subject: [PATCH 17/25] Precisely 4 template arguments for the sake of clang 3.6 (?) --- include/nlohmann/ordered_map.hpp | 6 +++--- single_include/nlohmann/json.hpp | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index a6e006e622..4a71951df5 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -11,12 +11,12 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> -struct ordered_map : Container + class Allocator = std::allocator>> +struct ordered_map : std::vector, Allocator> { using key_type = Key; using mapped_type = T; + using Container = std::vector, Allocator>; using typename Container::iterator; using typename Container::size_type; using typename Container::value_type; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 50e173e2b0..e5e3bc3e84 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2773,7 +2773,7 @@ uses the standard template types. */ using json = basic_json<>; -template +template struct ordered_map; /*! @@ -15880,12 +15880,12 @@ namespace nlohmann /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , - class Allocator = std::allocator>, - class Container = std::vector, Allocator>> -struct ordered_map : Container + class Allocator = std::allocator>> +struct ordered_map : std::vector, Allocator> { using key_type = Key; using mapped_type = T; + using Container = std::vector, Allocator>; using typename Container::iterator; using typename Container::size_type; using typename Container::value_type; @@ -16063,7 +16063,7 @@ class basic_json InputAdapterType adapter, detail::parser_callback_tcb = nullptr, bool allow_exceptions = true - ) + ) { return ::nlohmann::detail::parser(std::move(adapter), std::move(cb), allow_exceptions); } @@ -24534,7 +24534,7 @@ template<> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( is_nothrow_move_constructible::value and is_nothrow_move_assignable::value -) + ) { j1.swap(j2); } From 25f5d75e6e0fbdbff1a6341b112156ecfc726812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20F=2E=20Pozuelo?= Date: Fri, 3 Jul 2020 01:44:18 +0100 Subject: [PATCH 18/25] Fix compilation for xcode 9.x --- include/nlohmann/json_fwd.hpp | 2 +- include/nlohmann/ordered_map.hpp | 4 +++- single_include/nlohmann/json.hpp | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/nlohmann/json_fwd.hpp b/include/nlohmann/json_fwd.hpp index d9e5428d9e..332227c1ba 100644 --- a/include/nlohmann/json_fwd.hpp +++ b/include/nlohmann/json_fwd.hpp @@ -61,7 +61,7 @@ uses the standard template types. */ using json = basic_json<>; -template +template struct ordered_map; /*! diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 4a71951df5..29c52016d8 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -22,11 +22,13 @@ struct ordered_map : std::vector, Allocator> using typename Container::value_type; // Explicit constructors instead of `using Container::Container` - // otherwise older compilers like GCC 5.5 choke on it + // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} template ordered_map(It first, It last, const Allocator& alloc = Allocator()) : Container{first, last, alloc} {} + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + : Container{init, alloc} {} std::pair emplace(key_type&& key, T&& t) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index e5e3bc3e84..850ee6abb7 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15891,11 +15891,13 @@ struct ordered_map : std::vector, Allocator> using typename Container::value_type; // Explicit constructors instead of `using Container::Container` - // otherwise older compilers like GCC 5.5 choke on it + // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} template ordered_map(It first, It last, const Allocator& alloc = Allocator()) : Container{first, last, alloc} {} + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + : Container{init, alloc} {} std::pair emplace(key_type&& key, T&& t) { From 803c16e5af4ff173b00684e758f8487bf1c8b0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20F=2E=20Pozuelo?= Date: Fri, 3 Jul 2020 10:26:05 +0100 Subject: [PATCH 19/25] Clean-up unintended changes to whitespace --- .gitignore | 4 ---- doc/mkdocs/docs/features/types.md | 2 +- single_include/nlohmann/json.hpp | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 4a39c8747b..bec7f59820 100644 --- a/.gitignore +++ b/.gitignore @@ -25,11 +25,7 @@ benchmarks/files/numbers/*.json cmake-build-debug test/test-* -test/test_data.hpp -Temporary - /.vs -.vscode doc/mkdocs/venv/ doc/mkdocs/docs/images diff --git a/doc/mkdocs/docs/features/types.md b/doc/mkdocs/docs/features/types.md index 211595e58b..94e40cbaf3 100644 --- a/doc/mkdocs/docs/features/types.md +++ b/doc/mkdocs/docs/features/types.md @@ -89,7 +89,7 @@ From the template arguments, the following types are derived: ```cpp using object_comparator_t = std::less<>; using object_t = ObjectType>>; + AllocatorType>>; using array_t = ArrayType>; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 850ee6abb7..a944799ca6 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -24536,7 +24536,7 @@ template<> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( is_nothrow_move_constructible::value and is_nothrow_move_assignable::value - ) +) { j1.swap(j2); } From 0eb7b0a991b44425cd001f7c550e6f531c9b647e Mon Sep 17 00:00:00 2001 From: gatopeich <7722268+gatopeich@users.noreply.github.com> Date: Thu, 9 Jul 2020 20:47:19 +0100 Subject: [PATCH 20/25] Update README.md per review comments Co-authored-by: Niels Lohmann --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 972d857f5e..65e948fe59 100644 --- a/README.md +++ b/README.md @@ -1527,7 +1527,9 @@ This library will not support comments in the future. If you wish to use comment ### Order of object keys -By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can try the new [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179) specialization, or use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). +By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". + +If you do want to preserve the insertion order, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). ### Memory Release From f62b4626be3bef408b94c67330d5f5c4606512c8 Mon Sep 17 00:00:00 2001 From: gatopeich Date: Thu, 9 Jul 2020 21:12:11 +0100 Subject: [PATCH 21/25] Removing comment about AllocatorType per review request --- include/nlohmann/json.hpp | 4 ++-- single_include/nlohmann/json.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index c85147b3c9..15921726eb 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -496,8 +496,8 @@ class basic_json using object_t = ObjectType>>; + AllocatorType>>; /*! @brief a type for an array diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a944799ca6..0b19ea4572 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16363,8 +16363,8 @@ class basic_json using object_t = ObjectType>>; + AllocatorType>>; /*! @brief a type for an array From f9a1fec272d2e169d3ee56e9480c9c78b085c369 Mon Sep 17 00:00:00 2001 From: gatopeich <7722268+gatopeich@users.noreply.github.com> Date: Sat, 11 Jul 2020 00:34:02 +0100 Subject: [PATCH 22/25] Remove redundant comment --- include/nlohmann/ordered_map.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 29c52016d8..105f016766 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -57,7 +57,6 @@ struct ordered_map : std::vector, Allocator> // Since we cannot move const Keys, re-construct them in place for (auto next = it; ++next != this->end(); ++it) { - // *it = std::move(*next); // deleted it->~value_type(); // Destroy but keep allocation new (&*it) value_type{std::move(*next)}; } From 47d154dd49ed82da594f90fc5af0793407128e20 Mon Sep 17 00:00:00 2001 From: gatopeich <7722268+gatopeich@users.noreply.github.com> Date: Sat, 11 Jul 2020 00:34:12 +0100 Subject: [PATCH 23/25] Remove redundant comment --- single_include/nlohmann/json.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0b19ea4572..54f222746f 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15926,7 +15926,6 @@ struct ordered_map : std::vector, Allocator> // Since we cannot move const Keys, re-construct them in place for (auto next = it; ++next != this->end(); ++it) { - // *it = std::move(*next); // deleted it->~value_type(); // Destroy but keep allocation new (&*it) value_type{std::move(*next)}; } From 3a80823ff8b27352f9d98efbdef6b6a1ac6c8832 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 11 Jul 2020 13:21:13 +0200 Subject: [PATCH 24/25] :twisted_rightwards_arrows: merge develop branch and resolve conflicts --- include/nlohmann/ordered_map.hpp | 2 +- single_include/nlohmann/json.hpp | 90 +++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 105f016766..2a72fefd07 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -12,7 +12,7 @@ namespace nlohmann /// for use within nlohmann::basic_json template , class Allocator = std::allocator>> -struct ordered_map : std::vector, Allocator> + struct ordered_map : std::vector, Allocator> { using key_type = Key; using mapped_type = T; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index d6c420d172..0044d56505 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2822,6 +2822,19 @@ uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; + +template +struct ordered_map; + +/*! +@brief ordered JSON class + +This type preserves the insertion order of object keys. + +@since version 3.9.0 +*/ +using ordered_json = basic_json; + } // namespace nlohmann #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ @@ -16000,6 +16013,79 @@ class serializer // #include +// #include + + +#include // less +#include // allocator +#include // pair +#include // vector + +namespace nlohmann +{ + +/// ordered_map: a minimal map-like container that preserves insertion order +/// for use within nlohmann::basic_json +template , + class Allocator = std::allocator>> + struct ordered_map : std::vector, Allocator> +{ + using key_type = Key; + using mapped_type = T; + using Container = std::vector, Allocator>; + using typename Container::iterator; + using typename Container::size_type; + using typename Container::value_type; + + // Explicit constructors instead of `using Container::Container` + // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) + ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + template + ordered_map(It first, It last, const Allocator& alloc = Allocator()) + : Container{first, last, alloc} {} + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + : Container{init, alloc} {} + + std::pair emplace(key_type&& key, T&& t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return {it, false}; + } + } + Container::emplace_back(key, t); + return {--this->end(), true}; + } + + T& operator[](Key&& key) + { + return emplace(std::move(key), T{}).first->second; + } + + size_type erase(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } +}; + +} // namespace nlohmann + /*! @brief namespace for Niels Lohmann @@ -16126,7 +16212,7 @@ class basic_json detail::parser_callback_tcb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false - ) + ) { return ::nlohmann::detail::parser(std::move(adapter), std::move(cb), allow_exceptions, ignore_comments); @@ -24662,7 +24748,7 @@ template<> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( is_nothrow_move_constructible::value and is_nothrow_move_assignable::value -) + ) { j1.swap(j2); } From 738c83d6af9f482dccb8a5b021d84750828875ec Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 11 Jul 2020 19:24:32 +0200 Subject: [PATCH 25/25] :green_heart: add test for ordered_map --- test/src/unit-ordered_json.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/src/unit-ordered_json.cpp b/test/src/unit-ordered_json.cpp index e4ffd68ac2..2918e442f8 100644 --- a/test/src/unit-ordered_json.cpp +++ b/test/src/unit-ordered_json.cpp @@ -59,6 +59,13 @@ TEST_CASE("ordered_json") CHECK(j.dump() == "{\"element2\":2,\"element3\":3}"); CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}"); + // remove again and nothing changes + j.erase("element1"); + oj.erase("element1"); + + CHECK(j.dump() == "{\"element2\":2,\"element3\":3}"); + CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}"); + // There are no dup keys cause constructor calls emplace... json multi {{"z", 1}, {"m", 2}, {"m", 3}, {"y", 4}, {"m", 5}}; CHECK(multi.size() == 3);