mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Tier2: strong optimizations for JSON tools
- Fetch field name strlen at compile time using rapidjson's string refs. - Use from_chars to do string to number conversions which isn't locale aware, for maximum speed.
This commit is contained in:
parent
4188c13780
commit
18e71086b6
@ -62,7 +62,7 @@ void CBanSystem::LoadList(void)
|
|||||||
|
|
||||||
rapidjson::Value::ConstMemberIterator entryIt;
|
rapidjson::Value::ConstMemberIterator entryIt;
|
||||||
|
|
||||||
if (JSON_GetIterator(document, idx, JSONFieldType_e::kObject, entryIt))
|
if (JSON_GetIterator(document, rapidjson::StringRef(idx, strlen(idx)), JSONFieldType_e::kObject, entryIt))
|
||||||
{
|
{
|
||||||
const rapidjson::Value& entry = entryIt->value;
|
const rapidjson::Value& entry = entryIt->value;
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
enum class JSONFieldType_e
|
enum class JSONFieldType_e
|
||||||
{
|
{
|
||||||
|
kInvalid = -1,
|
||||||
|
|
||||||
kNull = 0,
|
kNull = 0,
|
||||||
kObject,
|
|
||||||
|
|
||||||
kBool,
|
kBool,
|
||||||
kNumber,
|
|
||||||
|
|
||||||
kSint32,
|
kSint32,
|
||||||
kUint32,
|
kUint32,
|
||||||
@ -29,14 +29,52 @@ enum class JSONFieldType_e
|
|||||||
kDouble,
|
kDouble,
|
||||||
kLDouble,
|
kLDouble,
|
||||||
|
|
||||||
|
kNumber,
|
||||||
|
|
||||||
kString,
|
kString,
|
||||||
kArray
|
kArray,
|
||||||
|
kObject,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline JSONFieldType_e JSON_ExtractType(const T& data)
|
||||||
|
{
|
||||||
|
if (data.IsNull())
|
||||||
|
return JSONFieldType_e::kNull;
|
||||||
|
if (data.IsBool())
|
||||||
|
return JSONFieldType_e::kBool;
|
||||||
|
if (data.IsInt())
|
||||||
|
return JSONFieldType_e::kSint32;
|
||||||
|
if (data.IsUint())
|
||||||
|
return JSONFieldType_e::kUint32;
|
||||||
|
if (data.IsInt64())
|
||||||
|
return JSONFieldType_e::kSint64;
|
||||||
|
if (data.IsUint64())
|
||||||
|
return JSONFieldType_e::kUint64;
|
||||||
|
if (data.IsFloat())
|
||||||
|
return JSONFieldType_e::kFloat;
|
||||||
|
if (data.IsLosslessFloat())
|
||||||
|
return JSONFieldType_e::kLFloat;
|
||||||
|
if (data.IsDouble())
|
||||||
|
return JSONFieldType_e::kDouble;
|
||||||
|
if (data.IsLosslessDouble())
|
||||||
|
return JSONFieldType_e::kLDouble;
|
||||||
|
if (data.IsNumber())
|
||||||
|
return JSONFieldType_e::kNumber;
|
||||||
|
if (data.IsString())
|
||||||
|
return JSONFieldType_e::kString;
|
||||||
|
if (data.IsArray())
|
||||||
|
return JSONFieldType_e::kArray;
|
||||||
|
if (data.IsObject())
|
||||||
|
return JSONFieldType_e::kObject;
|
||||||
|
|
||||||
|
return JSONFieldType_e::kInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Purpose: gets the object type as string
|
// Purpose: gets the object type as string
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
inline const char* JSON_TypeToString(const rapidjson::Type type)
|
inline const char* JSON_InternalTypeToString(const rapidjson::Type type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@ -50,8 +88,40 @@ inline const char* JSON_TypeToString(const rapidjson::Type type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const char* JSON_TypeToString(const JSONFieldType_e type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case JSONFieldType_e::kNull: return "null";
|
||||||
|
case JSONFieldType_e::kBool: return "bool";
|
||||||
|
case JSONFieldType_e::kSint32: return "signed int32";
|
||||||
|
case JSONFieldType_e::kUint32: return "unsigned int32";
|
||||||
|
case JSONFieldType_e::kSint64: return "signed int64";
|
||||||
|
case JSONFieldType_e::kUint64: return "unsigned int64";
|
||||||
|
case JSONFieldType_e::kFloat: return "float";
|
||||||
|
case JSONFieldType_e::kLFloat: return "lossless float";
|
||||||
|
case JSONFieldType_e::kDouble: return "double";
|
||||||
|
case JSONFieldType_e::kLDouble: return "lossless double";
|
||||||
|
case JSONFieldType_e::kNumber: return "number";
|
||||||
|
case JSONFieldType_e::kString: return "string";
|
||||||
|
case JSONFieldType_e::kArray: return "array";
|
||||||
|
case JSONFieldType_e::kObject: return "object";
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline bool JSON_TypeToString(const T& data)
|
||||||
|
{
|
||||||
|
return JSON_TypeToString(JSON_ExtractType(data));
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Purpose: checks if the member's value is of type provided
|
// Purpose: checks if the member's value is of type provided
|
||||||
|
// NOTE : the switch case was done intentionally instead of JSON_ExtractType
|
||||||
|
// on the object as this function gets used in most accessors that
|
||||||
|
// check on types, and this approach is faster as we already know the
|
||||||
|
// type beforehand
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <class T>
|
template <class T>
|
||||||
inline bool JSON_IsOfType(const T& data, const JSONFieldType_e type)
|
inline bool JSON_IsOfType(const T& data, const JSONFieldType_e type)
|
||||||
@ -60,12 +130,8 @@ inline bool JSON_IsOfType(const T& data, const JSONFieldType_e type)
|
|||||||
{
|
{
|
||||||
case JSONFieldType_e::kNull:
|
case JSONFieldType_e::kNull:
|
||||||
return data.IsNull();
|
return data.IsNull();
|
||||||
case JSONFieldType_e::kObject:
|
|
||||||
return data.IsObject();
|
|
||||||
case JSONFieldType_e::kBool:
|
case JSONFieldType_e::kBool:
|
||||||
return data.IsBool();
|
return data.IsBool();
|
||||||
case JSONFieldType_e::kNumber:
|
|
||||||
return data.IsNumber();
|
|
||||||
case JSONFieldType_e::kSint32:
|
case JSONFieldType_e::kSint32:
|
||||||
return data.IsInt();
|
return data.IsInt();
|
||||||
case JSONFieldType_e::kUint32:
|
case JSONFieldType_e::kUint32:
|
||||||
@ -82,10 +148,14 @@ inline bool JSON_IsOfType(const T& data, const JSONFieldType_e type)
|
|||||||
return data.IsDouble();
|
return data.IsDouble();
|
||||||
case JSONFieldType_e::kLDouble:
|
case JSONFieldType_e::kLDouble:
|
||||||
return data.IsLosslessDouble();
|
return data.IsLosslessDouble();
|
||||||
|
case JSONFieldType_e::kNumber:
|
||||||
|
return data.IsNumber();
|
||||||
case JSONFieldType_e::kString:
|
case JSONFieldType_e::kString:
|
||||||
return data.IsString();
|
return data.IsString();
|
||||||
case JSONFieldType_e::kArray:
|
case JSONFieldType_e::kArray:
|
||||||
return data.IsArray();
|
return data.IsArray();
|
||||||
|
case JSONFieldType_e::kObject:
|
||||||
|
return data.IsObject();
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -116,16 +186,16 @@ inline JSONFieldType_e JSON_GetTypeForType()
|
|||||||
else if constexpr (std::is_same<T, std::string>::value)
|
else if constexpr (std::is_same<T, std::string>::value)
|
||||||
return JSONFieldType_e::kString;
|
return JSONFieldType_e::kString;
|
||||||
else
|
else
|
||||||
static_assert(false, "Cannot classify data type; unsupported.");
|
static_assert(std::is_same_v<T, void>, "Cannot classify data type; unsupported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Purpose: checks if the member exists and if its value is of type provided
|
// Purpose: checks if the member exists and if its value is of type provided
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <class T>
|
template <class T>
|
||||||
inline bool JSON_HasMemberAndIsOfType(const T& data, const char* const member, const JSONFieldType_e type)
|
inline bool JSON_HasMemberAndIsOfType(const T& data, typename T::StringRefType member, const JSONFieldType_e type)
|
||||||
{
|
{
|
||||||
const T::ConstMemberIterator it = data.FindMember(member);
|
const T::ConstMemberIterator it = data.FindMember(rapidjson::Value(member));
|
||||||
|
|
||||||
if (it != data.MemberEnd())
|
if (it != data.MemberEnd())
|
||||||
{
|
{
|
||||||
@ -135,25 +205,63 @@ inline bool JSON_HasMemberAndIsOfType(const T& data, const char* const member, c
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Purpose: checks if the member exists, and sets 'out' to its iterator if the
|
||||||
|
// aforementioned condition is met
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <class T>
|
||||||
|
inline bool JSON_GetIterator(const T& data, typename T::StringRefType member, typename T::ConstMemberIterator& out)
|
||||||
|
{
|
||||||
|
const T::ConstMemberIterator it = data.FindMember(rapidjson::Value(member));
|
||||||
|
|
||||||
|
if (it != data.MemberEnd())
|
||||||
|
{
|
||||||
|
out = it;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Purpose: checks if the member exists and if its value is of type provided,
|
||||||
|
// and sets 'out' to its iterator if all aforementioned conditions
|
||||||
|
// are met
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <class T>
|
||||||
|
inline bool JSON_GetIterator(const T& data, typename T::StringRefType member,
|
||||||
|
const JSONFieldType_e type, typename T::ConstMemberIterator& out)
|
||||||
|
{
|
||||||
|
const T::ConstMemberIterator it = data.FindMember(rapidjson::Value(member));
|
||||||
|
|
||||||
|
if (it != data.MemberEnd())
|
||||||
|
{
|
||||||
|
if (JSON_IsOfType(it->value, type))
|
||||||
|
{
|
||||||
|
out = it;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found or didn't match specified type.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Purpose: checks if the member exists and if its value is of specified type,
|
// Purpose: checks if the member exists and if its value is of specified type,
|
||||||
// and sets 'out' to its value if all aforementioned conditions
|
// and sets 'out' to its value if all aforementioned conditions
|
||||||
// are met
|
// are met
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <class T, class V>
|
template <class T, class V>
|
||||||
inline bool JSON_GetValue(const T& data, const char* const member, const JSONFieldType_e type, V& out)
|
inline bool JSON_GetValue(const T& data, typename T::StringRefType member, const JSONFieldType_e type, V& out)
|
||||||
{
|
{
|
||||||
const T::ConstMemberIterator it = data.FindMember(member);
|
rapidjson::Document::ConstMemberIterator it;
|
||||||
|
|
||||||
if (it != data.MemberEnd())
|
if (JSON_GetIterator(data, member, type, it))
|
||||||
{
|
{
|
||||||
const rapidjson::Value& val = it->value;
|
out = it->value.Get<V>();
|
||||||
|
return true;
|
||||||
if (JSON_IsOfType(val, type))
|
|
||||||
{
|
|
||||||
out = val.Get<V>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not found or didn't match specified type.
|
// Not found or didn't match specified type.
|
||||||
@ -165,26 +273,21 @@ inline bool JSON_GetValue(const T& data, const char* const member, const JSONFie
|
|||||||
// and sets 'out' to its value if all aforementioned conditions are met
|
// and sets 'out' to its value if all aforementioned conditions are met
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <class T, class V>
|
template <class T, class V>
|
||||||
inline bool JSON_GetValue(const T& data, const char* const member, V& out)
|
inline bool JSON_GetValue(const T& data, typename T::StringRefType member, V& out)
|
||||||
{
|
{
|
||||||
const T::ConstMemberIterator it = data.FindMember(member);
|
rapidjson::Document::ConstMemberIterator it;
|
||||||
|
|
||||||
if (it != data.MemberEnd())
|
if (JSON_GetIterator(data, member, JSON_GetTypeForType<V>(), it))
|
||||||
{
|
{
|
||||||
const rapidjson::Value& val = it->value;
|
out = it->value.Get<V>();
|
||||||
|
return true;
|
||||||
if (JSON_IsOfType(val, JSON_GetTypeForType<V>()))
|
|
||||||
{
|
|
||||||
out = val.Get<V>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not found or didn't match classified type.
|
// Not found or didn't match classified type.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <class T>
|
template <class T>
|
||||||
inline bool JSON_GetValue(const T& data, const char* const member, std::string& out)
|
inline bool JSON_GetValue(const T& data, typename T::StringRefType member, std::string& out)
|
||||||
{
|
{
|
||||||
const char* stringVal;
|
const char* stringVal;
|
||||||
|
|
||||||
@ -203,7 +306,7 @@ inline bool JSON_GetValue(const T& data, const char* const member, std::string&
|
|||||||
// else the provided default gets returned
|
// else the provided default gets returned
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <class T, class V>
|
template <class T, class V>
|
||||||
inline V JSON_GetValueOrDefault(const T& data, const char* const member, const V def)
|
inline V JSON_GetValueOrDefault(const T& data, typename T::StringRefType member, const V def)
|
||||||
{
|
{
|
||||||
V val;
|
V val;
|
||||||
|
|
||||||
@ -215,47 +318,25 @@ inline V JSON_GetValueOrDefault(const T& data, const char* const member, const V
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
template <class V>
|
||||||
// Purpose: checks if the member exists and if its value is of type provided,
|
inline bool JSON_StringToNumber(const char* const str, const size_t len, V& num)
|
||||||
// and sets 'out' to its iterator if all aforementioned conditions
|
|
||||||
// are met
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <class T>
|
|
||||||
inline bool JSON_GetIterator(const T& data, const char* const member,
|
|
||||||
const JSONFieldType_e type, typename T::ConstMemberIterator& out)
|
|
||||||
{
|
{
|
||||||
const T::ConstMemberIterator it = data.FindMember(member);
|
const char* const end = &str[len];
|
||||||
|
std::from_chars_result result;
|
||||||
|
|
||||||
if (it != data.MemberEnd())
|
if constexpr ((std::is_same<V, int32_t>::value) || (std::is_same<V, int64_t>::value) ||
|
||||||
|
(std::is_same<V, uint32_t>::value) || (std::is_same<V, uint64_t>::value))
|
||||||
{
|
{
|
||||||
if (JSON_IsOfType(it->value, type))
|
result = std::from_chars(str, end, num, 0);
|
||||||
{
|
|
||||||
out = it;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if constexpr ((std::is_same<V, float>::value) || (std::is_same<V, double>::value))
|
||||||
// Not found or didn't match specified type.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Purpose: checks if the member exists, and sets 'out' to its iterator if the
|
|
||||||
// aforementioned condition is met
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <class T>
|
|
||||||
inline bool JSON_GetIterator(const T& data, const char* const member, typename T::ConstMemberIterator& out)
|
|
||||||
{
|
|
||||||
const T::ConstMemberIterator it = data.FindMember(member);
|
|
||||||
|
|
||||||
if (it != data.MemberEnd())
|
|
||||||
{
|
{
|
||||||
out = it;
|
result = std::from_chars(str, end, num, std::chars_format::general);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
static_assert(std::is_same_v<V, void>, "Cannot classify numeric type; unsupported.");
|
||||||
|
|
||||||
// Not found.
|
return (result.ptr == end) && (result.ec == std::errc());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -272,37 +353,19 @@ inline bool JSON_ParseNumber(const T& data, V& num)
|
|||||||
}
|
}
|
||||||
else if (JSON_IsOfType(data, JSONFieldType_e::kString))
|
else if (JSON_IsOfType(data, JSONFieldType_e::kString))
|
||||||
{
|
{
|
||||||
const char* const string = data.GetString();
|
return JSON_StringToNumber(data.GetString(), data.GetStringLength(), num);
|
||||||
char* end = nullptr;
|
|
||||||
|
|
||||||
if constexpr (std::is_same<V, int32_t>::value)
|
|
||||||
num = strtol(string, &end, 0);
|
|
||||||
else if constexpr (std::is_same<V, int64_t>::value)
|
|
||||||
num = strtoll(string, &end, 0);
|
|
||||||
else if constexpr (std::is_same<V, uint32_t>::value)
|
|
||||||
num = strtoul(string, &end, 0);
|
|
||||||
else if constexpr (std::is_same<V, uint64_t>::value)
|
|
||||||
num = strtoull(string, &end, 0);
|
|
||||||
else if constexpr (std::is_same<V, float>::value)
|
|
||||||
num = static_cast<float>(strtod(string, &end));
|
|
||||||
else if constexpr (std::is_same<V, double>::value)
|
|
||||||
num = strtod(string, &end);
|
|
||||||
else
|
|
||||||
static_assert(false, "Cannot classify numeric type; unsupported.");
|
|
||||||
|
|
||||||
return end == &string[data.GetStringLength()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <class T, class V>
|
template <class T, class V>
|
||||||
inline bool JSON_ParseNumber(const T& data, const char* const member, V& num)
|
inline bool JSON_ParseNumber(const T& data, typename T::StringRefType member, V& num)
|
||||||
{
|
{
|
||||||
rapidjson::Document::ConstMemberIterator it;
|
rapidjson::Document::ConstMemberIterator it;
|
||||||
|
|
||||||
if (JSON_GetIterator(data, member, it))
|
if (JSON_GetIterator(data, member, it))
|
||||||
{
|
{
|
||||||
return JSON_ParseNumber(it->value, num);;
|
return JSON_ParseNumber(it->value, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -314,7 +377,7 @@ inline bool JSON_ParseNumber(const T& data, const char* const member, V& num)
|
|||||||
// else the provided default gets returned
|
// else the provided default gets returned
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <class T, class V>
|
template <class T, class V>
|
||||||
inline V JSON_GetNumberOrDefault(const T& data, const char* const member, V def)
|
inline V JSON_GetNumberOrDefault(const T& data, typename T::StringRefType member, V def)
|
||||||
{
|
{
|
||||||
V num;
|
V num;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user