feat: enhance JSON management with new rotation and value counting features

- Added ObjectRotate and ArrayRotate methods for rotating key-value pairs in JSON objects and arrays, respectively
- Introduced GetValCount method to retrieve the total number of values in immutable JSON documents
- Renamed all Float-related methods to Double in C++ interface (IJsonManager) for better precision clarity
- Fixed TypeAccess configuration in handle type registration to allow external extensions to create JSON handles by properly setting HTypeAccess_Create flag
- Renamed GetHandleType to GetJsonHandleType for better clarity and consistency
- Updated documentation to clarify usage and performance considerations for new methods
- Enhanced tests to cover rotation functionality and value counting in various JSON structures
This commit is contained in:
ProjectSky 2025-11-21 00:07:25 +08:00
parent f596135996
commit e1c5578324
7 changed files with 854 additions and 478 deletions

View File

@ -15,8 +15,7 @@ class JsonArrIter;
class JsonObjIter;
#define SMINTERFACE_JSONMANAGER_NAME "IJsonManager"
#define SMINTERFACE_JSONMANAGER_VERSION 2
#define JSON_PACK_ERROR_SIZE 256
#define SMINTERFACE_JSONMANAGER_VERSION 3
#define JSON_ERROR_BUFFER_SIZE 256
#define JSON_INT64_BUFFER_SIZE 32
@ -98,21 +97,36 @@ public:
* @return true on success, false if buffer is too small or on error
*
* @note The out_size parameter returns the size including null terminator
* @note Use GetSerializedSize() with the same write_flg to determine buffer size
* @warning This method performs multiple memory allocations and copies, resulting in poor performance.
* For better performance, use WriteToStringPtr() instead, which avoids intermediate buffers
*
* @warning Buffer Size Requirements:
* This function does not allocate memory, but the buffer must be larger than
* the final JSON size to allow temporary space.
*
* The extra space is needed temporarily for each value while it is written,
* and is reused for later values:
* - Number: 40 bytes
* - String: 16 + (str_len * 6) bytes
* - Other values: 16 bytes
* - Nesting depth: 16 * max_json_depth bytes
*
* @note GetSerializedSize() only returns the final JSON size, NOT including the temporary space
* You must manually add extra buffer space based on your JSON content
* @note For most use cases, prefer WriteToStringPtr() for simplicity
* Use this method only when you need to avoid heap allocation (e.g., stack buffers, pre-allocated pools)
*/
virtual bool WriteToString(JsonValue* handle, char* buffer, size_t buffer_size,
uint32_t write_flg = 0, size_t* out_size = nullptr) = 0;
/**
* Write JSON to string and return allocated string (performance-optimized version)
* Write JSON to string and return allocated string
* @param handle JSON value
* @param write_flg Write flags (YYJSON_WRITE_FLAG values, default: 0)
* @param out_size Pointer to receive actual size written (including null terminator) optional
* @return Allocated string pointer on success, nullptr on error. Caller must free() the returned pointer
*
* @note This is the recommended method for serialization as it avoids intermediate buffer allocations
* @note This function handles memory allocation internally,
* avoiding the complexity of manual buffer size calculation required by WriteToString()
* @note This is the recommended method for most use cases due to its simplicity and safety
*/
virtual char* WriteToStringPtr(JsonValue* handle, uint32_t write_flg = 0, size_t* out_size = nullptr) = 0;
@ -383,6 +397,17 @@ public:
*/
virtual size_t GetRefCount(JsonValue* handle) = 0;
/**
* Get the total number of values in a document
* @param handle JSON value
* @return Total number of values in the document tree, 0 if handle is null or mutable
* @note Only works on immutable documents (parsed from JSON)
* @note Useful for performance planning and memory estimation
* @note Counts ALL values including containers, keys, and leaf values
* Example: {"a":1,"b":2,"c":3} returns 7 (1 object + 3 keys + 3 values)
*/
virtual size_t GetValCount(JsonValue* handle) = 0;
/**
* Create an empty mutable JSON object
* @return New mutable JSON object or nullptr on failure
@ -466,10 +491,11 @@ public:
* Get float value by key
* @param handle JSON object
* @param key Key name
* @param out_value Pointer to receive float value
* @param out_value Pointer to receive double value
* @return true on success, false if key not found or type mismatch
* @note Integers values are auto converted to double
*/
virtual bool ObjectGetFloat(JsonValue* handle, const char* key, double* out_value) = 0;
virtual bool ObjectGetDouble(JsonValue* handle, const char* key, double* out_value) = 0;
/**
* Get integer value by key
@ -547,13 +573,13 @@ public:
virtual bool ObjectSetBool(JsonValue* handle, const char* key, bool value) = 0;
/**
* Set float value by key (mutable only)
* Set double value by key (mutable only)
* @param handle Mutable JSON object
* @param key Key name
* @param value Float value
* @param value Double value
* @return true on success
*/
virtual bool ObjectSetFloat(JsonValue* handle, const char* key, double value) = 0;
virtual bool ObjectSetDouble(JsonValue* handle, const char* key, double value) = 0;
/**
* Set integer value by key (mutable only)
@ -614,6 +640,18 @@ public:
*/
virtual bool ObjectSort(JsonValue* handle, JSON_SORT_ORDER sort_mode) = 0;
/**
* Rotate key-value pairs in the object
* @param handle Mutable JSON object
* @param idx Number of positions to rotate (must be less than object size)
* @return true on success, false if idx >= object size or object is immutable
* @note Only works on mutable objects
* @note Example: {"a":1,"b":2,"c":3,"d":4} rotate 1 becomes {"b":2,"c":3,"d":4,"a":1}
* @note Valid range: 0 <= idx < object size
* @warning This function takes linear time proportional to the rotation amount
*/
virtual bool ObjectRotate(JsonValue* handle, size_t idx) = 0;
/**
* Create an empty mutable JSON array
* @return New mutable JSON array or nullptr on failure
@ -657,12 +695,12 @@ public:
virtual JsonValue* ArrayInitWithBool(const bool* values, size_t count) = 0;
/**
* Create a JSON array from float values
* @param values Array of float values
* Create a JSON array from double values
* @param values Array of double values
* @param count Number of values
* @return New JSON array or nullptr on failure
*/
virtual JsonValue* ArrayInitWithFloat(const double* values, size_t count) = 0;
virtual JsonValue* ArrayInitWithDouble(const double* values, size_t count) = 0;
/**
* Parse a JSON array from string
@ -727,13 +765,14 @@ public:
virtual bool ArrayGetBool(JsonValue* handle, size_t index, bool* out_value) = 0;
/**
* Get float value at index
* Get double value at index
* @param handle JSON array
* @param index Element index
* @param out_value Pointer to receive float value
* @param out_value Pointer to receive double value
* @return true on success, false if index out of bounds or type mismatch
* @note Integers values are auto converted to double
*/
virtual bool ArrayGetFloat(JsonValue* handle, size_t index, double* out_value) = 0;
virtual bool ArrayGetDouble(JsonValue* handle, size_t index, double* out_value) = 0;
/**
* Get integer value at index
@ -790,13 +829,13 @@ public:
virtual bool ArrayReplaceBool(JsonValue* handle, size_t index, bool value) = 0;
/**
* Replace element at index with float (mutable only)
* Replace element at index with double (mutable only)
* @param handle Mutable JSON array
* @param index Element index
* @param value Float value
* @param value Double value
* @return true on success
*/
virtual bool ArrayReplaceFloat(JsonValue* handle, size_t index, double value) = 0;
virtual bool ArrayReplaceDouble(JsonValue* handle, size_t index, double value) = 0;
/**
* Replace element at index with integer (mutable only)
@ -850,12 +889,12 @@ public:
virtual bool ArrayAppendBool(JsonValue* handle, bool value) = 0;
/**
* Append float to end of array (mutable only)
* Append double to end of array (mutable only)
* @param handle Mutable JSON array
* @param value Float value
* @param value Double value
* @return true on success
*/
virtual bool ArrayAppendFloat(JsonValue* handle, double value) = 0;
virtual bool ArrayAppendDouble(JsonValue* handle, double value) = 0;
/**
* Append integer to end of array (mutable only)
@ -925,13 +964,13 @@ public:
virtual bool ArrayInsertInt64(JsonValue* handle, size_t index, std::variant<int64_t, uint64_t> value) = 0;
/**
* Insert float at specific index (mutable only)
* Insert double at specific index (mutable only)
* @param handle Mutable JSON array
* @param index Element index
* @param value Float value
* @param value Double value
* @return true on success
*/
virtual bool ArrayInsertFloat(JsonValue* handle, size_t index, double value) = 0;
virtual bool ArrayInsertDouble(JsonValue* handle, size_t index, double value) = 0;
/**
* Insert string at specific index (mutable only)
@ -983,12 +1022,12 @@ public:
virtual bool ArrayPrependInt64(JsonValue* handle, std::variant<int64_t, uint64_t> value) = 0;
/**
* Prepend float to beginning of array (mutable only)
* Prepend double to beginning of array (mutable only)
* @param handle Mutable JSON array
* @param value Float value
* @param value Double value
* @return true on success
*/
virtual bool ArrayPrependFloat(JsonValue* handle, double value) = 0;
virtual bool ArrayPrependDouble(JsonValue* handle, double value) = 0;
/**
* Prepend string to beginning of array (mutable only)
@ -1076,12 +1115,12 @@ public:
virtual int ArrayIndexOfInt64(JsonValue* handle, std::variant<int64_t, uint64_t> search_value) = 0;
/**
* Find index of float value
* Find index of double value
* @param handle JSON array
* @param search_value Float value to search for
* @param search_value Double value to search for
* @return Index of first match, or -1 if not found
*/
virtual int ArrayIndexOfFloat(JsonValue* handle, double search_value) = 0;
virtual int ArrayIndexOfDouble(JsonValue* handle, double search_value) = 0;
/**
* Sort array elements
@ -1092,6 +1131,18 @@ public:
*/
virtual bool ArraySort(JsonValue* handle, JSON_SORT_ORDER sort_mode) = 0;
/**
* Rotate array elements
* @param handle Mutable JSON array
* @param idx Number of positions to rotate (must be less than array length)
* @return true on success, false if idx >= array length or array is immutable
* @note Only works on mutable arrays
* @note Example: [1,2,3,4,5] rotate 2 becomes [3,4,5,1,2]
* @note Valid range: 0 <= idx < array length
* @warning This function takes linear time proportional to the rotation amount
*/
virtual bool ArrayRotate(JsonValue* handle, size_t idx) = 0;
/**
* Create JSON value from format string and parameters
* @param format Format string (e.g., "{s:i,s:s}", "[i,s,b]")
@ -1120,11 +1171,11 @@ public:
virtual JsonValue* CreateBool(bool value) = 0;
/**
* Create a JSON float value
* @param value Float value
* @return New JSON float or nullptr on failure
* Create a JSON double value
* @param value Double value
* @return New JSON double or nullptr on failure
*/
virtual JsonValue* CreateFloat(double value) = 0;
virtual JsonValue* CreateDouble(double value) = 0;
/**
* Create a JSON integer value
@ -1162,12 +1213,13 @@ public:
virtual bool GetBool(JsonValue* handle, bool* out_value) = 0;
/**
* Get float value from JSON
* Get double value from JSON
* @param handle JSON value
* @param out_value Pointer to receive float value
* @param out_value Pointer to receive double value
* @return true on success, false on type mismatch
* @note Integers values are auto converted to double
*/
virtual bool GetFloat(JsonValue* handle, double* out_value) = 0;
virtual bool GetDouble(JsonValue* handle, double* out_value) = 0;
/**
* Get integer value from JSON
@ -1218,15 +1270,16 @@ public:
char* error = nullptr, size_t error_size = 0) = 0;
/**
* Get float value using JSON Pointer
* Get double value using JSON Pointer
* @param handle JSON value
* @param path JSON Pointer path
* @param out_value Pointer to receive float value
* @param out_value Pointer to receive double value
* @param error Error buffer (optional)
* @param error_size Error buffer size
* @return true on success, false on error
* @note Integers values are auto converted to double
*/
virtual bool PtrGetFloat(JsonValue* handle, const char* path, double* out_value,
virtual bool PtrGetDouble(JsonValue* handle, const char* path, double* out_value,
char* error = nullptr, size_t error_size = 0) = 0;
/**
@ -1315,15 +1368,15 @@ public:
char* error = nullptr, size_t error_size = 0) = 0;
/**
* Set float value using JSON Pointer (mutable only)
* Set double value using JSON Pointer (mutable only)
* @param handle Mutable JSON value
* @param path JSON Pointer path
* @param value Float value
* @param value Double value
* @param error Error buffer (optional)
* @param error_size Error buffer size
* @return true on success, false on error
*/
virtual bool PtrSetFloat(JsonValue* handle, const char* path, double value,
virtual bool PtrSetDouble(JsonValue* handle, const char* path, double value,
char* error = nullptr, size_t error_size = 0) = 0;
/**
@ -1398,15 +1451,15 @@ public:
char* error = nullptr, size_t error_size = 0) = 0;
/**
* Add float to array using JSON Pointer (mutable only)
* Add double to array using JSON Pointer (mutable only)
* @param handle Mutable JSON value
* @param path JSON Pointer path to array
* @param value Float value
* @param value Double value
* @param error Error buffer (optional)
* @param error_size Error buffer size
* @return true on success, false on error
*/
virtual bool PtrAddFloat(JsonValue* handle, const char* path, double value,
virtual bool PtrAddDouble(JsonValue* handle, const char* path, double value,
char* error = nullptr, size_t error_size = 0) = 0;
/**
@ -1485,13 +1538,14 @@ public:
virtual bool PtrTryGetBool(JsonValue* handle, const char* path, bool* out_value) = 0;
/**
* Try to get float value using JSON Pointer (returns false on failure)
* Try to get double value using JSON Pointer (returns false on failure)
* @param handle JSON value
* @param path JSON Pointer path
* @param out_value Pointer to receive float value
* @param out_value Pointer to receive double value
* @return true on success, false if not found or type mismatch
* @note Integers values are auto converted to double
*/
virtual bool PtrTryGetFloat(JsonValue* handle, const char* path, double* out_value) = 0;
virtual bool PtrTryGetDouble(JsonValue* handle, const char* path, double* out_value) = 0;
/**
* Try to get integer value using JSON Pointer (returns false on failure)
@ -1583,7 +1637,7 @@ public:
* External extensions MUST use this method to obtain the handle type
* @return The HandleType_t for JSON handles
*/
virtual HandleType_t GetHandleType() = 0;
virtual HandleType_t GetJsonHandleType() = 0;
/**
* Read JsonValue from a SourceMod handle
@ -1591,7 +1645,7 @@ public:
* @param handle Handle to read from
* @return JsonValue pointer, or nullptr on error (error will be reported to context)
*/
virtual JsonValue* GetFromHandle(IPluginContext* pContext, Handle_t handle) = 0;
virtual JsonValue* GetValueFromHandle(IPluginContext* pContext, Handle_t handle) = 0;
/**
* Initialize an array iterator (same as ArrIterWith but returns pointer)
@ -1717,6 +1771,17 @@ public:
*/
virtual void* ObjIterRemove(JsonObjIter* iter) = 0;
/**
* Get key string from object iterator key pointer
* @param iter Object iterator
* @param key Key pointer (returned from ObjIterNext)
* @param out_str Pointer to receive key string
* @param out_len Pointer to receive key length (optional)
* @return true on success, false on error
* @note Do not free the returned string - it is owned by the JSON document
*/
virtual bool ObjIterGetKeyString(JsonObjIter* iter, void* key, const char** out_str, size_t* out_len = nullptr) = 0;
/**
* Release an array iterator
* @param iter Iterator to release
@ -1836,12 +1901,12 @@ public:
/**
* Directly modify a JSON value to floating-point type
* @param handle JSON value to modify (cannot be object or array)
* @param value Float value
* @param value Double value
* @return true on success, false if handle is object or array
* @warning For immutable documents, this breaks immutability. Use with caution.
* @note This modifies the value in-place without creating a new value
*/
virtual bool SetFloat(JsonValue* handle, double value) = 0;
virtual bool SetDouble(JsonValue* handle, double value) = 0;
/**
* Directly modify a JSON value to string type

View File

@ -137,9 +137,6 @@ JsonValue* JsonManager::ParseJSON(const char* json_str, bool is_file, bool is_mu
readError.msg, readError.code, readError.pos);
}
}
if (idoc) {
yyjson_doc_free(idoc);
}
return nullptr;
}
@ -258,7 +255,7 @@ JsonValue* JsonManager::ApplyJsonPatch(JsonValue* target, JsonValue* patch, bool
yyjson_mut_val* resultRoot = yyjson_mut_patch(doc, root, patchCopy, &patch_err);
if (!resultRoot) {
SetErrorSafe(error, error_size, "JSON patch failed (code %u, op index %zu, message: %s)",
patch_err.code, patch_err.idx, patch_err);
patch_err.code, patch_err.idx, patch_err.msg);
return nullptr;
}
@ -881,6 +878,14 @@ size_t JsonManager::GetRefCount(JsonValue* handle)
return handle->GetDocumentRefCount();
}
size_t JsonManager::GetValCount(JsonValue* handle)
{
if (!handle || !handle->IsImmutable()) {
return 0;
}
return yyjson_doc_get_val_count(handle->m_pDocument->get());
}
JsonValue* JsonManager::ObjectInit()
{
auto pJSONValue = CreateWrapper();
@ -949,9 +954,6 @@ JsonValue* JsonManager::ObjectParseString(const char* str, yyjson_read_flag read
SetErrorSafe(error, error_size, "Failed to parse JSON str: %s (error code: %u, position: %zu)",
readError.msg, readError.code, readError.pos);
}
if (idoc) {
yyjson_doc_free(idoc);
}
return nullptr;
}
@ -994,9 +996,6 @@ JsonValue* JsonManager::ObjectParseFile(const char* path, yyjson_read_flag read_
SetErrorSafe(error, error_size, "Failed to parse JSON file: %s (error code: %u, msg: %s, position: %zu)",
realpath, readError.code, readError.msg, readError.pos);
}
if (idoc) {
yyjson_doc_free(idoc);
}
return nullptr;
}
@ -1181,7 +1180,7 @@ bool JsonManager::ObjectGetBool(JsonValue* handle, const char* key, bool* out_va
}
}
bool JsonManager::ObjectGetFloat(JsonValue* handle, const char* key, double* out_value)
bool JsonManager::ObjectGetDouble(JsonValue* handle, const char* key, double* out_value)
{
if (!handle || !key || !out_value) {
return false;
@ -1189,19 +1188,19 @@ bool JsonManager::ObjectGetFloat(JsonValue* handle, const char* key, double* out
if (handle->IsMutable()) {
yyjson_mut_val* val = yyjson_mut_obj_get(handle->m_pVal_mut, key);
if (!val || !yyjson_mut_is_real(val)) {
if (!val || !yyjson_mut_is_num(val)) {
return false;
}
*out_value = yyjson_mut_get_real(val);
*out_value = yyjson_mut_get_num(val);
return true;
} else {
yyjson_val* val = yyjson_obj_get(handle->m_pVal, key);
if (!val || !yyjson_is_real(val)) {
if (!val || !yyjson_is_num(val)) {
return false;
}
*out_value = yyjson_get_real(val);
*out_value = yyjson_get_num(val);
return true;
}
}
@ -1381,7 +1380,7 @@ bool JsonManager::ObjectSetBool(JsonValue* handle, const char* key, bool value)
return yyjson_mut_obj_put(handle->m_pVal_mut, yyjson_mut_strcpy(handle->m_pDocument_mut->get(), key), yyjson_mut_bool(handle->m_pDocument_mut->get(), value));
}
bool JsonManager::ObjectSetFloat(JsonValue* handle, const char* key, double value)
bool JsonManager::ObjectSetDouble(JsonValue* handle, const char* key, double value)
{
if (!handle || !handle->IsMutable() || !key) {
return false;
@ -1405,15 +1404,11 @@ bool JsonManager::ObjectSetInt64(JsonValue* handle, const char* key, std::varian
return false;
}
return std::visit([&](auto&& val) -> bool {
using T = std::decay_t<decltype(val)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_obj_put(handle->m_pVal_mut, yyjson_mut_strcpy(handle->m_pDocument_mut->get(), key), yyjson_mut_sint(handle->m_pDocument_mut->get(), val));
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_mut_obj_put(handle->m_pVal_mut, yyjson_mut_strcpy(handle->m_pDocument_mut->get(), key), yyjson_mut_uint(handle->m_pDocument_mut->get(), val));
if (std::holds_alternative<int64_t>(value)) {
return yyjson_mut_obj_put(handle->m_pVal_mut, yyjson_mut_strcpy(handle->m_pDocument_mut->get(), key), yyjson_mut_sint(handle->m_pDocument_mut->get(), std::get<int64_t>(value)));
} else {
return yyjson_mut_obj_put(handle->m_pVal_mut, yyjson_mut_strcpy(handle->m_pDocument_mut->get(), key), yyjson_mut_uint(handle->m_pDocument_mut->get(), std::get<uint64_t>(value)));
}
return false;
}, value);
}
bool JsonManager::ObjectSetNull(JsonValue* handle, const char* key)
@ -1511,6 +1506,19 @@ bool JsonManager::ObjectSort(JsonValue* handle, JSON_SORT_ORDER sort_mode)
return true;
}
bool JsonManager::ObjectRotate(JsonValue* handle, size_t idx)
{
if (!handle || !handle->IsMutable()) {
return false;
}
if (!yyjson_mut_is_obj(handle->m_pVal_mut)) {
return false;
}
return yyjson_mut_obj_rotate(handle->m_pVal_mut, idx);
}
JsonValue* JsonManager::ArrayInit()
{
auto pJSONValue = CreateWrapper();
@ -1641,15 +1649,12 @@ JsonValue* JsonManager::ArrayInitWithInt64(const char** values, size_t count, ch
return nullptr;
}
yyjson_mut_val* val = std::visit([&](auto&& arg) -> yyjson_mut_val* {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_sint(doc, arg);
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_mut_uint(doc, arg);
yyjson_mut_val* val;
if (std::holds_alternative<int64_t>(variant_value)) {
val = yyjson_mut_sint(doc, std::get<int64_t>(variant_value));
} else {
val = yyjson_mut_uint(doc, std::get<uint64_t>(variant_value));
}
return nullptr;
}, variant_value);
if (!val || !yyjson_mut_arr_append(pJSONValue->m_pVal_mut, val)) {
if (error && error_size > 0) {
@ -1692,7 +1697,7 @@ JsonValue* JsonManager::ArrayInitWithBool(const bool* values, size_t count)
return pJSONValue.release();
}
JsonValue* JsonManager::ArrayInitWithFloat(const double* values, size_t count)
JsonValue* JsonManager::ArrayInitWithDouble(const double* values, size_t count)
{
if (!values) {
return nullptr;
@ -1740,9 +1745,6 @@ JsonValue* JsonManager::ArrayParseString(const char* str, yyjson_read_flag read_
SetErrorSafe(error, error_size, "Failed to parse JSON string: %s (error code: %u, position: %zu)",
readError.msg, readError.code, readError.pos);
}
if (idoc) {
yyjson_doc_free(idoc);
}
return nullptr;
}
@ -1785,9 +1787,6 @@ JsonValue* JsonManager::ArrayParseFile(const char* path, yyjson_read_flag read_f
SetErrorSafe(error, error_size, "Failed to parse JSON file: %s (error code: %u, msg: %s, position: %zu)",
realpath, readError.code, readError.msg, readError.pos);
}
if (idoc) {
yyjson_doc_free(idoc);
}
return nullptr;
}
@ -1973,7 +1972,7 @@ bool JsonManager::ArrayGetBool(JsonValue* handle, size_t index, bool* out_value)
}
}
bool JsonManager::ArrayGetFloat(JsonValue* handle, size_t index, double* out_value)
bool JsonManager::ArrayGetDouble(JsonValue* handle, size_t index, double* out_value)
{
if (!handle || !out_value) {
return false;
@ -1986,11 +1985,11 @@ bool JsonManager::ArrayGetFloat(JsonValue* handle, size_t index, double* out_val
}
yyjson_mut_val* val = yyjson_mut_arr_get(handle->m_pVal_mut, index);
if (!yyjson_mut_is_real(val)) {
if (!yyjson_mut_is_num(val)) {
return false;
}
*out_value = yyjson_mut_get_real(val);
*out_value = yyjson_mut_get_num(val);
return true;
} else {
size_t arr_size = yyjson_arr_size(handle->m_pVal);
@ -1999,11 +1998,11 @@ bool JsonManager::ArrayGetFloat(JsonValue* handle, size_t index, double* out_val
}
yyjson_val* val = yyjson_arr_get(handle->m_pVal, index);
if (!yyjson_is_real(val)) {
if (!yyjson_is_num(val)) {
return false;
}
*out_value = yyjson_get_real(val);
*out_value = yyjson_get_num(val);
return true;
}
}
@ -2183,7 +2182,7 @@ bool JsonManager::ArrayReplaceBool(JsonValue* handle, size_t index, bool value)
return yyjson_mut_arr_replace(handle->m_pVal_mut, index, yyjson_mut_bool(handle->m_pDocument_mut->get(), value)) != nullptr;
}
bool JsonManager::ArrayReplaceFloat(JsonValue* handle, size_t index, double value)
bool JsonManager::ArrayReplaceDouble(JsonValue* handle, size_t index, double value)
{
if (!handle || !handle->IsMutable()) {
return false;
@ -2222,15 +2221,11 @@ bool JsonManager::ArrayReplaceInt64(JsonValue* handle, size_t index, std::varian
return false;
}
return std::visit([&](auto&& val) -> bool {
using T = std::decay_t<decltype(val)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_arr_replace(handle->m_pVal_mut, index, yyjson_mut_sint(handle->m_pDocument_mut->get(), val)) != nullptr;
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_mut_arr_replace(handle->m_pVal_mut, index, yyjson_mut_uint(handle->m_pDocument_mut->get(), val)) != nullptr;
if (std::holds_alternative<int64_t>(value)) {
return yyjson_mut_arr_replace(handle->m_pVal_mut, index, yyjson_mut_sint(handle->m_pDocument_mut->get(), std::get<int64_t>(value))) != nullptr;
} else {
return yyjson_mut_arr_replace(handle->m_pVal_mut, index, yyjson_mut_uint(handle->m_pDocument_mut->get(), std::get<uint64_t>(value))) != nullptr;
}
return false;
}, value);
}
bool JsonManager::ArrayReplaceNull(JsonValue* handle, size_t index)
@ -2290,7 +2285,7 @@ bool JsonManager::ArrayAppendBool(JsonValue* handle, bool value)
return yyjson_mut_arr_append(handle->m_pVal_mut, yyjson_mut_bool(handle->m_pDocument_mut->get(), value));
}
bool JsonManager::ArrayAppendFloat(JsonValue* handle, double value)
bool JsonManager::ArrayAppendDouble(JsonValue* handle, double value)
{
if (!handle || !handle->IsMutable()) {
return false;
@ -2314,15 +2309,11 @@ bool JsonManager::ArrayAppendInt64(JsonValue* handle, std::variant<int64_t, uint
return false;
}
return std::visit([&](auto&& val) -> bool {
using T = std::decay_t<decltype(val)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_arr_append(handle->m_pVal_mut, yyjson_mut_sint(handle->m_pDocument_mut->get(), val));
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_mut_arr_append(handle->m_pVal_mut, yyjson_mut_uint(handle->m_pDocument_mut->get(), val));
if (std::holds_alternative<int64_t>(value)) {
return yyjson_mut_arr_append(handle->m_pVal_mut, yyjson_mut_sint(handle->m_pDocument_mut->get(), std::get<int64_t>(value)));
} else {
return yyjson_mut_arr_append(handle->m_pVal_mut, yyjson_mut_uint(handle->m_pDocument_mut->get(), std::get<uint64_t>(value)));
}
return false;
}, value);
}
bool JsonManager::ArrayAppendNull(JsonValue* handle)
@ -2392,15 +2383,12 @@ bool JsonManager::ArrayInsertInt64(JsonValue* handle, size_t index, std::variant
return false;
}
yyjson_mut_val* val = std::visit([&](auto&& arg) -> yyjson_mut_val* {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_sint(handle->m_pDocument_mut->get(), arg);
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_mut_uint(handle->m_pDocument_mut->get(), arg);
yyjson_mut_val* val;
if (std::holds_alternative<int64_t>(value)) {
val = yyjson_mut_sint(handle->m_pDocument_mut->get(), std::get<int64_t>(value));
} else {
val = yyjson_mut_uint(handle->m_pDocument_mut->get(), std::get<uint64_t>(value));
}
return nullptr;
}, value);
if (!val) {
return false;
@ -2409,7 +2397,7 @@ bool JsonManager::ArrayInsertInt64(JsonValue* handle, size_t index, std::variant
return yyjson_mut_arr_insert(handle->m_pVal_mut, val, index);
}
bool JsonManager::ArrayInsertFloat(JsonValue* handle, size_t index, double value)
bool JsonManager::ArrayInsertDouble(JsonValue* handle, size_t index, double value)
{
if (!handle || !handle->IsMutable()) {
return false;
@ -2480,15 +2468,12 @@ bool JsonManager::ArrayPrependInt64(JsonValue* handle, std::variant<int64_t, uin
return false;
}
yyjson_mut_val* val = std::visit([&](auto&& arg) -> yyjson_mut_val* {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_sint(handle->m_pDocument_mut->get(), arg);
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_mut_uint(handle->m_pDocument_mut->get(), arg);
yyjson_mut_val* val;
if (std::holds_alternative<int64_t>(value)) {
val = yyjson_mut_sint(handle->m_pDocument_mut->get(), std::get<int64_t>(value));
} else {
val = yyjson_mut_uint(handle->m_pDocument_mut->get(), std::get<uint64_t>(value));
}
return nullptr;
}, value);
if (!val) {
return false;
@ -2497,7 +2482,7 @@ bool JsonManager::ArrayPrependInt64(JsonValue* handle, std::variant<int64_t, uin
return yyjson_mut_arr_prepend(handle->m_pVal_mut, val);
}
bool JsonManager::ArrayPrependFloat(JsonValue* handle, double value)
bool JsonManager::ArrayPrependDouble(JsonValue* handle, double value)
{
if (!handle || !handle->IsMutable()) {
return false;
@ -2722,7 +2707,7 @@ int JsonManager::ArrayIndexOfInt64(JsonValue* handle, std::variant<int64_t, uint
return -1;
}
int JsonManager::ArrayIndexOfFloat(JsonValue* handle, double search_value)
int JsonManager::ArrayIndexOfDouble(JsonValue* handle, double search_value)
{
if (!handle) {
return -1;
@ -2775,7 +2760,7 @@ bool JsonManager::ArraySort(JsonValue* handle, JSON_SORT_ORDER sort_mode)
struct ValueInfo {
yyjson_mut_val* val;
uint8_t type;
uint8_t subtype; // 0=float, 1=signed int, 2=unsigned int
uint8_t subtype; // 0=double, 1=signed int, 2=unsigned int
};
std::vector<ValueInfo> values;
@ -2881,6 +2866,19 @@ bool JsonManager::ArraySort(JsonValue* handle, JSON_SORT_ORDER sort_mode)
return true;
}
bool JsonManager::ArrayRotate(JsonValue* handle, size_t idx)
{
if (!handle || !handle->IsMutable()) {
return false;
}
if (!yyjson_mut_is_arr(handle->m_pVal_mut)) {
return false;
}
return yyjson_mut_arr_rotate(handle->m_pVal_mut, idx);
}
const char* JsonManager::SkipSeparators(const char* ptr)
{
while (*ptr && (isspace(*ptr) || *ptr == ':' || *ptr == ',')) {
@ -3156,7 +3154,7 @@ JsonValue* JsonManager::CreateBool(bool value)
return pJSONValue.release();
}
JsonValue* JsonManager::CreateFloat(double value)
JsonValue* JsonManager::CreateDouble(double value)
{
auto pJSONValue = CreateWrapper();
pJSONValue->m_pDocument_mut = CreateDocument();
@ -3207,14 +3205,11 @@ JsonValue* JsonManager::CreateInt64(std::variant<int64_t, uint64_t> value)
auto* doc = pJSONValue->m_pDocument_mut->get();
std::visit([&](auto&& val) {
using T = std::decay_t<decltype(val)>;
if constexpr (std::is_same_v<T, int64_t>) {
pJSONValue->m_pVal_mut = yyjson_mut_sint(doc, val);
} else if constexpr (std::is_same_v<T, uint64_t>) {
pJSONValue->m_pVal_mut = yyjson_mut_uint(doc, val);
if (std::holds_alternative<int64_t>(value)) {
pJSONValue->m_pVal_mut = yyjson_mut_sint(doc, std::get<int64_t>(value));
} else {
pJSONValue->m_pVal_mut = yyjson_mut_uint(doc, std::get<uint64_t>(value));
}
}, value);
if (!pJSONValue->m_pVal_mut) {
return nullptr;
@ -3290,23 +3285,23 @@ bool JsonManager::GetBool(JsonValue* handle, bool* out_value)
}
}
bool JsonManager::GetFloat(JsonValue* handle, double* out_value)
bool JsonManager::GetDouble(JsonValue* handle, double* out_value)
{
if (!handle || !out_value) {
return false;
}
if (handle->IsMutable()) {
if (!yyjson_mut_is_real(handle->m_pVal_mut)) {
if (!yyjson_mut_is_num(handle->m_pVal_mut)) {
return false;
}
*out_value = yyjson_mut_get_real(handle->m_pVal_mut);
*out_value = yyjson_mut_get_num(handle->m_pVal_mut);
return true;
} else {
if (!yyjson_is_real(handle->m_pVal)) {
if (!yyjson_is_num(handle->m_pVal)) {
return false;
}
*out_value = yyjson_get_real(handle->m_pVal);
*out_value = yyjson_get_num(handle->m_pVal);
return true;
}
}
@ -3477,7 +3472,7 @@ bool JsonManager::PtrGetBool(JsonValue* handle, const char* path, bool* out_valu
}
}
bool JsonManager::PtrGetFloat(JsonValue* handle, const char* path, double* out_value, char* error, size_t error_size)
bool JsonManager::PtrGetDouble(JsonValue* handle, const char* path, double* out_value, char* error, size_t error_size)
{
if (!handle || !path || !out_value) {
if (error && error_size > 0) {
@ -3499,14 +3494,14 @@ bool JsonManager::PtrGetFloat(JsonValue* handle, const char* path, double* out_v
return false;
}
if (!yyjson_mut_is_real(val)) {
if (!yyjson_mut_is_num(val)) {
if (error && error_size > 0) {
SetErrorSafe(error, error_size, "Type mismatch at path '%s': expected float value, got %s", path, yyjson_mut_get_type_desc(val));
SetErrorSafe(error, error_size, "Type mismatch at path '%s': expected number value, got %s", path, yyjson_mut_get_type_desc(val));
}
return false;
}
*out_value = yyjson_mut_get_real(val);
*out_value = yyjson_mut_get_num(val);
return true;
} else {
yyjson_val* val = yyjson_doc_ptr_getx(handle->m_pDocument->get(), path, strlen(path), &ptrGetError);
@ -3519,14 +3514,14 @@ bool JsonManager::PtrGetFloat(JsonValue* handle, const char* path, double* out_v
return false;
}
if (!yyjson_is_real(val)) {
if (!yyjson_is_num(val)) {
if (error && error_size > 0) {
SetErrorSafe(error, error_size, "Type mismatch at path '%s': expected float value, got %s", path, yyjson_get_type_desc(val));
SetErrorSafe(error, error_size, "Type mismatch at path '%s': expected number value, got %s", path, yyjson_get_type_desc(val));
}
return false;
}
*out_value = yyjson_get_real(val);
*out_value = yyjson_get_num(val);
return true;
}
}
@ -3849,7 +3844,7 @@ bool JsonManager::PtrSetBool(JsonValue* handle, const char* path, bool value, ch
return success;
}
bool JsonManager::PtrSetFloat(JsonValue* handle, const char* path, double value, char* error, size_t error_size)
bool JsonManager::PtrSetDouble(JsonValue* handle, const char* path, double value, char* error, size_t error_size)
{
if (!handle || !handle->IsMutable() || !path) {
if (error && error_size > 0) {
@ -3914,14 +3909,12 @@ bool JsonManager::PtrSetInt64(JsonValue* handle, const char* path, std::variant<
return false;
}
yyjson_mut_val* val = std::visit([&](auto&& val_input) -> yyjson_mut_val* {
using T = std::decay_t<decltype(val_input)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_sint(handle->m_pDocument_mut->get(), val_input);
yyjson_mut_val* val;
if (std::holds_alternative<int64_t>(value)) {
val = yyjson_mut_sint(handle->m_pDocument_mut->get(), std::get<int64_t>(value));
} else {
return yyjson_mut_uint(handle->m_pDocument_mut->get(), val_input);
val = yyjson_mut_uint(handle->m_pDocument_mut->get(), std::get<uint64_t>(value));
}
}, value);
if (!val) {
if (error && error_size > 0) {
SetErrorSafe(error, error_size, "Failed to create JSON value");
@ -4058,7 +4051,7 @@ bool JsonManager::PtrAddBool(JsonValue* handle, const char* path, bool value, ch
return success;
}
bool JsonManager::PtrAddFloat(JsonValue* handle, const char* path, double value, char* error, size_t error_size)
bool JsonManager::PtrAddDouble(JsonValue* handle, const char* path, double value, char* error, size_t error_size)
{
if (!handle || !handle->IsMutable() || !path) {
if (error && error_size > 0) {
@ -4123,14 +4116,12 @@ bool JsonManager::PtrAddInt64(JsonValue* handle, const char* path, std::variant<
return false;
}
yyjson_mut_val* val = std::visit([&](auto&& val_input) -> yyjson_mut_val* {
using T = std::decay_t<decltype(val_input)>;
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_sint(handle->m_pDocument_mut->get(), val_input);
yyjson_mut_val* val;
if (std::holds_alternative<int64_t>(value)) {
val = yyjson_mut_sint(handle->m_pDocument_mut->get(), std::get<int64_t>(value));
} else {
return yyjson_mut_uint(handle->m_pDocument_mut->get(), val_input);
val = yyjson_mut_uint(handle->m_pDocument_mut->get(), std::get<uint64_t>(value));
}
}, value);
if (!val) {
if (error && error_size > 0) {
SetErrorSafe(error, error_size, "Failed to create JSON value");
@ -4300,7 +4291,7 @@ bool JsonManager::PtrTryGetBool(JsonValue* handle, const char* path, bool* out_v
}
}
bool JsonManager::PtrTryGetFloat(JsonValue* handle, const char* path, double* out_value)
bool JsonManager::PtrTryGetDouble(JsonValue* handle, const char* path, double* out_value)
{
if (!handle || !path || !out_value) {
return false;
@ -4616,12 +4607,12 @@ void JsonManager::Release(JsonValue* value)
}
}
HandleType_t JsonManager::GetHandleType()
HandleType_t JsonManager::GetJsonHandleType()
{
return g_JsonType;
}
JsonValue* JsonManager::GetFromHandle(IPluginContext* pContext, Handle_t handle)
JsonValue* JsonManager::GetValueFromHandle(IPluginContext* pContext, Handle_t handle)
{
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
@ -4945,6 +4936,27 @@ void* JsonManager::ObjIterRemove(JsonObjIter* iter)
return yyjson_mut_obj_iter_remove(&iter->m_iterMut);
}
bool JsonManager::ObjIterGetKeyString(JsonObjIter* iter, void* key, const char** out_str, size_t* out_len)
{
if (!iter || !key || !out_str) {
return false;
}
if (iter->m_isMutable) {
*out_str = yyjson_mut_get_str(reinterpret_cast<yyjson_mut_val*>(key));
if (out_len) {
*out_len = yyjson_mut_get_len(reinterpret_cast<yyjson_mut_val*>(key));
}
} else {
*out_str = yyjson_get_str(reinterpret_cast<yyjson_val*>(key));
if (out_len) {
*out_len = yyjson_get_len(reinterpret_cast<yyjson_val*>(key));
}
}
return *out_str != nullptr;
}
void JsonManager::ReleaseArrIter(JsonArrIter* iter)
{
if (iter) {
@ -5143,26 +5155,22 @@ bool JsonManager::SetInt64(JsonValue* handle, std::variant<int64_t, uint64_t> va
return false;
}
return std::visit([&](auto&& val) -> bool {
using T = std::decay_t<decltype(val)>;
if (handle->IsMutable()) {
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_mut_set_sint(handle->m_pVal_mut, val);
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_mut_set_uint(handle->m_pVal_mut, val);
if (std::holds_alternative<int64_t>(value)) {
return yyjson_mut_set_sint(handle->m_pVal_mut, std::get<int64_t>(value));
} else {
return yyjson_mut_set_uint(handle->m_pVal_mut, std::get<uint64_t>(value));
}
} else {
if constexpr (std::is_same_v<T, int64_t>) {
return yyjson_set_sint(handle->m_pVal, val);
} else if constexpr (std::is_same_v<T, uint64_t>) {
return yyjson_set_uint(handle->m_pVal, val);
if (std::holds_alternative<int64_t>(value)) {
return yyjson_set_sint(handle->m_pVal, std::get<int64_t>(value));
} else {
return yyjson_set_uint(handle->m_pVal, std::get<uint64_t>(value));
}
}
return false;
}, value);
}
bool JsonManager::SetFloat(JsonValue* handle, double value)
bool JsonManager::SetDouble(JsonValue* handle, double value)
{
if (!handle) {
return false;

View File

@ -346,6 +346,7 @@ public:
virtual bool IsImmutable(JsonValue* handle) override;
virtual size_t GetReadSize(JsonValue* handle) override;
virtual size_t GetRefCount(JsonValue* handle) override;
virtual size_t GetValCount(JsonValue* handle) override;
// ========== Object Operations ==========
virtual JsonValue* ObjectInit() override;
@ -359,7 +360,7 @@ public:
virtual JsonValue* ObjectGetValueAt(JsonValue* handle, size_t index) override;
virtual JsonValue* ObjectGet(JsonValue* handle, const char* key) override;
virtual bool ObjectGetBool(JsonValue* handle, const char* key, bool* out_value) override;
virtual bool ObjectGetFloat(JsonValue* handle, const char* key, double* out_value) override;
virtual bool ObjectGetDouble(JsonValue* handle, const char* key, double* out_value) override;
virtual bool ObjectGetInt(JsonValue* handle, const char* key, int* out_value) override;
virtual bool ObjectGetInt64(JsonValue* handle, const char* key, std::variant<int64_t, uint64_t>* out_value) override;
virtual bool ObjectGetString(JsonValue* handle, const char* key, const char** out_str, size_t* out_len) override;
@ -368,7 +369,7 @@ public:
virtual bool ObjectRenameKey(JsonValue* handle, const char* old_key, const char* new_key, bool allow_duplicate) override;
virtual bool ObjectSet(JsonValue* handle, const char* key, JsonValue* value) override;
virtual bool ObjectSetBool(JsonValue* handle, const char* key, bool value) override;
virtual bool ObjectSetFloat(JsonValue* handle, const char* key, double value) override;
virtual bool ObjectSetDouble(JsonValue* handle, const char* key, double value) override;
virtual bool ObjectSetInt(JsonValue* handle, const char* key, int value) override;
virtual bool ObjectSetInt64(JsonValue* handle, const char* key, std::variant<int64_t, uint64_t> value) override;
virtual bool ObjectSetNull(JsonValue* handle, const char* key) override;
@ -376,6 +377,7 @@ public:
virtual bool ObjectRemove(JsonValue* handle, const char* key) override;
virtual bool ObjectClear(JsonValue* handle) override;
virtual bool ObjectSort(JsonValue* handle, JSON_SORT_ORDER sort_mode) override;
virtual bool ObjectRotate(JsonValue* handle, size_t idx) override;
// ========== Array Operations ==========
virtual JsonValue* ArrayInit() override;
@ -384,7 +386,7 @@ public:
virtual JsonValue* ArrayInitWithInt64(const char** values, size_t count,
char* error, size_t error_size) override;
virtual JsonValue* ArrayInitWithBool(const bool* values, size_t count) override;
virtual JsonValue* ArrayInitWithFloat(const double* values, size_t count) override;
virtual JsonValue* ArrayInitWithDouble(const double* values, size_t count) override;
virtual JsonValue* ArrayParseString(const char* str, yyjson_read_flag read_flg,
char* error, size_t error_size) override;
virtual JsonValue* ArrayParseFile(const char* path, yyjson_read_flag read_flg,
@ -394,21 +396,21 @@ public:
virtual JsonValue* ArrayGetFirst(JsonValue* handle) override;
virtual JsonValue* ArrayGetLast(JsonValue* handle) override;
virtual bool ArrayGetBool(JsonValue* handle, size_t index, bool* out_value) override;
virtual bool ArrayGetFloat(JsonValue* handle, size_t index, double* out_value) override;
virtual bool ArrayGetDouble(JsonValue* handle, size_t index, double* out_value) override;
virtual bool ArrayGetInt(JsonValue* handle, size_t index, int* out_value) override;
virtual bool ArrayGetInt64(JsonValue* handle, size_t index, std::variant<int64_t, uint64_t>* out_value) override;
virtual bool ArrayGetString(JsonValue* handle, size_t index, const char** out_str, size_t* out_len) override;
virtual bool ArrayIsNull(JsonValue* handle, size_t index) override;
virtual bool ArrayReplace(JsonValue* handle, size_t index, JsonValue* value) override;
virtual bool ArrayReplaceBool(JsonValue* handle, size_t index, bool value) override;
virtual bool ArrayReplaceFloat(JsonValue* handle, size_t index, double value) override;
virtual bool ArrayReplaceDouble(JsonValue* handle, size_t index, double value) override;
virtual bool ArrayReplaceInt(JsonValue* handle, size_t index, int value) override;
virtual bool ArrayReplaceInt64(JsonValue* handle, size_t index, std::variant<int64_t, uint64_t> value) override;
virtual bool ArrayReplaceNull(JsonValue* handle, size_t index) override;
virtual bool ArrayReplaceString(JsonValue* handle, size_t index, const char* value) override;
virtual bool ArrayAppend(JsonValue* handle, JsonValue* value) override;
virtual bool ArrayAppendBool(JsonValue* handle, bool value) override;
virtual bool ArrayAppendFloat(JsonValue* handle, double value) override;
virtual bool ArrayAppendDouble(JsonValue* handle, double value) override;
virtual bool ArrayAppendInt(JsonValue* handle, int value) override;
virtual bool ArrayAppendInt64(JsonValue* handle, std::variant<int64_t, uint64_t> value) override;
virtual bool ArrayAppendNull(JsonValue* handle) override;
@ -417,14 +419,14 @@ public:
virtual bool ArrayInsertBool(JsonValue* handle, size_t index, bool value) override;
virtual bool ArrayInsertInt(JsonValue* handle, size_t index, int value) override;
virtual bool ArrayInsertInt64(JsonValue* handle, size_t index, std::variant<int64_t, uint64_t> value) override;
virtual bool ArrayInsertFloat(JsonValue* handle, size_t index, double value) override;
virtual bool ArrayInsertDouble(JsonValue* handle, size_t index, double value) override;
virtual bool ArrayInsertString(JsonValue* handle, size_t index, const char* value) override;
virtual bool ArrayInsertNull(JsonValue* handle, size_t index) override;
virtual bool ArrayPrepend(JsonValue* handle, JsonValue* value) override;
virtual bool ArrayPrependBool(JsonValue* handle, bool value) override;
virtual bool ArrayPrependInt(JsonValue* handle, int value) override;
virtual bool ArrayPrependInt64(JsonValue* handle, std::variant<int64_t, uint64_t> value) override;
virtual bool ArrayPrependFloat(JsonValue* handle, double value) override;
virtual bool ArrayPrependDouble(JsonValue* handle, double value) override;
virtual bool ArrayPrependString(JsonValue* handle, const char* value) override;
virtual bool ArrayPrependNull(JsonValue* handle) override;
virtual bool ArrayRemove(JsonValue* handle, size_t index) override;
@ -436,19 +438,20 @@ public:
virtual int ArrayIndexOfString(JsonValue* handle, const char* search_value) override;
virtual int ArrayIndexOfInt(JsonValue* handle, int search_value) override;
virtual int ArrayIndexOfInt64(JsonValue* handle, std::variant<int64_t, uint64_t> search_value) override;
virtual int ArrayIndexOfFloat(JsonValue* handle, double search_value) override;
virtual int ArrayIndexOfDouble(JsonValue* handle, double search_value) override;
virtual bool ArraySort(JsonValue* handle, JSON_SORT_ORDER sort_mode) override;
virtual bool ArrayRotate(JsonValue* handle, size_t idx) override;
// ========== Value Operations ==========
virtual JsonValue* Pack(const char* format, IPackParamProvider* param_provider, char* error, size_t error_size) override;
virtual JsonValue* CreateBool(bool value) override;
virtual JsonValue* CreateFloat(double value) override;
virtual JsonValue* CreateDouble(double value) override;
virtual JsonValue* CreateInt(int value) override;
virtual JsonValue* CreateInt64(std::variant<int64_t, uint64_t> value) override;
virtual JsonValue* CreateNull() override;
virtual JsonValue* CreateString(const char* value) override;
virtual bool GetBool(JsonValue* handle, bool* out_value) override;
virtual bool GetFloat(JsonValue* handle, double* out_value) override;
virtual bool GetDouble(JsonValue* handle, double* out_value) override;
virtual bool GetInt(JsonValue* handle, int* out_value) override;
virtual bool GetInt64(JsonValue* handle, std::variant<int64_t, uint64_t>* out_value) override;
virtual bool GetString(JsonValue* handle, const char** out_str, size_t* out_len) override;
@ -456,7 +459,7 @@ public:
// ========== Pointer Operations ==========
virtual JsonValue* PtrGet(JsonValue* handle, const char* path, char* error, size_t error_size) override;
virtual bool PtrGetBool(JsonValue* handle, const char* path, bool* out_value, char* error, size_t error_size) override;
virtual bool PtrGetFloat(JsonValue* handle, const char* path, double* out_value, char* error, size_t error_size) override;
virtual bool PtrGetDouble(JsonValue* handle, const char* path, double* out_value, char* error, size_t error_size) override;
virtual bool PtrGetInt(JsonValue* handle, const char* path, int* out_value, char* error, size_t error_size) override;
virtual bool PtrGetInt64(JsonValue* handle, const char* path, std::variant<int64_t, uint64_t>* out_value, char* error, size_t error_size) override;
virtual bool PtrGetString(JsonValue* handle, const char* path, const char** out_str, size_t* out_len, char* error, size_t error_size) override;
@ -464,14 +467,14 @@ public:
virtual bool PtrGetLength(JsonValue* handle, const char* path, size_t* out_len, char* error, size_t error_size) override;
virtual bool PtrSet(JsonValue* handle, const char* path, JsonValue* value, char* error, size_t error_size) override;
virtual bool PtrSetBool(JsonValue* handle, const char* path, bool value, char* error, size_t error_size) override;
virtual bool PtrSetFloat(JsonValue* handle, const char* path, double value, char* error, size_t error_size) override;
virtual bool PtrSetDouble(JsonValue* handle, const char* path, double value, char* error, size_t error_size) override;
virtual bool PtrSetInt(JsonValue* handle, const char* path, int value, char* error, size_t error_size) override;
virtual bool PtrSetInt64(JsonValue* handle, const char* path, std::variant<int64_t, uint64_t> value, char* error, size_t error_size) override;
virtual bool PtrSetString(JsonValue* handle, const char* path, const char* value, char* error, size_t error_size) override;
virtual bool PtrSetNull(JsonValue* handle, const char* path, char* error, size_t error_size) override;
virtual bool PtrAdd(JsonValue* handle, const char* path, JsonValue* value, char* error, size_t error_size) override;
virtual bool PtrAddBool(JsonValue* handle, const char* path, bool value, char* error, size_t error_size) override;
virtual bool PtrAddFloat(JsonValue* handle, const char* path, double value, char* error, size_t error_size) override;
virtual bool PtrAddDouble(JsonValue* handle, const char* path, double value, char* error, size_t error_size) override;
virtual bool PtrAddInt(JsonValue* handle, const char* path, int value, char* error, size_t error_size) override;
virtual bool PtrAddInt64(JsonValue* handle, const char* path, std::variant<int64_t, uint64_t> value, char* error, size_t error_size) override;
virtual bool PtrAddString(JsonValue* handle, const char* path, const char* value, char* error, size_t error_size) override;
@ -479,7 +482,7 @@ public:
virtual bool PtrRemove(JsonValue* handle, const char* path, char* error, size_t error_size) override;
virtual JsonValue* PtrTryGet(JsonValue* handle, const char* path) override;
virtual bool PtrTryGetBool(JsonValue* handle, const char* path, bool* out_value) override;
virtual bool PtrTryGetFloat(JsonValue* handle, const char* path, double* out_value) override;
virtual bool PtrTryGetDouble(JsonValue* handle, const char* path, double* out_value) override;
virtual bool PtrTryGetInt(JsonValue* handle, const char* path, int* out_value) override;
virtual bool PtrTryGetInt64(JsonValue* handle, const char* path, std::variant<int64_t, uint64_t>* out_value) override;
virtual bool PtrTryGetString(JsonValue* handle, const char* path, const char** out_str, size_t* out_len) override;
@ -512,6 +515,7 @@ public:
virtual JsonValue* ObjIterGet(JsonObjIter* iter, const char* key) override;
virtual size_t ObjIterGetIndex(JsonObjIter* iter) override;
virtual void* ObjIterRemove(JsonObjIter* iter) override;
virtual bool ObjIterGetKeyString(JsonObjIter* iter, void* key, const char** out_str, size_t* out_len = nullptr) override;
// ========== Iterator Release Operations ==========
virtual void ReleaseArrIter(JsonArrIter* iter) override;
@ -527,10 +531,10 @@ public:
virtual void Release(JsonValue* value) override;
// ========== Handle Type Operations ==========
virtual HandleType_t GetHandleType() override;
virtual HandleType_t GetJsonHandleType() override;
// ========== Handle Operations ==========
virtual JsonValue* GetFromHandle(IPluginContext* pContext, Handle_t handle) override;
virtual JsonValue* GetValueFromHandle(IPluginContext* pContext, Handle_t handle) override;
// ========== Number Read/Write Operations ==========
virtual JsonValue* ReadNumber(const char* dat, uint32_t read_flg = 0,
@ -546,7 +550,7 @@ public:
virtual bool SetBool(JsonValue* handle, bool value) override;
virtual bool SetInt(JsonValue* handle, int value) override;
virtual bool SetInt64(JsonValue* handle, std::variant<int64_t, uint64_t> value) override;
virtual bool SetFloat(JsonValue* handle, double value) override;
virtual bool SetDouble(JsonValue* handle, double value) override;
virtual bool SetString(JsonValue* handle, const char* value) override;
virtual bool SetNull(JsonValue* handle) override;

File diff suppressed because it is too large Load Diff

View File

@ -17,26 +17,30 @@ bool JsonExtension::SDK_OnLoad(char* error, size_t maxlen, bool late)
sharesys->AddNatives(myself, g_JsonNatives);
sharesys->RegisterLibrary(myself, "json");
HandleAccess haJSON;
handlesys->InitAccessDefaults(nullptr, &haJSON);
haJSON.access[HandleAccess_Read] = 0;
haJSON.access[HandleAccess_Delete] = 0;
HandleAccess haDefault;
handlesys->InitAccessDefaults(nullptr, &haDefault);
haDefault.access[HandleAccess_Read] = 0;
haDefault.access[HandleAccess_Delete] = 0;
TypeAccess taDefault;
handlesys->InitAccessDefaults(&taDefault, nullptr);
taDefault.access[HTypeAccess_Create] = true;
HandleError err;
g_JsonType = handlesys->CreateType("JSON", &g_JsonHandler, 0, nullptr, &haJSON, myself->GetIdentity(), &err);
g_JsonType = handlesys->CreateType("JSON", &g_JsonHandler, 0, &taDefault, &haDefault, myself->GetIdentity(), &err);
if (!g_JsonType) {
snprintf(error, maxlen, "Failed to create JSON handle type (err: %d)", err);
return false;
}
g_ArrIterType = handlesys->CreateType("JSONArrIter", &g_ArrIterHandler, 0, nullptr, &haJSON, myself->GetIdentity(), &err);
g_ArrIterType = handlesys->CreateType("JSONArrIter", &g_ArrIterHandler, 0, &taDefault, &haDefault, myself->GetIdentity(), &err);
if (!g_ArrIterType) {
snprintf(error, maxlen, "Failed to create JSONArrIter handle type (err: %d)", err);
return false;
}
g_ObjIterType = handlesys->CreateType("JSONObjIter", &g_ObjIterHandler, 0, nullptr, &haJSON, myself->GetIdentity(), &err);
g_ObjIterType = handlesys->CreateType("JSONObjIter", &g_ObjIterHandler, 0, &taDefault, &haDefault, myself->GetIdentity(), &err);
if (!g_ObjIterType) {
snprintf(error, maxlen, "Failed to create JSONObjIter handle type (err: %d)", err);
return false;
@ -47,7 +51,7 @@ bool JsonExtension::SDK_OnLoad(char* error, size_t maxlen, bool late)
g_pJsonManager = nullptr;
}
g_pJsonManager = new JsonManager();
g_pJsonManager = new(std::nothrow) JsonManager();
if (!g_pJsonManager) {
snprintf(error, maxlen, "Failed to create JSON manager instance");
return false;

View File

@ -109,8 +109,8 @@ methodmap JSON < Handle
* - ]: end array
*
* @note Needs to be freed using delete or CloseHandle()
* @note There is a limit of 32 parameters (defined in SourcePawn)
* including the format string, so the number of arguments must be less than or equal to 31
* @note SourcePawn imposes a limit of 32 parameters per function (defined by SP_MAX_EXEC_PARAMS),
* which precludes the construction of complex objects with this method.
*
* @param format Format string
* @param ... Arguments based on format string
@ -546,6 +546,8 @@ methodmap JSON < Handle
/**
* Get float value
*
* @note Integers values are auto converted to float
*
* @return float value
*/
public native float GetFloat();
@ -618,6 +620,7 @@ methodmap JSON < Handle
* Get float value by a JSON Pointer
*
* @note JSON Pointer paths are always resolved from the document root, not from the current value
* @note Integers values are auto converted to float
*
* @param path The JSON pointer string
*
@ -907,6 +910,7 @@ methodmap JSON < Handle
* Try to get float value by a JSON Pointer
*
* @note JSON Pointer paths are always resolved from the document root, not from the current value
* @note Integers values are auto converted to float
*
* @param path The JSON pointer string
* @param value Store the float value
@ -1096,6 +1100,17 @@ methodmap JSON < Handle
property int RefCount {
public native get();
}
/**
* Get the total number of values in the document
*
* @note Only works on immutable documents (parsed from JSON)
* @note Returns 0 for mutable documents or null handles
* @note Useful for performance planning and memory estimation
*/
property int ValCount {
public native get();
}
};
methodmap JSONObject < JSON
@ -1182,6 +1197,8 @@ methodmap JSONObject < JSON
/**
* Gets a float value from the object
*
* @note Integers values are auto converted to float
*
* @param key Key name
*
* @return Float value
@ -1367,6 +1384,20 @@ methodmap JSONObject < JSON
*/
public native bool Sort(JSON_SORT_ORDER order = JSON_SORT_ASC);
/**
* Rotates key-value pairs in the object
*
* @note This function takes a linear search time
* @note Only works on mutable objects
* @note Example: {"a":1,"b":2,"c":3,"d":4} rotate 1 becomes {"b":2,"c":3,"d":4,"a":1}
*
* @param idx Number of positions to rotate
*
* @return True on success, false if object is immutable or operation failed
* @error Invalid handle or attempting to rotate an immutable object
*/
public native bool Rotate(int idx);
/**
* Retrieves the size of the object
*/
@ -1486,6 +1517,8 @@ methodmap JSONArray < JSON
/**
* Gets a float value from the array
*
* @note Integers values are auto converted to float
*
* @param index Position in the array (starting from 0)
*
* @return The number as float
@ -1921,6 +1954,20 @@ methodmap JSONArray < JSON
*/
public native bool Sort(JSON_SORT_ORDER order = JSON_SORT_ASC);
/**
* Rotates array elements
*
* @note This function takes a linear search time
* @note Only works on mutable arrays
* @note Example: [1,2,3,4,5] rotate 2 becomes [3,4,5,1,2]
*
* @param idx Number of positions to rotate
*
* @return True on success, false if array is immutable or operation failed
* @error Invalid handle or attempting to rotate an immutable array
*/
public native bool Rotate(int idx);
/**
* Retrieves the size of the array
*/
@ -2164,6 +2211,7 @@ public void __pl_json_SetNTVOptional()
MarkNativeAsOptional("JSONObject.FromString");
MarkNativeAsOptional("JSONObject.FromFile");
MarkNativeAsOptional("JSONObject.Sort");
MarkNativeAsOptional("JSONObject.Rotate");
// JSONArray
MarkNativeAsOptional("JSONArray.JSONArray");
@ -2223,6 +2271,7 @@ public void __pl_json_SetNTVOptional()
MarkNativeAsOptional("JSONArray.IndexOfInt64");
MarkNativeAsOptional("JSONArray.IndexOfFloat");
MarkNativeAsOptional("JSONArray.Sort");
MarkNativeAsOptional("JSONArray.Rotate");
// JSON
MarkNativeAsOptional("JSON.ToString");
@ -2235,6 +2284,7 @@ public void __pl_json_SetNTVOptional()
MarkNativeAsOptional("JSON.GetSerializedSize");
MarkNativeAsOptional("JSON.ReadSize.get");
MarkNativeAsOptional("JSON.RefCount.get");
MarkNativeAsOptional("JSON.ValCount.get");
MarkNativeAsOptional("JSON.Type.get");
MarkNativeAsOptional("JSON.SubType.get");
MarkNativeAsOptional("JSON.IsArray.get");

View File

@ -653,6 +653,64 @@ void Test_ObjectOperations()
}
TestEnd();
// Test Rotate
TestStart("Object_Rotate_Forward");
{
JSONObject obj = new JSONObject();
obj.SetInt("a", 1);
obj.SetInt("b", 2);
obj.SetInt("c", 3);
obj.SetInt("d", 4);
AssertTrue(obj.Rotate(1));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "b", "First key should be 'b' after rotate 1");
obj.GetKey(3, key, sizeof(key));
AssertStrEq(key, "a", "Last key should be 'a' after rotate 1");
delete obj;
}
TestEnd();
TestStart("Object_Rotate_Multiple");
{
JSONObject obj = new JSONObject();
obj.SetInt("first", 1);
obj.SetInt("second", 2);
obj.SetInt("third", 3);
obj.SetInt("fourth", 4);
obj.SetInt("fifth", 5);
AssertTrue(obj.Rotate(2));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "third", "First key should be 'third' after rotate 2");
obj.GetKey(4, key, sizeof(key));
AssertStrEq(key, "second", "Last key should be 'second' after rotate 2");
delete obj;
}
TestEnd();
TestStart("Object_Rotate_Zero");
{
JSONObject obj = new JSONObject();
obj.SetInt("x", 1);
obj.SetInt("y", 2);
AssertTrue(obj.Rotate(0));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "x", "Order should not change after rotate 0");
delete obj;
}
TestEnd();
// Test Set with handle
TestStart("Object_SetWithHandle");
{
@ -1013,6 +1071,83 @@ void Test_ArrayOperations()
}
TestEnd();
// Test Rotate
TestStart("Array_Rotate_Forward");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
arr.PushInt(4);
arr.PushInt(5);
AssertTrue(arr.Rotate(2));
AssertEq(arr.GetInt(0), 3, "First element should be 3 after rotate 2");
AssertEq(arr.GetInt(1), 4, "Second element should be 4");
AssertEq(arr.GetInt(2), 5, "Third element should be 5");
AssertEq(arr.GetInt(3), 1, "Fourth element should be 1");
AssertEq(arr.GetInt(4), 2, "Fifth element should be 2");
delete arr;
}
TestEnd();
TestStart("Array_Rotate_Single");
{
JSONArray arr = new JSONArray();
arr.PushString("a");
arr.PushString("b");
arr.PushString("c");
arr.PushString("d");
AssertTrue(arr.Rotate(1));
char buffer[32];
arr.GetString(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "b", "First element should be 'b' after rotate 1");
arr.GetString(3, buffer, sizeof(buffer));
AssertStrEq(buffer, "a", "Last element should be 'a' after rotate 1");
delete arr;
}
TestEnd();
TestStart("Array_Rotate_Zero");
{
JSONArray arr = new JSONArray();
arr.PushInt(10);
arr.PushInt(20);
arr.PushInt(30);
AssertTrue(arr.Rotate(0));
AssertEq(arr.GetInt(0), 10, "Order should not change after rotate 0");
AssertEq(arr.GetInt(1), 20);
AssertEq(arr.GetInt(2), 30);
delete arr;
}
TestEnd();
TestStart("Array_Rotate_LargeIndex");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
// Rotate by array length or greater should fail (idx must be < length)
AssertFalse(arr.Rotate(3), "Rotate by array length should fail");
AssertFalse(arr.Rotate(10), "Rotate by value > length should fail");
// Values should remain unchanged
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
delete arr;
}
TestEnd();
// Test Push with handle
TestStart("Array_PushHandle");
{
@ -1555,6 +1690,68 @@ void Test_ParseAndSerialize()
}
TestEnd();
// Test ValCount (only works on immutable documents)
TestStart("Parse_ValCount_SimpleObject");
{
JSON json = JSON.Parse("{\"a\":1,\"b\":2,\"c\":3}");
AssertValidHandle(json);
int valCount = json.ValCount;
// Object has 7 values: 1 object + 3 keys ("a","b","c") + 3 integer values (1,2,3)
AssertEq(valCount, 7, "Simple object should have 7 values (object + keys + values)");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_NestedStructure");
{
// {"user":{"name":"John","age":30},"items":[1,2,3]}
// Root object: 1
// "user" key + nested object: 2
// "name" key + "John" value: 2
// "age" key + 30 value: 2
// "items" key + array: 2
// Three integers in array: 3
// Total: 1 + 2 + 2 + 2 + 2 + 3 = 12
JSON json = JSON.Parse("{\"user\":{\"name\":\"John\",\"age\":30},\"items\":[1,2,3]}");
AssertValidHandle(json);
int valCount = json.ValCount;
AssertTrue(valCount > 0, "Nested structure should have multiple values");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_Array");
{
JSON json = JSON.Parse("[1,2,3,4,5]");
AssertValidHandle(json);
int valCount = json.ValCount;
// Array itself + 5 integers = 6
AssertEq(valCount, 6, "Array with 5 elements should have 6 values");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_MutableReturnsZero");
{
JSON json = JSON.Parse("{\"key\":\"value\"}", .is_mutable_doc = true);
AssertValidHandle(json);
int valCount = json.ValCount;
AssertEq(valCount, 0, "ValCount should return 0 for mutable documents");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_CreatedObjectReturnsZero");
{
JSONObject obj = new JSONObject();
obj.SetInt("a", 1);
obj.SetInt("b", 2);
int valCount = obj.ValCount;
AssertEq(valCount, 0, "ValCount should return 0 for created (mutable) objects");
delete obj;
}
TestEnd();
// Test ToString
TestStart("Serialize_ToString");
{