aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2023-06-15 18:24:59 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2023-06-15 18:26:33 +0300
commit068d4453cf9fc68c875eee73f5c637bb076f6a71 (patch)
treeda3e83fdb9488ea08faa39d8b41916744f9acad7 /library
parent7e7de263d4acbc6eacf92b618bcb5f9049bccc9b (diff)
downloadydb-068d4453cf9fc68c875eee73f5c637bb076f6a71.tar.gz
Create stable-23-2 branch
x-stable-origin-commit: 3fd4d58117c143ed9e6b21813ccd9e507d2cd4d3
Diffstat (limited to 'library')
-rw-r--r--library/cpp/actors/core/monotonic.cpp8
-rw-r--r--library/cpp/actors/core/monotonic.h3
-rw-r--r--library/cpp/actors/core/monotonic_provider.cpp8
-rw-r--r--library/cpp/actors/core/monotonic_provider.h4
-rw-r--r--library/cpp/lwtrace/control.cpp9
-rw-r--r--library/cpp/lwtrace/trace_ut.cpp46
-rw-r--r--library/cpp/time_provider/monotonic.cpp83
-rw-r--r--library/cpp/time_provider/monotonic.h197
-rw-r--r--library/cpp/time_provider/monotonic_provider.cpp44
-rw-r--r--library/cpp/time_provider/monotonic_provider.h28
-rw-r--r--library/cpp/time_provider/time_provider.cpp2
-rw-r--r--library/cpp/yaml/fyamlcpp/fyamlcpp.cpp142
-rw-r--r--library/cpp/yaml/fyamlcpp/fyamlcpp.h23
-rw-r--r--library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp371
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);
+ }
+ }
+
}