From a144800774357d44668f21b3aa246f1034bf7e47 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
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<nlohmann::json>::value and
+                         is_nothrow_move_assignable<nlohmann::json>::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<nlohmann::json>::value and
+                         is_nothrow_move_assignable<nlohmann::json>::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<bool>() == 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<double>() == 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")