diff options
author | Alexander Smirnov <alex@ydb.tech> | 2024-10-16 12:11:24 +0000 |
---|---|---|
committer | Alexander Smirnov <alex@ydb.tech> | 2024-10-16 12:11:24 +0000 |
commit | 40811e93f3fdf9342a9295369994012420fac548 (patch) | |
tree | a8d85e094a9c21e10aa250f537c101fc2016a049 /library/cpp | |
parent | 30ebe5357bb143648c6be4d151ecd4944af81ada (diff) | |
parent | 28a0c4a9f297064538a018c512cd9bbd00a1a35d (diff) | |
download | ydb-40811e93f3fdf9342a9295369994012420fac548.tar.gz |
Merge branch 'rightlib' into mergelibs-241016-1210
Diffstat (limited to 'library/cpp')
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_ |