123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- #pragma once
- #include "scimpl_defs.h"
- #include "fwd.h"
- #include <util/generic/maybe.h>
- #include <iterator>
- #include <utility>
- namespace NSc {
- #ifdef _MSC_VER
- #pragma warning(disable : 4521 4522)
- #endif
- struct TMergeOptions {
- enum class EArrayMergeMode {
- Replace,
- Merge
- };
- EArrayMergeMode ArrayMergeMode = EArrayMergeMode::Replace;
- };
- // 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:
- // XXX: A newly constructed standalone TValue instance (even null!) consumes ~4 KB of memory because it allocates a memory pool inside.
- // Consider building a tree of TValues in top-down order (from root to leaves) to share a single pool
- // instead of creating child TValues first and appending them to a parent TValue.
- // All somehow cached values should be constant, otherwise the shared pool can grow infinitely.
- 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;
- [[nodiscard]] static TValue FromJson(TStringBuf, const TJsonOpts& = TJsonOpts());
- [[nodiscard]] 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, TMaybe<TMergeOptions> mergeOptions = {}); // returns self
- TValue& ReverseMergeJson(TStringBuf json, TMaybe<TMergeOptions> mergeOptions = {}); // returns self
- static bool MergeUpdateJson(TValue&, TStringBuf json, TMaybe<TMergeOptions> mergeOptions = {}); // returns true unless failed to parse the json
- static bool ReverseMergeJson(TValue&, TStringBuf json, TMaybe<TMergeOptions> mergeOptions = {}); // returns true unless failed to parse the json
- TValue& MergeUpdate(const TValue& delta, TMaybe<TMergeOptions> mergeOptions = {}); // return self
- TValue& ReverseMerge(const TValue& delta, TMaybe<TMergeOptions> mergeOptions = {}); // 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 CreateNew() const; // returns a new null value which shares a memory pool with 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, TMaybe<TMergeOptions> mergeOptions);
- TValue& DoMergeImpl(const TValue& delta, bool olddelta, TMaybe<TMergeOptions> mergeOptions, 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
|