mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 15:42:02 +00:00
Rework JSON functions to use the new simdjson interface.
This commit is contained in:
parent
4cc101f1d4
commit
8bcaf7908e
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/StringRef.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Core/Types.h>
|
||||
|
||||
@ -15,43 +14,73 @@ namespace ErrorCodes
|
||||
/// It can't do anything useful and just throws an exception.
|
||||
struct DummyJSONParser
|
||||
{
|
||||
static constexpr bool need_preallocate = false;
|
||||
void preallocate(size_t) {}
|
||||
class Array;
|
||||
class Object;
|
||||
|
||||
bool parse(const StringRef &) { throw Exception{"Functions JSON* are not supported without AVX2", ErrorCodes::NOT_IMPLEMENTED}; }
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
Element() {}
|
||||
bool isInt64() const { return false; }
|
||||
bool isUInt64() const { return false; }
|
||||
bool isDouble() const { return false; }
|
||||
bool isString() const { return false; }
|
||||
bool isArray() const { return false; }
|
||||
bool isObject() const { return false; }
|
||||
bool isBool() const { return false; }
|
||||
bool isNull() const { return false; }
|
||||
|
||||
using Iterator = std::nullptr_t;
|
||||
Iterator getRoot() const { return nullptr; }
|
||||
Int64 getInt64() const { return 0; }
|
||||
UInt64 getUInt64() const { return 0; }
|
||||
double getDouble() const { return 0; }
|
||||
bool getBool() const { return false; }
|
||||
std::string_view getString() const { return {}; }
|
||||
Array getArray() const;
|
||||
Object getObject() const;
|
||||
};
|
||||
|
||||
static bool isInt64(const Iterator &) { return false; }
|
||||
static bool isUInt64(const Iterator &) { return false; }
|
||||
static bool isDouble(const Iterator &) { return false; }
|
||||
static bool isString(const Iterator &) { return false; }
|
||||
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 true; }
|
||||
class Array
|
||||
{
|
||||
public:
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Element operator*() const { return {}; }
|
||||
Iterator & operator ++() { return *this; }
|
||||
Iterator operator ++(int) { return *this; }
|
||||
friend bool operator ==(const Iterator &, const Iterator &) { return true; }
|
||||
friend bool operator !=(const Iterator &, const Iterator &) { return false; }
|
||||
};
|
||||
|
||||
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 {}; }
|
||||
Iterator begin() const { return {}; }
|
||||
Iterator end() const { return {}; }
|
||||
size_t size() const { return 0; }
|
||||
Element operator[](size_t) const { 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; }
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
using KeyValuePair = std::pair<std::string_view, Element>;
|
||||
|
||||
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 {}; }
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
KeyValuePair operator *() const { return {}; }
|
||||
Iterator & operator ++() { return *this; }
|
||||
Iterator operator ++(int) { return *this; }
|
||||
friend bool operator ==(const Iterator &, const Iterator &) { return true; }
|
||||
friend bool operator !=(const Iterator &, const Iterator &) { return false; }
|
||||
};
|
||||
|
||||
Iterator begin() const { return {}; }
|
||||
Iterator end() const { return {}; }
|
||||
size_t size() const { return 0; }
|
||||
KeyValuePair operator[](size_t) const { return {}; }
|
||||
bool find(const std::string_view &, Element &) const { return false; }
|
||||
};
|
||||
|
||||
bool parse(const std::string_view &, Element &) { throw Exception{"Functions JSON* are not supported", ErrorCodes::NOT_IMPLEMENTED}; }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,57 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
}
|
||||
|
||||
|
||||
std::vector<FunctionJSONHelpers::Move> FunctionJSONHelpers::prepareMoves(const char * function_name, Block & block, const ColumnNumbers & arguments, size_t first_index_argument, size_t num_index_arguments)
|
||||
{
|
||||
std::vector<Move> moves;
|
||||
moves.reserve(num_index_arguments);
|
||||
for (const auto i : ext::range(first_index_argument, first_index_argument + num_index_arguments))
|
||||
{
|
||||
const auto & column = block.getByPosition(arguments[i]);
|
||||
if (!isString(column.type) && !isInteger(column.type))
|
||||
throw Exception{"The argument " + std::to_string(i + 1) + " of function " + String(function_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(*column.column))
|
||||
{
|
||||
const auto & column_const = assert_cast<const ColumnConst &>(*column.column);
|
||||
if (isString(column.type))
|
||||
moves.emplace_back(MoveType::ConstKey, column_const.getValue<String>());
|
||||
else
|
||||
moves.emplace_back(MoveType::ConstIndex, column_const.getInt(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isString(column.type))
|
||||
moves.emplace_back(MoveType::Key, "");
|
||||
else
|
||||
moves.emplace_back(MoveType::Index, 0);
|
||||
}
|
||||
}
|
||||
return moves;
|
||||
}
|
||||
|
||||
size_t FunctionJSONHelpers::calculateMaxSize(const ColumnString::Offsets & offsets)
|
||||
{
|
||||
size_t max_size = 0;
|
||||
for (const auto i : ext::range(0, offsets.size()))
|
||||
{
|
||||
size_t size = offsets[i] - offsets[i - 1];
|
||||
if (max_size < size)
|
||||
max_size = size;
|
||||
}
|
||||
if (max_size)
|
||||
--max_size;
|
||||
return max_size;
|
||||
}
|
||||
|
||||
|
||||
void registerFunctionsJSON(FunctionFactory & factory)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,9 +6,7 @@
|
||||
|
||||
#if USE_RAPIDJSON
|
||||
# include <Core/Types.h>
|
||||
# include <Common/Exception.h>
|
||||
# include <common/StringRef.h>
|
||||
|
||||
# include <common/defines.h>
|
||||
# include <rapidjson/document.h>
|
||||
|
||||
|
||||
@ -19,197 +17,130 @@ namespace DB
|
||||
/// It provides ability to parse JSONs using rapidjson library.
|
||||
struct RapidJSONParser
|
||||
{
|
||||
static constexpr bool need_preallocate = false;
|
||||
void preallocate(size_t) {}
|
||||
class Array;
|
||||
class Object;
|
||||
|
||||
bool parse(const StringRef & json)
|
||||
{
|
||||
rapidjson::MemoryStream ms(json.data, json.size);
|
||||
rapidjson::EncodedInputStream<rapidjson::UTF8<>, rapidjson::MemoryStream> is(ms);
|
||||
document.ParseStream(is);
|
||||
return !document.HasParseError() && (ms.Tell() == json.size);
|
||||
}
|
||||
|
||||
struct Iterator
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
Iterator() {}
|
||||
Iterator(const rapidjson::Document & document_) : value(&document_) {}
|
||||
Iterator(const Iterator & src)
|
||||
: value(src.value)
|
||||
, is_object_member(src.is_object_member)
|
||||
, current_in_array(src.current_in_array)
|
||||
, end_of_array(src.end_of_array) {}
|
||||
ALWAYS_INLINE Element() {}
|
||||
ALWAYS_INLINE Element(const rapidjson::Value & value_) : ptr(&value_) {}
|
||||
|
||||
Iterator & operator =(const Iterator & src)
|
||||
ALWAYS_INLINE bool isInt64() const { return ptr->IsInt64(); }
|
||||
ALWAYS_INLINE bool isUInt64() const { return ptr->IsUint64(); }
|
||||
ALWAYS_INLINE bool isDouble() const { return ptr->IsDouble(); }
|
||||
ALWAYS_INLINE bool isString() const { return ptr->IsString(); }
|
||||
ALWAYS_INLINE bool isArray() const { return ptr->IsArray(); }
|
||||
ALWAYS_INLINE bool isObject() const { return ptr->IsObject(); }
|
||||
ALWAYS_INLINE bool isBool() const { return ptr->IsBool(); }
|
||||
ALWAYS_INLINE bool isNull() const { return ptr->IsNull(); }
|
||||
|
||||
ALWAYS_INLINE Int64 getInt64() const { return ptr->GetInt64(); }
|
||||
ALWAYS_INLINE UInt64 getUInt64() const { return ptr->GetUint64(); }
|
||||
ALWAYS_INLINE double getDouble() const { return ptr->GetDouble(); }
|
||||
ALWAYS_INLINE bool getBool() const { return ptr->GetBool(); }
|
||||
ALWAYS_INLINE std::string_view getString() const { return {ptr->GetString(), ptr->GetStringLength()}; }
|
||||
Array getArray() const;
|
||||
Object getObject() const;
|
||||
|
||||
private:
|
||||
const rapidjson::Value * ptr = nullptr;
|
||||
};
|
||||
|
||||
class Array
|
||||
{
|
||||
public:
|
||||
class Iterator
|
||||
{
|
||||
value = src.value;
|
||||
is_object_member = src.is_object_member;
|
||||
current_in_array = src.current_in_array;
|
||||
end_of_array = src.end_of_array;
|
||||
return *this;
|
||||
public:
|
||||
ALWAYS_INLINE Iterator(const rapidjson::Value::ConstValueIterator & it_) : it(it_) {}
|
||||
ALWAYS_INLINE Element operator*() const { return *it; }
|
||||
ALWAYS_INLINE Iterator & operator ++() { ++it; return *this; }
|
||||
ALWAYS_INLINE Iterator operator ++(int) { auto res = *this; ++it; return res; }
|
||||
ALWAYS_INLINE friend bool operator ==(const Iterator & left, const Iterator & right) { return left.it == right.it; }
|
||||
ALWAYS_INLINE friend bool operator !=(const Iterator & left, const Iterator & right) { return !(left == right); }
|
||||
private:
|
||||
rapidjson::Value::ConstValueIterator it;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE Array(const rapidjson::Value & value_) : ptr(&value_) {}
|
||||
ALWAYS_INLINE Iterator begin() const { return ptr->Begin(); }
|
||||
ALWAYS_INLINE Iterator end() const { return ptr->End(); }
|
||||
ALWAYS_INLINE size_t size() const { return ptr->Size(); }
|
||||
ALWAYS_INLINE Element operator[](size_t index) const { return *(ptr->Begin() + index); }
|
||||
|
||||
private:
|
||||
const rapidjson::Value * ptr = nullptr;
|
||||
};
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
using KeyValuePair = std::pair<std::string_view, Element>;
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
ALWAYS_INLINE Iterator(const rapidjson::Value::ConstMemberIterator & it_) : it(it_) {}
|
||||
ALWAYS_INLINE KeyValuePair operator *() const { std::string_view key{it->name.GetString(), it->name.GetStringLength()}; return {key, it->value}; }
|
||||
ALWAYS_INLINE Iterator & operator ++() { ++it; return *this; }
|
||||
ALWAYS_INLINE Iterator operator ++(int) { auto res = *this; ++it; return res; }
|
||||
ALWAYS_INLINE friend bool operator ==(const Iterator & left, const Iterator & right) { return left.it == right.it; }
|
||||
ALWAYS_INLINE friend bool operator !=(const Iterator & left, const Iterator & right) { return !(left == right); }
|
||||
private:
|
||||
rapidjson::Value::ConstMemberIterator it;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE Object(const rapidjson::Value & value_) : ptr(&value_) {}
|
||||
ALWAYS_INLINE Iterator begin() const { return ptr->MemberBegin(); }
|
||||
ALWAYS_INLINE Iterator end() const { return ptr->MemberEnd(); }
|
||||
ALWAYS_INLINE size_t size() const { return ptr->MemberCount(); }
|
||||
|
||||
ALWAYS_INLINE KeyValuePair operator[](size_t index) const
|
||||
{
|
||||
auto it = ptr->MemberBegin() + index;
|
||||
std::string_view key{it->name.GetString(), it->name.GetStringLength()};
|
||||
return KeyValuePair{key, it->value};
|
||||
}
|
||||
|
||||
bool isInt64() const { return value->IsInt64(); }
|
||||
bool isUInt64() const { return value->IsUint64(); }
|
||||
bool isDouble() const { return value->IsDouble(); }
|
||||
bool isBool() const { return value->IsBool(); }
|
||||
bool isString() const { return value->IsString(); }
|
||||
bool isArray() const { return value->IsArray(); }
|
||||
bool isObject() const { return value->IsObject(); }
|
||||
bool isNull() const { return value->IsNull(); }
|
||||
|
||||
Int64 getInt64() const { return value->GetInt64(); }
|
||||
UInt64 getUInt64() const { return value->GetUint64(); }
|
||||
double getDouble() const { return value->GetDouble(); }
|
||||
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)
|
||||
ALWAYS_INLINE bool find(const std::string_view & key, Element & result) const
|
||||
{
|
||||
if (index >= value->Size())
|
||||
auto it = ptr->FindMember(rapidjson::StringRef(key.data(), key.length()));
|
||||
if (it == ptr->MemberEnd())
|
||||
return false;
|
||||
setRange(value->Begin() + index, value->End());
|
||||
value = current_in_array++;
|
||||
|
||||
result = it->value;
|
||||
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 is_object_member = false;
|
||||
|
||||
union
|
||||
{
|
||||
const rapidjson::GenericMember<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<>> * current_in_object;
|
||||
const rapidjson::Value * current_in_array;
|
||||
};
|
||||
union
|
||||
{
|
||||
const rapidjson::GenericMember<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<>> * end_of_object;
|
||||
const rapidjson::Value * end_of_array;
|
||||
};
|
||||
const rapidjson::Value * ptr = nullptr;
|
||||
};
|
||||
|
||||
Iterator getRoot() { return Iterator{document}; }
|
||||
|
||||
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 isNull(const Iterator & it) { return it.isNull(); }
|
||||
|
||||
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(); }
|
||||
bool parse(const std::string_view & json, Element & result)
|
||||
{
|
||||
rapidjson::MemoryStream ms(json.data(), json.size());
|
||||
rapidjson::EncodedInputStream<rapidjson::UTF8<>, rapidjson::MemoryStream> is(ms);
|
||||
document.ParseStream(is);
|
||||
if (document.HasParseError() || (ms.Tell() != json.size()))
|
||||
return false;
|
||||
result = document;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
rapidjson::Document document;
|
||||
};
|
||||
|
||||
inline ALWAYS_INLINE RapidJSONParser::Array RapidJSONParser::Element::getArray() const
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline ALWAYS_INLINE RapidJSONParser::Object RapidJSONParser::Element::getObject() const
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@ -7,9 +7,8 @@
|
||||
#if USE_SIMDJSON
|
||||
# include <Core/Types.h>
|
||||
# include <Common/Exception.h>
|
||||
# include <common/StringRef.h>
|
||||
|
||||
# include <simdjson/jsonparser.h>
|
||||
# include <common/defines.h>
|
||||
# include <simdjson.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -23,121 +22,138 @@ namespace ErrorCodes
|
||||
/// It provides ability to parse JSONs using simdjson library.
|
||||
struct SimdJSONParser
|
||||
{
|
||||
static constexpr bool need_preallocate = true;
|
||||
class Array;
|
||||
class Object;
|
||||
|
||||
void preallocate(size_t max_size)
|
||||
class Element
|
||||
{
|
||||
if (!pj.allocate_capacity(max_size))
|
||||
throw Exception{"Can not allocate memory for " + std::to_string(max_size) + " units when parsing JSON",
|
||||
public:
|
||||
ALWAYS_INLINE Element() {}
|
||||
ALWAYS_INLINE Element(const simdjson::dom::element & element_) : element(element_) {}
|
||||
|
||||
ALWAYS_INLINE bool isInt64() const { return element.type() == simdjson::dom::element_type::INT64; }
|
||||
ALWAYS_INLINE bool isUInt64() const { return element.type() == simdjson::dom::element_type::UINT64; }
|
||||
ALWAYS_INLINE bool isDouble() const { return element.type() == simdjson::dom::element_type::DOUBLE; }
|
||||
ALWAYS_INLINE bool isString() const { return element.type() == simdjson::dom::element_type::STRING; }
|
||||
ALWAYS_INLINE bool isArray() const { return element.type() == simdjson::dom::element_type::ARRAY; }
|
||||
ALWAYS_INLINE bool isObject() const { return element.type() == simdjson::dom::element_type::OBJECT; }
|
||||
ALWAYS_INLINE bool isBool() const { return element.type() == simdjson::dom::element_type::BOOL; }
|
||||
ALWAYS_INLINE bool isNull() const { return element.type() == simdjson::dom::element_type::NULL_VALUE; }
|
||||
|
||||
ALWAYS_INLINE Int64 getInt64() const { return element.get_int64().first; }
|
||||
ALWAYS_INLINE UInt64 getUInt64() const { return element.get_uint64().first; }
|
||||
ALWAYS_INLINE double getDouble() const { return element.get_double().first; }
|
||||
ALWAYS_INLINE bool getBool() const { return element.get_bool().first; }
|
||||
ALWAYS_INLINE std::string_view getString() const { return element.get_string().first; }
|
||||
ALWAYS_INLINE Array getArray() const;
|
||||
ALWAYS_INLINE Object getObject() const;
|
||||
|
||||
private:
|
||||
simdjson::dom::element element;
|
||||
};
|
||||
|
||||
class Array
|
||||
{
|
||||
public:
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
ALWAYS_INLINE Iterator(const simdjson::dom::array::iterator & it_) : it(it_) {}
|
||||
ALWAYS_INLINE Element operator *() const { return *it; }
|
||||
ALWAYS_INLINE Iterator & operator ++() { ++it; return *this; }
|
||||
ALWAYS_INLINE Iterator operator ++(int) { auto res = *this; ++it; return res; }
|
||||
ALWAYS_INLINE friend bool operator !=(const Iterator & left, const Iterator & right) { return left.it != right.it; }
|
||||
ALWAYS_INLINE friend bool operator ==(const Iterator & left, const Iterator & right) { return !(left != right); }
|
||||
private:
|
||||
simdjson::dom::array::iterator it;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE Array(const simdjson::dom::array & array_) : array(array_) {}
|
||||
ALWAYS_INLINE Iterator begin() const { return array.begin(); }
|
||||
ALWAYS_INLINE Iterator end() const { return array.end(); }
|
||||
ALWAYS_INLINE size_t size() const { return array.size(); }
|
||||
ALWAYS_INLINE Element operator[](size_t index) const { return array.at(index).first; }
|
||||
|
||||
private:
|
||||
simdjson::dom::array array;
|
||||
};
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
using KeyValuePair = std::pair<std::string_view, Element>;
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
ALWAYS_INLINE Iterator(const simdjson::dom::object::iterator & it_) : it(it_) {}
|
||||
ALWAYS_INLINE KeyValuePair operator *() const { const auto & res = *it; return {res.key, res.value}; }
|
||||
ALWAYS_INLINE Iterator & operator ++() { ++it; return *this; }
|
||||
ALWAYS_INLINE Iterator operator ++(int) { auto res = *this; ++it; return res; }
|
||||
ALWAYS_INLINE friend bool operator !=(const Iterator & left, const Iterator & right) { return left.it != right.it; }
|
||||
ALWAYS_INLINE friend bool operator ==(const Iterator & left, const Iterator & right) { return !(left != right); }
|
||||
private:
|
||||
simdjson::dom::object::iterator it;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE Object(const simdjson::dom::object & object_) : object(object_) {}
|
||||
ALWAYS_INLINE Iterator begin() const { return object.begin(); }
|
||||
ALWAYS_INLINE Iterator end() const { return object.end(); }
|
||||
ALWAYS_INLINE size_t size() const { return object.size(); }
|
||||
|
||||
KeyValuePair operator [](size_t index) const
|
||||
{
|
||||
Iterator it = begin();
|
||||
while (index--)
|
||||
++it;
|
||||
return *it;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool find(const std::string_view & key, Element & result) const
|
||||
{
|
||||
auto x = object.at_key(key);
|
||||
if (x.error())
|
||||
return false;
|
||||
|
||||
result = x.first;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
simdjson::dom::object object;
|
||||
};
|
||||
|
||||
void reserve(size_t max_size)
|
||||
{
|
||||
if (parser.allocate(max_size) != simdjson::error_code::SUCCESS)
|
||||
throw Exception{"Couldn't allocate " + std::to_string(max_size) + " bytes when parsing JSON",
|
||||
ErrorCodes::CANNOT_ALLOCATE_MEMORY};
|
||||
}
|
||||
|
||||
bool parse(const StringRef & json) { return !json_parse(json.data, json.size, pj); }
|
||||
|
||||
using Iterator = simdjson::ParsedJson::Iterator;
|
||||
Iterator getRoot() { return Iterator{pj}; }
|
||||
|
||||
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(); }
|
||||
static bool isString(const Iterator & it) { return it.is_string(); }
|
||||
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.is_null(); }
|
||||
|
||||
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)
|
||||
bool parse(const std::string_view & json, Element & result)
|
||||
{
|
||||
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())
|
||||
auto document = parser.parse(json.data(), json.size());
|
||||
if (document.error())
|
||||
return false;
|
||||
while (index--)
|
||||
if (!it.next())
|
||||
return false;
|
||||
|
||||
result = document.first;
|
||||
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()); //-V501
|
||||
}
|
||||
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()) //-V501
|
||||
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(); } //-V501
|
||||
|
||||
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:
|
||||
simdjson::ParsedJson pj;
|
||||
simdjson::dom::parser parser;
|
||||
};
|
||||
|
||||
inline ALWAYS_INLINE SimdJSONParser::Array SimdJSONParser::Element::getArray() const
|
||||
{
|
||||
return element.get_array().first;
|
||||
}
|
||||
|
||||
inline ALWAYS_INLINE SimdJSONParser::Object SimdJSONParser::Element::getObject() const
|
||||
{
|
||||
return element.get_object().first;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user