summaryrefslogtreecommitdiff
path: root/rapidjsonwrapper.h
diff options
context:
space:
mode:
authorJosh Ferrell <josh@vector35.com>2022-11-17 14:45:22 -0500
committerJosh Ferrell <josh@vector35.com>2022-11-27 13:43:44 -0500
commit8961a635ba84471b614e9416b890652fe0c71159 (patch)
tree8dd243b459855c998a61bdbc1ff358f226d4a4c6 /rapidjsonwrapper.h
parent5f4c09be61de34bb92575a76e52c68f4cc9db5ca (diff)
Implement hash function for rapidjson values
Diffstat (limited to 'rapidjsonwrapper.h')
-rw-r--r--rapidjsonwrapper.h95
1 files changed, 95 insertions, 0 deletions
diff --git a/rapidjsonwrapper.h b/rapidjsonwrapper.h
index 18e6bd8f..cce07f9e 100644
--- a/rapidjsonwrapper.h
+++ b/rapidjsonwrapper.h
@@ -51,6 +51,101 @@ struct ParseException : public std::runtime_error, public rapidjson::ParseResult
#include "rapidjson/writer.h"
#include "rapidjson/prettywriter.h"
+
+
+inline size_t combine(size_t seed, size_t h) noexcept
+{
+ seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
+ return seed;
+}
+
+
+inline size_t HashBytes(const void* const ptr, const size_t len)
+{
+ // Taken from https://stackoverflow.com/questions/34597260/stdhash-value-on-char-value-and-not-on-memory-address
+ const char* cdata = static_cast<const char *>(ptr);
+ uint64_t acc = 0;
+ for (rapidjson::SizeType i = 0; i < len; ++i)
+ {
+ const size_t next = cdata[i];
+ acc = (acc ^ next) * 1099511628211;
+ }
+ return acc;
+}
+
+
+static uint64_t HashRapidValue(const rapidjson::Value& val)
+{
+ const auto type = static_cast<std::size_t>(val.GetType());
+ switch (val.GetType())
+ {
+ case rapidjson::kNullType:
+ case rapidjson::kFalseType:
+ {
+ return combine(type, 0);
+ }
+ case rapidjson::kObjectType:
+ {
+ auto seed = combine(type, val.MemberCount());
+ for (const auto& element : val.GetObject())
+ {
+ const auto h = HashBytes(element.name.GetString(), element.name.GetStringLength());
+ seed = combine(seed, h);
+ seed = combine(seed, HashRapidValue(element.value));
+ }
+ return seed;
+ }
+ case rapidjson::kArrayType:
+ {
+ auto seed = combine(type, val.Size());
+ for (const auto& element : val.GetArray())
+ {
+ seed = combine(seed, HashRapidValue(element));
+ }
+ return seed;
+ }
+ case rapidjson::kStringType:
+ {
+ return combine(type, HashBytes(val.GetString(), val.GetStringLength()));
+ }
+ case rapidjson::kTrueType:
+ {
+ return combine(type, 1);
+ }
+ case rapidjson::kNumberType:
+ {
+ size_t h;
+ if (val.IsDouble())
+ {
+ const double dVal = val.GetDouble();
+ h = HashBytes(&dVal, sizeof(dVal));
+ }
+ else if (val.IsInt())
+ {
+ h = static_cast<size_t>(val.GetInt());
+ }
+ else if (val.IsInt64())
+ {
+ h = static_cast<size_t>(val.GetUint64());
+ }
+ else if (val.IsUint())
+ {
+ h = static_cast<size_t>(val.GetUint());
+ }
+ else
+ {
+ h = val.GetUint64();
+ }
+ return combine(type, h);
+ }
+
+ default:
+ RAPIDJSON_ASSERT(false);
+ return 0;
+ }
+}
+
+
#if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif