diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 409a6e79..15921726 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 824e86a1..d9e5428d 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 00000000..744541f3 --- /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 cc822a54..f7f1664e 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 fdf5ac5b..8e663f49 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 00000000..1a97ece6 --- /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}"); +}