123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- #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, TMaybe<TMergeOptions> mergeOptions) {
- return DoMerge(delta, false, mergeOptions);
- }
- TValue& TValue::ReverseMerge(const TValue& delta, TMaybe<TMergeOptions> mergeOptions) {
- return DoMerge(delta, true, mergeOptions);
- }
- TValue& TValue::MergeUpdateJson(TStringBuf data, TMaybe<TMergeOptions> mergeOptions) {
- return MergeUpdate(FromJson(data), mergeOptions);
- }
- TValue& TValue::ReverseMergeJson(TStringBuf data, TMaybe<TMergeOptions> mergeOptions) {
- return ReverseMerge(FromJson(data), mergeOptions);
- }
- bool TValue::MergeUpdateJson(TValue& v, TStringBuf data, TMaybe<TMergeOptions> mergeOptions) {
- NSc::TValue m;
- if (!FromJson(m, data)) {
- return false;
- }
- v.MergeUpdate(m, mergeOptions);
- return true;
- }
- bool TValue::ReverseMergeJson(TValue& v, TStringBuf data, TMaybe<TMergeOptions> mergeOptions) {
- NSc::TValue m;
- if (!FromJson(m, data)) {
- return false;
- }
- v.ReverseMerge(m, mergeOptions);
- return true;
- }
- TValue TValue::Clone() const {
- return TValue().CopyFrom(*this);
- }
- TValue TValue::CreateNew() const {
- return Y_LIKELY(TheCore) ? TValue(TheCore->Pool) : TValue();
- }
- 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 && b.TheCore && 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, TMaybe<TMergeOptions> mergeOptions) {
- if (Same(*this, delta)) {
- return *this;
- }
- using namespace NImpl;
- return DoMergeImpl(delta, lowPriorityDelta, mergeOptions, GetTlsInstance<TSelfLoopContext>(), GetTlsInstance<TSelfOverrideContext>());
- }
- TValue& TValue::DoMergeImpl(const TValue& delta, bool lowPriorityDelta, TMaybe<TMergeOptions> mergeOptions,
- NImpl::TSelfLoopContext& otherLoopCtx,
- NImpl::TSelfOverrideContext& selfOverrideGuard) {
- if (Same(*this, delta)) {
- return *this;
- }
- bool allowMergeArray = mergeOptions.Defined() && mergeOptions->ArrayMergeMode == TMergeOptions::EArrayMergeMode::Merge;
- 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, mergeOptions, otherLoopCtx, selfOverrideGuard);
- }
- } else if (delta.IsArray() && allowMergeArray && (!lowPriorityDelta || IsArray() || 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()) {
- SetArray();
- }
- Y_ASSERT(IsArray());
- const TArray& adelta = deltaCore.Array;
- if (adelta.size() > core.Array.size()) {
- core.Array.resize(adelta.size());
- }
- for (size_t i = 0; i < adelta.size(); ++i) {
- core.Array[i].DoMergeImpl(adelta[i], lowPriorityDelta, mergeOptions, 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));
- }
|