aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/scheme/scheme.cpp
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.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/scheme/scheme.cpp')
-rw-r--r--library/cpp/scheme/scheme.cpp598
1 files changed, 598 insertions, 0 deletions
diff --git a/library/cpp/scheme/scheme.cpp b/library/cpp/scheme/scheme.cpp
new file mode 100644
index 0000000000..3efd116d4f
--- /dev/null
+++ b/library/cpp/scheme/scheme.cpp
@@ -0,0 +1,598 @@
+#include "scheme.h"
+#include "scimpl_private.h"
+
+#include <util/generic/algorithm.h>
+#include <util/string/cast.h>
+
+namespace NSc {
+ TStringBufs& TValue::DictKeys(TStringBufs& vs, bool sorted) const {
+ if (!IsDict()) {
+ return vs;
+ }
+
+ const ::NSc::TDict& dict = GetDict();
+ vs.reserve(vs.size() + dict.size());
+ for (const auto& it : dict)
+ vs.push_back(it.first);
+
+ if (sorted) {
+ Sort(vs.begin(), vs.end());
+ }
+
+ return vs;
+ }
+
+ TStringBufs TValue::DictKeys(bool sorted) const {
+ TStringBufs bufs;
+ DictKeys(bufs, sorted);
+ return bufs;
+ }
+
+ TValue& TValue::MergeUpdate(const TValue& delta) {
+ return DoMerge(delta, false);
+ }
+
+ TValue& TValue::ReverseMerge(const TValue& delta) {
+ return DoMerge(delta, true);
+ }
+
+ TValue& TValue::MergeUpdateJson(TStringBuf data) {
+ return MergeUpdate(FromJson(data));
+ }
+
+ TValue& TValue::ReverseMergeJson(TStringBuf data) {
+ return ReverseMerge(FromJson(data));
+ }
+
+ bool TValue::MergeUpdateJson(TValue& v, TStringBuf data) {
+ NSc::TValue m;
+ if (!FromJson(m, data)) {
+ return false;
+ }
+
+ v.MergeUpdate(m);
+ return true;
+ }
+
+ bool TValue::ReverseMergeJson(TValue& v, TStringBuf data) {
+ NSc::TValue m;
+ if (!FromJson(m, data)) {
+ return false;
+ }
+
+ v.ReverseMerge(m);
+ return true;
+ }
+
+ TValue TValue::Clone() const {
+ return TValue().CopyFrom(*this);
+ }
+
+ double TValue::ForceNumber(double deflt) const {
+ const TScCore& core = Core();
+ if (core.IsNumber()) {
+ return core.GetNumber(deflt);
+ }
+
+ if (TStringBuf str = core.GetString(TStringBuf())) {
+ {
+ double result = 0;
+ if (TryFromString<double>(str, result)) {
+ return result;
+ }
+ }
+ {
+ i64 result = 0;
+ if (TryFromString<i64>(str, result)) {
+ return result;
+ }
+ }
+ {
+ ui64 result = 0;
+ if (TryFromString<ui64>(str, result)) {
+ return result;
+ }
+ }
+ }
+
+ return deflt;
+ }
+
+ i64 TValue::ForceIntNumber(i64 deflt) const {
+ const TScCore& core = Core();
+ if (core.IsNumber()) {
+ return core.GetIntNumber(deflt);
+ }
+
+ if (TStringBuf str = core.GetString(TStringBuf())) {
+ {
+ i64 result = 0;
+ if (TryFromString<i64>(str, result)) {
+ return result;
+ }
+ }
+ {
+ ui64 result = 0;
+ if (TryFromString<ui64>(str, result)) {
+ return result;
+ }
+ }
+ {
+ double result = 0;
+ if (TryFromString<double>(str, result)) {
+ return result;
+ }
+ }
+ }
+
+ return deflt;
+ }
+
+ TString TValue::ForceString(const TString& deflt) const {
+ const TScCore& core = Core();
+ if (core.IsString()) {
+ return ToString(core.GetString(TStringBuf()));
+ }
+
+ if (core.IsIntNumber()) {
+ return ToString(core.GetIntNumber(0));
+ }
+
+ if (core.IsNumber()) {
+ return ToString(core.GetNumber(0));
+ }
+
+ return deflt;
+ }
+
+ TValue& /*this*/ TValue::CopyFrom(const TValue& other) {
+ if (Same(*this, other)) {
+ return *this;
+ }
+
+ using namespace NImpl;
+ return DoCopyFromImpl(other, GetTlsInstance<TSelfLoopContext>(), GetTlsInstance<TSelfOverrideContext>());
+ }
+
+ TValue& TValue::DoCopyFromImpl(const TValue& other,
+ NImpl::TSelfLoopContext& otherLoopCtx,
+ NImpl::TSelfOverrideContext& selfOverrideCtx) {
+ if (Same(*this, other)) {
+ return *this;
+ }
+
+ CoreMutableForSet(); // trigger COW
+
+ TScCore& selfCore = *TheCore;
+ const TScCore& otherCore = other.Core();
+
+ NImpl::TSelfLoopContext::TGuard loopCheck(otherLoopCtx, otherCore);
+ NImpl::TSelfOverrideContext::TGuard overrideGuard(selfOverrideCtx, selfCore);
+
+ selfCore.SetNull();
+
+ if (!loopCheck.Ok) {
+ return *this; // a loop encountered (and asserted), skip the back reference
+ }
+
+ switch (otherCore.ValueType) {
+ default:
+ Y_ASSERT(false);
+ [[fallthrough]];
+ case EType::Null:
+ break;
+ case EType::Bool:
+ selfCore.SetBool(otherCore.IntNumber);
+ break;
+ case EType::IntNumber:
+ selfCore.SetIntNumber(otherCore.IntNumber);
+ break;
+ case EType::FloatNumber:
+ selfCore.SetNumber(otherCore.FloatNumber);
+ break;
+ case EType::String:
+ if (selfCore.Pool.Get() == otherCore.Pool.Get()) {
+ selfCore.SetOwnedString(otherCore.String);
+ } else {
+ selfCore.SetString(otherCore.String);
+ }
+ break;
+ case EType::Array:
+ selfCore.SetArray();
+ for (const TValue& e : otherCore.GetArray()) {
+ selfCore.Push().DoCopyFromImpl(e, otherLoopCtx, selfOverrideCtx);
+ }
+ break;
+ case EType::Dict: {
+ TCorePtr tmp = NewCore(selfCore.Pool);
+ auto& tmpCore = *tmp;
+ tmpCore.SetDict();
+ const TDict& d = otherCore.GetDict();
+ tmpCore.Dict.reserve(d.size());
+ for (const TDict::value_type& e : d) {
+ tmpCore.Add(e.first).DoCopyFromImpl(e.second, otherLoopCtx, selfOverrideCtx);
+ }
+ TheCore = std::move(tmp);
+ break;
+ }
+ }
+
+ return *this;
+ }
+
+ TValue& TValue::Swap(TValue& v) {
+ DoSwap(TheCore, v.TheCore);
+ DoSwap(CopyOnWrite, v.CopyOnWrite);
+ return *this;
+ }
+
+ bool TValue::Same(const TValue& a, const TValue& b) {
+ return a.TheCore.Get() == b.TheCore.Get();
+ }
+
+ bool TValue::SamePool(const TValue& a, const TValue& b) {
+ return Same(a, b) || a.TheCore->Pool.Get() == b.TheCore->Pool.Get();
+ }
+
+ bool TValue::Equal(const TValue& a, const TValue& b) {
+ if (Same(a, b)) {
+ return true;
+ }
+
+ const NSc::TValue::TScCore& coreA = a.Core();
+ const NSc::TValue::TScCore& coreB = b.Core();
+
+ if (coreA.IsNumber() && coreB.IsNumber()) {
+ return coreA.GetIntNumber(0) == coreB.GetIntNumber(0) && coreA.GetNumber(0) == coreB.GetNumber(0);
+ }
+
+ if (coreA.ValueType != coreB.ValueType) {
+ return false;
+ }
+
+ if (coreA.IsString()) {
+ std::string_view strA = coreA.String;
+ std::string_view strB = coreB.String;
+
+ if (strA != strB) {
+ return false;
+ }
+ } else if (coreA.IsArray()) {
+ const TArray& arrA = coreA.Array;
+ const TArray& arrB = coreB.Array;
+
+ if (arrA.size() != arrB.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < arrA.size(); ++i) {
+ if (!Equal(arrA[i], arrB[i])) {
+ return false;
+ }
+ }
+ } else if (coreA.IsDict()) {
+ const ::NSc::TDict& dictA = coreA.Dict;
+ const ::NSc::TDict& dictB = coreB.Dict;
+
+ if (dictA.size() != dictB.size()) {
+ return false;
+ }
+
+ for (const auto& ita : dictA) {
+ ::NSc::TDict::const_iterator itb = dictB.find(ita.first);
+
+ if (itb == dictB.end() || !Equal(ita.second, itb->second)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ TValue& TValue::DoMerge(const TValue& delta, bool lowPriorityDelta) {
+ if (Same(*this, delta)) {
+ return *this;
+ }
+
+ using namespace NImpl;
+ return DoMergeImpl(delta, lowPriorityDelta, GetTlsInstance<TSelfLoopContext>(), GetTlsInstance<TSelfOverrideContext>());
+ }
+
+ TValue& TValue::DoMergeImpl(const TValue& delta, bool lowPriorityDelta,
+ NImpl::TSelfLoopContext& otherLoopCtx,
+ NImpl::TSelfOverrideContext& selfOverrideGuard) {
+ if (Same(*this, delta)) {
+ return *this;
+ }
+
+ if (delta.IsDict() && (!lowPriorityDelta || IsDict() || IsNull())) {
+ TScCore& core = CoreMutable();
+ const TScCore& deltaCore = delta.Core();
+
+ NImpl::TSelfLoopContext::TGuard loopCheck(otherLoopCtx, deltaCore);
+
+ if (!loopCheck.Ok) {
+ return *this; // a loop encountered (and asserted), skip the back reference
+ }
+
+ if (!lowPriorityDelta || IsNull()) {
+ SetDict();
+ }
+
+ const TDict& ddelta = deltaCore.Dict;
+
+ for (const auto& dit : ddelta) {
+ core.GetOrAdd(dit.first).DoMergeImpl(dit.second, lowPriorityDelta, otherLoopCtx, selfOverrideGuard);
+ }
+ } else if (!delta.IsNull() && (!lowPriorityDelta || IsNull())) {
+ DoCopyFromImpl(delta, otherLoopCtx, selfOverrideGuard);
+ }
+
+ return *this;
+ }
+
+ NJson::TJsonValue TValue::ToJsonValue() const {
+ using namespace NImpl;
+ return ToJsonValueImpl(GetTlsInstance<TSelfLoopContext>());
+ }
+
+ NJson::TJsonValue TValue::ToJsonValueImpl(NImpl::TSelfLoopContext& loopCtx) const {
+ const TScCore& core = Core();
+
+ switch (core.ValueType) {
+ default:
+ case EType::Null:
+ return NJson::TJsonValue(NJson::JSON_NULL);
+ case EType::Bool:
+ return NJson::TJsonValue(core.GetBool());
+ case EType::IntNumber:
+ return NJson::TJsonValue(core.GetIntNumber());
+ case EType::FloatNumber:
+ return NJson::TJsonValue(core.GetNumber());
+ case EType::String:
+ return NJson::TJsonValue(core.String);
+ case EType::Array: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return NJson::TJsonValue(NJson::JSON_NULL);
+ }
+
+ NJson::TJsonValue result(NJson::JSON_ARRAY);
+ const TArray& arr = core.Array;
+
+ for (const auto& item : arr) {
+ result.AppendValue(NJson::TJsonValue::UNDEFINED) = item.ToJsonValueImpl(loopCtx);
+ }
+
+ return result;
+ }
+ case EType::Dict: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return NJson::TJsonValue(NJson::JSON_NULL);
+ }
+
+ NJson::TJsonValue result(NJson::JSON_MAP);
+ const TDict& dict = core.Dict;
+
+ for (const auto& item : dict) {
+ result.InsertValue(item.first, NJson::TJsonValue::UNDEFINED) = item.second.ToJsonValueImpl(loopCtx);
+ }
+
+ return result;
+ }
+ }
+ }
+
+ TValue TValue::FromJsonValue(const NJson::TJsonValue& val) {
+ TValue result;
+ FromJsonValue(result, val);
+ return result;
+ }
+
+ TValue& TValue::FromJsonValue(TValue& res, const NJson::TJsonValue& val) {
+ TScCore& core = res.CoreMutableForSet();
+ core.SetNull();
+
+ switch (val.GetType()) {
+ default:
+ case NJson::JSON_UNDEFINED:
+ case NJson::JSON_NULL:
+ break;
+ case NJson::JSON_BOOLEAN:
+ core.SetBool(val.GetBoolean());
+ break;
+ case NJson::JSON_INTEGER:
+ core.SetIntNumber(val.GetInteger());
+ break;
+ case NJson::JSON_UINTEGER:
+ core.SetIntNumber(val.GetUInteger());
+ break;
+ case NJson::JSON_DOUBLE:
+ core.SetNumber(val.GetDouble());
+ break;
+ case NJson::JSON_STRING:
+ core.SetString(val.GetString());
+ break;
+ case NJson::JSON_ARRAY: {
+ core.SetArray();
+ for (const auto& item : val.GetArray()) {
+ FromJsonValue(core.Push(), item);
+ }
+ break;
+ }
+ case NJson::JSON_MAP: {
+ core.SetDict();
+ for (const auto& item : val.GetMap()) {
+ FromJsonValue(core.Add(item.first), item.second);
+ }
+ break;
+ }
+ }
+
+ return res;
+ }
+
+ struct TDefaults {
+ TValue::TPoolPtr Pool = MakeIntrusive<NDefinitions::TPool>();
+ TValue::TScCore Core{Pool};
+ };
+
+ const TValue::TScCore& TValue::DefaultCore() {
+ return Default<TDefaults>().Core;
+ }
+
+ const TArray& TValue::DefaultArray() {
+ return Default<TDefaults>().Core.Array;
+ }
+
+ const TDict& TValue::DefaultDict() {
+ return Default<TDefaults>().Core.Dict;
+ }
+
+ const TValue& TValue::DefaultValue() {
+ return *FastTlsSingleton<TValue>();
+ }
+
+ bool TValue::IsSameOrAncestorOf(const TValue& other) const {
+ using namespace NImpl;
+ return IsSameOrAncestorOfImpl(other.Core(), GetTlsInstance<TSelfLoopContext>());
+ }
+
+ bool TValue::IsSameOrAncestorOfImpl(const TScCore& other, NImpl::TSelfLoopContext& loopCtx) const {
+ const TScCore& core = Core();
+
+ if (&core == &other) {
+ return true;
+ }
+
+ switch (core.ValueType) {
+ default:
+ return false;
+ case EType::Array: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return false;
+ }
+
+ for (const auto& item : core.Array) {
+ if (item.IsSameOrAncestorOfImpl(other, loopCtx)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ case EType::Dict: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return false;
+ }
+
+ for (const auto& item : core.Dict) {
+ if (item.second.IsSameOrAncestorOfImpl(other, loopCtx)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+
+ namespace NPrivate {
+ int CompareStr(const NSc::TValue& a, TStringBuf b) {
+ return a.GetString().compare(b);
+ }
+
+ int CompareInt(const NSc::TValue& a, i64 r) {
+ i64 l = a.GetIntNumber();
+ return l < r ? -1 : l > r ? 1 : 0;
+ }
+
+ int CompareFloat(const NSc::TValue& a, double r) {
+ double l = a.GetNumber();
+ return l < r ? -1 : l > r ? 1 : 0;
+ }
+
+ }
+
+ bool operator==(const NSc::TValue& a, const NSc::TValue& b) {
+ return NSc::TValue::Equal(a, b);
+ }
+
+ bool operator!=(const NSc::TValue& a, const NSc::TValue& b) {
+ return !NSc::TValue::Equal(a, b);
+ }
+
+#define LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(T, Impl) \
+ bool operator==(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) == 0; \
+ } \
+ bool operator==(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) == 0; \
+ } \
+ bool operator!=(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) != 0; \
+ } \
+ bool operator!=(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) != 0; \
+ } \
+ bool operator<=(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) <= 0; \
+ } \
+ bool operator<=(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) >= 0; \
+ } \
+ bool operator>=(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) >= 0; \
+ } \
+ bool operator>=(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) <= 0; \
+ } \
+ bool operator<(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) < 0; \
+ } \
+ bool operator<(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) > 0; \
+ } \
+ bool operator>(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) > 0; \
+ } \
+ bool operator>(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) < 0; \
+ }
+
+#define LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(T) \
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(signed T, CompareInt) \
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(unsigned T, CompareInt)
+
+ //LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(bool, CompareInt)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(char, CompareInt)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(char)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(short)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(int)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(long)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(long long)
+
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(float, CompareFloat)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(double, CompareFloat)
+
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(TStringBuf, CompareStr)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(const TString&, CompareStr)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(const char* const, CompareStr)
+
+#undef LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL
+#undef LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL
+
+}
+
+template <>
+void Out<NSc::TValue>(IOutputStream& o, TTypeTraits<NSc::TValue>::TFuncParam v) {
+ o.Write(v.ToJson(true));
+}