Make DqnJson handle more cases
This commit is contained in:
parent
33cf476d29
commit
f1efb6f8f1
117
DqnJson.cpp
Normal file
117
DqnJson.cpp
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
void DqnJson_Test()
|
||||||
|
{
|
||||||
|
char const json[] =
|
||||||
|
R"FOO(
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"cumulative_difficulty": 282912831023,
|
||||||
|
"difficulty": 18293,
|
||||||
|
"name": "Block",
|
||||||
|
"array_of_objects": [{
|
||||||
|
"hash": "83abdc3f",
|
||||||
|
"time": 102981029381,
|
||||||
|
}, {
|
||||||
|
"hash": "12acf73d",
|
||||||
|
"time": 123761239789,
|
||||||
|
}],
|
||||||
|
"time": 3498573485,
|
||||||
|
"embed_object": {
|
||||||
|
"proof": "axcbde",
|
||||||
|
"signature": "l9382kjabmznmx129aslzejs"
|
||||||
|
}
|
||||||
|
"bits": [1, 0, 1, 1, 0, 1, 0],
|
||||||
|
"hex": ["AF", "BE", "0C", "FF"],
|
||||||
|
"extra": [123],
|
||||||
|
"serialise": [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)FOO";
|
||||||
|
|
||||||
|
DqnJson result = DqnJson_Get(DqnSlice<const char>(json, DQN_ARRAY_COUNT(json)), DQN_SLICE("result"));
|
||||||
|
DqnJson cumulativeDifficulty = DqnJson_Get(result, DQN_SLICE("cumulative_difficulty"));
|
||||||
|
DqnJson difficulty = DqnJson_Get(result, DQN_SLICE("difficulty"));
|
||||||
|
DqnJson name = DqnJson_Get(result, DQN_SLICE("name"));
|
||||||
|
DqnJson arrayOfObjects = DqnJson_Get(result, DQN_SLICE("array_of_objects"));
|
||||||
|
DqnJson time = DqnJson_Get(result, DQN_SLICE("time"));
|
||||||
|
DqnJson embedObject = DqnJson_Get(result, DQN_SLICE("embed_object"));
|
||||||
|
DqnJson bits = DqnJson_Get(result, DQN_SLICE("bits"));
|
||||||
|
DqnJson hex = DqnJson_Get(result, DQN_SLICE("hex"));
|
||||||
|
DqnJson extra = DqnJson_Get(result, DQN_SLICE("extra"));
|
||||||
|
DqnJson serialise = DqnJson_Get(result, DQN_SLICE("serialise"));
|
||||||
|
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(cumulativeDifficulty.value, DQN_SLICE("282912831023"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(difficulty.value, DQN_SLICE("18293"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(name.value, DQN_SLICE("\"Block\""), Dqn::IgnoreCase::No));
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_ASSERT(arrayOfObjects.IsArray() && arrayOfObjects.numEntries == 2);
|
||||||
|
isize count = 0;
|
||||||
|
while(DqnJson it = DqnJson_GetNextArrayItem(&arrayOfObjects))
|
||||||
|
{
|
||||||
|
DqnJson hash = DqnJson_Get(it, DQN_SLICE("hash"));
|
||||||
|
DqnJson time2 = DqnJson_Get(it, DQN_SLICE("time"));
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(hash.value, DQN_SLICE("\"83abdc3f\""), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(time2.value, DQN_SLICE("102981029381"), Dqn::IgnoreCase::No));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(hash.value, DQN_SLICE("\"12acf73d\""), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(time2.value, DQN_SLICE("123761239789"), Dqn::IgnoreCase::No));
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DqnJson proof = DqnJson_Get(embedObject, DQN_SLICE("proof"));
|
||||||
|
DqnJson signature = DqnJson_Get(embedObject, DQN_SLICE("signature"));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(proof.value, DQN_SLICE("\"axcbde\""), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(signature.value, DQN_SLICE("\"l9382kjabmznmx129aslzejs\""), Dqn::IgnoreCase::No));
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(time.value, DQN_SLICE("3498573485"), Dqn::IgnoreCase::No));
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_ASSERT(bits.IsArray() && bits.numEntries == 7);
|
||||||
|
DqnJson bitsArray[7];
|
||||||
|
isize bitsIndex = 0;
|
||||||
|
|
||||||
|
while(DqnJson it = DqnJson_GetNextArrayItem(&bits))
|
||||||
|
bitsArray[bitsIndex++] = it;
|
||||||
|
|
||||||
|
DQN_ASSERT(bitsIndex == DQN_ARRAY_COUNT(bitsArray));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[0].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[1].value, DQN_SLICE("0"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[2].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[3].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[4].value, DQN_SLICE("0"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[5].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[6].value, DQN_SLICE("0"), Dqn::IgnoreCase::No));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_ASSERT(hex.IsArray() && hex.numEntries == 4);
|
||||||
|
DqnJson hexArray[4];
|
||||||
|
isize hexIndex = 0;
|
||||||
|
|
||||||
|
while(DqnJson it = DqnJson_GetNextArrayItem(&hex))
|
||||||
|
hexArray[hexIndex++] = it;
|
||||||
|
|
||||||
|
DQN_ASSERT(hexIndex == DQN_ARRAY_COUNT(hexArray));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(hexArray[0].value, DQN_SLICE("\"AF\""), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(hexArray[1].value, DQN_SLICE("\"BE\""), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(hexArray[2].value, DQN_SLICE("\"0C\""), Dqn::IgnoreCase::No));
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(hexArray[3].value, DQN_SLICE("\"FF\""), Dqn::IgnoreCase::No));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_ASSERT(extra.IsArray() && extra.numEntries == 1);
|
||||||
|
while(DqnJson it = DqnJson_GetNextArrayItem(&extra))
|
||||||
|
{
|
||||||
|
DQN_ASSERT(DQN_SLICE_CMP(it.value, DQN_SLICE("123"), Dqn::IgnoreCase::No));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -139,6 +139,7 @@ void LogHeader(char const *funcName)
|
|||||||
|
|
||||||
#include "DqnFixedString.cpp"
|
#include "DqnFixedString.cpp"
|
||||||
#include "DqnOS.cpp"
|
#include "DqnOS.cpp"
|
||||||
|
#include "DqnJson.cpp"
|
||||||
|
|
||||||
void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
|
void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
|
||||||
{
|
{
|
||||||
@ -2897,6 +2898,7 @@ int main(void)
|
|||||||
Dqn_BSearch_Test();
|
Dqn_BSearch_Test();
|
||||||
DqnMemSet_Test();
|
DqnMemSet_Test();
|
||||||
DqnFixedString_Test();
|
DqnFixedString_Test();
|
||||||
|
DqnJson_Test();
|
||||||
|
|
||||||
#ifdef DQN_PLATFORM_HEADER
|
#ifdef DQN_PLATFORM_HEADER
|
||||||
DqnOS_Test();
|
DqnOS_Test();
|
||||||
|
182
dqn.h
182
dqn.h
@ -2825,15 +2825,17 @@ struct DqnJson
|
|||||||
enum struct Type
|
enum struct Type
|
||||||
{
|
{
|
||||||
Object,
|
Object,
|
||||||
Array,
|
ArrayOfObjects,
|
||||||
|
ArrayOfPrimitives,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
DqnSlice<char> value;
|
DqnSlice<char> value;
|
||||||
i32 numEntries;
|
i32 numEntries;
|
||||||
|
|
||||||
operator bool () const { return (value.data != nullptr); }
|
operator bool () const { return (value.data != nullptr); }
|
||||||
i64 ToI64() const { return Dqn_StrToI64(value.data, value.len); }
|
bool IsArray() const { return (type == Type::ArrayOfObjects || type == Type::ArrayOfPrimitives); }
|
||||||
|
i64 ToI64() const { return Dqn_StrToI64(value.data, value.len); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Zero allocation json finder. Returns the data of the value.
|
// Zero allocation json finder. Returns the data of the value.
|
||||||
@ -6802,17 +6804,69 @@ DQN_FILE_SCOPE i64 Dqn_BSearch(i64 *array, i64 size, i64 find,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(doyle): This should maybe be a tokenizer ...
|
||||||
DQN_FILE_SCOPE DqnJson DqnJson_Get(char const *buf, i32 bufLen, char const *findProperty, i32 findPropertyLen)
|
DQN_FILE_SCOPE DqnJson DqnJson_Get(char const *buf, i32 bufLen, char const *findProperty, i32 findPropertyLen)
|
||||||
{
|
{
|
||||||
DqnJson result = {};
|
DqnJson result = {};
|
||||||
|
char const *tmp = DqnChar_SkipWhitespace(buf);
|
||||||
|
bufLen = static_cast<int>((buf + bufLen) - tmp);
|
||||||
|
buf = tmp;
|
||||||
|
|
||||||
|
if (buf[0] == '{' || buf[1] == '[')
|
||||||
|
{
|
||||||
|
buf++;
|
||||||
|
bufLen--;
|
||||||
|
}
|
||||||
|
|
||||||
TryNext:
|
TryNext:
|
||||||
char *locate = DqnStr_GetFirstOccurence(buf, bufLen, findProperty, findPropertyLen);
|
char const *locate = nullptr;
|
||||||
|
for (i32 indexIntoBuf = 0; indexIntoBuf < bufLen; ++indexIntoBuf)
|
||||||
|
{
|
||||||
|
i32 remainingLenInSrcStr = bufLen - indexIntoBuf;
|
||||||
|
if (remainingLenInSrcStr < findPropertyLen) break;
|
||||||
|
|
||||||
|
char const *bufSubStr = buf + indexIntoBuf;
|
||||||
|
if (bufSubStr[0] == '{' || bufSubStr[0] == '[')
|
||||||
|
{
|
||||||
|
int bracketCount = 0;
|
||||||
|
int braceCount = 0;
|
||||||
|
int *searchCharCount = nullptr;
|
||||||
|
if (bufSubStr[0] == '[')
|
||||||
|
{
|
||||||
|
bracketCount++;
|
||||||
|
searchCharCount = &bracketCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
braceCount++;
|
||||||
|
searchCharCount = &braceCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (++indexIntoBuf; (*searchCharCount) != 0; ++indexIntoBuf)
|
||||||
|
{
|
||||||
|
bufSubStr = buf + indexIntoBuf;
|
||||||
|
if (!bufSubStr[0])
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (bufSubStr[0] == '{') ++braceCount;
|
||||||
|
else if (bufSubStr[0] == '}') --braceCount;
|
||||||
|
else if (bufSubStr[0] == '[') ++bracketCount;
|
||||||
|
else if (bufSubStr[0] == ']') --bracketCount;
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DqnStr_Cmp(bufSubStr, findProperty, findPropertyLen, Dqn::IgnoreCase::No) == 0)
|
||||||
|
{
|
||||||
|
locate = buf + indexIntoBuf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!locate) return result;
|
if (!locate) return result;
|
||||||
|
|
||||||
// NOTE: if find property is '{' we are looking for an object in array or the global scope etc
|
// NOTE: if find property is '{' we are looking for an object in array or the global scope etc
|
||||||
// which doesn't have a specific property name
|
// which doesn't have a specific property name
|
||||||
char *startOfValue = locate;
|
char const *startOfValue = locate;
|
||||||
char const *bufPtr = startOfValue;
|
char const *bufPtr = startOfValue;
|
||||||
if (findProperty[0] != '{' && findProperty[0] != '[')
|
if (findProperty[0] != '{' && findProperty[0] != '[')
|
||||||
{
|
{
|
||||||
@ -6844,11 +6898,19 @@ TryNext:
|
|||||||
startOfValue++;
|
startOfValue++;
|
||||||
|
|
||||||
i32 *searchCharCount = nullptr;
|
i32 *searchCharCount = nullptr;
|
||||||
if (bufPtr[0] == '[')
|
if (*bufPtr++ == '[')
|
||||||
{
|
{
|
||||||
bracketCount++;
|
bracketCount++;
|
||||||
result.type = DqnJson::Type::Array;
|
|
||||||
searchCharCount = &bracketCount;
|
searchCharCount = &bracketCount;
|
||||||
|
|
||||||
|
while(bufPtr[0] != '{' && bufPtr[0] != '[' && bufPtr[0] != '"' && !DqnChar_IsAlphaNum(bufPtr[0]) && !bufPtr[0])
|
||||||
|
bufPtr++;
|
||||||
|
|
||||||
|
if (!bufPtr[0])
|
||||||
|
return result;
|
||||||
|
|
||||||
|
const b32 arrayOfPrimitives = (DqnChar_IsAlphaNum(bufPtr[0]) || bufPtr[0] == '"');
|
||||||
|
result.type = (arrayOfPrimitives) ? DqnJson::Type::ArrayOfPrimitives : DqnJson::Type::ArrayOfObjects;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -6857,24 +6919,43 @@ TryNext:
|
|||||||
searchCharCount = &braceCount;
|
searchCharCount = &braceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.numEntries = 0;
|
if (result.type == DqnJson::Type::ArrayOfPrimitives)
|
||||||
for (bufPtr++; (*searchCharCount) != 0; bufPtr++)
|
|
||||||
{
|
{
|
||||||
bool countsChanged = true;
|
for (result.numEntries = 1;;)
|
||||||
if (!bufPtr[0])
|
|
||||||
return result;
|
|
||||||
|
|
||||||
if (bufPtr[0] == '{') braceCount++;
|
|
||||||
else if (bufPtr[0] == '}') braceCount--;
|
|
||||||
else if (bufPtr[0] == '[') bracketCount++;
|
|
||||||
else if (bufPtr[0] == ']') bracketCount--;
|
|
||||||
else countsChanged = false;
|
|
||||||
|
|
||||||
if (countsChanged)
|
|
||||||
{
|
{
|
||||||
if (result.type == DqnJson::Type::Array)
|
while(bufPtr[0] && (bufPtr[0] != ',' && bufPtr[0] != ']'))
|
||||||
|
bufPtr++;
|
||||||
|
|
||||||
|
if (bufPtr[0] == ',')
|
||||||
{
|
{
|
||||||
if (braceCount == 0 && bracketCount == 1)
|
result.numEntries++;
|
||||||
|
bufPtr++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bufPtr[0])
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (bufPtr[0] == ']')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (; (*searchCharCount) != 0; ++bufPtr)
|
||||||
|
{
|
||||||
|
if (!bufPtr[0])
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (bufPtr[0] == '{') ++braceCount;
|
||||||
|
else if (bufPtr[0] == '}') --braceCount;
|
||||||
|
else if (bufPtr[0] == '[') ++bracketCount;
|
||||||
|
else if (bufPtr[0] == ']') --bracketCount;
|
||||||
|
else continue;
|
||||||
|
|
||||||
|
if (result.type == DqnJson::Type::ArrayOfObjects)
|
||||||
|
{
|
||||||
|
if (braceCount == 0 && bracketCount == 1)
|
||||||
{
|
{
|
||||||
result.numEntries++;
|
result.numEntries++;
|
||||||
}
|
}
|
||||||
@ -6887,9 +6968,10 @@ TryNext:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Don't include the open and closing braces/brackets.
|
||||||
|
bufPtr--;
|
||||||
}
|
}
|
||||||
// Don't include the open and closing braces/brackets.
|
|
||||||
bufPtr--;
|
|
||||||
}
|
}
|
||||||
else if (bufPtr[0] == '"' || DqnChar_IsAlphaNum(bufPtr[0]))
|
else if (bufPtr[0] == '"' || DqnChar_IsAlphaNum(bufPtr[0]))
|
||||||
{
|
{
|
||||||
@ -6906,7 +6988,7 @@ TryNext:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.value.data = startOfValue;
|
result.value.data = (char *)startOfValue;
|
||||||
result.value.len = static_cast<i32>(bufPtr - result.value.data);
|
result.value.len = static_cast<i32>(bufPtr - result.value.data);
|
||||||
result.value.data = DqnChar_TrimWhitespaceAround(result.value.data, result.value.len, &result.value.len);
|
result.value.data = DqnChar_TrimWhitespaceAround(result.value.data, result.value.len, &result.value.len);
|
||||||
return result;
|
return result;
|
||||||
@ -6945,25 +7027,49 @@ DQN_FILE_SCOPE DqnJson DqnJson_Get(DqnJson const input, DqnSlice<char const> con
|
|||||||
DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator)
|
DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator)
|
||||||
{
|
{
|
||||||
DqnJson result = {};
|
DqnJson result = {};
|
||||||
if (iterator->type != DqnJson::Type::Array || iterator->numEntries <= 0)
|
if (!iterator->IsArray() || iterator->numEntries <= 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = DqnJson_Get(iterator->value, DQN_SLICE("{"));
|
if (iterator->type == DqnJson::Type::ArrayOfObjects)
|
||||||
if (result)
|
|
||||||
{
|
{
|
||||||
char const *end = iterator->value.data + iterator->value.len;
|
if (result = DqnJson_Get(iterator->value, DQN_SLICE("{")))
|
||||||
iterator->value.data = result.value.data + result.value.len;
|
{
|
||||||
iterator->numEntries--;
|
char const *end = iterator->value.data + iterator->value.len;
|
||||||
|
iterator->value.data = result.value.data + result.value.len;
|
||||||
|
--iterator->numEntries;
|
||||||
|
|
||||||
while (iterator->value.data[0] && *iterator->value.data++ != '}')
|
while (iterator->value.data[0] && *iterator->value.data++ != '}')
|
||||||
;
|
;
|
||||||
|
|
||||||
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
|
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
|
||||||
if (iterator->value.data[0] && iterator->value.data[0] == ',')
|
if (iterator->value.data[0] && iterator->value.data[0] == ',')
|
||||||
iterator->value.data++;
|
iterator->value.data++;
|
||||||
|
|
||||||
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
|
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
|
||||||
iterator->value.len = (iterator->value.data) ? static_cast<i32>(end - iterator->value.data) : 0;
|
iterator->value.len = (iterator->value.data) ? static_cast<i32>(end - iterator->value.data) : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char const *end = iterator->value.data + iterator->value.len;
|
||||||
|
result.value.data = iterator->value.data;
|
||||||
|
--iterator->numEntries;
|
||||||
|
|
||||||
|
if (iterator->numEntries == 0)
|
||||||
|
{
|
||||||
|
while (iterator->value.data[0] && iterator->value.data[0] != ']')
|
||||||
|
++iterator->value.data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (iterator->value.data[0] && iterator->value.data[0] != ',')
|
||||||
|
++iterator->value.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result.value.len = static_cast<i32>(iterator->value.data - result.value.data);
|
||||||
|
iterator->value.data = DqnChar_SkipWhitespace(++iterator->value.data);
|
||||||
|
iterator->value.len = (iterator->value.data) ? static_cast<i32>(end - iterator->value.data) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
Loading…
Reference in New Issue
Block a user