aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yson/node/node.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/yson/node/node.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yson/node/node.h')
-rw-r--r--library/cpp/yson/node/node.h523
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