Optimization by using implementation-specific JSONParser::sizeOfArray(), JSONParser::sizeOfObject().

This commit is contained in:
Vitaly Baranov 2019-05-17 17:21:37 +03:00
parent 823d862ceb
commit 095fc7b454
4 changed files with 294 additions and 289 deletions

View File

@ -17,18 +17,12 @@ struct DummyJSONParser
{
static constexpr bool need_preallocate = false;
void preallocate(size_t) {}
bool parse(const char *, size_t) { throw Exception{"Functions JSON* are not supported without AVX2", ErrorCodes::NOT_IMPLEMENTED}; }
bool parse(const StringRef &) { throw Exception{"Functions JSON* are not supported without AVX2", ErrorCodes::NOT_IMPLEMENTED}; }
using Iterator = std::nullptr_t;
Iterator getRoot() const { return nullptr; }
static bool downToArray(Iterator &) { return false; }
static bool downToObject(Iterator &) { return false; }
static bool downToObject(Iterator &, StringRef &) { return false; }
static bool parentScopeIsObject(const Iterator &) { return false; }
static bool next(Iterator &) { return false; }
static bool nextKeyValue(Iterator &) { return false; }
static bool nextKeyValue(Iterator &, StringRef &) { return false; }
static bool isInt64(const Iterator &) { return false; }
static bool isUInt64(const Iterator &) { return false; }
static bool isDouble(const Iterator &) { return false; }
@ -36,13 +30,28 @@ struct DummyJSONParser
static bool isArray(const Iterator &) { return false; }
static bool isObject(const Iterator &) { return false; }
static bool isBool(const Iterator &) { return false; }
static bool isNull(const Iterator &) { return false; }
static StringRef getKey(const Iterator &) { return {}; }
static StringRef getString(const Iterator &) { return {}; }
static bool isNull(const Iterator &) { return true; }
static Int64 getInt64(const Iterator &) { return 0; }
static UInt64 getUInt64(const Iterator &) { return 0; }
static double getDouble(const Iterator &) { return 0; }
static bool getBool(const Iterator &) { return false; }
static StringRef getString(const Iterator &) { return {}; }
static size_t sizeOfArray(const Iterator &) { return 0; }
static bool firstArrayElement(Iterator &) { return false; }
static bool arrayElementByIndex(Iterator &, size_t) { return false; }
static bool nextArrayElement(Iterator &) { return false; }
static size_t sizeOfObject(const Iterator &) { return 0; }
static bool firstObjectMember(Iterator &) { return false; }
static bool firstObjectMember(Iterator &, StringRef &) { return false; }
static bool objectMemberByIndex(Iterator &, size_t) { return false; }
static bool objectMemberByName(Iterator &, const StringRef &) { return false; }
static bool nextObjectMember(Iterator &) { return false; }
static bool nextObjectMember(Iterator &, StringRef &) { return false; }
static bool isObjectMember(const Iterator &) { return false; }
static StringRef getKey(const Iterator &) { return {}; }
};
}

View File

@ -108,50 +108,12 @@ private:
const ColumnString::Chars & chars = col_json_string->getChars();
const ColumnString::Offsets & offsets = col_json_string->getOffsets();
/// Prepare list of moves.
std::vector<Move> moves;
constexpr size_t num_extra_arguments = Impl<JSONParser>::num_extra_arguments;
const size_t num_moves = arguments.size() - num_extra_arguments - 1;
moves.reserve(num_moves);
for (const auto i : ext::range(0, num_moves))
{
const auto & column = block.getByPosition(arguments[i + 1]);
if (!isString(column.type) && !isInteger(column.type))
throw Exception{"The argument " + std::to_string(i + 2) + " of function " + String(Name::name)
+ " should be a string specifying key or an integer specifying index, illegal type: " + column.type->getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
if (column.column->isColumnConst())
{
const auto & column_const = static_cast<const ColumnConst &>(*column.column);
if (isString(column.type))
moves.emplace_back(MoveType::ConstKey, column_const.getField().get<String>());
else
moves.emplace_back(MoveType::ConstIndex, column_const.getField().get<Int64>());
}
else
{
if (isString(column.type))
moves.emplace_back(MoveType::Key, "");
else
moves.emplace_back(MoveType::Index, 0);
}
}
std::vector<Move> moves = prepareListOfMoves(block, arguments);
/// Preallocate memory in parser if necessary.
JSONParser parser;
if (parser.need_preallocate)
{
size_t max_size = 0;
for (const auto i : ext::range(0, input_rows_count))
if (max_size < offsets[i] - offsets[i - 1])
max_size = offsets[i] - offsets[i - 1];
if (max_size < 1)
max_size = 1;
parser.preallocate(max_size);
}
parser.preallocate(calculateMaxSize(offsets));
Impl<JSONParser> impl;
@ -160,7 +122,8 @@ private:
for (const auto i : ext::range(0, input_rows_count))
{
bool ok = parser.parse(reinterpret_cast<const char *>(&chars[offsets[i - 1]]), offsets[i] - offsets[i - 1] - 1);
StringRef json{reinterpret_cast<const char *>(&chars[offsets[i - 1]]), offsets[i] - offsets[i - 1] - 1};
bool ok = parser.parse(json);
if (ok)
{
@ -215,6 +178,7 @@ private:
ConstKey,
ConstIndex,
};
struct Move
{
Move(MoveType type_, size_t index_ = 0) : type(type_), index(index_) {}
@ -224,6 +188,39 @@ private:
String key;
};
static std::vector<Move> prepareListOfMoves(Block & block, const ColumnNumbers & arguments)
{
constexpr size_t num_extra_arguments = Impl<JSONParser>::num_extra_arguments;
const size_t num_moves = arguments.size() - num_extra_arguments - 1;
std::vector<Move> moves;
moves.reserve(num_moves);
for (const auto i : ext::range(0, num_moves))
{
const auto & column = block.getByPosition(arguments[i + 1]);
if (!isString(column.type) && !isInteger(column.type))
throw Exception{"The argument " + std::to_string(i + 2) + " of function " + String(Name::name)
+ " should be a string specifying key or an integer specifying index, illegal type: " + column.type->getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
if (column.column->isColumnConst())
{
const auto & column_const = static_cast<const ColumnConst &>(*column.column);
if (isString(column.type))
moves.emplace_back(MoveType::ConstKey, column_const.getField().get<String>());
else
moves.emplace_back(MoveType::ConstIndex, column_const.getField().get<Int64>());
}
else
{
if (isString(column.type))
moves.emplace_back(MoveType::Key, "");
else
moves.emplace_back(MoveType::Index, 0);
}
}
return moves;
}
using Iterator = typename JSONParser::Iterator;
/// Performs moves of types MoveType::Index and MoveType::ConstIndex.
@ -231,51 +228,17 @@ private:
{
if (JSONParser::isArray(it))
{
if (!JSONParser::downToArray(it))
return false;
size_t steps;
if (index > 0)
{
steps = index - 1;
}
return JSONParser::arrayElementByIndex(it, index - 1);
else
{
size_t length = 1;
Iterator it2 = it;
while (JSONParser::next(it2))
++length;
steps = index + length;
}
while (steps--)
{
if (!JSONParser::next(it))
return false;
}
return true;
return JSONParser::arrayElementByIndex(it, JSONParser::sizeOfArray(it) + index);
}
if (JSONParser::isObject(it))
{
if (!JSONParser::downToObject(it))
return false;
size_t steps;
if (index > 0)
{
steps = index - 1;
}
return JSONParser::objectMemberByIndex(it, index - 1);
else
{
size_t length = 1;
Iterator it2 = it;
while (JSONParser::nextKeyValue(it2))
++length;
steps = index + length;
}
while (steps--)
{
if (!JSONParser::nextKeyValue(it))
return false;
}
return true;
return JSONParser::objectMemberByIndex(it, JSONParser::sizeOfObject(it) + index);
}
return false;
}
@ -284,18 +247,21 @@ private:
static bool moveIteratorToElementByKey(Iterator & it, const String & key)
{
if (JSONParser::isObject(it))
{
StringRef current_key;
if (!JSONParser::downToObject(it, current_key))
return false;
do
{
if (current_key == key)
return true;
} while (JSONParser::nextKeyValue(it, current_key));
}
return JSONParser::objectMemberByName(it, key);
return false;
}
static size_t calculateMaxSize(const ColumnString::Offsets & offsets)
{
size_t max_size = 0;
for (const auto i : ext::range(0, offsets.size()))
if (max_size < offsets[i] - offsets[i - 1])
max_size = offsets[i] - offsets[i - 1];
if (max_size < 1)
max_size = 1;
return max_size;
}
};
};
@ -347,27 +313,9 @@ public:
{
size_t size;
if (JSONParser::isArray(it))
{
size = 0;
Iterator it2 = it;
if (JSONParser::downToArray(it2))
{
do
++size;
while (JSONParser::next(it2));
}
}
size = JSONParser::sizeOfArray(it);
else if (JSONParser::isObject(it))
{
size = 0;
Iterator it2 = it;
if (JSONParser::downToObject(it2))
{
do
++size;
while (JSONParser::nextKeyValue(it2));
}
}
size = JSONParser::sizeOfObject(it);
else
return false;
@ -393,7 +341,7 @@ public:
using Iterator = typename JSONParser::Iterator;
static bool addValueToColumn(IColumn & dest, const Iterator & it)
{
if (!JSONParser::parentScopeIsObject(it))
if (!JSONParser::isObjectMember(it))
return false;
StringRef key = JSONParser::getKey(it);
ColumnString & col_str = static_cast<ColumnString &>(dest);
@ -705,7 +653,7 @@ struct JSONExtractTree
return false;
Iterator it2 = it;
if (!JSONParser::downToArray(it2))
if (!JSONParser::firstArrayElement(it2))
return false;
ColumnArray & col_arr = static_cast<ColumnArray &>(dest);
@ -720,7 +668,7 @@ struct JSONExtractTree
else
data.insertDefault();
}
while (JSONParser::next(it2));
while (JSONParser::nextArrayElement(it2));
if (!were_valid_elements)
{
@ -770,7 +718,7 @@ struct JSONExtractTree
if (JSONParser::isArray(it))
{
Iterator it2 = it;
if (!JSONParser::downToArray(it2))
if (!JSONParser::firstArrayElement(it2))
return false;
size_t index = 0;
@ -782,7 +730,7 @@ struct JSONExtractTree
tuple.getColumn(index).insertDefault();
++index;
}
while (JSONParser::next(it2));
while (JSONParser::nextArrayElement(it2));
set_size(old_size + static_cast<size_t>(were_valid_elements));
return were_valid_elements;
@ -793,7 +741,7 @@ struct JSONExtractTree
if (name_to_index_map.empty())
{
Iterator it2 = it;
if (!JSONParser::downToObject(it2))
if (!JSONParser::firstObjectMember(it2))
return false;
size_t index = 0;
@ -805,13 +753,13 @@ struct JSONExtractTree
tuple.getColumn(index).insertDefault();
++index;
}
while (JSONParser::nextKeyValue(it2));
while (JSONParser::nextObjectMember(it2));
}
else
{
Iterator it2 = it;
StringRef key;
if (!JSONParser::downToObject(it2, key))
if (!JSONParser::firstObjectMember(it2, key))
return false;
do
@ -823,7 +771,7 @@ struct JSONExtractTree
were_valid_elements = true;
}
}
while (JSONParser::nextKeyValue(it2, key));
while (JSONParser::nextObjectMember(it2, key));
}
set_size(old_size + static_cast<size_t>(were_valid_elements));
@ -965,7 +913,7 @@ public:
StringRef key;
Iterator it2 = it;
if (!JSONParser::downToObject(it2, key))
if (!JSONParser::firstObjectMember(it2, key))
return false;
do
@ -973,7 +921,7 @@ public:
if (extract_tree->addValueToColumn(col_value, it2))
col_key.insertData(key.data, key.size);
}
while (JSONParser::nextKeyValue(it2, key));
while (JSONParser::nextObjectMember(it2, key));
if (col_tuple.size() == old_size)
return false;
@ -1047,10 +995,10 @@ private:
{
writeChar('[', buf);
Iterator it2 = it;
if (JSONParser::downToArray(it2))
if (JSONParser::firstArrayElement(it2))
{
traverse(it2, buf);
while (JSONParser::next(it2))
while (JSONParser::nextArrayElement(it2))
{
writeChar(',', buf);
traverse(it2, buf);
@ -1064,12 +1012,12 @@ private:
writeChar('{', buf);
Iterator it2 = it;
StringRef key;
if (JSONParser::downToObject(it2, key))
if (JSONParser::firstObjectMember(it2, key))
{
writeJSONString(key, buf, format_settings());
writeChar(':', buf);
traverse(it2, buf);
while (JSONParser::nextKeyValue(it2, key))
while (JSONParser::nextObjectMember(it2, key))
{
writeChar(',', buf);
writeJSONString(key, buf, format_settings());

View File

@ -20,10 +20,9 @@ struct RapidJSONParser
static constexpr bool need_preallocate = false;
void preallocate(size_t) {}
bool parse(const char * data, size_t size)
bool parse(const StringRef & json)
{
InputStream in(data, size);
document.ParseStream(in);
document.Parse(json.data);
return !document.HasParseError();
}
@ -34,98 +33,19 @@ struct RapidJSONParser
Iterator(const rapidjson::Document & document) : value(&document) {}
Iterator(const Iterator & src)
: value(src.value)
, parent_scope_is_object(src.parent_scope_is_object)
, is_object_member(src.is_object_member)
, current_in_array(src.current_in_array)
, end_of_array(src.end_of_array) {}
Iterator & operator =(const Iterator & src)
{
value = src.value;
parent_scope_is_object = src.parent_scope_is_object;
is_object_member = src.is_object_member;
current_in_array = src.current_in_array;
end_of_array = src.end_of_array;
return *this;
}
const rapidjson::Value & getValue() const { return *value; }
bool downToArray()
{
if (value->Empty())
return false;
current_in_array = &*value->Begin();
end_of_array = &*value->End();
value = current_in_array;
++current_in_array;
parent_scope_is_object = false;
return true;
}
bool next()
{
if (current_in_array == end_of_array)
return false;
value = current_in_array;
++current_in_array;
return true;
}
bool downToObject()
{
if (value->ObjectEmpty())
return false;
current_in_object = &*value->MemberBegin();
end_of_object = &*value->MemberEnd();
value = &current_in_object->value;
++current_in_object;
parent_scope_is_object = true;
return true;
}
bool downToObject(StringRef & first_key)
{
if (value->ObjectEmpty())
return false;
current_in_object = &*value->MemberBegin();
end_of_object = &*value->MemberEnd();
const auto & name = current_in_object->name;
first_key.data = name.GetString();
first_key.size = name.GetStringLength();
value = &current_in_object->value;
++current_in_object;
parent_scope_is_object = true;
return true;
}
bool nextKeyValue()
{
if (current_in_object == end_of_object)
return false;
value = &current_in_object->value;
++current_in_object;
return true;
}
bool nextKeyValue(StringRef & key)
{
if (current_in_object == end_of_object)
return false;
const auto & name = current_in_object->name;
key.data = name.GetString();
key.size = name.GetStringLength();
value = &current_in_object->value;
++current_in_object;
return true;
}
StringRef getKey() const
{
const auto & name = (current_in_object - 1)->name;
return {name.GetString(), name.GetStringLength()};
}
bool parentScopeIsObject() const { return parent_scope_is_object; }
bool isInt64() const { return value->IsInt64(); }
bool isUInt64() const { return value->IsUint64(); }
bool isDouble() const { return value->IsDouble(); }
@ -141,9 +61,103 @@ struct RapidJSONParser
bool getBool() const { return value->GetBool(); }
StringRef getString() const { return {value->GetString(), value->GetStringLength()}; }
size_t sizeOfArray() const { return value->Size(); }
bool arrayElementByIndex(size_t index)
{
if (index >= value->Size())
return false;
setRange(value->Begin() + index, value->End());
value = current_in_array++;
return true;
}
bool nextArrayElement()
{
if (current_in_array == end_of_array)
return false;
value = current_in_array++;
return true;
}
size_t sizeOfObject() const { return value->MemberCount(); }
bool objectMemberByIndex(size_t index)
{
if (index >= value->MemberCount())
return false;
setRange(value->MemberBegin() + index, value->MemberEnd());
value = &(current_in_object++)->value;
return true;
}
bool objectMemberByIndex(size_t index, StringRef & key)
{
if (index >= value->MemberCount())
return false;
setRange(value->MemberBegin() + index, value->MemberEnd());
key = getKeyImpl(current_in_object);
value = &(current_in_object++)->value;
return true;
}
bool objectMemberByName(const StringRef & name)
{
auto it = value->FindMember(name.data);
if (it == value->MemberEnd())
return false;
setRange(it, value->MemberEnd());
value = &(current_in_object++)->value;
return true;
}
bool nextObjectMember()
{
if (current_in_object == end_of_object)
return false;
value = &(current_in_object++)->value;
return true;
}
bool nextObjectMember(StringRef & key)
{
if (current_in_object == end_of_object)
return false;
key = getKeyImpl(current_in_object);
value = &(current_in_object++)->value;
return true;
}
bool isObjectMember() const { return is_object_member; }
StringRef getKey() const
{
return getKeyImpl(current_in_object - 1);
}
private:
void setRange(rapidjson::Value::ConstValueIterator current, rapidjson::Value::ConstValueIterator end)
{
current_in_array = &*current;
end_of_array = &*end;
is_object_member = false;
}
void setRange(rapidjson::Value::ConstMemberIterator current, rapidjson::Value::ConstMemberIterator end)
{
current_in_object = &*current;
end_of_object = &*end;
is_object_member = true;
}
static StringRef getKeyImpl(const rapidjson::GenericMember<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<>> * member)
{
const auto & name = member->name;
return {name.GetString(), name.GetStringLength()};
}
const rapidjson::Value * value = nullptr;
bool parent_scope_is_object = false;
bool is_object_member = false;
union
{
@ -159,50 +173,37 @@ struct RapidJSONParser
Iterator getRoot() { return Iterator{document}; }
static bool downToArray(Iterator & it) { return it.downToArray(); }
static bool downToObject(Iterator & it) { return it.downToObject(); }
static bool downToObject(Iterator & it, StringRef & first_key) { return it.downToObject(first_key); }
static bool parentScopeIsObject(const Iterator & it) { return it.parentScopeIsObject(); }
static bool next(Iterator & it) { return it.next(); }
static bool nextKeyValue(Iterator & it) { return it.nextKeyValue(); }
static bool nextKeyValue(Iterator & it, StringRef & key) { return it.nextKeyValue(key); }
static bool isInt64(const Iterator & it) { return it.isInt64(); }
static bool isUInt64(const Iterator & it) { return it.isUInt64(); }
static bool isDouble(const Iterator & it) { return it.isDouble(); }
static bool isBool(const Iterator & it) { return it.isBool(); }
static bool isString(const Iterator & it) { return it.isString(); }
static bool isArray(const Iterator & it) { return it.isArray(); }
static bool isObject(const Iterator & it) { return it.isObject(); }
static bool isBool(const Iterator & it) { return it.isBool(); }
static bool isNull(const Iterator & it) { return it.isNull(); }
static StringRef getKey(const Iterator & it) { return it.getKey(); }
static StringRef getString(const Iterator & it) { return it.getString(); }
static Int64 getInt64(const Iterator & it) { return it.getInt64(); }
static UInt64 getUInt64(const Iterator & it) { return it.getUInt64(); }
static double getDouble(const Iterator & it) { return it.getDouble(); }
static bool getBool(const Iterator & it) { return it.getBool(); }
static StringRef getString(const Iterator & it) { return it.getString(); }
static size_t sizeOfArray(const Iterator & it) { return it.sizeOfArray(); }
static bool firstArrayElement(Iterator & it) { return it.arrayElementByIndex(0); }
static bool arrayElementByIndex(Iterator & it, size_t index) { return it.arrayElementByIndex(index); }
static bool nextArrayElement(Iterator & it) { return it.nextArrayElement(); }
static size_t sizeOfObject(const Iterator & it) { return it.sizeOfObject(); }
static bool firstObjectMember(Iterator & it) { return it.objectMemberByIndex(0); }
static bool firstObjectMember(Iterator & it, StringRef & first_key) { return it.objectMemberByIndex(0, first_key); }
static bool objectMemberByIndex(Iterator & it, size_t index) { return it.objectMemberByIndex(index); }
static bool objectMemberByName(Iterator & it, const StringRef & name) { return it.objectMemberByName(name); }
static bool nextObjectMember(Iterator & it) { return it.nextObjectMember(); }
static bool nextObjectMember(Iterator & it, StringRef & next_key) { return it.nextObjectMember(next_key); }
static bool isObjectMember(const Iterator & it) { return it.isObjectMember(); }
static StringRef getKey(const Iterator & it) { return it.getKey(); }
private:
class InputStream
{
public:
InputStream(const char * data, size_t size) : begin(data), end(data + size), current(data) {}
using Ch = char;
Ch Peek() { if (current == end) return 0; return *current; }
Ch Take() { if (current == end) return 0; return *current++; }
size_t Tell() const { return current - begin; }
Ch* PutBegin() { return nullptr; }
void Put(Ch) {}
void Flush() {}
size_t PutEnd(Ch*) { return 0; }
private:
const char * begin;
const char * end;
const char * current;
};
rapidjson::Document document;
};

View File

@ -40,46 +40,11 @@ struct SimdJSONParser
ErrorCodes::CANNOT_ALLOCATE_MEMORY};
}
bool parse(const char * data, size_t size) { return !json_parse(data, size, pj); }
bool parse(const StringRef & json) { return !json_parse(json.data, json.size, pj); }
using Iterator = ParsedJson::iterator;
Iterator getRoot() { return Iterator{pj}; }
static bool downToArray(Iterator & it) { return it.down(); }
static bool downToObject(Iterator & it) { return it.down() && it.next(); }
static bool downToObject(Iterator & it, StringRef & first_key)
{
if (!it.down())
return false;
first_key.data = it.get_string();
first_key.size = it.get_string_length();
return it.next();
}
static bool parentScopeIsObject(const Iterator & it) { return it.get_scope_type() == '{'; }
static bool next(Iterator & it) { return it.next(); }
static bool nextKeyValue(Iterator & it) { return it.next() && it.next(); }
static bool nextKeyValue(Iterator & it, StringRef & key)
{
if (!it.next())
return false;
key.data = it.get_string();
key.size = it.get_string_length();
return it.next();
}
static StringRef getKey(const Iterator & it)
{
Iterator it2 = it;
it2.prev();
return StringRef{it2.get_string(), it2.get_string_length()};
}
static bool isInt64(const Iterator & it) { return it.is_integer(); }
static bool isUInt64(const Iterator &) { return false; /* See https://github.com/lemire/simdjson/issues/68 */ }
static bool isDouble(const Iterator & it) { return it.is_double(); }
@ -87,13 +52,95 @@ struct SimdJSONParser
static bool isArray(const Iterator & it) { return it.is_array(); }
static bool isObject(const Iterator & it) { return it.is_object(); }
static bool isBool(const Iterator & it) { return it.get_type() == 't' || it.get_type() == 'f'; }
static bool isNull(const Iterator & it) { return it.get_type() == 'n'; }
static bool isNull(const Iterator & it) { return it.is_null(); }
static StringRef getString(const Iterator & it) { return StringRef{it.get_string(), it.get_string_length()}; }
static Int64 getInt64(const Iterator & it) { return it.get_integer(); }
static UInt64 getUInt64(const Iterator &) { return 0; /* isUInt64() never returns true */ }
static double getDouble(const Iterator & it) { return it.get_double(); }
static bool getBool(const Iterator & it) { return it.get_type() == 't'; }
static StringRef getString(const Iterator & it) { return StringRef{it.get_string(), it.get_string_length()}; }
static size_t sizeOfArray(const Iterator & it)
{
size_t size = 0;
Iterator it2 = it;
if (it2.down())
{
do
++size;
while (it2.next());
}
return size;
}
static bool firstArrayElement(Iterator & it) { return it.down(); }
static bool arrayElementByIndex(Iterator & it, size_t index)
{
if (!it.down())
return false;
while (index--)
if (!it.next())
return false;
return true;
}
static bool nextArrayElement(Iterator & it) { return it.next(); }
static size_t sizeOfObject(const Iterator & it)
{
size_t size = 0;
Iterator it2 = it;
if (it2.down())
{
do
++size;
while (it2.next() && it2.next());
}
return size;
}
static bool firstObjectMember(Iterator & it) { return it.down() && it.next(); }
static bool firstObjectMember(Iterator & it, StringRef & first_key)
{
if (!it.down())
return false;
first_key.data = it.get_string();
first_key.size = it.get_string_length();
return it.next();
}
static bool objectMemberByIndex(Iterator & it, size_t index)
{
if (!it.down())
return false;
while (index--)
if (!it.next() || !it.next())
return false;
return it.next();
}
static bool objectMemberByName(Iterator & it, const StringRef & name) { return it.move_to_key(name.data); }
static bool nextObjectMember(Iterator & it) { return it.next() && it.next(); }
static bool nextObjectMember(Iterator & it, StringRef & next_key)
{
if (!it.next())
return false;
next_key.data = it.get_string();
next_key.size = it.get_string_length();
return it.next();
}
static bool isObjectMember(const Iterator & it) { return it.get_scope_type() == '{'; }
static StringRef getKey(const Iterator & it)
{
Iterator it2 = it;
it2.prev();
return StringRef{it2.get_string(), it2.get_string_length()};
}
private:
ParsedJson pj;