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/scheme/scheme.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/scheme/scheme.h')
-rw-r--r-- | library/cpp/scheme/scheme.h | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/library/cpp/scheme/scheme.h b/library/cpp/scheme/scheme.h new file mode 100644 index 0000000000..3d7c59f3c9 --- /dev/null +++ b/library/cpp/scheme/scheme.h @@ -0,0 +1,538 @@ +#pragma once + +#include "scimpl_defs.h" + +#include "fwd.h" + +#include <iterator> +#include <utility> + +namespace NSc { +#ifdef _MSC_VER +#pragma warning(disable : 4521 4522) +#endif + + // todo: try to remove some rarely used methods + class TValue { + public: + enum class EType { + Null = 0 /* "Null" */, + Bool /* "Bool" */, + IntNumber /* "Int" */, + FloatNumber /* "Float" */, + String /* "String" */, + Array /* "Array" */, + Dict /* "Dict" */ + }; + + struct TScCore; + using TCorePtr = TIntrusivePtr<TScCore>; + using TPoolPtr = TIntrusivePtr<NDefinitions::TPool>; + + using TArray = ::NSc::TArray; + using TDict = ::NSc::TDict; + + private: // A TValue instance has only these 3 fields + mutable TCorePtr TheCore; // a pointer to a refcounted (kind of) variant + bool CopyOnWrite = false; // a flag that thevalue is a COW shallow copy and should produce a deep copy once modified + + // Thus all copies of a TValue are by default shallow. Use TValue::Clone to force a deep copy. + // A COW copy will see changes in its parent, but no change in the COW copy will propagate to its parent. + + public: + inline TValue(); + inline TValue(TValue& v); + inline TValue(const TValue& v); + inline TValue(TValue&& v) noexcept; + + public: // Operators + inline TValue(double t); + inline TValue(unsigned long long t); + inline TValue(unsigned long t); + inline TValue(unsigned t); + inline TValue(long long t); + inline TValue(long t); + inline TValue(int t); + // inline TValue(bool b); + + inline TValue(TStringBuf t); + inline TValue(const char*); + + inline operator double() const; + inline operator float() const; + inline operator long long() const; + inline operator long() const; + inline operator int() const; + inline operator short() const; + inline operator char() const; + inline operator unsigned long long() const; + inline operator unsigned long() const; + inline operator unsigned() const; + inline operator unsigned short() const; + inline operator unsigned char() const; + inline operator signed char() const; + + inline operator TStringBuf() const; + + inline operator const ::NSc::TArray&() const; + inline operator const ::NSc::TDict&() const; + + inline TValue& operator=(double t); + + inline TValue& operator=(unsigned long long t); + inline TValue& operator=(unsigned long t); + inline TValue& operator=(unsigned t); + + inline TValue& operator=(long long t); + inline TValue& operator=(long t); + inline TValue& operator=(int t); + // inline TValue& operator=(bool t); + + inline TValue& operator=(TStringBuf t); + inline TValue& operator=(const char* t); + + inline TValue& operator=(TValue& v) &; + inline TValue& operator=(const TValue& v) &; + inline TValue& operator=(TValue&& v) & noexcept; + + inline TValue& operator=(TValue& v) && = delete; + inline TValue& operator=(const TValue& v) && = delete; + inline TValue& operator=(TValue&& v) && = delete; + + public: + template <class T> // ui16 or TStringBuf + inline TValue& operator[](const T& idx) { + return GetOrAdd(idx); + } + + template <class T> // ui16 or TStringBuf + inline const TValue& operator[](const T& idx) const { + return Get(idx); + } + + public: // Data methods /////////////////////////////////////////////////////////// + inline EType GetType() const; + + inline bool IsNull() const; + + inline TValue& SetNull(); // returns self, will set type to Null + + TValue& Clear() { + return ClearArray().ClearDict().SetNull(); + } + + public: // Number methods ///////////////////////////////////////////////////////// + // Bool, IntNumber and FloatNumber are all compatible. + // If a TValue node has one of the types it may as well be used as another. + // FloatNumber methods. Forces FloatNumber representation. Compatible with IntNumber and Bool + + inline bool IsNumber() const; // true if any of FloatNumber, IntNumber, Bool + + inline double GetNumber(double defaultval = 0) const; // Compatible with Bool, IntNumber and FloatNumber types + + inline double& GetNumberMutable(double defaultval = 0); // Will switch the type to FloatNumber + + inline TValue& SetNumber(double val = 0); // returns self, will switch the type to FloatNumber + + double ForceNumber(double deflt = 0) const; // Best-effort cast to double (will do TryFromString if applicable) + + // IntNumber methods. Forces integer representation. Compatible with FloatNumber and Bool types. + // Note: if you don't care about distinguishing bools, ints and doubles, use *Number methods above + + inline bool IsIntNumber() const; // true only if IntNumber or Bool + + inline i64 GetIntNumber(i64 defaultval = 0) const; // Compatible with Bool, IntNumber and FloatNumber types + + inline i64& GetIntNumberMutable(i64 defaultval = 0); // Will switch the type to IntNumber + + inline TValue& SetIntNumber(i64 val = 0); // returns self, will switch the type to IntNumber + + i64 ForceIntNumber(i64 deflt = 0) const; // Best-effort cast to i64 (will do TryFromString for String) + + // Bool methods. Forces bool representation. Compatible with Float Number and Int Number methods above. + // Note: if you don't care about distinguishing Bool, IntNumber and FloatNumber, use *Number methods above + + inline bool IsBool() const; // true only if Bool + + inline bool GetBool(bool defaultval = false) const; // Compatible with Bool, IntNumber and FloatNumber types + + inline TValue& SetBool(bool val = false); // returns self, will switch the type to Bool + + public: // Arcadia-specific boolean representation support + // Tests for explicit True, also checks for arcadia-specific boolean representation + bool IsTrue() const { + return IsNumber() ? GetNumber() : ::IsTrue(GetString()); + } + + // Tests for explicit False, also checks for arcadia-specific boolean representation + bool IsExplicitFalse() const { + return IsNumber() ? !GetNumber() : IsFalse(GetString()); + } + + public: // String methods ///////////////////////////////////////////////////////// + inline bool IsString() const; + + inline TStringBuf GetString(TStringBuf defaultval = TStringBuf()) const; + + inline TValue& SetString(TStringBuf val = TStringBuf()); // returns self + + TString ForceString(const TString& deflt = TString()) const; // Best-effort cast to TString (will do ToString for numeric types) + + // todo: remove + inline bool StringEmpty() const; + inline size_t StringSize() const; + + public: // Array methods ////////////////////////////////////////////////////////// + inline bool IsArray() const; + + inline const TArray& GetArray() const; + inline TArray& GetArrayMutable(); + inline TValue& SetArray(); // turns into array if needed, returns self + inline TValue& ClearArray(); + + inline bool Has(size_t idx) const; + + inline const TValue& Get(size_t idx) const; // returns child or default + inline TValue* GetNoAdd(size_t idx); // returns link to existing child or nullptr + + inline TValue& Push(); // returns new child + + template <class T> + TValue& Push(T&& t) { + return Push() = std::forward<T>(t); + } // returns new child + + TValue& Insert(ui16 idx) { + return InsertUnsafe(idx); + } // creates missing values, returns new child + + template <class T> + TValue& Insert(ui16 idx, T&& v) { + return InsertUnsafe(idx, std::forward<T>(v)); + } // creates missing values, returns new child + + template <class TIt> + inline TValue& AppendAll(TIt begin, TIt end); // Append(vec.begin(), vec.end()) + + template <class TColl> + inline TValue& AppendAll(TColl&& coll); // Append(vec) + + inline TValue& AppendAll(std::initializer_list<TValue> coll); + + TValue& GetOrAdd(ui16 idx) { + return GetOrAddUnsafe(idx); + } // creates missing values, returns new child + + inline TValue& InsertUnsafe(size_t idx); // creates missing values, returns new child + + template <class T> + TValue& InsertUnsafe(size_t idx, T&& t) { + return InsertUnsafe(idx) = std::forward<T>(t); + } // creates missing values, returns new child + + inline TValue& GetOrAddUnsafe(size_t idx); // creates missing values, returns new child + + inline TValue Pop(); // returns popped value + inline TValue Delete(size_t idx); // returns deleted value if it existed, NSc::Null() otherwise + + inline TValue& Front() { + return GetOrAdd(0); + } // creates missing value, returns child + inline const TValue& Front() const { + return Get(0); + } // returns child or default + + inline TValue& Back(); // creates missing value, returns child + inline const TValue& Back() const; // returns child or default + + // todo: remove + inline bool ArrayEmpty() const; + inline size_t ArraySize() const; + + public: // Dict methods + inline bool IsDict() const; + + inline const TDict& GetDict() const; + inline TDict& GetDictMutable(); + inline TValue& SetDict(); // turns into dict if not one, returns self + inline TValue& ClearDict(); + + inline bool Has(TStringBuf idx) const; + + inline const TValue& Get(TStringBuf idx) const; + inline TValue* GetNoAdd(TStringBuf idx); // returns link to existing child or nullptr + + TValue& Add(TStringBuf idx) { + return GetOrAdd(idx); + } + + template <class T> + TValue& Add(TStringBuf idx, T&& t) { + return Add(idx) = std::forward<T>(t); + } + + inline TValue& GetOrAdd(TStringBuf idx); // creates missing value, returns child + + inline TValue Delete(TStringBuf idx); // returns deleted value + + inline TValue& AddAll(std::initializer_list<std::pair<TStringBuf, TValue>> t); + + TStringBufs DictKeys(bool sorted = true) const; + TStringBufs& DictKeys(TStringBufs&, bool sorted = true) const; + + // todo: remove + inline bool DictEmpty() const; + inline size_t DictSize() const; + + public: // Json methods //////////////////////////////////////////////// + using TJsonOpts = NSc::TJsonOpts; + using EJsonOpts = TJsonOpts::EJsonOpts; + static const EJsonOpts JO_DEFAULT = TJsonOpts::JO_DEFAULT; + static const EJsonOpts JO_SORT_KEYS = TJsonOpts::JO_SORT_KEYS; + static const EJsonOpts JO_SKIP_UNSAFE = TJsonOpts::JO_SKIP_UNSAFE; // skip non-utf8 strings + static const EJsonOpts JO_PRETTY = TJsonOpts::JO_PRETTY; + static const EJsonOpts JO_SAFE = TJsonOpts::JO_SAFE; // JO_SORT_KEYS | JO_SKIP_UNSAFE + static const EJsonOpts JO_PARSER_STRICT_WITH_COMMENTS = TJsonOpts::JO_PARSER_STRICT_WITH_COMMENTS; // strict json + strict utf8 + static const EJsonOpts JO_PARSER_STRICT = TJsonOpts::JO_PARSER_STRICT; // strict json + strict utf8 + comments are disallowed + static const EJsonOpts JO_PARSER_DISALLOW_DUPLICATE_KEYS = TJsonOpts::JO_PARSER_DISALLOW_DUPLICATE_KEYS; + + static TValue FromJson(TStringBuf, const TJsonOpts& = TJsonOpts()); + static TValue FromJsonThrow(TStringBuf, const TJsonOpts& = TJsonOpts()); + static bool FromJson(TValue&, TStringBuf, const TJsonOpts& = TJsonOpts()); + + // TODO: Переименовать ToJson в ToJsonUnsafe, а ToJsonSafe в ToJson + TString ToJson(const TJsonOpts& = TJsonOpts()) const; + const TValue& ToJson(IOutputStream&, const TJsonOpts& = TJsonOpts()) const; // returns self + + // ToJson(JO_SORT_KEYS | JO_SKIP_UNSAFE) + TString ToJsonSafe(const TJsonOpts& = TJsonOpts()) const; + const TValue& ToJsonSafe(IOutputStream&, const TJsonOpts& = TJsonOpts()) const; + + // ToJson(JO_SORT_KEYS | JO_PRETTY | JO_SKIP_UNSAFE) + TString ToJsonPretty(const TJsonOpts& = TJsonOpts()) const; + const TValue& ToJsonPretty(IOutputStream&, const TJsonOpts& = TJsonOpts()) const; + + NJson::TJsonValue ToJsonValue() const; + + static TValue FromJsonValue(const NJson::TJsonValue&); + static TValue& FromJsonValue(TValue&, const NJson::TJsonValue&); // returns self + + static TJsonOpts MakeOptsSafeForSerializer(TJsonOpts = TJsonOpts()); + static TJsonOpts MakeOptsPrettyForSerializer(TJsonOpts = TJsonOpts()); + + public: // Merge methods //////////////////////////////////////////////// + /* + * LHS.MergeUpdate(RHS): + * 1. Dict <- Dict: + * - Copy all nonconflicting key-value pairs from RHS to LHS. + * - For every pair of conflicting values apply LHS[key].MergeUpdate(RHS[key]). + * 2. Anything <- Null: + * - Do nothing. + * 3. Other conflicts: + * - Copy RHS over LHS. + * + * LHS.ReverseMerge(RHS): + * 1. Dict <- Dict: + * - Copy all nonconflicting key-value pairs from RHS to LHS. + * - For every pair of conflicting values apply LHS[key].ReverseMerge(RHS[key]). + * 2. Null <- Anything: + * - Copy RHS over LHS. + * 3. Other conflicts: + * - Do nothing. + */ + + TValue& MergeUpdateJson(TStringBuf json); // returns self + TValue& ReverseMergeJson(TStringBuf json); // returns self + + static bool MergeUpdateJson(TValue&, TStringBuf json); // returns true unless failed to parse the json + static bool ReverseMergeJson(TValue&, TStringBuf json); // returns true unless failed to parse the json + + TValue& MergeUpdate(const TValue& delta); // return self + TValue& ReverseMerge(const TValue& delta); // return self + + public: // Path methods ///////////////////////////////////////////////////////// + // TODO: add throwing variants + // make sure to properly escape the tokens + + static TString EscapeForPath(TStringBuf rawKey); // converts a raw dict key into a valid token for a selector path + + static bool PathValid(TStringBuf path); // returns true if the path is syntactically valid + + bool PathExists(TStringBuf path) const; // returns true if the path is syntactically valid and the target value exists + + const TValue& TrySelect(TStringBuf path) const; // returns the target value + // if the path is syntactically valid and the target value exists + // otherwise returns NSc::Null() + + TValue* TrySelectOrAdd(TStringBuf path); // returns the target value if it exists or creates if not + // if the path is syntactically valid + // otherwise returns NSc::Null() + + TValue TrySelectAndDelete(TStringBuf path); // deletes and returns the target value + // if the path is syntactically valid and the target value existed + // otherwise returns NSc::Null() + + public: // Copy methods ///////////////////////////////////////////////////////// + TValue Clone() const; // returns deep copy of self (on the separate pool) + TValue& CopyFrom(const TValue& other); // deep copy other value into self, returns self + + TValue& Swap(TValue& v); + + static bool Same(const TValue&, const TValue&); // point to the same core + static bool Equal(const TValue&, const TValue&); // recursively equal + static bool SamePool(const TValue&, const TValue&); // share arena + + public: + // very specific methods useful in very specific corner cases + + static TValue From(const ::google::protobuf::Message&, bool mapAsDict = false); + + void To(::google::protobuf::Message&, const TProtoOpts& opts = {}) const; + + public: + inline explicit TValue(TPoolPtr&); + + static const TScCore& DefaultCore(); + static const TArray& DefaultArray(); + static const TDict& DefaultDict(); + static const TValue& DefaultValue(); + static const TValue& Null() { + return DefaultValue(); + } + + void DoWriteJsonImpl(IOutputStream&, const TJsonOpts&, NImpl::TKeySortContext&, NImpl::TSelfLoopContext&) const; + + bool IsSameOrAncestorOf(const TValue& other) const; + + private: + TValue& DoMerge(const TValue& delta, bool olddelta); + TValue& DoMergeImpl(const TValue& delta, bool olddelta, NImpl::TSelfLoopContext&, NImpl::TSelfOverrideContext&); + TValue& DoCopyFromImpl(const TValue& other, NImpl::TSelfLoopContext&, NImpl::TSelfOverrideContext&); + NJson::TJsonValue ToJsonValueImpl(NImpl::TSelfLoopContext&) const; + + bool IsSameOrAncestorOfImpl(const TScCore& other, NImpl::TSelfLoopContext& loopCtx) const; + + inline TScCore& CoreMutable(); + inline TScCore& CoreMutableForSet(); + inline const TScCore& Core() const; + + static inline TScCore* NewCore(TPoolPtr&); + + static TValue FromField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*); + static TValue FromRepeatedField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, int index); + + void ValueToField(const TValue& value, ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToEnumField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToRepeatedField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToMapField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + }; + + + inline const TValue& Null() { + return TValue::DefaultValue(); + } + + + class TArray: public TDeque<TValue, TPoolAllocator>, TNonCopyable { + using TParent = TDeque<TValue, TPoolAllocator>; + + public: + TArray(TMemoryPool* p) + : TParent(p) + { + } + + template <class TIt> + void AppendAll(TIt begin, TIt end) { + TParent::insert(TParent::end(), begin, end); + } + + template <class TColl> + void AppendAll(TColl&& coll) { + AppendAll(std::begin(coll), std::end(coll)); + } + + void AppendAll(std::initializer_list<TValue> coll) { + AppendAll(coll.begin(), coll.end()); + } + + const TValue& operator[](size_t i) const { + return EnsureIndex(i); + } + + TValue& operator[](size_t i) { + return EnsureIndex(i); + } + + const TValue& front() const { + return EnsureIndex(0); + } + + TValue& front() { + return EnsureIndex(0); + } + + const TValue& back() const { + return EnsureIndex(LastIndex()); + } + + TValue& back() { + return EnsureIndex(LastIndex()); + } + + void pop_back() { + if (empty()) + return; + TParent::pop_back(); + } + + void pop_front() { + if (empty()) + return; + TParent::pop_front(); + } + + private: + size_t LastIndex() const { + return ::Max<size_t>(size(), 1) - 1; + } + + TValue& EnsureIndex(size_t i) { + if (i >= size()) + resize(::Min<size_t>(i + 1, ::Max<ui16>()), TValue::DefaultValue()); + return TParent::operator[](i); + } + + const TValue& EnsureIndex(size_t i) const { + return i < size() ? TParent::operator[](i) : TValue::DefaultValue(); + } + }; + + + // todo: densehashtable + // todo: allow insertions + // todo: make TDict methods safe + class TDict: public THashMap<TStringBuf, TValue, THash<TStringBuf>, TEqualTo<TStringBuf>, TPoolAllocator>, TNonCopyable { + using TParent = THashMap<TStringBuf, TValue, THash<TStringBuf>, TEqualTo<TStringBuf>, TPoolAllocator>; + + public: + TDict(TMemoryPool* p) + : TParent(p) + { + } + + template <class TStr> + const TValue& Get(const TStr& key) const { + const_iterator it = find(key); + return it != end() ? it->second : TValue::DefaultValue(); + } + }; +} + +#include "scimpl.h" +#include "scheme_cast.h" + +#ifdef _MSC_VER +#pragma warning(default : 4521 4522) +#endif |