scheme.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. #pragma once
  2. #include "scimpl_defs.h"
  3. #include "fwd.h"
  4. #include <util/generic/maybe.h>
  5. #include <iterator>
  6. #include <utility>
  7. namespace NSc {
  8. #ifdef _MSC_VER
  9. #pragma warning(disable : 4521 4522)
  10. #endif
  11. struct TMergeOptions {
  12. enum class EArrayMergeMode {
  13. Replace,
  14. Merge
  15. };
  16. EArrayMergeMode ArrayMergeMode = EArrayMergeMode::Replace;
  17. };
  18. // todo: try to remove some rarely used methods
  19. class TValue {
  20. public:
  21. enum class EType {
  22. Null = 0 /* "Null" */,
  23. Bool /* "Bool" */,
  24. IntNumber /* "Int" */,
  25. FloatNumber /* "Float" */,
  26. String /* "String" */,
  27. Array /* "Array" */,
  28. Dict /* "Dict" */
  29. };
  30. struct TScCore;
  31. using TCorePtr = TIntrusivePtr<TScCore>;
  32. using TPoolPtr = TIntrusivePtr<NDefinitions::TPool>;
  33. using TArray = ::NSc::TArray;
  34. using TDict = ::NSc::TDict;
  35. private: // A TValue instance has only these 3 fields
  36. mutable TCorePtr TheCore; // a pointer to a refcounted (kind of) variant
  37. bool CopyOnWrite = false; // a flag that thevalue is a COW shallow copy and should produce a deep copy once modified
  38. // Thus all copies of a TValue are by default shallow. Use TValue::Clone to force a deep copy.
  39. // A COW copy will see changes in its parent, but no change in the COW copy will propagate to its parent.
  40. public:
  41. // XXX: A newly constructed standalone TValue instance (even null!) consumes ~4 KB of memory because it allocates a memory pool inside.
  42. // Consider building a tree of TValues in top-down order (from root to leaves) to share a single pool
  43. // instead of creating child TValues first and appending them to a parent TValue.
  44. // All somehow cached values should be constant, otherwise the shared pool can grow infinitely.
  45. inline TValue();
  46. inline TValue(TValue& v);
  47. inline TValue(const TValue& v);
  48. inline TValue(TValue&& v) noexcept;
  49. public: // Operators
  50. inline TValue(double t);
  51. inline TValue(unsigned long long t);
  52. inline TValue(unsigned long t);
  53. inline TValue(unsigned t);
  54. inline TValue(long long t);
  55. inline TValue(long t);
  56. inline TValue(int t);
  57. // inline TValue(bool b);
  58. inline TValue(TStringBuf t);
  59. inline TValue(const char*);
  60. inline operator double() const;
  61. inline operator float() const;
  62. inline operator long long() const;
  63. inline operator long() const;
  64. inline operator int() const;
  65. inline operator short() const;
  66. inline operator char() const;
  67. inline operator unsigned long long() const;
  68. inline operator unsigned long() const;
  69. inline operator unsigned() const;
  70. inline operator unsigned short() const;
  71. inline operator unsigned char() const;
  72. inline operator signed char() const;
  73. inline operator TStringBuf() const;
  74. inline operator const ::NSc::TArray&() const;
  75. inline operator const ::NSc::TDict&() const;
  76. inline TValue& operator=(double t);
  77. inline TValue& operator=(unsigned long long t);
  78. inline TValue& operator=(unsigned long t);
  79. inline TValue& operator=(unsigned t);
  80. inline TValue& operator=(long long t);
  81. inline TValue& operator=(long t);
  82. inline TValue& operator=(int t);
  83. // inline TValue& operator=(bool t);
  84. inline TValue& operator=(TStringBuf t);
  85. inline TValue& operator=(const char* t);
  86. inline TValue& operator=(TValue& v) &;
  87. inline TValue& operator=(const TValue& v) &;
  88. inline TValue& operator=(TValue&& v) & noexcept;
  89. inline TValue& operator=(TValue& v) && = delete;
  90. inline TValue& operator=(const TValue& v) && = delete;
  91. inline TValue& operator=(TValue&& v) && = delete;
  92. public:
  93. template <class T> // ui16 or TStringBuf
  94. inline TValue& operator[](const T& idx) {
  95. return GetOrAdd(idx);
  96. }
  97. template <class T> // ui16 or TStringBuf
  98. inline const TValue& operator[](const T& idx) const {
  99. return Get(idx);
  100. }
  101. public: // Data methods ///////////////////////////////////////////////////////////
  102. inline EType GetType() const;
  103. inline bool IsNull() const;
  104. inline TValue& SetNull(); // returns self, will set type to Null
  105. TValue& Clear() {
  106. return ClearArray().ClearDict().SetNull();
  107. }
  108. public: // Number methods /////////////////////////////////////////////////////////
  109. // Bool, IntNumber and FloatNumber are all compatible.
  110. // If a TValue node has one of the types it may as well be used as another.
  111. // FloatNumber methods. Forces FloatNumber representation. Compatible with IntNumber and Bool
  112. inline bool IsNumber() const; // true if any of FloatNumber, IntNumber, Bool
  113. inline double GetNumber(double defaultval = 0) const; // Compatible with Bool, IntNumber and FloatNumber types
  114. inline double& GetNumberMutable(double defaultval = 0); // Will switch the type to FloatNumber
  115. inline TValue& SetNumber(double val = 0); // returns self, will switch the type to FloatNumber
  116. double ForceNumber(double deflt = 0) const; // Best-effort cast to double (will do TryFromString if applicable)
  117. // IntNumber methods. Forces integer representation. Compatible with FloatNumber and Bool types.
  118. // Note: if you don't care about distinguishing bools, ints and doubles, use *Number methods above
  119. inline bool IsIntNumber() const; // true only if IntNumber or Bool
  120. inline i64 GetIntNumber(i64 defaultval = 0) const; // Compatible with Bool, IntNumber and FloatNumber types
  121. inline i64& GetIntNumberMutable(i64 defaultval = 0); // Will switch the type to IntNumber
  122. inline TValue& SetIntNumber(i64 val = 0); // returns self, will switch the type to IntNumber
  123. i64 ForceIntNumber(i64 deflt = 0) const; // Best-effort cast to i64 (will do TryFromString for String)
  124. // Bool methods. Forces bool representation. Compatible with Float Number and Int Number methods above.
  125. // Note: if you don't care about distinguishing Bool, IntNumber and FloatNumber, use *Number methods above
  126. inline bool IsBool() const; // true only if Bool
  127. inline bool GetBool(bool defaultval = false) const; // Compatible with Bool, IntNumber and FloatNumber types
  128. inline TValue& SetBool(bool val = false); // returns self, will switch the type to Bool
  129. public: // Arcadia-specific boolean representation support
  130. // Tests for explicit True, also checks for arcadia-specific boolean representation
  131. bool IsTrue() const {
  132. return IsNumber() ? GetNumber() : ::IsTrue(GetString());
  133. }
  134. // Tests for explicit False, also checks for arcadia-specific boolean representation
  135. bool IsExplicitFalse() const {
  136. return IsNumber() ? !GetNumber() : IsFalse(GetString());
  137. }
  138. public: // String methods /////////////////////////////////////////////////////////
  139. inline bool IsString() const;
  140. inline TStringBuf GetString(TStringBuf defaultval = TStringBuf()) const;
  141. inline TValue& SetString(TStringBuf val = TStringBuf()); // returns self
  142. TString ForceString(const TString& deflt = TString()) const; // Best-effort cast to TString (will do ToString for numeric types)
  143. // todo: remove
  144. inline bool StringEmpty() const;
  145. inline size_t StringSize() const;
  146. public: // Array methods //////////////////////////////////////////////////////////
  147. inline bool IsArray() const;
  148. inline const TArray& GetArray() const;
  149. inline TArray& GetArrayMutable();
  150. inline TValue& SetArray(); // turns into array if needed, returns self
  151. inline TValue& ClearArray();
  152. inline bool Has(size_t idx) const;
  153. inline const TValue& Get(size_t idx) const; // returns child or default
  154. inline TValue* GetNoAdd(size_t idx); // returns link to existing child or nullptr
  155. inline TValue& Push(); // returns new child
  156. template <class T>
  157. TValue& Push(T&& t) {
  158. return Push() = std::forward<T>(t);
  159. } // returns new child
  160. TValue& Insert(ui16 idx) {
  161. return InsertUnsafe(idx);
  162. } // creates missing values, returns new child
  163. template <class T>
  164. TValue& Insert(ui16 idx, T&& v) {
  165. return InsertUnsafe(idx, std::forward<T>(v));
  166. } // creates missing values, returns new child
  167. template <class TIt>
  168. inline TValue& AppendAll(TIt begin, TIt end); // Append(vec.begin(), vec.end())
  169. template <class TColl>
  170. inline TValue& AppendAll(TColl&& coll); // Append(vec)
  171. inline TValue& AppendAll(std::initializer_list<TValue> coll);
  172. TValue& GetOrAdd(ui16 idx) {
  173. return GetOrAddUnsafe(idx);
  174. } // creates missing values, returns new child
  175. inline TValue& InsertUnsafe(size_t idx); // creates missing values, returns new child
  176. template <class T>
  177. TValue& InsertUnsafe(size_t idx, T&& t) {
  178. return InsertUnsafe(idx) = std::forward<T>(t);
  179. } // creates missing values, returns new child
  180. inline TValue& GetOrAddUnsafe(size_t idx); // creates missing values, returns new child
  181. inline TValue Pop(); // returns popped value
  182. inline TValue Delete(size_t idx); // returns deleted value if it existed, NSc::Null() otherwise
  183. inline TValue& Front() {
  184. return GetOrAdd(0);
  185. } // creates missing value, returns child
  186. inline const TValue& Front() const {
  187. return Get(0);
  188. } // returns child or default
  189. inline TValue& Back(); // creates missing value, returns child
  190. inline const TValue& Back() const; // returns child or default
  191. // todo: remove
  192. inline bool ArrayEmpty() const;
  193. inline size_t ArraySize() const;
  194. public: // Dict methods
  195. inline bool IsDict() const;
  196. inline const TDict& GetDict() const;
  197. inline TDict& GetDictMutable();
  198. inline TValue& SetDict(); // turns into dict if not one, returns self
  199. inline TValue& ClearDict();
  200. inline bool Has(TStringBuf idx) const;
  201. inline const TValue& Get(TStringBuf idx) const;
  202. inline TValue* GetNoAdd(TStringBuf idx); // returns link to existing child or nullptr
  203. TValue& Add(TStringBuf idx) {
  204. return GetOrAdd(idx);
  205. }
  206. template <class T>
  207. TValue& Add(TStringBuf idx, T&& t) {
  208. return Add(idx) = std::forward<T>(t);
  209. }
  210. inline TValue& GetOrAdd(TStringBuf idx); // creates missing value, returns child
  211. inline TValue Delete(TStringBuf idx); // returns deleted value
  212. inline TValue& AddAll(std::initializer_list<std::pair<TStringBuf, TValue>> t);
  213. TStringBufs DictKeys(bool sorted = true) const;
  214. TStringBufs& DictKeys(TStringBufs&, bool sorted = true) const;
  215. // todo: remove
  216. inline bool DictEmpty() const;
  217. inline size_t DictSize() const;
  218. public: // Json methods ////////////////////////////////////////////////
  219. using TJsonOpts = NSc::TJsonOpts;
  220. using EJsonOpts = TJsonOpts::EJsonOpts;
  221. static const EJsonOpts JO_DEFAULT = TJsonOpts::JO_DEFAULT;
  222. static const EJsonOpts JO_SORT_KEYS = TJsonOpts::JO_SORT_KEYS;
  223. static const EJsonOpts JO_SKIP_UNSAFE = TJsonOpts::JO_SKIP_UNSAFE; // skip non-utf8 strings
  224. static const EJsonOpts JO_PRETTY = TJsonOpts::JO_PRETTY;
  225. static const EJsonOpts JO_SAFE = TJsonOpts::JO_SAFE; // JO_SORT_KEYS | JO_SKIP_UNSAFE
  226. static const EJsonOpts JO_PARSER_STRICT_WITH_COMMENTS = TJsonOpts::JO_PARSER_STRICT_WITH_COMMENTS; // strict json + strict utf8
  227. static const EJsonOpts JO_PARSER_STRICT = TJsonOpts::JO_PARSER_STRICT; // strict json + strict utf8 + comments are disallowed
  228. static const EJsonOpts JO_PARSER_DISALLOW_DUPLICATE_KEYS = TJsonOpts::JO_PARSER_DISALLOW_DUPLICATE_KEYS;
  229. [[nodiscard]] static TValue FromJson(TStringBuf, const TJsonOpts& = TJsonOpts());
  230. [[nodiscard]] static TValue FromJsonThrow(TStringBuf, const TJsonOpts& = TJsonOpts());
  231. static bool FromJson(TValue&, TStringBuf, const TJsonOpts& = TJsonOpts());
  232. // TODO: Переименовать ToJson в ToJsonUnsafe, а ToJsonSafe в ToJson
  233. TString ToJson(const TJsonOpts& = TJsonOpts()) const;
  234. const TValue& ToJson(IOutputStream&, const TJsonOpts& = TJsonOpts()) const; // returns self
  235. // ToJson(JO_SORT_KEYS | JO_SKIP_UNSAFE)
  236. TString ToJsonSafe(const TJsonOpts& = TJsonOpts()) const;
  237. const TValue& ToJsonSafe(IOutputStream&, const TJsonOpts& = TJsonOpts()) const;
  238. // ToJson(JO_SORT_KEYS | JO_PRETTY | JO_SKIP_UNSAFE)
  239. TString ToJsonPretty(const TJsonOpts& = TJsonOpts()) const;
  240. const TValue& ToJsonPretty(IOutputStream&, const TJsonOpts& = TJsonOpts()) const;
  241. NJson::TJsonValue ToJsonValue() const;
  242. static TValue FromJsonValue(const NJson::TJsonValue&);
  243. static TValue& FromJsonValue(TValue&, const NJson::TJsonValue&); // returns self
  244. static TJsonOpts MakeOptsSafeForSerializer(TJsonOpts = TJsonOpts());
  245. static TJsonOpts MakeOptsPrettyForSerializer(TJsonOpts = TJsonOpts());
  246. public: // Merge methods ////////////////////////////////////////////////
  247. /*
  248. * LHS.MergeUpdate(RHS):
  249. * 1. Dict <- Dict:
  250. * - Copy all nonconflicting key-value pairs from RHS to LHS.
  251. * - For every pair of conflicting values apply LHS[key].MergeUpdate(RHS[key]).
  252. * 2. Anything <- Null:
  253. * - Do nothing.
  254. * 3. Other conflicts:
  255. * - Copy RHS over LHS.
  256. *
  257. * LHS.ReverseMerge(RHS):
  258. * 1. Dict <- Dict:
  259. * - Copy all nonconflicting key-value pairs from RHS to LHS.
  260. * - For every pair of conflicting values apply LHS[key].ReverseMerge(RHS[key]).
  261. * 2. Null <- Anything:
  262. * - Copy RHS over LHS.
  263. * 3. Other conflicts:
  264. * - Do nothing.
  265. */
  266. TValue& MergeUpdateJson(TStringBuf json, TMaybe<TMergeOptions> mergeOptions = {}); // returns self
  267. TValue& ReverseMergeJson(TStringBuf json, TMaybe<TMergeOptions> mergeOptions = {}); // returns self
  268. static bool MergeUpdateJson(TValue&, TStringBuf json, TMaybe<TMergeOptions> mergeOptions = {}); // returns true unless failed to parse the json
  269. static bool ReverseMergeJson(TValue&, TStringBuf json, TMaybe<TMergeOptions> mergeOptions = {}); // returns true unless failed to parse the json
  270. TValue& MergeUpdate(const TValue& delta, TMaybe<TMergeOptions> mergeOptions = {}); // return self
  271. TValue& ReverseMerge(const TValue& delta, TMaybe<TMergeOptions> mergeOptions = {}); // return self
  272. public: // Path methods /////////////////////////////////////////////////////////
  273. // TODO: add throwing variants
  274. // make sure to properly escape the tokens
  275. static TString EscapeForPath(TStringBuf rawKey); // converts a raw dict key into a valid token for a selector path
  276. static bool PathValid(TStringBuf path); // returns true if the path is syntactically valid
  277. bool PathExists(TStringBuf path) const; // returns true if the path is syntactically valid and the target value exists
  278. const TValue& TrySelect(TStringBuf path) const; // returns the target value
  279. // if the path is syntactically valid and the target value exists
  280. // otherwise returns NSc::Null()
  281. TValue* TrySelectOrAdd(TStringBuf path); // returns the target value if it exists or creates if not
  282. // if the path is syntactically valid
  283. // otherwise returns NSc::Null()
  284. TValue TrySelectAndDelete(TStringBuf path); // deletes and returns the target value
  285. // if the path is syntactically valid and the target value existed
  286. // otherwise returns NSc::Null()
  287. public: // Copy methods /////////////////////////////////////////////////////////
  288. TValue Clone() const; // returns deep copy of self (on the separate pool)
  289. TValue& CopyFrom(const TValue& other); // deep copy other value into self, returns self
  290. TValue CreateNew() const; // returns a new null value which shares a memory pool with self
  291. TValue& Swap(TValue& v);
  292. static bool Same(const TValue&, const TValue&); // point to the same core
  293. static bool Equal(const TValue&, const TValue&); // recursively equal
  294. static bool SamePool(const TValue&, const TValue&); // share arena
  295. public:
  296. // very specific methods useful in very specific corner cases
  297. static TValue From(const ::google::protobuf::Message&, bool mapAsDict = false);
  298. void To(::google::protobuf::Message&, const TProtoOpts& opts = {}) const;
  299. public:
  300. inline explicit TValue(TPoolPtr&);
  301. static const TScCore& DefaultCore();
  302. static const TArray& DefaultArray();
  303. static const TDict& DefaultDict();
  304. static const TValue& DefaultValue();
  305. static const TValue& Null() {
  306. return DefaultValue();
  307. }
  308. void DoWriteJsonImpl(IOutputStream&, const TJsonOpts&, NImpl::TKeySortContext&, NImpl::TSelfLoopContext&) const;
  309. bool IsSameOrAncestorOf(const TValue& other) const;
  310. private:
  311. TValue& DoMerge(const TValue& delta, bool olddelta, TMaybe<TMergeOptions> mergeOptions);
  312. TValue& DoMergeImpl(const TValue& delta, bool olddelta, TMaybe<TMergeOptions> mergeOptions, NImpl::TSelfLoopContext&, NImpl::TSelfOverrideContext&);
  313. TValue& DoCopyFromImpl(const TValue& other, NImpl::TSelfLoopContext&, NImpl::TSelfOverrideContext&);
  314. NJson::TJsonValue ToJsonValueImpl(NImpl::TSelfLoopContext&) const;
  315. bool IsSameOrAncestorOfImpl(const TScCore& other, NImpl::TSelfLoopContext& loopCtx) const;
  316. inline TScCore& CoreMutable();
  317. inline TScCore& CoreMutableForSet();
  318. inline const TScCore& Core() const;
  319. static inline TScCore* NewCore(TPoolPtr&);
  320. static TValue FromField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*);
  321. static TValue FromRepeatedField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, int index);
  322. void ValueToField(const TValue& value, ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
  323. void ToField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
  324. void ToEnumField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
  325. void ToRepeatedField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
  326. void ToMapField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
  327. };
  328. inline const TValue& Null() {
  329. return TValue::DefaultValue();
  330. }
  331. class TArray: public TDeque<TValue, TPoolAllocator>, TNonCopyable {
  332. using TParent = TDeque<TValue, TPoolAllocator>;
  333. public:
  334. TArray(TMemoryPool* p)
  335. : TParent(p)
  336. {
  337. }
  338. template <class TIt>
  339. void AppendAll(TIt begin, TIt end) {
  340. TParent::insert(TParent::end(), begin, end);
  341. }
  342. template <class TColl>
  343. void AppendAll(TColl&& coll) {
  344. AppendAll(std::begin(coll), std::end(coll));
  345. }
  346. void AppendAll(std::initializer_list<TValue> coll) {
  347. AppendAll(coll.begin(), coll.end());
  348. }
  349. const TValue& operator[](size_t i) const {
  350. return EnsureIndex(i);
  351. }
  352. TValue& operator[](size_t i) {
  353. return EnsureIndex(i);
  354. }
  355. const TValue& front() const {
  356. return EnsureIndex(0);
  357. }
  358. TValue& front() {
  359. return EnsureIndex(0);
  360. }
  361. const TValue& back() const {
  362. return EnsureIndex(LastIndex());
  363. }
  364. TValue& back() {
  365. return EnsureIndex(LastIndex());
  366. }
  367. void pop_back() {
  368. if (empty())
  369. return;
  370. TParent::pop_back();
  371. }
  372. void pop_front() {
  373. if (empty())
  374. return;
  375. TParent::pop_front();
  376. }
  377. private:
  378. size_t LastIndex() const {
  379. return ::Max<size_t>(size(), 1) - 1;
  380. }
  381. TValue& EnsureIndex(size_t i) {
  382. if (i >= size())
  383. resize(::Min<size_t>(i + 1, ::Max<ui16>()), TValue::DefaultValue());
  384. return TParent::operator[](i);
  385. }
  386. const TValue& EnsureIndex(size_t i) const {
  387. return i < size() ? TParent::operator[](i) : TValue::DefaultValue();
  388. }
  389. };
  390. // todo: densehashtable
  391. // todo: allow insertions
  392. // todo: make TDict methods safe
  393. class TDict: public THashMap<TStringBuf, TValue, THash<TStringBuf>, TEqualTo<TStringBuf>, TPoolAllocator>, TNonCopyable {
  394. using TParent = THashMap<TStringBuf, TValue, THash<TStringBuf>, TEqualTo<TStringBuf>, TPoolAllocator>;
  395. public:
  396. TDict(TMemoryPool* p)
  397. : TParent(p)
  398. {
  399. }
  400. template <class TStr>
  401. const TValue& Get(const TStr& key) const {
  402. const_iterator it = find(key);
  403. return it != end() ? it->second : TValue::DefaultValue();
  404. }
  405. };
  406. }
  407. #include "scimpl.h"
  408. #include "scheme_cast.h"
  409. #ifdef _MSC_VER
  410. #pragma warning(default : 4521 4522)
  411. #endif