diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/yson/node/node.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yson/node/node.h')
-rw-r--r-- | library/cpp/yson/node/node.h | 523 |
1 files changed, 523 insertions, 0 deletions
diff --git a/library/cpp/yson/node/node.h b/library/cpp/yson/node/node.h new file mode 100644 index 0000000000..5f90f95df0 --- /dev/null +++ b/library/cpp/yson/node/node.h @@ -0,0 +1,523 @@ +#pragma once + +#include <util/generic/bt_exception.h> +#include <util/generic/cast.h> +#include <util/generic/hash.h> +#include <util/generic/variant.h> +#include <util/generic/vector.h> +#include <util/generic/yexception.h> +#include <util/generic/ylimits.h> +#include <util/string/cast.h> + +#include <cmath> +#include <variant> + +class IInputStream; +class IOutputStream; + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +class TNode +{ +public: + class TLookupError + : public TWithBackTrace<yexception> + { }; + + class TTypeError + : public TWithBackTrace<yexception> + { }; + + enum EType { + Undefined = 0 /*"undefined"*/, + + // NOTE: string representation of all node types + // are compatible with server node type (except `Undefined' which is missing on server). + String = 1 /*"string_node"*/, + Int64 = 2 /*"int64_node"*/, + Uint64 = 3 /*"uint64_node"*/, + Double = 4 /*"double_node"*/, + Bool = 5 /*"boolean_node"*/, + List = 6 /*"list_node"*/, + Map = 7 /*"map_node"*/, + Null = 8 /*"null"*/, + }; + + using TListType = TVector<TNode>; + using TMapType = THashMap<TString, TNode>; + +private: + struct TNull { + bool operator==(const TNull&) const; + }; + + struct TUndefined { + bool operator==(const TUndefined&) const; + }; + + using TValue = std::variant< + bool, + i64, + ui64, + double, + TString, + TListType, + TMapType, + TNull, + TUndefined + >; + +public: + + TNode(); + TNode(const char* s); + TNode(TStringBuf s); + explicit TNode(std::string_view s); + explicit TNode(const std::string& s); + TNode(TString s); + TNode(int i); + + //this case made speccially for prevent mess cast of EType into TNode through TNode(int) constructor + //usual case of error SomeNode == TNode::Undefined <-- SomeNode indeed will be compared with TNode(0) without this method + //correct way is SomeNode.GetType() == TNode::Undefined + template<class T = EType> + Y_FORCE_INLINE TNode(EType) + { + static_assert(!std::is_same<T, EType>::value, "looks like a mistake, may be you forget .GetType()"); + } + + //this case made speccially for prevent mess cast of T* into TNode through implicit bool ctr + template<class T = int> + Y_FORCE_INLINE TNode(const T*) : TNode() { + static_assert(!std::is_same<T,T>::value, "looks like a mistake, and pointer have converted to bool"); + } + + TNode(unsigned int ui); + TNode(long i); + TNode(unsigned long ui); + TNode(long long i); + TNode(unsigned long long ui); + TNode(double d); + TNode(bool b); + TNode(TMapType map); + + TNode(const TNode& rhs); + TNode& operator=(const TNode& rhs); + + TNode(TNode&& rhs) noexcept; + TNode& operator=(TNode&& rhs) noexcept; + + ~TNode(); + + void Clear(); + + bool IsString() const; + bool IsInt64() const; + bool IsUint64() const; + bool IsDouble() const; + bool IsBool() const; + bool IsList() const; + bool IsMap() const; + + // `IsEntity' is deprecated use `IsNull' instead. + bool IsEntity() const; + bool IsNull() const; + bool IsUndefined() const; + // Returns true if TNode is neither Null, nor Undefined + bool HasValue() const; + + template<typename T> + bool IsOfType() const noexcept; + + // Int64, Uint64, Double, or Bool + bool IsArithmetic() const; + + bool Empty() const; + size_t Size() const; + + EType GetType() const; + + const TString& AsString() const; + i64 AsInt64() const; + ui64 AsUint64() const; + double AsDouble() const; + bool AsBool() const; + const TListType& AsList() const; + const TMapType& AsMap() const; + TListType& AsList(); + TMapType& AsMap(); + + const TString& UncheckedAsString() const noexcept; + i64 UncheckedAsInt64() const noexcept; + ui64 UncheckedAsUint64() const noexcept; + double UncheckedAsDouble() const noexcept; + bool UncheckedAsBool() const noexcept; + const TListType& UncheckedAsList() const noexcept; + const TMapType& UncheckedAsMap() const noexcept; + TListType& UncheckedAsList() noexcept; + TMapType& UncheckedAsMap() noexcept; + + // integer types cast + // makes overflow checks + template<typename T> + T IntCast() const; + + // integers <-> double <-> string + // makes overflow checks + template<typename T> + T ConvertTo() const; + + template<typename T> + T& As(); + + template<typename T> + const T& As() const; + + static TNode CreateList(); + static TNode CreateList(TListType list); + static TNode CreateMap(); + static TNode CreateMap(TMapType map); + static TNode CreateEntity(); + + const TNode& operator[](size_t index) const; + TNode& operator[](size_t index); + const TNode& At(size_t index) const; + TNode& At(size_t index); + + TNode& Add() &; + TNode Add() &&; + TNode& Add(const TNode& node) &; + TNode Add(const TNode& node) &&; + TNode& Add(TNode&& node) &; + TNode Add(TNode&& node) &&; + + bool HasKey(const TStringBuf key) const; + + TNode& operator()(const TString& key, const TNode& value) &; + TNode operator()(const TString& key, const TNode& value) &&; + TNode& operator()(const TString& key, TNode&& value) &; + TNode operator()(const TString& key, TNode&& value) &&; + + const TNode& operator[](const TStringBuf key) const; + TNode& operator[](const TStringBuf key); + const TNode& At(const TStringBuf key) const; + TNode& At(const TStringBuf key); + + // map getters + // works the same way like simple getters + const TString& ChildAsString(const TStringBuf key) const; + i64 ChildAsInt64(const TStringBuf key) const; + ui64 ChildAsUint64(const TStringBuf key) const; + double ChildAsDouble(const TStringBuf key) const; + bool ChildAsBool(const TStringBuf key) const; + const TListType& ChildAsList(const TStringBuf key) const; + const TMapType& ChildAsMap(const TStringBuf key) const; + TListType& ChildAsList(const TStringBuf key); + TMapType& ChildAsMap(const TStringBuf key); + + template<typename T> + T ChildIntCast(const TStringBuf key) const; + + template<typename T> + T ChildConvertTo(const TStringBuf key) const; + + template<typename T> + const T& ChildAs(const TStringBuf key) const; + + template<typename T> + T& ChildAs(const TStringBuf key); + + // list getters + // works the same way like simple getters + const TString& ChildAsString(size_t index) const; + i64 ChildAsInt64(size_t index) const; + ui64 ChildAsUint64(size_t index) const; + double ChildAsDouble(size_t index) const; + bool ChildAsBool(size_t index) const; + const TListType& ChildAsList(size_t index) const; + const TMapType& ChildAsMap(size_t index) const; + TListType& ChildAsList(size_t index); + TMapType& ChildAsMap(size_t index); + + template<typename T> + T ChildIntCast(size_t index) const; + + template<typename T> + T ChildConvertTo(size_t index) const; + + template<typename T> + const T& ChildAs(size_t index) const; + + template<typename T> + T& ChildAs(size_t index); + + + // attributes + bool HasAttributes() const; + void ClearAttributes(); + const TNode& GetAttributes() const; + TNode& Attributes(); + + void MoveWithoutAttributes(TNode&& rhs); + + // Serialize TNode using binary yson format. + // Methods for ysaveload. + void Save(IOutputStream* output) const; + void Load(IInputStream* input); + +private: + void Move(TNode&& rhs); + + void CheckType(EType type) const; + + void AssureMap(); + void AssureList(); + + void CreateAttributes(); + +private: + TValue Value_; + THolder<TNode> Attributes_; + + friend bool operator==(const TNode& lhs, const TNode& rhs); + friend bool operator!=(const TNode& lhs, const TNode& rhs); +}; + +bool operator==(const TNode& lhs, const TNode& rhs); +bool operator!=(const TNode& lhs, const TNode& rhs); + +bool GetBool(const TNode& node); + +inline bool TNode::IsArithmetic() const { + return IsInt64() || IsUint64() || IsDouble() || IsBool(); +} + +template<typename T> +inline T TNode::IntCast() const { + if constexpr (std::is_integral<T>::value) { + try { + switch (GetType()) { + case TNode::Uint64: + return SafeIntegerCast<T>(AsUint64()); + case TNode::Int64: + return SafeIntegerCast<T>(AsInt64()); + default: + ythrow TTypeError() << "IntCast() called for type " << GetType(); + } + } catch(TBadCastException& exc) { + ythrow TTypeError() << "TBadCastException during IntCast(): " << exc.what(); + } + } else { + static_assert(sizeof(T) != sizeof(T), "implemented only for std::is_integral types"); + } +} + +template<typename T> +inline T TNode::ConvertTo() const { + if constexpr (std::is_integral<T>::value) { + switch (GetType()) { + case NYT::TNode::String: + return ::FromString(AsString()); + case NYT::TNode::Int64: + case NYT::TNode::Uint64: + return IntCast<T>(); + case NYT::TNode::Double: + if (AsDouble() < Min<T>() || AsDouble() > MaxFloor<T>() || !std::isfinite(AsDouble())) { + ythrow TTypeError() << AsDouble() << " can't be converted to " << TypeName<T>(); + } + return AsDouble(); + case NYT::TNode::Bool: + return AsBool(); + case NYT::TNode::List: + case NYT::TNode::Map: + case NYT::TNode::Null: + case NYT::TNode::Undefined: + ythrow TTypeError() << "ConvertTo<" << TypeName<T>() << ">() called for type " << GetType(); + }; + } else { + static_assert(sizeof(T) != sizeof(T), "should have template specialization"); + } +} + +template<> +inline TString TNode::ConvertTo<TString>() const { + switch (GetType()) { + case NYT::TNode::String: + return AsString(); + case NYT::TNode::Int64: + return ::ToString(AsInt64()); + case NYT::TNode::Uint64: + return ::ToString(AsUint64()); + case NYT::TNode::Double: + return ::ToString(AsDouble()); + case NYT::TNode::Bool: + return ::ToString(AsBool()); + case NYT::TNode::List: + case NYT::TNode::Map: + case NYT::TNode::Null: + case NYT::TNode::Undefined: + ythrow TTypeError() << "ConvertTo<TString>() called for type " << GetType(); + } + Y_UNREACHABLE(); +} + +template<> +inline double TNode::ConvertTo<double>() const { + switch (GetType()) { + case NYT::TNode::String: + return ::FromString(AsString()); + case NYT::TNode::Int64: + return AsInt64(); + case NYT::TNode::Uint64: + return AsUint64(); + case NYT::TNode::Double: + return AsDouble(); + case NYT::TNode::Bool: + return AsBool(); + case NYT::TNode::List: + case NYT::TNode::Map: + case NYT::TNode::Null: + case NYT::TNode::Undefined: + ythrow TTypeError() << "ConvertTo<double>() called for type " << GetType(); + } +} + +template<> +inline bool TNode::ConvertTo<bool>() const { + switch (GetType()) { + case NYT::TNode::String: + return ::FromString(AsString()); + case NYT::TNode::Int64: + return AsInt64(); + case NYT::TNode::Uint64: + return AsUint64(); + case NYT::TNode::Double: + return AsDouble(); + case NYT::TNode::Bool: + return AsBool(); + case NYT::TNode::List: + case NYT::TNode::Map: + case NYT::TNode::Null: + case NYT::TNode::Undefined: + ythrow TTypeError() << "ConvertTo<bool>() called for type " << GetType(); + } +} + +template<typename T> +inline T TNode::ChildIntCast(const TStringBuf key) const { + const auto& node = At(key); + try { + return node.IntCast<T>(); + } catch (TTypeError& e) { + e << ", during getting key=" << key; + throw e; + } catch (...) { + ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key; + } +} + +template<typename T> +inline T TNode::ChildIntCast(size_t index) const { + const auto& node = At(index); + try { + return node.IntCast<T>(); + } catch (TTypeError& e) { + e << ", during getting index=" << index; + throw e; + } catch (...) { + ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index; + } +} + +template<typename T> +inline T TNode::ChildConvertTo(const TStringBuf key) const { + const auto& node = At(key); + try { + return node.ConvertTo<T>(); + } catch (TTypeError& e) { + e << ", during getting key=" << key; + throw e; + } catch (...) { + ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key; + } +} + +template<typename T> +inline T TNode::ChildConvertTo(size_t index) const { + const auto& node = At(index); + try { + return node.ConvertTo<T>(); + } catch (TTypeError& e) { + e << ", during getting index=" << index; + throw e; + } catch (...) { + ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index; + } +} + +template<typename T> +inline const T& TNode::ChildAs(const TStringBuf key) const { + const auto& node = At(key); + try { + return node.As<T>(); + } catch (TTypeError& e) { + e << ", during getting key=" << key; + throw e; + } catch (...) { + ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key; + } +} + +template<typename T> +inline const T& TNode::ChildAs(size_t index) const { + const auto& node = At(index); + try { + return node.As<T>(); + } catch (TTypeError& e) { + e << ", during getting index=" << index; + throw e; + } catch (...) { + ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index; + } +} + +template<typename T> +inline T& TNode::ChildAs(const TStringBuf key) { + return const_cast<T&>(static_cast<const TNode*>(this)->ChildAs<T>(key)); +} + +template<typename T> +inline T& TNode::ChildAs(size_t index) { + return const_cast<T&>(static_cast<const TNode*>(this)->ChildAs<T>(index)); +} + +template<typename T> +inline bool TNode::IsOfType() const noexcept { + return std::holds_alternative<T>(Value_); +} + +template<typename T> +inline T& TNode::As() { + return std::get<T>(Value_); +} + +template<typename T> +inline const T& TNode::As() const { + return std::get<T>(Value_); +} + +//////////////////////////////////////////////////////////////////////////////// + +namespace NNodeCmp { + bool operator<(const TNode& lhs, const TNode& rhs); + bool operator<=(const TNode& lhs, const TNode& rhs); + bool operator>(const TNode& lhs, const TNode& rhs); + bool operator>=(const TNode& lhs, const TNode& rhs); + bool IsComparableType(const TNode::EType type); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT |