mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-12 17:32:32 +00:00
157 lines
5.8 KiB
C++
157 lines
5.8 KiB
C++
#pragma once
|
|
|
|
#include "config_functions.h"
|
|
|
|
#if USE_RAPIDJSON
|
|
# include <base/types.h>
|
|
# include <base/defines.h>
|
|
# include <rapidjson/document.h>
|
|
|
|
|
|
namespace DB
|
|
{
|
|
|
|
/// This class can be used as an argument for the template class FunctionJSON.
|
|
/// It provides ability to parse JSONs using rapidjson library.
|
|
struct RapidJSONParser
|
|
{
|
|
class Array;
|
|
class Object;
|
|
|
|
/// References an element in a JSON document, representing a JSON null, boolean, string, number,
|
|
/// array or object.
|
|
class Element
|
|
{
|
|
public:
|
|
ALWAYS_INLINE Element() {}
|
|
ALWAYS_INLINE Element(const rapidjson::Value & value_) : ptr(&value_) {}
|
|
|
|
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;
|
|
};
|
|
|
|
/// References an array in a JSON document.
|
|
class Array
|
|
{
|
|
public:
|
|
class Iterator
|
|
{
|
|
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 { assert(index < size()); return *(ptr->Begin() + index); }
|
|
|
|
private:
|
|
const rapidjson::Value * ptr = nullptr;
|
|
};
|
|
|
|
using KeyValuePair = std::pair<std::string_view, Element>;
|
|
|
|
/// References an object in a JSON document.
|
|
class Object
|
|
{
|
|
public:
|
|
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(); }
|
|
|
|
bool find(const std::string_view & key, Element & result) const
|
|
{
|
|
auto it = ptr->FindMember(rapidjson::StringRef(key.data(), key.length()));
|
|
if (it == ptr->MemberEnd())
|
|
return false;
|
|
|
|
result = it->value;
|
|
return true;
|
|
}
|
|
|
|
/// Optional: Provides access to an object's element by index.
|
|
ALWAYS_INLINE KeyValuePair operator[](size_t index) const
|
|
{
|
|
assert (index < size());
|
|
auto it = ptr->MemberBegin() + index;
|
|
std::string_view key{it->name.GetString(), it->name.GetStringLength()};
|
|
return {key, it->value};
|
|
}
|
|
|
|
private:
|
|
const rapidjson::Value * ptr = nullptr;
|
|
};
|
|
|
|
/// Parses a JSON document, returns the reference to its root element if succeeded.
|
|
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;
|
|
}
|
|
|
|
#if 0
|
|
/// Optional: Allocates memory to parse JSON documents faster.
|
|
void reserve(size_t max_size);
|
|
#endif
|
|
|
|
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
|