aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorAlexander Smirnov <alex@ydb.tech>2024-10-16 12:11:24 +0000
committerAlexander Smirnov <alex@ydb.tech>2024-10-16 12:11:24 +0000
commit40811e93f3fdf9342a9295369994012420fac548 (patch)
treea8d85e094a9c21e10aa250f537c101fc2016a049 /library
parent30ebe5357bb143648c6be4d151ecd4944af81ada (diff)
parent28a0c4a9f297064538a018c512cd9bbd00a1a35d (diff)
downloadydb-40811e93f3fdf9342a9295369994012420fac548.tar.gz
Merge branch 'rightlib' into mergelibs-241016-1210
Diffstat (limited to 'library')
-rw-r--r--library/cpp/containers/compact_vector/compact_vector.h1
-rw-r--r--library/cpp/monlib/encode/buffered/string_pool.cpp2
-rw-r--r--library/cpp/monlib/metrics/histogram_snapshot.h1
-rw-r--r--library/cpp/netliba/v6/cpu_affinity.cpp2
-rw-r--r--library/cpp/netliba/v6/ib_low.cpp2
-rw-r--r--library/cpp/netliba/v6/ib_low.h4
-rw-r--r--library/cpp/resource/registry.cpp51
-rw-r--r--library/cpp/skiff/public.h2
-rw-r--r--library/cpp/skiff/skiff.cpp70
-rw-r--r--library/cpp/skiff/skiff.h29
-rw-r--r--library/cpp/skiff/skiff_schema-inl.h2
-rw-r--r--library/cpp/skiff/skiff_validator.cpp2
-rw-r--r--library/cpp/skiff/unittests/skiff_ut.cpp46
-rw-r--r--library/cpp/threading/equeue/fast/equeue.h1
-rw-r--r--library/cpp/tld/tlds-alpha-by-domain.txt2
-rw-r--r--library/cpp/unified_agent_client/client_impl.cpp4
-rw-r--r--library/cpp/unified_agent_client/examples/ua_grpc_client/main.cpp6
-rw-r--r--library/cpp/unified_agent_client/grpc_io.cpp2
-rw-r--r--library/cpp/unified_agent_client/logger.cpp2
-rw-r--r--library/cpp/unified_agent_client/proto_weighing.cpp2
-rw-r--r--library/cpp/yson/varint.cpp1
-rw-r--r--library/cpp/yt/logging/unittests/static_analysis_ut.cpp18
-rw-r--r--library/cpp/yt/malloc/malloc.cpp7
-rw-r--r--library/cpp/yt/malloc/malloc.h5
-rw-r--r--library/cpp/yt/misc/cast-inl.h30
-rw-r--r--library/cpp/yt/misc/cast.h10
-rw-r--r--library/cpp/yt/misc/enum.h3
-rw-r--r--library/cpp/yt/small_containers/compact_flat_map.h2
-rw-r--r--library/cpp/yt/string/format-inl.h104
-rw-r--r--library/cpp/yt/string/format.h60
-rw-r--r--library/cpp/yt/string/format_analyser.h40
-rw-r--r--library/cpp/yt/string/string_builder-inl.h121
-rw-r--r--library/cpp/yt/string/string_builder.cpp30
-rw-r--r--library/cpp/yt/string/string_builder.h80
-rw-r--r--library/cpp/yt/string/ya.make1
-rw-r--r--library/cpp/yt/threading/atomic_object-inl.h97
-rw-r--r--library/cpp/yt/threading/atomic_object.h63
37 files changed, 642 insertions, 263 deletions
diff --git a/library/cpp/containers/compact_vector/compact_vector.h b/library/cpp/containers/compact_vector/compact_vector.h
index 0c6c563d71..984ec6ac00 100644
--- a/library/cpp/containers/compact_vector/compact_vector.h
+++ b/library/cpp/containers/compact_vector/compact_vector.h
@@ -1,5 +1,6 @@
#pragma once
+#include <util/generic/bitops.h>
#include <util/generic/yexception.h>
#include <util/system/sys_alloc.h>
diff --git a/library/cpp/monlib/encode/buffered/string_pool.cpp b/library/cpp/monlib/encode/buffered/string_pool.cpp
index b4c7988ba3..0ac5c780fc 100644
--- a/library/cpp/monlib/encode/buffered/string_pool.cpp
+++ b/library/cpp/monlib/encode/buffered/string_pool.cpp
@@ -1,5 +1,7 @@
#include "string_pool.h"
+#include <util/generic/ylimits.h>
+
namespace NMonitoring {
////////////////////////////////////////////////////////////////////////////////
// TStringPoolBuilder
diff --git a/library/cpp/monlib/metrics/histogram_snapshot.h b/library/cpp/monlib/metrics/histogram_snapshot.h
index 6cd9f1dab5..88ea07cafd 100644
--- a/library/cpp/monlib/metrics/histogram_snapshot.h
+++ b/library/cpp/monlib/metrics/histogram_snapshot.h
@@ -4,6 +4,7 @@
#include <util/generic/ptr.h>
#include <util/generic/vector.h>
#include <util/generic/yexception.h>
+#include <util/generic/ylimits.h>
#include <cmath>
#include <limits>
diff --git a/library/cpp/netliba/v6/cpu_affinity.cpp b/library/cpp/netliba/v6/cpu_affinity.cpp
index 55b4c98b71..26544bc376 100644
--- a/library/cpp/netliba/v6/cpu_affinity.cpp
+++ b/library/cpp/netliba/v6/cpu_affinity.cpp
@@ -35,7 +35,7 @@ namespace NNetliba {
void Set(size_t i) {
CPU_SET(i, CpuInfo);
}
-#elif defined(_linux_)
+#elif defined(_linux_) && !defined(__ANDROID__)
public:
#define NUMCPU ((CPU_SETSIZE > MAX_SIZE) ? 1 : (MAX_SIZE / CPU_SETSIZE))
cpu_set_t CpuInfo[NUMCPU];
diff --git a/library/cpp/netliba/v6/ib_low.cpp b/library/cpp/netliba/v6/ib_low.cpp
index 4dff3ac5cd..99d77d593f 100644
--- a/library/cpp/netliba/v6/ib_low.cpp
+++ b/library/cpp/netliba/v6/ib_low.cpp
@@ -8,7 +8,7 @@ namespace NNetliba {
EnableROCEFlag = f;
}
-#if defined(_linux_)
+#if defined(_linux_) && !defined(__ANDROID__)
static TMutex IBPortMutex;
static TIntrusivePtr<TIBPort> IBPort;
static bool IBWasInitialized;
diff --git a/library/cpp/netliba/v6/ib_low.h b/library/cpp/netliba/v6/ib_low.h
index f75f1e5379..19be819b43 100644
--- a/library/cpp/netliba/v6/ib_low.h
+++ b/library/cpp/netliba/v6/ib_low.h
@@ -2,7 +2,7 @@
#include "udp_address.h"
-#if defined(_linux_)
+#if defined(_linux_) && !defined(__ANDROID__)
#include <contrib/libs/ibdrv/include/infiniband/verbs.h>
#include <contrib/libs/ibdrv/include/rdma/rdma_cma.h>
#endif
@@ -22,7 +22,7 @@ namespace NNetliba {
const size_t MAX_INLINE_DATA_SIZE = 16;
const int MAX_OUTSTANDING_RDMA = 10;
-#if defined(_linux_)
+#if defined(_linux_) && !defined(__ANDROID__)
class TIBContext: public TThrRefBase, TNonCopyable {
ibv_context* Context;
ibv_pd* ProtDomain;
diff --git a/library/cpp/resource/registry.cpp b/library/cpp/resource/registry.cpp
index 28300043d2..62d49c9c90 100644
--- a/library/cpp/resource/registry.cpp
+++ b/library/cpp/resource/registry.cpp
@@ -21,6 +21,33 @@ namespace {
typedef std::pair<TStringBuf, TStringBuf> TDescriptor;
+ [[noreturn]]
+ void ReportRedefinitionError(const TStringBuf key, const TStringBuf data, const ui64 kk, const TDescriptor& prev) noexcept {
+ const auto& [prevKey, value] = prev;
+ Y_ABORT_UNLESS(key == prevKey, "Internal hash collision:"
+ " old key: %s,"
+ " new key: %s,"
+ " hash: %" PRIx64 ".",
+ TString{prevKey}.Quote().c_str(),
+ TString{key}.Quote().c_str(),
+ kk);
+ size_t vsize = GetCodec()->DecompressedLength(value);
+ size_t dsize = GetCodec()->DecompressedLength(data);
+ if (vsize + dsize < 1000) {
+ Y_ABORT_UNLESS(false, "Redefinition of key %s:\n"
+ " old value: %s,\n"
+ " new value: %s.",
+ TString{key}.Quote().c_str(),
+ Decompress(value).Quote().c_str(),
+ Decompress(data).Quote().c_str());
+ } else {
+ Y_ABORT_UNLESS(false, "Redefinition of key %s,"
+ " old size: %zu,"
+ " new size: %zu.",
+ TString{key}.Quote().c_str(), vsize, dsize);
+ }
+ }
+
struct TStore final: public IStore, public absl::flat_hash_map<ui64, TDescriptor*> {
static inline ui64 ToK(TStringBuf k) {
return NHashPrivate::ComputeStringHash(k.data(), k.size());
@@ -29,28 +56,16 @@ namespace {
void Store(const TStringBuf key, const TStringBuf data) override {
auto kk = ToK(key);
- if (contains(kk)) {
- const TStringBuf value = (*this)[kk]->second;
+ const auto [it, unique] = try_emplace(kk, nullptr);
+ if (!unique) {
+ const auto& [_, value] = *it->second;
if (value != data) {
- size_t vsize = GetCodec()->DecompressedLength(value);
- size_t dsize = GetCodec()->DecompressedLength(data);
- if (vsize + dsize < 1000) {
- Y_ABORT_UNLESS(false, "Redefinition of key %s:\n"
- " old value: %s,\n"
- " new value: %s.",
- TString{key}.Quote().c_str(),
- Decompress(value).Quote().c_str(),
- Decompress(data).Quote().c_str());
- } else {
- Y_ABORT_UNLESS(false, "Redefinition of key %s,"
- " old size: %zu,"
- " new size: %zu.",
- TString{key}.Quote().c_str(), vsize, dsize);
- }
+ ReportRedefinitionError(key, data, kk, *it->second);
+ Y_UNREACHABLE();
}
} else {
D_.push_back(TDescriptor(key, data));
- (*this)[kk] = &D_.back();
+ it->second = &D_.back();
}
Y_ABORT_UNLESS(size() == Count(), "size mismatch");
diff --git a/library/cpp/skiff/public.h b/library/cpp/skiff/public.h
index d67c6f26ee..aa2c0a5bb4 100644
--- a/library/cpp/skiff/public.h
+++ b/library/cpp/skiff/public.h
@@ -15,11 +15,13 @@ enum class EWireType
Int32 /* "int32" */,
Int64 /* "int64" */,
Int128 /* "int128" */,
+ Int256 /* "int256" */,
Uint8 /* "uint8" */,
Uint16 /* "uint16" */,
Uint32 /* "uint32" */,
Uint64 /* "uint64" */,
Uint128 /* "uint128" */,
+ Uint256 /* "uint256" */,
Double /* "double" */,
Boolean /* "boolean" */,
String32 /* "string32" */,
diff --git a/library/cpp/skiff/skiff.cpp b/library/cpp/skiff/skiff.cpp
index cbdbdfe364..9b42628cc6 100644
--- a/library/cpp/skiff/skiff.cpp
+++ b/library/cpp/skiff/skiff.cpp
@@ -32,6 +32,18 @@ bool operator!=(TUint128 lhs, TUint128 rhs)
////////////////////////////////////////////////////////////////////////////////
+bool operator==(const TInt256& lhs, const TInt256& rhs)
+{
+ return lhs.Parts == rhs.Parts;
+}
+
+bool operator==(const TUint256& lhs, const TUint256& rhs)
+{
+ return lhs.Parts == rhs.Parts;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
TUncheckedSkiffParser::TUncheckedSkiffParser(IZeroCopyInput* underlying)
: Underlying_(underlying)
, Buffer_(512 * 1024)
@@ -95,6 +107,26 @@ TUint128 TUncheckedSkiffParser::ParseUint128()
return {low, high};
}
+TInt256 TUncheckedSkiffParser::ParseInt256()
+{
+ TInt256 result;
+ for (auto& part : result.Parts) {
+ part = ParseSimple<ui64>();
+ }
+
+ return result;
+}
+
+TUint256 TUncheckedSkiffParser::ParseUint256()
+{
+ TUint256 result;
+ for (auto& part : result.Parts) {
+ part = ParseSimple<ui64>();
+ }
+
+ return result;
+}
+
double TUncheckedSkiffParser::ParseDouble()
{
return ParseSimple<double>();
@@ -274,6 +306,18 @@ TUint128 TCheckedSkiffParser::ParseUint128()
return Parser_.ParseUint128();
}
+TInt256 TCheckedSkiffParser::ParseInt256()
+{
+ Validator_->OnSimpleType(EWireType::Int256);
+ return Parser_.ParseInt256();
+}
+
+TUint256 TCheckedSkiffParser::ParseUint256()
+{
+ Validator_->OnSimpleType(EWireType::Uint256);
+ return Parser_.ParseUint256();
+}
+
double TCheckedSkiffParser::ParseDouble()
{
Validator_->OnSimpleType(EWireType::Double);
@@ -389,6 +433,20 @@ void TUncheckedSkiffWriter::WriteUint128(TUint128 value)
WriteSimple<ui64>(value.High);
}
+void TUncheckedSkiffWriter::WriteInt256(const TInt256& value)
+{
+ for (auto part : value.Parts) {
+ WriteSimple<ui64>(part);
+ }
+}
+
+void TUncheckedSkiffWriter::WriteUint256(const TUint256& value)
+{
+ for (auto part : value.Parts) {
+ WriteSimple<ui64>(part);
+ }
+}
+
void TUncheckedSkiffWriter::WriteUint8(ui8 value)
{
WriteSimple<ui8>(value);
@@ -551,6 +609,18 @@ void TCheckedSkiffWriter::WriteUint128(TUint128 value)
Writer_.WriteUint128(value);
}
+void TCheckedSkiffWriter::WriteInt256(TInt256 value)
+{
+ Validator_->OnSimpleType(EWireType::Int256);
+ Writer_.WriteInt256(std::move(value));
+}
+
+void TCheckedSkiffWriter::WriteUint256(TUint256 value)
+{
+ Validator_->OnSimpleType(EWireType::Uint256);
+ Writer_.WriteUint256(std::move(value));
+}
+
void TCheckedSkiffWriter::WriteString32(TStringBuf value)
{
Validator_->OnSimpleType(EWireType::String32);
diff --git a/library/cpp/skiff/skiff.h b/library/cpp/skiff/skiff.h
index 183c112700..c1315081d3 100644
--- a/library/cpp/skiff/skiff.h
+++ b/library/cpp/skiff/skiff.h
@@ -49,6 +49,23 @@ bool operator!=(TUint128 lhs, TUint128 rhs);
////////////////////////////////////////////////////////////////////////////////
+struct TInt256
+{
+ std::array<ui64, 4> Parts;
+};
+
+struct TUint256
+{
+ std::array<ui64, 4> Parts;
+};
+
+// Operator != is synthesized since C++ 20.
+bool operator==(const TInt256& lhs, const TInt256& rhs);
+
+bool operator==(const TUint256& lhs, const TUint256& rhs);
+
+////////////////////////////////////////////////////////////////////////////////
+
class TUncheckedSkiffParser
{
public:
@@ -68,6 +85,9 @@ public:
TInt128 ParseInt128();
TUint128 ParseUint128();
+ TInt256 ParseInt256();
+ TUint256 ParseUint256();
+
double ParseDouble();
bool ParseBoolean();
@@ -127,6 +147,9 @@ public:
TInt128 ParseInt128();
TUint128 ParseUint128();
+ TInt256 ParseInt256();
+ TUint256 ParseUint256();
+
double ParseDouble();
bool ParseBoolean();
@@ -177,6 +200,9 @@ public:
void WriteInt128(TInt128 value);
void WriteUint128(TUint128 value);
+ void WriteInt256(const TInt256& value);
+ void WriteUint256(const TUint256& value);
+
void WriteString32(TStringBuf value);
void WriteYson32(TStringBuf value);
@@ -223,6 +249,9 @@ public:
void WriteInt128(TInt128 value);
void WriteUint128(TUint128 value);
+ void WriteInt256(TInt256 value);
+ void WriteUint256(TUint256 value);
+
void WriteString32(TStringBuf value);
void WriteYson32(TStringBuf value);
diff --git a/library/cpp/skiff/skiff_schema-inl.h b/library/cpp/skiff/skiff_schema-inl.h
index 853ff36738..a977194180 100644
--- a/library/cpp/skiff/skiff_schema-inl.h
+++ b/library/cpp/skiff/skiff_schema-inl.h
@@ -19,12 +19,14 @@ inline bool IsSimpleType(EWireType type)
case EWireType::Int32:
case EWireType::Int64:
case EWireType::Int128:
+ case EWireType::Int256:
case EWireType::Uint8:
case EWireType::Uint16:
case EWireType::Uint32:
case EWireType::Uint64:
case EWireType::Uint128:
+ case EWireType::Uint256:
case EWireType::Double:
case EWireType::Boolean:
diff --git a/library/cpp/skiff/skiff_validator.cpp b/library/cpp/skiff/skiff_validator.cpp
index 76dd3b7600..a2e9e1db90 100644
--- a/library/cpp/skiff/skiff_validator.cpp
+++ b/library/cpp/skiff/skiff_validator.cpp
@@ -363,12 +363,14 @@ std::shared_ptr<IValidatorNode> CreateUsageValidatorNode(const std::shared_ptr<T
case EWireType::Int32:
case EWireType::Int64:
case EWireType::Int128:
+ case EWireType::Int256:
case EWireType::Uint8:
case EWireType::Uint16:
case EWireType::Uint32:
case EWireType::Uint64:
case EWireType::Uint128:
+ case EWireType::Uint256:
case EWireType::Double:
case EWireType::Boolean:
diff --git a/library/cpp/skiff/unittests/skiff_ut.cpp b/library/cpp/skiff/unittests/skiff_ut.cpp
index 5e4c709611..cdb09e7d52 100644
--- a/library/cpp/skiff/unittests/skiff_ut.cpp
+++ b/library/cpp/skiff/unittests/skiff_ut.cpp
@@ -209,6 +209,29 @@ Y_UNIT_TEST_SUITE(Skiff)
UNIT_ASSERT_EQUAL(parser.ParseInt128(), val2);
}
+ Y_UNIT_TEST(TestInt256)
+ {
+ TBufferStream bufferStream;
+
+ auto schema = CreateSimpleTypeSchema(EWireType::Int256);
+
+ const TInt256 val1 = {0x1924cd4aeb9ced82, 0x0885e83f456d6a7e, 0xe9ba36585eccae1a, 0x7854b6f9ce448be9};
+ const TInt256 val2 = {0xe9ba36585eccae1a, 0x1924cd4aeb9ced82, 0x0885e83f456d6a7e, static_cast<ui64>(-0x7854b6f9ce448be9)};
+
+ TCheckedSkiffWriter writer(schema, &bufferStream);
+ writer.WriteInt256(val1);
+ writer.WriteInt256(val2);
+ writer.Finish();
+
+ UNIT_ASSERT_VALUES_EQUAL(HexEncode(bufferStream.Buffer()),
+ "82ed9ceb4acd2419" "7e6a6d453fe88508" "1aaecc5e5836bae9" "e98b44cef9b65478"
+ "1aaecc5e5836bae9" "82ed9ceb4acd2419" "7e6a6d453fe88508" "1774bb310649ab87");
+
+ TCheckedSkiffParser parser(schema, &bufferStream);
+ UNIT_ASSERT_EQUAL(parser.ParseInt256(), val1);
+ UNIT_ASSERT_EQUAL(parser.ParseInt256(), val2);
+ }
+
Y_UNIT_TEST(TestUint128)
{
TBufferStream bufferStream;
@@ -232,6 +255,29 @@ Y_UNIT_TEST_SUITE(Skiff)
UNIT_ASSERT_EQUAL(parser.ParseUint128(), val2);
}
+ Y_UNIT_TEST(TestUint256)
+ {
+ TBufferStream bufferStream;
+
+ auto schema = CreateSimpleTypeSchema(EWireType::Uint256);
+
+ const auto val1 = TUint256{0x1924cd4aeb9ced82, 0x7854b6f9ce448be9, 0x8854b6f9ce448be9, 0x0885e83f456d6a7e};
+ const auto val2 = TUint256{0xe9ba36585eccae1a, 0x8854b6f9ce448be9, 0x1924cd4aeb9ced82, 0xabacabadabacaba0};
+
+ TCheckedSkiffWriter writer(schema, &bufferStream);
+ writer.WriteUint256(val1);
+ writer.WriteUint256(val2);
+ writer.Finish();
+
+ UNIT_ASSERT_VALUES_EQUAL(HexEncode(bufferStream.Buffer()),
+ "82ed9ceb4acd2419" "e98b44cef9b65478" "e98b44cef9b65488" "7e6a6d453fe88508"
+ "1aaecc5e5836bae9" "e98b44cef9b65488" "82ed9ceb4acd2419" "a0abacabadabacab");
+
+ TCheckedSkiffParser parser(schema, &bufferStream);
+ UNIT_ASSERT_EQUAL(parser.ParseUint256(), val1);
+ UNIT_ASSERT_EQUAL(parser.ParseUint256(), val2);
+ }
+
Y_UNIT_TEST(TestBoolean)
{
auto schema = CreateSimpleTypeSchema(EWireType::Boolean);
diff --git a/library/cpp/threading/equeue/fast/equeue.h b/library/cpp/threading/equeue/fast/equeue.h
index 0a3ba47184..f294a4513d 100644
--- a/library/cpp/threading/equeue/fast/equeue.h
+++ b/library/cpp/threading/equeue/fast/equeue.h
@@ -5,6 +5,7 @@
#include <util/datetime/base.h>
#include <util/thread/lfqueue.h>
#include <util/system/thread.h>
+#include <util/generic/bitops.h>
#include <util/generic/vector.h>
#include <util/generic/scope.h>
#include <util/stream/str.h>
diff --git a/library/cpp/tld/tlds-alpha-by-domain.txt b/library/cpp/tld/tlds-alpha-by-domain.txt
index 879392378d..f755065df7 100644
--- a/library/cpp/tld/tlds-alpha-by-domain.txt
+++ b/library/cpp/tld/tlds-alpha-by-domain.txt
@@ -1,4 +1,4 @@
-# Version 2024100700, Last Updated Mon Oct 7 07:07:01 2024 UTC
+# Version 2024101300, Last Updated Sun Oct 13 07:07:01 2024 UTC
AAA
AARP
ABB
diff --git a/library/cpp/unified_agent_client/client_impl.cpp b/library/cpp/unified_agent_client/client_impl.cpp
index 17e2cd6b9d..bd2859f466 100644
--- a/library/cpp/unified_agent_client/client_impl.cpp
+++ b/library/cpp/unified_agent_client/client_impl.cpp
@@ -1222,10 +1222,10 @@ namespace NUnifiedAgent::NPrivate {
namespace NUnifiedAgent {
size_t SizeOf(const TClientMessage& message) {
- auto result = message.Payload.Size() + sizeof(TInstant);
+ auto result = message.Payload.size() + sizeof(TInstant);
if (message.Meta.Defined()) {
for (const auto& m: *message.Meta) {
- result += m.first.Size() + m.second.Size();
+ result += m.first.size() + m.second.size();
}
}
return result;
diff --git a/library/cpp/unified_agent_client/examples/ua_grpc_client/main.cpp b/library/cpp/unified_agent_client/examples/ua_grpc_client/main.cpp
index 8f247cf9ad..188491eb7a 100644
--- a/library/cpp/unified_agent_client/examples/ua_grpc_client/main.cpp
+++ b/library/cpp/unified_agent_client/examples/ua_grpc_client/main.cpp
@@ -74,12 +74,12 @@ int main(int argc, const char* argv[]) {
{
TLog emptyLog;
auto clientParameters = TClientParameters(options.Uri).SetLog(emptyLog);
- if (!options.SharedSecretKey.Empty()) {
+ if (!options.SharedSecretKey.empty()) {
clientParameters.SetSharedSecretKey(options.SharedSecretKey);
}
auto clientPtr = MakeClient(clientParameters);
auto sessionParameters = TSessionParameters();
- if (!options.SessionId.Empty()) {
+ if (!options.SessionId.empty()) {
sessionParameters.SetSessionId(options.SessionId);
}
if (!options.SessionMeta.empty()) {
@@ -95,7 +95,7 @@ int main(int argc, const char* argv[]) {
TString line;
while (true) {
Cin.ReadLine(line);
- if (line.Empty()) {
+ if (line.empty()) {
break;
}
diff --git a/library/cpp/unified_agent_client/grpc_io.cpp b/library/cpp/unified_agent_client/grpc_io.cpp
index 8c679ea924..0eb17e5d30 100644
--- a/library/cpp/unified_agent_client/grpc_io.cpp
+++ b/library/cpp/unified_agent_client/grpc_io.cpp
@@ -143,7 +143,7 @@ namespace NUnifiedAgent {
std::call_once(GrpcConfigured, []() {
const auto limitStr = GetEnv("UA_GRPC_EXECUTOR_THREADS_LIMIT");
ui64 limit;
- if (limitStr.Empty() || !TryFromString(limitStr, limit)) {
+ if (limitStr.empty() || !TryFromString(limitStr, limit)) {
limit = 2;
}
grpc_core::Executor::SetThreadsLimit(limit);
diff --git a/library/cpp/unified_agent_client/logger.cpp b/library/cpp/unified_agent_client/logger.cpp
index abe049d7eb..8afc5499ef 100644
--- a/library/cpp/unified_agent_client/logger.cpp
+++ b/library/cpp/unified_agent_client/logger.cpp
@@ -20,7 +20,7 @@ namespace NUnifiedAgent {
<< " " << GetPID()
<< " " << TThread::CurrentThreadId()
<< " " << logLevel;
- if (!scope.Empty()) {
+ if (!scope.empty()) {
output << " " << scope;
}
output << " " << message << "\n";
diff --git a/library/cpp/unified_agent_client/proto_weighing.cpp b/library/cpp/unified_agent_client/proto_weighing.cpp
index 7a532213ea..2c3e32dc10 100644
--- a/library/cpp/unified_agent_client/proto_weighing.cpp
+++ b/library/cpp/unified_agent_client/proto_weighing.cpp
@@ -84,7 +84,7 @@ namespace NUnifiedAgent::NPW {
}
void TStringField::SetValue(const TString& value) {
- Link.SetValueSize(value.Empty(), value.Size() + SizeOf(static_cast<ui32>(value.Size())));
+ Link.SetValueSize(value.empty(), value.size() + SizeOf(static_cast<ui32>(value.size())));
}
template class TNumberField<ui64>;
diff --git a/library/cpp/yson/varint.cpp b/library/cpp/yson/varint.cpp
index deed1fdbd6..ff451990f9 100644
--- a/library/cpp/yson/varint.cpp
+++ b/library/cpp/yson/varint.cpp
@@ -3,6 +3,7 @@
#include "zigzag.h"
#include <util/generic/yexception.h>
+#include <util/generic/ylimits.h>
namespace NYson {
////////////////////////////////////////////////////////////////////////////////
diff --git a/library/cpp/yt/logging/unittests/static_analysis_ut.cpp b/library/cpp/yt/logging/unittests/static_analysis_ut.cpp
index 7fb4c0150c..b9a01b334f 100644
--- a/library/cpp/yt/logging/unittests/static_analysis_ut.cpp
+++ b/library/cpp/yt/logging/unittests/static_analysis_ut.cpp
@@ -23,15 +23,15 @@ TEST(TStaticAnalysisTest, ValidFormats)
}
// Uncomment this test to see that we don't have false negatives!
-// TEST(TStaticAnalysisTest, InvalidFormats)
-// {
-// YT_LOG_INFO("Hello", 1);
-// YT_LOG_INFO("Hello %");
-// YT_LOG_INFO("Hello %false");
-// YT_LOG_INFO("Hello ", "World");
-// YT_LOG_INFO("Hello ", "(World: %v)", 42);
-// YT_LOG_INFO("Hello %lbov", 42); // There is no 'b' flag.
-// }
+TEST(TStaticAnalysisTest, InvalidFormats)
+{
+ // YT_LOG_INFO("Hello", 1);
+ // YT_LOG_INFO("Hello %");
+ // YT_LOG_INFO("Hello %false");
+ // YT_LOG_INFO("Hello ", "World");
+ // YT_LOG_INFO("Hello ", "(World: %v)", 42);
+ // YT_LOG_INFO("Hello %lbov", 42); // There is no 'b' flag.
+}
////////////////////////////////////////////////////////////////////////////////
diff --git a/library/cpp/yt/malloc/malloc.cpp b/library/cpp/yt/malloc/malloc.cpp
index de45aa37fa..90da501518 100644
--- a/library/cpp/yt/malloc/malloc.cpp
+++ b/library/cpp/yt/malloc/malloc.cpp
@@ -12,7 +12,12 @@ extern "C" Y_WEAK size_t nallocx(size_t size, int /*flags*/) noexcept
return size;
}
-#ifndef _win_
+#if defined(__ANDROID__)
+extern "C" Y_WEAK size_t malloc_usable_size(const void* /*ptr*/)
+{
+ return 0;
+}
+#elif !defined(_win_)
extern "C" Y_WEAK size_t malloc_usable_size(void* /*ptr*/) noexcept
{
return 0;
diff --git a/library/cpp/yt/malloc/malloc.h b/library/cpp/yt/malloc/malloc.h
index 2b3efbfd00..8e3f03ccb4 100644
--- a/library/cpp/yt/malloc/malloc.h
+++ b/library/cpp/yt/malloc/malloc.h
@@ -1,8 +1,13 @@
#include <cstddef>
+
////////////////////////////////////////////////////////////////////////////////
+#if defined(__ANDROID__)
+extern "C" size_t malloc_usable_size(const void* ptr);
+#else
extern "C" size_t malloc_usable_size(void* ptr) noexcept;
+#endif
extern "C" size_t nallocx(size_t size, int flags) noexcept;
diff --git a/library/cpp/yt/misc/cast-inl.h b/library/cpp/yt/misc/cast-inl.h
index a694394f88..00e6e240b8 100644
--- a/library/cpp/yt/misc/cast-inl.h
+++ b/library/cpp/yt/misc/cast-inl.h
@@ -18,35 +18,35 @@ namespace NYT {
namespace NDetail {
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_signed_v<T> && std::is_signed_v<S>
{
return value >= std::numeric_limits<T>::lowest() && value <= std::numeric_limits<T>::max();
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_signed_v<T> && std::is_unsigned_v<S>
{
return value <= static_cast<typename std::make_unsigned<T>::type>(std::numeric_limits<T>::max());
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_unsigned_v<T> && std::is_signed_v<S>
{
return value >= 0 && static_cast<typename std::make_unsigned<S>::type>(value) <= std::numeric_limits<T>::max();
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_unsigned_v<T> && std::is_unsigned_v<S>
{
return value <= std::numeric_limits<T>::max();
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_enum_v<S>
{
return IsInIntegralRange<T>(static_cast<std::underlying_type_t<S>>(value));
@@ -79,10 +79,24 @@ inline TString FormatInvalidCastValue(char8_t value)
////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class S>
+constexpr bool CanFitSubtype()
+{
+ return NDetail::IsInIntegralRange<T>(std::numeric_limits<S>::min()) &&
+ NDetail::IsInIntegralRange<T>(std::numeric_limits<S>::max());
+}
+
+template <class T, class S>
+constexpr bool IsInIntegralRange(S value)
+{
+ return NDetail::IsInIntegralRange<T>(value);
+}
+
template <class T, class S>
-bool TryIntegralCast(S value, T* result)
+constexpr bool TryIntegralCast(S value, T* result)
{
- if (!NYT::NDetail::IsInIntegralRange<T>(value)) {
+ if (!NDetail::IsInIntegralRange<T>(value)) {
return false;
}
*result = static_cast<T>(value);
@@ -105,7 +119,7 @@ T CheckedIntegralCast(S value)
}
template <class T, class S>
-bool TryEnumCast(S value, T* result)
+constexpr bool TryEnumCast(S value, T* result)
{
std::underlying_type_t<T> underlying;
if (!TryIntegralCast<std::underlying_type_t<T>>(value, &underlying)) {
diff --git a/library/cpp/yt/misc/cast.h b/library/cpp/yt/misc/cast.h
index c7565c9e6d..e8654cc122 100644
--- a/library/cpp/yt/misc/cast.h
+++ b/library/cpp/yt/misc/cast.h
@@ -7,7 +7,13 @@ namespace NYT {
////////////////////////////////////////////////////////////////////////////////
template <class T, class S>
-bool TryIntegralCast(S value, T* result);
+constexpr bool CanFitSubtype();
+
+template <class T, class S>
+constexpr bool IsInIntegralRange(S value);
+
+template <class T, class S>
+constexpr bool TryIntegralCast(S value, T* result);
template <class T, class S>
T CheckedIntegralCast(S value);
@@ -15,7 +21,7 @@ T CheckedIntegralCast(S value);
////////////////////////////////////////////////////////////////////////////////
template <class T, class S>
-bool TryEnumCast(S value, T* result);
+constexpr bool TryEnumCast(S value, T* result);
template <class T, class S>
T CheckedEnumCast(S value);
diff --git a/library/cpp/yt/misc/enum.h b/library/cpp/yt/misc/enum.h
index 954b63cbc0..4d40ab8ec4 100644
--- a/library/cpp/yt/misc/enum.h
+++ b/library/cpp/yt/misc/enum.h
@@ -26,6 +26,9 @@ namespace NYT {
template <class T>
void GetEnumTraitsImpl(T);
+template <class T, class S>
+constexpr bool CanFitSubtype();
+
template <class T>
using TEnumTraitsImpl = decltype(GetEnumTraitsImpl(T()));
diff --git a/library/cpp/yt/small_containers/compact_flat_map.h b/library/cpp/yt/small_containers/compact_flat_map.h
index 120c2141b9..d4e9366843 100644
--- a/library/cpp/yt/small_containers/compact_flat_map.h
+++ b/library/cpp/yt/small_containers/compact_flat_map.h
@@ -4,6 +4,8 @@
namespace NYT {
+///////////////////////////////////////////////////////////////////////////////
+
namespace NDetail {
template <typename T>
diff --git a/library/cpp/yt/string/format-inl.h b/library/cpp/yt/string/format-inl.h
index 188a699a3d..7f1f725966 100644
--- a/library/cpp/yt/string/format-inl.h
+++ b/library/cpp/yt/string/format-inl.h
@@ -38,110 +38,6 @@ namespace NYT {
////////////////////////////////////////////////////////////////////////////////
-inline char* TStringBuilderBase::Preallocate(size_t size)
-{
- Reserve(size + GetLength());
- return Current_;
-}
-
-inline void TStringBuilderBase::Reserve(size_t size)
-{
- if (Y_UNLIKELY(End_ - Begin_ < static_cast<ssize_t>(size))) {
- size_t length = GetLength();
- auto newLength = std::max(size, MinBufferLength);
- DoReserve(newLength);
- Current_ = Begin_ + length;
- }
-}
-
-inline size_t TStringBuilderBase::GetLength() const
-{
- return Current_ ? Current_ - Begin_ : 0;
-}
-
-inline TStringBuf TStringBuilderBase::GetBuffer() const
-{
- return TStringBuf(Begin_, Current_);
-}
-
-inline void TStringBuilderBase::Advance(size_t size)
-{
- Current_ += size;
- YT_ASSERT(Current_ <= End_);
-}
-
-inline void TStringBuilderBase::AppendChar(char ch)
-{
- *Preallocate(1) = ch;
- Advance(1);
-}
-
-inline void TStringBuilderBase::AppendChar(char ch, int n)
-{
- YT_ASSERT(n >= 0);
- if (Y_LIKELY(0 != n)) {
- char* dst = Preallocate(n);
- ::memset(dst, ch, n);
- Advance(n);
- }
-}
-
-inline void TStringBuilderBase::AppendString(TStringBuf str)
-{
- if (Y_LIKELY(str)) {
- char* dst = Preallocate(str.length());
- ::memcpy(dst, str.begin(), str.length());
- Advance(str.length());
- }
-}
-
-inline void TStringBuilderBase::AppendString(const char* str)
-{
- AppendString(TStringBuf(str));
-}
-
-inline void TStringBuilderBase::Reset()
-{
- Begin_ = Current_ = End_ = nullptr;
- DoReset();
-}
-
-template <class... TArgs>
-void TStringBuilderBase::AppendFormat(TStringBuf format, TArgs&& ... args)
-{
- Format(this, TRuntimeFormat{format}, std::forward<TArgs>(args)...);
-}
-
-template <size_t Length, class... TArgs>
-void TStringBuilderBase::AppendFormat(const char (&format)[Length], TArgs&& ... args)
-{
- Format(this, TRuntimeFormat{format}, std::forward<TArgs>(args)...);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-inline TString TStringBuilder::Flush()
-{
- Buffer_.resize(GetLength());
- auto result = std::move(Buffer_);
- Reset();
- return result;
-}
-
-inline void TStringBuilder::DoReset()
-{
- Buffer_ = {};
-}
-
-inline void TStringBuilder::DoReserve(size_t newLength)
-{
- Buffer_.ReserveAndResize(newLength);
- auto capacity = Buffer_.capacity();
- Buffer_.ReserveAndResize(capacity);
- Begin_ = &*Buffer_.begin();
- End_ = Begin_ + capacity;
-}
-
inline void FormatValue(TStringBuilderBase* builder, const TStringBuilder& value, TStringBuf /*spec*/)
{
builder->AppendString(value.GetBuffer());
diff --git a/library/cpp/yt/string/format.h b/library/cpp/yt/string/format.h
index a6ab1f76f4..5e5a76db9d 100644
--- a/library/cpp/yt/string/format.h
+++ b/library/cpp/yt/string/format.h
@@ -1,6 +1,7 @@
#pragma once
#include "format_string.h"
+#include "string_builder.h"
#include <util/generic/string.h>
@@ -61,65 +62,6 @@ TString Format(TFormatString<TArgs...> format, TArgs&&... args);
////////////////////////////////////////////////////////////////////////////////
-// StringBuilder(Base) definition.
-
-//! A simple helper for constructing strings by a sequence of appends.
-class TStringBuilderBase
-{
-public:
- virtual ~TStringBuilderBase() = default;
-
- char* Preallocate(size_t size);
-
- void Reserve(size_t size);
-
- size_t GetLength() const;
-
- TStringBuf GetBuffer() const;
-
- void Advance(size_t size);
-
- void AppendChar(char ch);
- void AppendChar(char ch, int n);
-
- void AppendString(TStringBuf str);
- void AppendString(const char* str);
-
- template <size_t Length, class... TArgs>
- void AppendFormat(const char (&format)[Length], TArgs&&... args);
- template <class... TArgs>
- void AppendFormat(TStringBuf format, TArgs&&... args);
-
- void Reset();
-
-protected:
- char* Begin_ = nullptr;
- char* Current_ = nullptr;
- char* End_ = nullptr;
-
- virtual void DoReset() = 0;
- virtual void DoReserve(size_t newLength) = 0;
-
- static constexpr size_t MinBufferLength = 128;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-class TStringBuilder
- : public TStringBuilderBase
-{
-public:
- TString Flush();
-
-protected:
- TString Buffer_;
-
- void DoReset() override;
- void DoReserve(size_t size) override;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
template <class... TArgs>
void Format(TStringBuilderBase* builder, TFormatString<TArgs...> format, TArgs&&... args);
diff --git a/library/cpp/yt/string/format_analyser.h b/library/cpp/yt/string/format_analyser.h
index e8287ea8f3..20eee60580 100644
--- a/library/cpp/yt/string/format_analyser.h
+++ b/library/cpp/yt/string/format_analyser.h
@@ -24,27 +24,6 @@ public:
}
private:
- // Non-constexpr function call will terminate compilation.
- // Purposefully undefined and non-constexpr/consteval
- template <class T>
- static void CrashCompilerNotFormattable(std::string_view /*msg*/)
- { /*Suppress "internal linkage but undefined" warning*/ }
- static void CrashCompilerNotEnoughArguments(std::string_view /*msg*/)
- { }
-
- static void CrashCompilerTooManyArguments(std::string_view /*msg*/)
- { }
-
- static void CrashCompilerWrongTermination(std::string_view /*msg*/)
- { }
-
- static void CrashCompilerMissingTermination(std::string_view /*msg*/)
- { }
-
- static void CrashCompilerWrongFlagSpecifier(std::string_view /*msg*/)
- { }
-
-
static consteval bool Contains(std::string_view sv, char symbol)
{
return sv.find(symbol) != std::string_view::npos;
@@ -59,10 +38,6 @@ private:
template <class TArg>
static consteval auto GetSpecifiers()
{
- if constexpr (!CFormattable<TArg>) {
- CrashCompilerNotFormattable<TArg>("Your specialization of TFormatArg is broken");
- }
-
return TSpecifiers{
.Conversion = std::string_view{
std::data(TFormatArg<TArg>::ConversionSpecifiers),
@@ -103,8 +78,7 @@ private:
if (symbol == IntroductorySymbol) {
if (currentMarkerStart + 1 != index) {
// '%a% detected'
- CrashCompilerWrongTermination("You may not terminate flag sequence other than %% with \'%\' symbol");
- return;
+ throw "You may not terminate flag sequence other than %% with \'%\' symbol";
}
// '%%' detected --- skip
currentMarkerStart = -1;
@@ -113,9 +87,8 @@ private:
// We are inside of marker.
if (markerCount == std::ssize(markers)) {
- // To many markers
- CrashCompilerNotEnoughArguments("Number of arguments supplied to format is smaller than the number of flag sequences");
- return;
+ // Too many markers
+ throw "Number of arguments supplied to format is smaller than the number of flag sequences";
}
if (Contains(specifiers[markerCount].Conversion, symbol)) {
@@ -130,20 +103,19 @@ private:
}
if (!Contains(specifiers[markerCount].Flags, symbol)) {
- CrashCompilerWrongFlagSpecifier("Symbol is not a valid flag specifier; See FlagSpecifiers");
+ throw "Symbol is not a valid flag specifier; See FlagSpecifiers";
}
}
if (currentMarkerStart != -1) {
// Runaway marker.
- CrashCompilerMissingTermination("Unterminated flag sequence detected; Use \'%%\' to type plain %");
+ throw "Unterminated flag sequence detected; Use \'%%\' to type plain %";
return;
}
if (markerCount < std::ssize(markers)) {
// Missing markers.
- CrashCompilerTooManyArguments("Number of arguments supplied to format is greater than the number of flag sequences");
- return;
+ throw "Number of arguments supplied to format is greater than the number of flag sequences";
}
// TODO(arkady-e1ppa): Consider per-type verification
diff --git a/library/cpp/yt/string/string_builder-inl.h b/library/cpp/yt/string/string_builder-inl.h
new file mode 100644
index 0000000000..7027f9acc1
--- /dev/null
+++ b/library/cpp/yt/string/string_builder-inl.h
@@ -0,0 +1,121 @@
+#ifndef STRING_BUILDER_INL_H_
+#error "Direct inclusion of this file is not allowed, include string_builder.h"
+// For the sake of sane code completion.
+#include "string_builder.h"
+#endif
+
+#include "format_string.h"
+
+#include <library/cpp/yt/assert/assert.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline char* TStringBuilderBase::Preallocate(size_t size)
+{
+ Reserve(size + GetLength());
+ return Current_;
+}
+
+inline void TStringBuilderBase::Reserve(size_t size)
+{
+ if (Y_UNLIKELY(End_ - Begin_ < static_cast<ssize_t>(size))) {
+ size_t length = GetLength();
+ auto newLength = std::max(size, MinBufferLength);
+ DoReserve(newLength);
+ Current_ = Begin_ + length;
+ }
+}
+
+inline size_t TStringBuilderBase::GetLength() const
+{
+ return Current_ ? Current_ - Begin_ : 0;
+}
+
+inline TStringBuf TStringBuilderBase::GetBuffer() const
+{
+ return TStringBuf(Begin_, Current_);
+}
+
+inline void TStringBuilderBase::Advance(size_t size)
+{
+ Current_ += size;
+ YT_ASSERT(Current_ <= End_);
+}
+
+inline void TStringBuilderBase::AppendChar(char ch)
+{
+ *Preallocate(1) = ch;
+ Advance(1);
+}
+
+inline void TStringBuilderBase::AppendChar(char ch, int n)
+{
+ YT_ASSERT(n >= 0);
+ if (Y_LIKELY(0 != n)) {
+ char* dst = Preallocate(n);
+ ::memset(dst, ch, n);
+ Advance(n);
+ }
+}
+
+inline void TStringBuilderBase::AppendString(TStringBuf str)
+{
+ if (Y_LIKELY(str)) {
+ char* dst = Preallocate(str.length());
+ ::memcpy(dst, str.begin(), str.length());
+ Advance(str.length());
+ }
+}
+
+inline void TStringBuilderBase::AppendString(const char* str)
+{
+ AppendString(TStringBuf(str));
+}
+
+inline void TStringBuilderBase::Reset()
+{
+ Begin_ = Current_ = End_ = nullptr;
+ DoReset();
+}
+
+template <class... TArgs>
+void TStringBuilderBase::AppendFormat(TStringBuf format, TArgs&& ... args)
+{
+ Format(this, TRuntimeFormat{format}, std::forward<TArgs>(args)...);
+}
+
+template <size_t Length, class... TArgs>
+void TStringBuilderBase::AppendFormat(const char (&format)[Length], TArgs&& ... args)
+{
+ Format(this, TRuntimeFormat{format}, std::forward<TArgs>(args)...);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline TString TStringBuilder::Flush()
+{
+ Buffer_.resize(GetLength());
+ auto result = std::move(Buffer_);
+ Reset();
+ return result;
+}
+
+inline void TStringBuilder::DoReset()
+{
+ Buffer_ = {};
+}
+
+inline void TStringBuilder::DoReserve(size_t newLength)
+{
+ Buffer_.ReserveAndResize(newLength);
+ auto capacity = Buffer_.capacity();
+ Buffer_.ReserveAndResize(capacity);
+ Begin_ = &*Buffer_.begin();
+ End_ = Begin_ + capacity;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/string_builder.cpp b/library/cpp/yt/string/string_builder.cpp
new file mode 100644
index 0000000000..bca493fa32
--- /dev/null
+++ b/library/cpp/yt/string/string_builder.cpp
@@ -0,0 +1,30 @@
+#include "string_builder.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TDelimitedStringBuilderWrapper::TDelimitedStringBuilderWrapper(
+ TStringBuilderBase* builder,
+ TStringBuf delimiter)
+ : Builder_(builder)
+ , Delimiter_(delimiter)
+{ }
+
+TStringBuilderBase* TDelimitedStringBuilderWrapper::operator->()
+{
+ return operator&();
+}
+
+TStringBuilderBase* TDelimitedStringBuilderWrapper::operator&()
+{
+ if (!FirstCall_) {
+ Builder_->AppendString(Delimiter_);
+ }
+ FirstCall_ = false;
+ return Builder_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/string_builder.h b/library/cpp/yt/string/string_builder.h
index de1c1abb1e..ac3aa26a7c 100644
--- a/library/cpp/yt/string/string_builder.h
+++ b/library/cpp/yt/string/string_builder.h
@@ -1,13 +1,68 @@
#pragma once
-#include "format.h"
-
#include <util/generic/string.h>
namespace NYT {
////////////////////////////////////////////////////////////////////////////////
+//! A simple helper for constructing strings by a sequence of appends.
+class TStringBuilderBase
+{
+public:
+ virtual ~TStringBuilderBase() = default;
+
+ char* Preallocate(size_t size);
+
+ void Reserve(size_t size);
+
+ size_t GetLength() const;
+
+ TStringBuf GetBuffer() const;
+
+ void Advance(size_t size);
+
+ void AppendChar(char ch);
+ void AppendChar(char ch, int n);
+
+ void AppendString(TStringBuf str);
+ void AppendString(const char* str);
+
+ template <size_t Length, class... TArgs>
+ void AppendFormat(const char (&format)[Length], TArgs&&... args);
+ template <class... TArgs>
+ void AppendFormat(TStringBuf format, TArgs&&... args);
+
+ void Reset();
+
+protected:
+ char* Begin_ = nullptr;
+ char* Current_ = nullptr;
+ char* End_ = nullptr;
+
+ virtual void DoReset() = 0;
+ virtual void DoReserve(size_t newLength) = 0;
+
+ static constexpr size_t MinBufferLength = 128;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TStringBuilder
+ : public TStringBuilderBase
+{
+public:
+ TString Flush();
+
+protected:
+ TString Buffer_;
+
+ void DoReset() override;
+ void DoReserve(size_t size) override;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
//! Appends a certain delimiter starting from the second call.
class TDelimitedStringBuilderWrapper
: private TNonCopyable
@@ -15,19 +70,10 @@ class TDelimitedStringBuilderWrapper
public:
TDelimitedStringBuilderWrapper(
TStringBuilderBase* builder,
- TStringBuf delimiter = TStringBuf(", "))
- : Builder_(builder)
- , Delimiter_(delimiter)
- { }
-
- TStringBuilderBase* operator->()
- {
- if (!FirstCall_) {
- Builder_->AppendString(Delimiter_);
- }
- FirstCall_ = false;
- return Builder_;
- }
+ TStringBuf delimiter = TStringBuf(", "));
+
+ TStringBuilderBase* operator->();
+ TStringBuilderBase* operator&();
private:
TStringBuilderBase* const Builder_;
@@ -39,3 +85,7 @@ private:
////////////////////////////////////////////////////////////////////////////////
} // namespace NYT
+
+#define STRING_BUILDER_INL_H_
+#include "string_builder-inl.h"
+#undef STRING_BUILDER_INL_H_
diff --git a/library/cpp/yt/string/ya.make b/library/cpp/yt/string/ya.make
index db3a477b35..2071e0a115 100644
--- a/library/cpp/yt/string/ya.make
+++ b/library/cpp/yt/string/ya.make
@@ -8,6 +8,7 @@ SRCS(
string.cpp
format_string.cpp
format.cpp
+ string_builder.cpp
)
PEERDIR(
diff --git a/library/cpp/yt/threading/atomic_object-inl.h b/library/cpp/yt/threading/atomic_object-inl.h
new file mode 100644
index 0000000000..452f5a0bc7
--- /dev/null
+++ b/library/cpp/yt/threading/atomic_object-inl.h
@@ -0,0 +1,97 @@
+#ifndef ATOMIC_OBJECT_INL_H_
+#error "Direct inclusion of this file is not allowed, include atomic_object.h"
+// For the sake of sane code completion.
+#include "atomic_object.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+template <class U>
+TAtomicObject<T>::TAtomicObject(U&& u)
+ : Object_(std::forward<U>(u))
+{ }
+
+template <class T>
+template <class U>
+void TAtomicObject<T>::Store(U&& u)
+{
+ // NB: Using exchange to avoid destructing the old object while holding the lock.
+ std::ignore = Exchange(std::forward<U>(u));
+}
+
+template <class T>
+template <class U>
+T TAtomicObject<T>::Exchange(U&& u)
+{
+ T tmpObject = std::forward<U>(u);
+ {
+ auto guard = WriterGuard(Spinlock_);
+ std::swap(Object_, tmpObject);
+ }
+ return tmpObject;
+}
+
+template <class T>
+bool TAtomicObject<T>::CompareExchange(T& expected, const T& desired)
+{
+ auto guard = WriterGuard(Spinlock_);
+ if (Object_ == expected) {
+ auto oldObject = std::move(Object_);
+ Y_UNUSED(oldObject);
+ Object_ = desired;
+ guard.Release();
+ return true;
+ } else {
+ auto oldExpected = std::move(expected);
+ Y_UNUSED(oldExpected);
+ expected = Object_;
+ guard.Release();
+ return false;
+ }
+}
+
+template <class T>
+template <std::invocable<T&> F>
+std::invoke_result_t<F, T&> TAtomicObject<T>::Transform(const F& func)
+{
+ auto guard = WriterGuard(Spinlock_);
+ return func(Object_);
+}
+
+template <class T>
+template <std::invocable<const T&> F>
+std::invoke_result_t<F, const T&> TAtomicObject<T>::Read(const F& func) const
+{
+ auto guard = ReaderGuard(Spinlock_);
+ return func(Object_);
+}
+
+template <class T>
+T TAtomicObject<T>::Load() const
+{
+ auto guard = ReaderGuard(Spinlock_);
+ return Object_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TOriginal, class TSerialized>
+void ToProto(TSerialized* serialized, const TAtomicObject<TOriginal>& original)
+{
+ ToProto(serialized, original.Load());
+}
+
+template <class TOriginal, class TSerialized>
+void FromProto(TAtomicObject<TOriginal>* original, const TSerialized& serialized)
+{
+ TOriginal data;
+ FromProto(&data, serialized);
+ original->Store(std::move(data));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/threading/atomic_object.h b/library/cpp/yt/threading/atomic_object.h
new file mode 100644
index 0000000000..e986f872a0
--- /dev/null
+++ b/library/cpp/yt/threading/atomic_object.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <library/cpp/yt/threading/rw_spin_lock.h>
+
+#include <concepts>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A synchronization object to load and store nontrivial object.
+//! It looks like atomics but for objects.
+template <class T>
+class TAtomicObject
+{
+public:
+ TAtomicObject() = default;
+
+ template <class U>
+ TAtomicObject(U&& u);
+
+ template <class U>
+ void Store(U&& u);
+
+ //! Atomically replaces the old value with the new one and returns the old value.
+ template <class U>
+ T Exchange(U&& u);
+
+ //! Atomically checks if then current value equals #expected.
+ //! If so, replaces it with #desired and returns |true|.
+ //! Otherwise, copies it into #expected and returns |false|.
+ bool CompareExchange(T& expected, const T& desired);
+
+ //! Atomically transforms the value with function #func.
+ template <std::invocable<T&> F>
+ std::invoke_result_t<F, T&> Transform(const F& func);
+
+ //! Atomicaly reads the value with function #func.
+ template <std::invocable<const T&> F>
+ std::invoke_result_t<F, const T&> Read(const F& func) const;
+
+ T Load() const;
+
+private:
+ T Object_;
+ YT_DECLARE_SPIN_LOCK(NThreading::TReaderWriterSpinLock, Spinlock_);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TOriginal, class TSerialized>
+void ToProto(TSerialized* serialized, const TAtomicObject<TOriginal>& original);
+
+template <class TOriginal, class TSerialized>
+void FromProto(TAtomicObject<TOriginal>* original, const TSerialized& serialized);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define ATOMIC_OBJECT_INL_H_
+#include "atomic_object-inl.h"
+#undef ATOMIC_OBJECT_INL_H_