From a144800774357d44668f21b3aa246f1034bf7e47 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 19 Jan 2015 19:51:07 +0100 Subject: [PATCH] + implemented member and non-member swap --- header_only/json.h | 26 ++++++++++- src/json.cc | 6 +++ src/json.h | 19 +++++++- test/json_unit.cc | 107 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 4 deletions(-) diff --git a/header_only/json.h b/header_only/json.h index 857e9376..14be12c3 100644 --- a/header_only/json.h +++ b/header_only/json.h @@ -34,7 +34,6 @@ due to alignment. @bug Numbers are currently handled too generously. There are several formats that are forbidden by the standard, but are accepted by the parser. -@todo Implement json::swap() @todo Implement json::insert(), json::emplace(), json::emplace_back, json::erase @todo Implement json::reverse_iterator, json::const_reverse_iterator, json::rbegin(), json::rend(), json::crbegin(), json::crend()? @@ -178,6 +177,7 @@ class json operator std::string() const; /// implicit conversion to integer (only for numbers) operator int() const; + operator long() const; /// implicit conversion to double (only for numbers) operator double() const; /// implicit conversion to Boolean (only for Booleans) @@ -289,6 +289,9 @@ class json /// removes all elements from compounds and resets values to default void clear() noexcept; + /// swaps content with other object + void swap(json&) noexcept; + /// return the type of the object value_type type() const noexcept; @@ -418,7 +421,7 @@ class json /// read the next character, stripping whitespace bool next(); /// raise an exception with an error message - inline void error(const std::string&) const __attribute__((noreturn)); + [[noreturn]] inline void error(const std::string&) const; /// parse a quoted string inline std::string parseString(); /// transforms a unicode codepoint to it's UTF-8 presentation @@ -450,6 +453,19 @@ class json /// user-defined literal operator to create JSON objects from strings nlohmann::json operator "" _json(const char*, std::size_t); + +// specialization of std::swap +namespace std +{ +template <> +/// swaps the values of two JSON objects +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept(is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value) +{ + j1.swap(j2); +} +} /*! @file @copyright The code is licensed under the MIT License @@ -1720,6 +1736,12 @@ void json::clear() noexcept } } +void json::swap(json& o) noexcept +{ + std::swap(type_, o.type_); + std::swap(value_, o.value_); +} + json::value_type json::type() const noexcept { return type_; diff --git a/src/json.cc b/src/json.cc index 30c37877..3ae9d15f 100644 --- a/src/json.cc +++ b/src/json.cc @@ -1268,6 +1268,12 @@ void json::clear() noexcept } } +void json::swap(json& o) noexcept +{ + std::swap(type_, o.type_); + std::swap(value_, o.value_); +} + json::value_type json::type() const noexcept { return type_; diff --git a/src/json.h b/src/json.h index 9fe4beb2..f806fe06 100644 --- a/src/json.h +++ b/src/json.h @@ -34,7 +34,6 @@ due to alignment. @bug Numbers are currently handled too generously. There are several formats that are forbidden by the standard, but are accepted by the parser. -@todo Implement json::swap() @todo Implement json::insert(), json::emplace(), json::emplace_back, json::erase @todo Implement json::reverse_iterator, json::const_reverse_iterator, json::rbegin(), json::rend(), json::crbegin(), json::crend()? @@ -289,6 +288,9 @@ class json /// removes all elements from compounds and resets values to default void clear() noexcept; + /// swaps content with other object + void swap(json&) noexcept; + /// return the type of the object value_type type() const noexcept; @@ -418,7 +420,7 @@ class json /// read the next character, stripping whitespace bool next(); /// raise an exception with an error message - inline void error(const std::string&) const __attribute__((noreturn)); + [[noreturn]] inline void error(const std::string&) const; /// parse a quoted string inline std::string parseString(); /// transforms a unicode codepoint to it's UTF-8 presentation @@ -450,3 +452,16 @@ class json /// user-defined literal operator to create JSON objects from strings nlohmann::json operator "" _json(const char*, std::size_t); + +// specialization of std::swap +namespace std +{ +template <> +/// swaps the values of two JSON objects +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept(is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value) +{ + j1.swap(j2); +} +} diff --git a/test/json_unit.cc b/test/json_unit.cc index fb3abbeb..57fc6cfc 100644 --- a/test/json_unit.cc +++ b/test/json_unit.cc @@ -311,6 +311,17 @@ TEST_CASE("array") json::const_iterator i4(i1); json::const_iterator i5(i2); } + + SECTION("Container operations") + { + json a1 = {1, 2, 3, 4}; + json a2 = {"one", "two", "three"}; + + a1.swap(a2); + + CHECK(a1 == json({"one", "two", "three"})); + CHECK(a2 == json({1, 2, 3, 4})); + } } TEST_CASE("object") @@ -714,6 +725,22 @@ TEST_CASE("object") json::const_iterator i4(i1); json::const_iterator i5(i2); } + + SECTION("Container operations") + { + json o1 = { {"one", "eins"}, {"two", "zwei"} }; + json o2 = { {"one", 1}, {"two", 2} }; + + o1.swap(o2); + + CHECK(o1 == json({ {"one", 1}, {"two", 2} })); + CHECK(o2 == json({ {"one", "eins"}, {"two", "zwei"} })); + + std::swap(o1, o2); + + CHECK(o1 == json({ {"one", "eins"}, {"two", "zwei"} })); + CHECK(o2 == json({ {"one", 1}, {"two", 2} })); + } } TEST_CASE("null") @@ -777,6 +804,22 @@ TEST_CASE("null") j1.clear(); CHECK(j1 == json(nullptr)); } + + SECTION("Container operations") + { + json n1; + json n2; + + n1.swap(n2); + + CHECK(n1 == json()); + CHECK(n2 == json()); + + std::swap(n1, n2); + + CHECK(n1 == json()); + CHECK(n2 == json()); + } } TEST_CASE("string") @@ -871,6 +914,22 @@ TEST_CASE("string") CHECK(json("\f").dump(0) == "\"\\f\""); CHECK(json("\r").dump(0) == "\"\\r\""); } + + SECTION("Container operations") + { + json s1 = "foo"; + json s2 = "bar"; + + s1.swap(s2); + + CHECK(s1 == json("bar")); + CHECK(s2 == json("foo")); + + std::swap(s1, s2); + + CHECK(s1 == json("foo")); + CHECK(s2 == json("bar")); + } } TEST_CASE("boolean") @@ -950,6 +1009,22 @@ TEST_CASE("boolean") j1.clear(); CHECK(j1.get() == false); } + + SECTION("Container operations") + { + json b1 = true; + json b2 = false; + + b1.swap(b2); + + CHECK(b1 == json(false)); + CHECK(b2 == json(true)); + + std::swap(b1, b2); + + CHECK(b1 == json(true)); + CHECK(b2 == json(false)); + } } TEST_CASE("number (int)") @@ -1036,6 +1111,22 @@ TEST_CASE("number (int)") CHECK(j2.find("foo") == j2.end()); CHECK(j2.find(std::string("foo")) == j2.end()); } + + SECTION("Container operations") + { + json n1 = 23; + json n2 = 42; + + n1.swap(n2); + + CHECK(n1 == json(42)); + CHECK(n2 == json(23)); + + std::swap(n1, n2); + + CHECK(n1 == json(23)); + CHECK(n2 == json(42)); + } } TEST_CASE("number (float)") @@ -1115,6 +1206,22 @@ TEST_CASE("number (float)") j1.clear(); CHECK(j1.get() == 0.0); } + + SECTION("Container operations") + { + json n1 = 23.42; + json n2 = 42.23; + + n1.swap(n2); + + CHECK(n1 == json(42.23)); + CHECK(n2 == json(23.42)); + + std::swap(n1, n2); + + CHECK(n1 == json(23.42)); + CHECK(n2 == json(42.23)); + } } TEST_CASE("Iterators")