Make DqnJson handle more cases

This commit is contained in:
Doyle T 2018-07-13 00:46:08 +10:00
parent 33cf476d29
commit f1efb6f8f1
3 changed files with 263 additions and 38 deletions

117
DqnJson.cpp Normal file
View 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));
}
}
}

View File

@ -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
View File

@ -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;