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.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/scheme/scheme.cpp')
-rw-r--r-- | library/cpp/scheme/scheme.cpp | 598 |
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)); +} |