From 095fc7b45446355d5cbe916c2fea9f6266d7bc3c Mon Sep 17 00:00:00 2001 From: Vitaly Baranov Date: Fri, 17 May 2019 17:21:37 +0300 Subject: [PATCH] Optimization by using implementation-specific JSONParser::sizeOfArray(), JSONParser::sizeOfObject(). --- dbms/src/Functions/DummyJSONParser.h | 31 ++-- dbms/src/Functions/FunctionsJSON.h | 196 +++++++++------------- dbms/src/Functions/RapidJSONParser.h | 233 ++++++++++++++------------- dbms/src/Functions/SimdJSONParser.h | 123 +++++++++----- 4 files changed, 294 insertions(+), 289 deletions(-) diff --git a/dbms/src/Functions/DummyJSONParser.h b/dbms/src/Functions/DummyJSONParser.h index 41a046ec502..51b30f569e7 100644 --- a/dbms/src/Functions/DummyJSONParser.h +++ b/dbms/src/Functions/DummyJSONParser.h @@ -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 {}; } }; } diff --git a/dbms/src/Functions/FunctionsJSON.h b/dbms/src/Functions/FunctionsJSON.h index 808b3b1d1ca..bc1764d2e26 100644 --- a/dbms/src/Functions/FunctionsJSON.h +++ b/dbms/src/Functions/FunctionsJSON.h @@ -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 moves; - constexpr size_t num_extra_arguments = Impl::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(*column.column); - if (isString(column.type)) - moves.emplace_back(MoveType::ConstKey, column_const.getField().get()); - else - moves.emplace_back(MoveType::ConstIndex, column_const.getField().get()); - } - else - { - if (isString(column.type)) - moves.emplace_back(MoveType::Key, ""); - else - moves.emplace_back(MoveType::Index, 0); - } - } + std::vector 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 impl; @@ -160,7 +122,8 @@ private: for (const auto i : ext::range(0, input_rows_count)) { - bool ok = parser.parse(reinterpret_cast(&chars[offsets[i - 1]]), offsets[i] - offsets[i - 1] - 1); + StringRef json{reinterpret_cast(&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 prepareListOfMoves(Block & block, const ColumnNumbers & arguments) + { + constexpr size_t num_extra_arguments = Impl::num_extra_arguments; + const size_t num_moves = arguments.size() - num_extra_arguments - 1; + std::vector 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(*column.column); + if (isString(column.type)) + moves.emplace_back(MoveType::ConstKey, column_const.getField().get()); + else + moves.emplace_back(MoveType::ConstIndex, column_const.getField().get()); + } + 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(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(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(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(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()); diff --git a/dbms/src/Functions/RapidJSONParser.h b/dbms/src/Functions/RapidJSONParser.h index 0a52b5b524d..930f0e4b063 100644 --- a/dbms/src/Functions/RapidJSONParser.h +++ b/dbms/src/Functions/RapidJSONParser.h @@ -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 = ¤t_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 = ¤t_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 = ¤t_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 = ¤t_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::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; }; diff --git a/dbms/src/Functions/SimdJSONParser.h b/dbms/src/Functions/SimdJSONParser.h index d9128c6fef2..7965507c529 100644 --- a/dbms/src/Functions/SimdJSONParser.h +++ b/dbms/src/Functions/SimdJSONParser.h @@ -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;