From b821ed074ff93e7108deb81cb5191ef13297b2eb Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Wed, 15 Jul 2020 13:45:16 +0200
Subject: [PATCH] :bulb: add documentation

---
 include/nlohmann/detail/hash.hpp | 35 +++++++++++++++++++++++---------
 single_include/nlohmann/json.hpp | 35 +++++++++++++++++++++++---------
 test/src/unit-hash.cpp           |  4 ++--
 3 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/include/nlohmann/detail/hash.hpp b/include/nlohmann/detail/hash.hpp
index a4aaae4a..d3313e96 100644
--- a/include/nlohmann/detail/hash.hpp
+++ b/include/nlohmann/detail/hash.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <cstddef> // size_t
+#include <cstddef> // size_t, uint8_t
 #include <functional> // hash
 
 namespace nlohmann
@@ -8,12 +8,24 @@ namespace nlohmann
 namespace detail
 {
 
+// boost::hash_combine
 std::size_t combine(std::size_t seed, std::size_t h) noexcept
 {
     seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
     return seed;
 }
 
+/*!
+@brief hash a JSON value
+
+The hash function tries to rely on std::hash where possible. Furthermore, the
+type of the JSON value is taken into account to have different hash values for
+null, 0, 0U, and false, etc.
+
+@tparam BasicJsonType basic_json specialization
+@param j JSON value to hash
+@return hash value of j
+*/
 template<typename BasicJsonType>
 std::size_t hash(const BasicJsonType& j)
 {
@@ -22,15 +34,18 @@ std::size_t hash(const BasicJsonType& j)
     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
     using number_float_t = typename BasicJsonType::number_float_t;
 
+    const auto type = static_cast<std::size_t>(j.type());
     switch (j.type())
     {
         case BasicJsonType::value_t::null:
         case BasicJsonType::value_t::discarded:
-            return combine(static_cast<std::size_t>(j.type()), 0);
+        {
+            return combine(type, 0);
+        }
 
         case BasicJsonType::value_t::object:
         {
-            auto seed = combine(static_cast<std::size_t>(j.type()), j.size());
+            auto seed = combine(type, j.size());
             for (const auto& element : j.items())
             {
                 const auto h = std::hash<string_t> {}(element.key());
@@ -42,7 +57,7 @@ std::size_t hash(const BasicJsonType& j)
 
         case BasicJsonType::value_t::array:
         {
-            auto seed = combine(static_cast<std::size_t>(j.type()), j.size());
+            auto seed = combine(type, j.size());
             for (const auto& element : j)
             {
                 seed = combine(seed, hash(element));
@@ -53,36 +68,36 @@ std::size_t hash(const BasicJsonType& j)
         case BasicJsonType::value_t::string:
         {
             const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case BasicJsonType::value_t::boolean:
         {
             const auto h = std::hash<bool> {}(j.template get<bool>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case BasicJsonType::value_t::number_integer:
         {
             const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case nlohmann::detail::value_t::number_unsigned:
         {
             const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case nlohmann::detail::value_t::number_float:
         {
             const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case nlohmann::detail::value_t::binary:
         {
-            auto seed = combine(static_cast<std::size_t>(j.type()), j.get_binary().size());
+            auto seed = combine(type, j.get_binary().size());
             const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
             seed = combine(seed, h);
             seed = combine(seed, j.get_binary().subtype());
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index f5a6d8fe..5e32f0b6 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -4445,7 +4445,7 @@ class byte_container_with_subtype : public BinaryType
 // #include <nlohmann/detail/hash.hpp>
 
 
-#include <cstddef> // size_t
+#include <cstddef> // size_t, uint8_t
 #include <functional> // hash
 
 namespace nlohmann
@@ -4453,12 +4453,24 @@ namespace nlohmann
 namespace detail
 {
 
+// boost::hash_combine
 std::size_t combine(std::size_t seed, std::size_t h) noexcept
 {
     seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
     return seed;
 }
 
+/*!
+@brief hash a JSON value
+
+The hash function tries to rely on std::hash where possible. Furthermore, the
+type of the JSON value is taken into account to have different hash values for
+null, 0, 0U, and false, etc.
+
+@tparam BasicJsonType basic_json specialization
+@param j JSON value to hash
+@return hash value of j
+*/
 template<typename BasicJsonType>
 std::size_t hash(const BasicJsonType& j)
 {
@@ -4467,15 +4479,18 @@ std::size_t hash(const BasicJsonType& j)
     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
     using number_float_t = typename BasicJsonType::number_float_t;
 
+    const auto type = static_cast<std::size_t>(j.type());
     switch (j.type())
     {
         case BasicJsonType::value_t::null:
         case BasicJsonType::value_t::discarded:
-            return combine(static_cast<std::size_t>(j.type()), 0);
+        {
+            return combine(type, 0);
+        }
 
         case BasicJsonType::value_t::object:
         {
-            auto seed = combine(static_cast<std::size_t>(j.type()), j.size());
+            auto seed = combine(type, j.size());
             for (const auto& element : j.items())
             {
                 const auto h = std::hash<string_t> {}(element.key());
@@ -4487,7 +4502,7 @@ std::size_t hash(const BasicJsonType& j)
 
         case BasicJsonType::value_t::array:
         {
-            auto seed = combine(static_cast<std::size_t>(j.type()), j.size());
+            auto seed = combine(type, j.size());
             for (const auto& element : j)
             {
                 seed = combine(seed, hash(element));
@@ -4498,36 +4513,36 @@ std::size_t hash(const BasicJsonType& j)
         case BasicJsonType::value_t::string:
         {
             const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case BasicJsonType::value_t::boolean:
         {
             const auto h = std::hash<bool> {}(j.template get<bool>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case BasicJsonType::value_t::number_integer:
         {
             const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case nlohmann::detail::value_t::number_unsigned:
         {
             const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case nlohmann::detail::value_t::number_float:
         {
             const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
-            return combine(static_cast<std::size_t>(j.type()), h);
+            return combine(type, h);
         }
 
         case nlohmann::detail::value_t::binary:
         {
-            auto seed = combine(static_cast<std::size_t>(j.type()), j.get_binary().size());
+            auto seed = combine(type, j.get_binary().size());
             const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
             seed = combine(seed, h);
             seed = combine(seed, j.get_binary().subtype());
diff --git a/test/src/unit-hash.cpp b/test/src/unit-hash.cpp
index fddaceb9..186cad88 100644
--- a/test/src/unit-hash.cpp
+++ b/test/src/unit-hash.cpp
@@ -54,7 +54,7 @@ TEST_CASE("hash")
     hashes.insert(std::hash<json> {}(json("foo")));
 
     // number
-    hashes.insert(std::hash<json> {}(json(int(0))));
+    hashes.insert(std::hash<json> {}(json(0)));
     hashes.insert(std::hash<json> {}(json(unsigned(0))));
 
     hashes.insert(std::hash<json> {}(json(-1)));
@@ -81,4 +81,4 @@ TEST_CASE("hash")
     hashes.insert(std::hash<json> {}(json(json::value_t::discarded)));
 
     CHECK(hashes.size() == 21);
-}
\ No newline at end of file
+}