diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2023-06-15 18:24:59 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2023-06-15 18:26:33 +0300 |
commit | 068d4453cf9fc68c875eee73f5c637bb076f6a71 (patch) | |
tree | da3e83fdb9488ea08faa39d8b41916744f9acad7 /library/cpp | |
parent | 7e7de263d4acbc6eacf92b618bcb5f9049bccc9b (diff) | |
download | ydb-068d4453cf9fc68c875eee73f5c637bb076f6a71.tar.gz |
Create stable-23-2 branch
x-stable-origin-commit: 3fd4d58117c143ed9e6b21813ccd9e507d2cd4d3
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/actors/core/monotonic.cpp | 8 | ||||
-rw-r--r-- | library/cpp/actors/core/monotonic.h | 3 | ||||
-rw-r--r-- | library/cpp/actors/core/monotonic_provider.cpp | 8 | ||||
-rw-r--r-- | library/cpp/actors/core/monotonic_provider.h | 4 | ||||
-rw-r--r-- | library/cpp/lwtrace/control.cpp | 9 | ||||
-rw-r--r-- | library/cpp/lwtrace/trace_ut.cpp | 46 | ||||
-rw-r--r-- | library/cpp/time_provider/monotonic.cpp | 83 | ||||
-rw-r--r-- | library/cpp/time_provider/monotonic.h | 197 | ||||
-rw-r--r-- | library/cpp/time_provider/monotonic_provider.cpp | 44 | ||||
-rw-r--r-- | library/cpp/time_provider/monotonic_provider.h | 28 | ||||
-rw-r--r-- | library/cpp/time_provider/time_provider.cpp | 2 | ||||
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp.cpp | 142 | ||||
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp.h | 23 | ||||
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp | 371 |
14 files changed, 787 insertions, 181 deletions
diff --git a/library/cpp/actors/core/monotonic.cpp b/library/cpp/actors/core/monotonic.cpp index 4d2c28ef0c..581d80d849 100644 --- a/library/cpp/actors/core/monotonic.cpp +++ b/library/cpp/actors/core/monotonic.cpp @@ -1,9 +1 @@ #include "monotonic.h" - -namespace NActors { - -ui64 GetMonotonicMicroSeconds() { - return NMonotonic::GetMonotonicMicroSeconds(); -} - -} // namespace NActors diff --git a/library/cpp/actors/core/monotonic.h b/library/cpp/actors/core/monotonic.h index 46fd13f335..2c53785390 100644 --- a/library/cpp/actors/core/monotonic.h +++ b/library/cpp/actors/core/monotonic.h @@ -5,7 +5,8 @@ namespace NActors { -ui64 GetMonotonicMicroSeconds(); +using NMonotonic::GetMonotonicMicroSeconds; using TMonotonic = NMonotonic::TMonotonic; + } // namespace NActors diff --git a/library/cpp/actors/core/monotonic_provider.cpp b/library/cpp/actors/core/monotonic_provider.cpp index 9e5bb1aadf..f8d91a4eec 100644 --- a/library/cpp/actors/core/monotonic_provider.cpp +++ b/library/cpp/actors/core/monotonic_provider.cpp @@ -1,9 +1 @@ #include "monotonic_provider.h" - -namespace NActors { - -TIntrusivePtr<NActors::IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider() { - return NMonotonic::CreateDefaultMonotonicTimeProvider(); -} - -} // namespace NActors diff --git a/library/cpp/actors/core/monotonic_provider.h b/library/cpp/actors/core/monotonic_provider.h index 1f6c44aeb9..befe4f7b90 100644 --- a/library/cpp/actors/core/monotonic_provider.h +++ b/library/cpp/actors/core/monotonic_provider.h @@ -4,8 +4,8 @@ namespace NActors { -using IMonotonicTimeProvider = ::IMonotonicTimeProvider; +using IMonotonicTimeProvider = NMonotonic::IMonotonicTimeProvider; -TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider(); +using NMonotonic::CreateDefaultMonotonicTimeProvider; } // namespace NActors diff --git a/library/cpp/lwtrace/control.cpp b/library/cpp/lwtrace/control.cpp index d9404ff269..b0d40f7063 100644 --- a/library/cpp/lwtrace/control.cpp +++ b/library/cpp/lwtrace/control.cpp @@ -73,11 +73,18 @@ TTraceDeserializeStatus TManager::HandleTraceResponse( LWTRACK(DeserializationError, orbit, probe->Event.Name, probe->Event.GetProvider()); result.AddFailedEventName(v.GetName()); } else { + // in case of fork join probes would be like "start 0 fork 1 ....... join 10 forked 5 forked 6" ui64 timestamp = EpochNanosecondsToCycles(v.GetTimestampNanosec()); + if (timestamp > prev) { + timestamp = prev + (timestamp-prev)*timeScale + timeOffset; + } else { + timestamp += timeOffset; + } + orbit.AddProbe( probe, params, - prev + (timestamp-prev)*timeScale + timeOffset); + timestamp); probe->Event.Signature.DestroyParams(params); prev = timestamp; } diff --git a/library/cpp/lwtrace/trace_ut.cpp b/library/cpp/lwtrace/trace_ut.cpp index afb2f4e53f..9a29923e28 100644 --- a/library/cpp/lwtrace/trace_ut.cpp +++ b/library/cpp/lwtrace/trace_ut.cpp @@ -717,27 +717,59 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { TManager manager(*Singleton<TProbeRegistry>(), false); TOrbit orbit; + TOrbit child; + TTraceRequest req; req.SetIsTraced(true); - manager.HandleTraceRequest(req, orbit); + bool traced = manager.HandleTraceRequest(req, orbit); + UNIT_ASSERT(traced); LWTRACK(NoParam, orbit); + + orbit.Fork(child); + LWTRACK(IntParam, orbit, 1); - LWTRACK(StringParam, orbit, "str"); + LWTRACK(IntParam, child, 2); + + LWTRACK(StringParam, orbit, "str1"); + LWTRACK(StringParam, child, "str2"); + LWTRACK(EnumParams, orbit, ValueA, EEnumClass::ValueC); LWTRACK(InstantParam, orbit, TInstant::Seconds(42)); LWTRACK(DurationParam, orbit, TDuration::MilliSeconds(146)); LWTRACK(ProtoEnum, orbit, OT_EQ); LWTRACK(IntIntParams, orbit, 1, 2); - TTraceResponse resp; - auto& r = *resp.MutableTrace(); - orbit.Serialize(0, r); + orbit.Join(child); + + TTraceResponse resp1; + auto& r1 = *resp1.MutableTrace(); + orbit.Serialize(0, r1); + + UNIT_ASSERT_VALUES_EQUAL(r1.EventsSize(), 12); + + TOrbit other; + traced = manager.HandleTraceRequest(req, other); + UNIT_ASSERT(traced); - TOrbit orbit1; UNIT_ASSERT_VALUES_EQUAL( - manager.HandleTraceResponse(resp, manager.GetProbesMap(), orbit1).IsSuccess, + manager.HandleTraceResponse(resp1, manager.GetProbesMap(), other).IsSuccess, true); + + TTraceResponse resp2; + auto& r2 = *resp2.MutableTrace(); + other.Serialize(0, r2); + UNIT_ASSERT_VALUES_EQUAL(r2.EventsSize(), 12); + + TString proto1; + bool parsed = NProtoBuf::TextFormat::PrintToString(resp1, &proto1); + UNIT_ASSERT(parsed); + + TString proto2; + parsed = NProtoBuf::TextFormat::PrintToString(resp2, &proto2); + UNIT_ASSERT(parsed); + + UNIT_ASSERT_VALUES_EQUAL(proto1, proto2); } Y_UNIT_TEST(TrackForkJoin) { diff --git a/library/cpp/time_provider/monotonic.cpp b/library/cpp/time_provider/monotonic.cpp index 99126080e2..f9fb6c5e19 100644 --- a/library/cpp/time_provider/monotonic.cpp +++ b/library/cpp/time_provider/monotonic.cpp @@ -1,28 +1,81 @@ #include "monotonic.h" #include <chrono> +#include <optional> +#include <system_error> +#include <util/system/platform.h> + +#ifdef _linux_ + #include <time.h> + #include <string.h> +#endif namespace NMonotonic { -namespace { -// Unfortunately time_since_epoch() is sometimes negative on wine -// Remember initial time point at program start and use offsets from that -std::chrono::steady_clock::time_point MonotonicOffset = std::chrono::steady_clock::now(); -} + namespace { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + std::optional<ui64> GetClockBootTimeMicroSeconds() { + struct timespec t; + std::optional<ui64> r; + if (0 == ::clock_gettime(CLOCK_BOOTTIME, &t)) { + r.emplace(t.tv_nsec / 1000ULL + t.tv_sec * 1000000ULL); + } + return r; + } +#endif + + struct TMonotonicSupport { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + // We remember initial offset to measure time relative to program + // start and so we never return a zero time. + std::optional<ui64> BootTimeOffset; +#endif + // Unfortunately time_since_epoch() is sometimes negative on wine + // Remember initial time point at program start and use offsets from that + std::chrono::steady_clock::time_point SteadyClockOffset; + + TMonotonicSupport() { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + BootTimeOffset = GetClockBootTimeMicroSeconds(); +#endif + SteadyClockOffset = std::chrono::steady_clock::now(); + } + + ui64 GetMicroSeconds() const { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + if (Y_LIKELY(BootTimeOffset)) { + auto r = GetClockBootTimeMicroSeconds(); + if (Y_UNLIKELY(!r)) { + throw std::system_error( + std::error_code(errno, std::system_category()), + "clock_gettime(CLOCK_BOOTTIME) failed"); + } + // Note: we add 1 so we never return zero + return *r - *BootTimeOffset + 1; + } +#endif + auto elapsed = std::chrono::steady_clock::now() - SteadyClockOffset; + auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count(); + // Steady clock is supposed to never jump backwards, but it's + // better to be safe in case of buggy implementations + if (Y_UNLIKELY(microseconds < 0)) { + microseconds = 0; + } + // Note: we add 1 so we never return zero + return ui64(microseconds) + 1; + } + }; -ui64 GetMonotonicMicroSeconds() { - auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - MonotonicOffset).count(); - // Steady clock is supposed to never jump backwards, but it's better to be safe in case of buggy implementations - if (Y_UNLIKELY(microseconds < 0)) { - microseconds = 0; + TMonotonicSupport MonotonicSupport; + } + + ui64 GetMonotonicMicroSeconds() { + return MonotonicSupport.GetMicroSeconds(); } - // Add one so we never return zero - return microseconds + 1; -} -} // namespace TMonotonic +} -template<> +template <> void Out<NMonotonic::TMonotonic>( IOutputStream& o, NMonotonic::TMonotonic t) diff --git a/library/cpp/time_provider/monotonic.h b/library/cpp/time_provider/monotonic.h index e36902d884..a1258e3342 100644 --- a/library/cpp/time_provider/monotonic.h +++ b/library/cpp/time_provider/monotonic.h @@ -1,111 +1,124 @@ #pragma once #include <util/datetime/base.h> -namespace NMonotonic { -/** - * Returns current monotonic time in microseconds - */ -ui64 GetMonotonicMicroSeconds(); - -/** - * Similar to TInstant, but measuring monotonic time - */ -class TMonotonic: public TTimeBase<TMonotonic> { - using TBase = TTimeBase<TMonotonic>; - -private: - constexpr explicit TMonotonic(TValue value) noexcept - : TBase(value) { - } - -public: - constexpr TMonotonic() noexcept { - } - - static constexpr TMonotonic FromValue(TValue value) noexcept { - return TMonotonic(value); - } - - static inline TMonotonic Now() { - return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds()); - } - - using TBase::Days; - using TBase::Hours; - using TBase::MicroSeconds; - using TBase::MilliSeconds; - using TBase::Minutes; - using TBase::Seconds; - static constexpr TMonotonic Max() noexcept { - return TMonotonic(::Max<ui64>()); - } - - static constexpr TMonotonic Zero() noexcept { - return TMonotonic(); - } - - static constexpr TMonotonic MicroSeconds(ui64 us) noexcept { - return TMonotonic(TInstant::MicroSeconds(us).GetValue()); - } - - static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept { - return TMonotonic(TInstant::MilliSeconds(ms).GetValue()); - } - - static constexpr TMonotonic Seconds(ui64 s) noexcept { - return TMonotonic(TInstant::Seconds(s).GetValue()); - } - - static constexpr TMonotonic Minutes(ui64 m) noexcept { - return TMonotonic(TInstant::Minutes(m).GetValue()); - } - - static constexpr TMonotonic Hours(ui64 h) noexcept { - return TMonotonic(TInstant::Hours(h).GetValue()); - } - - static constexpr TMonotonic Days(ui64 d) noexcept { - return TMonotonic(TInstant::Days(d).GetValue()); - } +namespace NMonotonic { - template<class T> - inline TMonotonic& operator+=(const T& t) noexcept { - return (*this = (*this + t)); - } + /** + * Returns current monotonic time in microseconds + * + * On Linux uses CLOCK_BOOTTIME under the hood, so it includes time passed + * during suspend and makes it safe for measuring lease times. + */ + ui64 GetMonotonicMicroSeconds(); + + /** + * Similar to TInstant, but measuring monotonic time + * + * On Linux uses CLOCK_BOOTTIME under the hood, so it includes time passed + * during suspend and makes it safe for measuring lease times. + */ + class TMonotonic: public TTimeBase<TMonotonic> { + using TBase = TTimeBase<TMonotonic>; + + protected: + constexpr explicit TMonotonic(TValue value) noexcept + : TBase(value) + { + } + + public: + constexpr TMonotonic() noexcept { + } + + static constexpr TMonotonic FromValue(TValue value) noexcept { + return TMonotonic(value); + } + + static inline TMonotonic Now() { + return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds()); + } + + using TBase::Days; + using TBase::Hours; + using TBase::MicroSeconds; + using TBase::MilliSeconds; + using TBase::Minutes; + using TBase::Seconds; + + static constexpr TMonotonic Max() noexcept { + return TMonotonic::FromValue(::Max<ui64>()); + } + + static constexpr TMonotonic Zero() noexcept { + return TMonotonic::FromValue(0); + } + + static constexpr TMonotonic MicroSeconds(ui64 us) noexcept { + return TMonotonic::FromValue(TInstant::MicroSeconds(us).GetValue()); + } + + static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept { + return TMonotonic::FromValue(TInstant::MilliSeconds(ms).GetValue()); + } + + static constexpr TMonotonic Seconds(ui64 s) noexcept { + return TMonotonic::FromValue(TInstant::Seconds(s).GetValue()); + } + + static constexpr TMonotonic Minutes(ui64 m) noexcept { + return TMonotonic::FromValue(TInstant::Minutes(m).GetValue()); + } + + static constexpr TMonotonic Hours(ui64 h) noexcept { + return TMonotonic::FromValue(TInstant::Hours(h).GetValue()); + } + + static constexpr TMonotonic Days(ui64 d) noexcept { + return TMonotonic::FromValue(TInstant::Days(d).GetValue()); + } + + template <class T> + inline TMonotonic& operator+=(const T& t) noexcept { + return (*this = (*this + t)); + } + + template <class T> + inline TMonotonic& operator-=(const T& t) noexcept { + return (*this = (*this - t)); + } + }; - template<class T> - inline TMonotonic& operator-=(const T& t) noexcept { - return (*this = (*this - t)); - } -}; } // namespace NMonotonic Y_DECLARE_PODTYPE(NMonotonic::TMonotonic); -template<> -struct THash<NMonotonic::TMonotonic> { - size_t operator()(const NMonotonic::TMonotonic& key) const { - return THash<NMonotonic::TMonotonic::TValue>()(key.GetValue()); - } -}; +namespace std { + template <> + struct hash<NMonotonic::TMonotonic> { + size_t operator()(const NMonotonic::TMonotonic& key) const noexcept { + return hash<NMonotonic::TMonotonic::TValue>()(key.GetValue()); + } + }; +} namespace NMonotonic { -constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) { - return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue()); -} + constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) { + return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue()); + } -constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) { - TInstant result = TInstant::FromValue(l.GetValue()) + r; - return TMonotonic::FromValue(result.GetValue()); -} + constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) { + TInstant result = TInstant::FromValue(l.GetValue()) + r; + return TMonotonic::FromValue(result.GetValue()); + } -constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) { - TInstant result = TInstant::FromValue(l.GetValue()) - r; - return TMonotonic::FromValue(result.GetValue()); -} + constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) { + TInstant result = TInstant::FromValue(l.GetValue()) - r; + return TMonotonic::FromValue(result.GetValue()); + } } // namespace NMonotonic +// TODO: remove, alias for compatibility using TMonotonic = NMonotonic::TMonotonic; diff --git a/library/cpp/time_provider/monotonic_provider.cpp b/library/cpp/time_provider/monotonic_provider.cpp index 22937bd873..6b116a0e73 100644 --- a/library/cpp/time_provider/monotonic_provider.cpp +++ b/library/cpp/time_provider/monotonic_provider.cpp @@ -1,32 +1,32 @@ #include "monotonic_provider.h" -namespace { -TIntrusivePtr<IMonotonicTimeProvider> GlobalMonotonicTimeProvider; -} - -void TMonotonicOperator::RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider) { - GlobalMonotonicTimeProvider = provider; -} +namespace NMonotonic { -NMonotonic::TMonotonic TMonotonicOperator::Now() { - if (GlobalMonotonicTimeProvider) { - return GlobalMonotonicTimeProvider->Now(); - } else { - return TMonotonic::Now(); + namespace { + TIntrusivePtr<IMonotonicTimeProvider> GlobalMonotonicTimeProvider; } -} -namespace NMonotonic { + void TMonotonicOperator::RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider) { + GlobalMonotonicTimeProvider = provider; + } -class TDefaultMonotonicTimeProvider: public IMonotonicTimeProvider { -public: - TMonotonic Now() override { - return TMonotonic::Now(); + NMonotonic::TMonotonic TMonotonicOperator::Now() { + if (GlobalMonotonicTimeProvider) { + return GlobalMonotonicTimeProvider->Now(); + } else { + return TMonotonic::Now(); + } } -}; -TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider() { - return TIntrusivePtr<IMonotonicTimeProvider>(new TDefaultMonotonicTimeProvider); -} + class TDefaultMonotonicTimeProvider: public IMonotonicTimeProvider { + public: + TMonotonic Now() override { + return TMonotonic::Now(); + } + }; + + TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider() { + return TIntrusivePtr<IMonotonicTimeProvider>(new TDefaultMonotonicTimeProvider); + } } diff --git a/library/cpp/time_provider/monotonic_provider.h b/library/cpp/time_provider/monotonic_provider.h index 966e2e496b..17b57e4075 100644 --- a/library/cpp/time_provider/monotonic_provider.h +++ b/library/cpp/time_provider/monotonic_provider.h @@ -3,19 +3,25 @@ #include <util/datetime/base.h> #include "monotonic.h" -class IMonotonicTimeProvider: public TThrRefBase { -public: - virtual TMonotonic Now() = 0; -}; +namespace NMonotonic { -class TMonotonicOperator { -public: - static void RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider); - static TMonotonic Now(); -}; + class IMonotonicTimeProvider: public TThrRefBase { + public: + virtual TMonotonic Now() = 0; + }; -namespace NMonotonic { + class TMonotonicOperator { + public: + static void RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider); + static TMonotonic Now(); + }; -TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider(); + TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider(); } + +// TODO: remove, alias for compatibility +using IMonotonicTimeProvider = NMonotonic::IMonotonicTimeProvider; + +// TODO: remove, alias for compatibility +using NMonotonic::CreateDefaultMonotonicTimeProvider; diff --git a/library/cpp/time_provider/time_provider.cpp b/library/cpp/time_provider/time_provider.cpp index 687681f1ff..e1045dae05 100644 --- a/library/cpp/time_provider/time_provider.cpp +++ b/library/cpp/time_provider/time_provider.cpp @@ -30,7 +30,7 @@ TIntrusivePtr<ITimeProvider> CreateDeterministicTimeProvider(ui64 seed) { } namespace { -TIntrusivePtr<ITimeProvider> GlobalTimeProvider; + TIntrusivePtr<ITimeProvider> GlobalTimeProvider; } void TInstantOperator::RegisterProvider(TIntrusivePtr<ITimeProvider> provider) { diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp index b8d8b17596..d006001b9e 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp @@ -155,18 +155,6 @@ enum EEmitterCfgFlags { Default = FYECF_DEFAULT, }; -enum class ENodeStyle { - Any = FYNS_ANY, - Flow = FYNS_FLOW, - Block = FYNS_BLOCK, - Plain = FYNS_PLAIN, - SingleQuoted = FYNS_SINGLE_QUOTED, - DoubleQuoted = FYNS_DOUBLE_QUOTED, - Literal = FYNS_LITERAL, - Folded = FYNS_FOLDED, - Alias = FYNS_ALIAS, -}; - enum class ENodeWalkFlags { DontFollow = FYNWF_DONT_FOLLOW, Follow = FYNWF_FOLLOW, @@ -330,6 +318,115 @@ TString TNodeRef::Scalar() const { return TString(text, size); } +TMark TNodeRef::BeginMark() const { + ENSURE_NODE_NOT_EMPTY(Node_); + std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> it( + fy_document_iterator_create(), + &fy_document_iterator_destroy); + fy_document_iterator_node_start(it.get(), Node_); + auto deleter = [&](fy_event* fye){ fy_document_iterator_event_free(it.get(), fye); }; + std::unique_ptr<fy_event, decltype(deleter)> ev( + fy_document_iterator_body_next(it.get()), + deleter); + auto* mark = fy_event_start_mark(ev.get()); + + if (!mark) { + ythrow yexception() << "can't get begin mark for a node"; + } + + return TMark{ + mark->input_pos, + mark->line, + mark->column, + }; +} + +bool IsComplexType(ENodeType type) { + return type == ENodeType::Mapping || type == ENodeType::Sequence; +} + +fy_event_type GetOpenEventType(ENodeType type) { + switch(type) { + case ENodeType::Mapping: + return FYET_MAPPING_START; + case ENodeType::Sequence: + return FYET_SEQUENCE_START; + default: + Y_FAIL("Not a brackets type"); + } +} + +fy_event_type GetCloseEventType(ENodeType type) { + switch(type) { + case ENodeType::Mapping: + return FYET_MAPPING_END; + case ENodeType::Sequence: + return FYET_SEQUENCE_END; + default: + Y_FAIL("Not a brackets type"); + } +} + +TMark TNodeRef::EndMark() const { + ENSURE_NODE_NOT_EMPTY(Node_); + std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> it( + fy_document_iterator_create(), + &fy_document_iterator_destroy); + fy_document_iterator_node_start(it.get(), Node_); + + auto deleter = [&](fy_event* fye){ fy_document_iterator_event_free(it.get(), fye); }; + std::unique_ptr<fy_event, decltype(deleter)> prevEv( + nullptr, + deleter); + std::unique_ptr<fy_event, decltype(deleter)> ev( + fy_document_iterator_body_next(it.get()), + deleter); + + if (IsComplexType(Type())) { + int openBrackets = 0; + if (ev->type == GetOpenEventType(Type())) { + ++openBrackets; + } + if (ev->type == GetCloseEventType(Type())) { + --openBrackets; + } + while (ev->type != GetCloseEventType(Type()) || openBrackets != 0) { + std::unique_ptr<fy_event, decltype(deleter)> cur( + fy_document_iterator_body_next(it.get()), + deleter); + if (cur == nullptr) { + break; + } + if (cur->type == GetOpenEventType(Type())) { + ++openBrackets; + } + if (cur->type == GetCloseEventType(Type())) { + --openBrackets; + } + if (fy_event_get_node_style(cur.get()) != FYNS_BLOCK) { + prevEv.reset(ev.release()); + ev.reset(cur.release()); + } + } + } + + auto* mark = fy_event_end_mark(ev.get()); + + if (!mark && prevEv) { + mark = fy_event_end_mark(prevEv.get()); + } + + if (!mark) { + ythrow yexception() << "can't get end mark for a node"; + } + + return TMark{ + mark->input_pos, + mark->line, + mark->column, + }; +} + TMapping TNodeRef::Map() const { ENSURE_NODE_NOT_EMPTY(Node_); Y_ENSURE_EX(fy_node_is_mapping(Node_), TFyamlEx() << "Node is not Mapping: " << Path()); @@ -400,6 +497,16 @@ std::unique_ptr<char, void(*)(char*)> TNodeRef::EmitToCharArray() const { return res; } +void TNodeRef::SetStyle(ENodeStyle style) { + ENSURE_NODE_NOT_EMPTY(Node_); + fy_node_set_style(Node_, (enum fy_node_style)style); +} + +ENodeStyle TNodeRef::Style() const { + ENSURE_NODE_NOT_EMPTY(Node_); + return (ENodeStyle)fy_node_get_style(Node_); +} + void TNodeRef::SetUserData(NDetail::IBasicUserData* data) { ENSURE_NODE_NOT_EMPTY(Node_); fy_node_set_meta(Node_, data); @@ -429,6 +536,12 @@ TNodeRef TNodePairRef::Key() const { return TNodeRef(fy_node_pair_key(Pair_)); } +int TNodePairRef::Index(const TNodeRef& node) const { + ENSURE_NODE_NOT_EMPTY(node); + ENSURE_NODE_NOT_EMPTY(Pair_); + return fy_node_mapping_get_pair_index(node.Node_, Pair_); +} + void TNodePairRef::SetKey(const TNodeRef& node) { ENSURE_NODE_NOT_EMPTY(Pair_); ENSURE_NODE_NOT_EMPTY(node); @@ -542,6 +655,9 @@ void TMapping::Remove(const TNodePairRef& toRemove) { ENSURE_NODE_NOT_EMPTY(Node_); ENSURE_NODE_NOT_EMPTY(toRemove); NDetail::RethrowOnError(fy_node_mapping_remove(Node_, toRemove.Pair_), Node_); + fy_node_free(fy_node_pair_key(toRemove.Pair_)); + fy_node_free(fy_node_pair_value(toRemove.Pair_)); + free(toRemove.Pair_); } TMappingIterator TMapping::Remove(const TMappingIterator& toRemove) { @@ -819,7 +935,7 @@ std::unique_ptr<char, void(*)(char*)> TDocument::EmitToCharArray() const { std::unique_ptr<char, void(*)(char*)> res( fy_emit_document_to_string( Document_.get(), - (fy_emitter_cfg_flags)(FYECF_DEFAULT | FYECF_OUTPUT_COMMENTS)), &NDetail::FreeChar); + (fy_emitter_cfg_flags)(FYECF_DEFAULT | FYECF_MODE_PRETTY | FYECF_OUTPUT_COMMENTS)), &NDetail::FreeChar); return res; } diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.h b/library/cpp/yaml/fyamlcpp/fyamlcpp.h index bcf9362d73..6df7b244c6 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp.h +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.h @@ -15,6 +15,7 @@ struct fy_document; struct fy_diag; struct fy_document_iterator; struct fy_node_pair; +extern "C" struct fy_node *fy_node_buildf(struct fy_document *fyd, const char *fmt, ...); namespace NFyaml { @@ -32,6 +33,18 @@ enum class ENodeType { Mapping, }; +enum class ENodeStyle { + Any = -1, + Flow, + Block, + Plain, + SingleQuoted, + DoubleQuoted, + Literal, + Folded, + Alias, +}; + namespace NDetail { class IBasicUserData { @@ -137,6 +150,10 @@ public: TString Scalar() const; + TMark BeginMark() const; + + TMark EndMark() const; + void Insert(const TNodeRef& node); bool Empty() const { return Node_ == nullptr; } @@ -155,6 +172,10 @@ public: std::unique_ptr<char, void(*)(char*)> EmitToCharArray() const; + void SetStyle(ENodeStyle style); + + ENodeStyle Style() const; + protected: fy_node* Node_ = nullptr; @@ -198,6 +219,8 @@ public: TNodeRef Key() const; + int Index(const TNodeRef& node) const; + void SetKey(const TNodeRef& node); TNodeRef Value() const; diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp index ffe1d4368c..2f6e14138c 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp @@ -11,6 +11,16 @@ Y_UNIT_TEST_SUITE(FYamlCpp) { UNIT_ASSERT_EQUAL((int)NFyaml::ENodeType::Scalar, FYNT_SCALAR); UNIT_ASSERT_EQUAL((int)NFyaml::ENodeType::Sequence, FYNT_SEQUENCE); UNIT_ASSERT_EQUAL((int)NFyaml::ENodeType::Mapping, FYNT_MAPPING); + + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::Any, FYNS_ANY); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::Flow, FYNS_FLOW); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::Block, FYNS_BLOCK); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::Plain, FYNS_PLAIN); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::SingleQuoted, FYNS_SINGLE_QUOTED); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::DoubleQuoted, FYNS_DOUBLE_QUOTED); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::Literal, FYNS_LITERAL); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::Folded, FYNS_FOLDED); + UNIT_ASSERT_EQUAL((int)NFyaml::ENodeStyle::Alias, FYNS_ALIAS); } Y_UNIT_TEST(ErrorHandling) { @@ -153,4 +163,365 @@ x: b UNIT_ASSERT_VALUES_EQUAL(seq[1].Map().at("b").Sequence().at(1).Scalar(), "2"); UNIT_ASSERT_VALUES_EQUAL(seq[1].Map().at("b").Sequence().at(2).Scalar(), "3"); } + + Y_UNIT_TEST(SimpleScalarMark) { + auto check = [](const TString& str, const NFyaml::TNodeRef& node) { + auto pos = str.find("123"); + auto endPos = pos + strlen("123"); + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + UNIT_ASSERT_VALUES_EQUAL(begin, pos); + UNIT_ASSERT_VALUES_EQUAL(end, endPos); + }; + + { + TString str = R"(obj: 123)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"(obj: 123 # test)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +# test +obj: 123 # test +# test +)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +--- +obj: 123 +... +)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +a: foo +test: [{obj: 123}] +b: bar + )"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("test").Sequence().at(0).Map().at("obj"); + check(str, node); + } + + { + TString str = R"(obj: '123')"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"(obj: '123' # test)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +# test +obj: '123' # test +# test +)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +--- +obj: '123' +... +)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +a: foo +test: [{obj: "123"}] +b: bar + )"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("test").Sequence().at(0).Map().at("obj"); + check(str, node); + } + + { + TString str = R"(obj: "123")"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"(obj: "123" # test)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +# test +obj: "123" # test +# test +)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +--- +obj: "123" +... +)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +a: foo +test: [{obj: "123"}] +b: bar + )"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("test").Sequence().at(0).Map().at("obj"); + check(str, node); + } + + { + TString str = R"( +a: foo +test: [{obj: !!int "123"}] +b: bar + )"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("test").Sequence().at(0).Map().at("obj"); + check(str, node); + } + + } + + Y_UNIT_TEST(MultilineScalarMark) { + { + TString str = R"(obj: >+2 + some + multiline + + scalar with couple words)"; + auto doc = NFyaml::TDocument::Parse(str); + auto node = doc.Root().Map().at("obj"); + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + UNIT_ASSERT_VALUES_EQUAL(begin, 9); + UNIT_ASSERT_VALUES_EQUAL(end, 55); + } + } + + Y_UNIT_TEST(MapMark) { + { + TString str = R"( +a: foo +map: !!map + internal_map1: {} + internal_map2: + internal_map3: + internal_map4: + value: 1 + internal_map5: { + internal_map6: {test1: 1, test2: 2}, + internal_map7: { + value: 1 + } + } +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("map"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 21); + UNIT_ASSERT_VALUES_EQUAL(end, 246); + } + + { + TString str = R"( +a: foo +map: !!map # comment +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("map"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 11); + UNIT_ASSERT_VALUES_EQUAL(end, 11); + } + + { + TString str = R"( +a: foo +map: {} # comment +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("map"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 13); + UNIT_ASSERT_VALUES_EQUAL(end, 15); + } + + { + TString str = R"( +a: foo +map: + value: 1 +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("map"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 15); + UNIT_ASSERT_VALUES_EQUAL(end, 23); + } + } + + Y_UNIT_TEST(SequenceMark) { + { + TString str = R"( +a: foo +seq: !!seq +- internal_map1: {} +- internal_seq2: + - internal_seq3: + - internal_seq4: + value: 1 + - internal_seq5: [ + internal_seq6: [{test1: 1}, {test2: 2}], + internal_seq7: [ + {value: 1} + ] + ] +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("seq"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 19); + UNIT_ASSERT_VALUES_EQUAL(end, 252); + } + + { + TString str = R"( +a: foo +seq: !!seq # comment +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("seq"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 11); + UNIT_ASSERT_VALUES_EQUAL(end, 11); + } + + { + TString str = R"( +a: foo +seq: [] # comment +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("seq"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 13); + UNIT_ASSERT_VALUES_EQUAL(end, 15); + } + + { + TString str = R"( +a: foo +seq: +- value: 1 +# comment +c: bar + )"; + + auto doc = NFyaml::TDocument::Parse(str); + + auto node = doc.Root().Map().at("seq"); + + auto begin = node.BeginMark().InputPos; + auto end = node.EndMark().InputPos; + + UNIT_ASSERT_VALUES_EQUAL(begin, 13); + UNIT_ASSERT_VALUES_EQUAL(end, 23); + } + } + } |