aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/scheme/scheme.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/scheme/scheme.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/scheme/scheme.h')
-rw-r--r--library/cpp/scheme/scheme.h538
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