diff options
author | babenko <babenko@yandex-team.ru> | 2022-02-10 16:49:19 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:49:19 +0300 |
commit | cec37806d8847aa3db53bafc9e251d4aaf325c12 (patch) | |
tree | 4a61c191e93e31d9ab423e258c71ab43550ee3d2 | |
parent | 58cd0b86ed99a72df22479e26a20bc1c1e57e65e (diff) | |
download | ydb-cec37806d8847aa3db53bafc9e251d4aaf325c12.tar.gz |
Restoring authorship annotation for <babenko@yandex-team.ru>. Commit 1 of 2.
123 files changed, 11889 insertions, 11889 deletions
diff --git a/build/docs/all.md b/build/docs/all.md index 50051b596c..cfca68adcd 100644 --- a/build/docs/all.md +++ b/build/docs/all.md @@ -1022,7 +1022,7 @@ Available allocators are: "LF", "LF\_YT", "LF\_DBG", "YT", "J", "B", "BM", "C", - LF - lfalloc (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc) - LF\_YT - Allocator selection for YT (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc/yt/ya.make) - LF\_DBG - Debug allocator selection (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc/dbg/ya.make) - - YT - The YTAlloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/ytalloc/impl/ya.make) + - YT - The YTAlloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/ytalloc/impl/ya.make) - J - The JEMalloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/malloc/jemalloc) - B - The balloc allocator named Pyotr Popov and Anton Samokhvalov - Discussion: https://ironpeter.at.yandex-team.ru/replies.xml?item\_no=126 diff --git a/build/docs/readme.md b/build/docs/readme.md index 3db0a653c7..2e8d9699de 100644 --- a/build/docs/readme.md +++ b/build/docs/readme.md @@ -754,7 +754,7 @@ Available allocators are: "LF", "LF\_YT", "LF\_DBG", "YT", "J", "B", "BM", "C", - LF - lfalloc (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc) - LF\_YT - Allocator selection for YT (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc/yt/ya.make) - LF\_DBG - Debug allocator selection (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc/dbg/ya.make) - - YT - The YTAlloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/ytalloc/impl/ya.make) + - YT - The YTAlloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/ytalloc/impl/ya.make) - J - The JEMalloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/malloc/jemalloc) - B - The balloc allocator named Pyotr Popov and Anton Samokhvalov - Discussion: https://ironpeter.at.yandex-team.ru/replies.xml?item\_no=126 diff --git a/build/ymake.core.conf b/build/ymake.core.conf index 081833998b..3cd46963d0 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -1484,9 +1484,9 @@ when ($COMMON_LINK_SETTINGS == "yes") { "LOCKLESS" ? { PEERDIR+=library/cpp/malloc/lockless } - "YT" ? { - PEERDIR+=library/cpp/ytalloc/impl - } + "YT" ? { + PEERDIR+=library/cpp/ytalloc/impl + } } } @@ -1706,7 +1706,7 @@ module PY2_PROGRAM: _PY2_PROGRAM { otherwise { PEERDIR+=build/rules/py2_deprecation } - ASSERT(_OK You are using deprecated Python2-only code (PY2_PROGRAM). Please consider rewriting to Python 3.) + ASSERT(_OK You are using deprecated Python2-only code (PY2_PROGRAM). Please consider rewriting to Python 3.) } # tag:python-specific @@ -2187,7 +2187,7 @@ module PY2TEST: PYTEST_BIN { PEERDIR+=build/rules/py2_deprecation } SET(MODULE_LANG PY2) - ASSERT(_OK You are using deprecated Python2-only code (PY2TEST). Please consider rewriting to Python 3.) + ASSERT(_OK You are using deprecated Python2-only code (PY2TEST). Please consider rewriting to Python 3.) } # tag:python-specific tag:deprecated tag:test @@ -5008,7 +5008,7 @@ multimodule SANDBOX_TASK { PEERDIR+=build/rules/py2_deprecation } - ASSERT(_OK You are using deprecated Python2-only code (SANDBOX_TASK). Please consider rewriting to 2/3-compatible code.) + ASSERT(_OK You are using deprecated Python2-only code (SANDBOX_TASK). Please consider rewriting to 2/3-compatible code.) } module PY2: PY2_LIBRARY { PEERDIR(sandbox/sdk2 sandbox/sandboxsdk) @@ -5262,7 +5262,7 @@ macro ADD_PERL_MODULE(Dir, Module) { ### - LF - lfalloc (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc) ### - LF_YT - Allocator selection for YT (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc/yt/ya.make) ### - LF_DBG - Debug allocator selection (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/lfalloc/dbg/ya.make) -### - YT - The YTAlloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/ytalloc/impl/ya.make) +### - YT - The YTAlloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/ytalloc/impl/ya.make) ### - J - The JEMalloc allocator (https://a.yandex-team.ru/arc/trunk/arcadia/library/malloc/jemalloc) ### - B - The balloc allocator named Pyotr Popov and Anton Samokhvalov ### - Discussion: https://ironpeter.at.yandex-team.ru/replies.xml?item_no=126 diff --git a/library/cpp/actors/prof/tag.cpp b/library/cpp/actors/prof/tag.cpp index 9ccf03e1a9..acbc9f2c0c 100644 --- a/library/cpp/actors/prof/tag.cpp +++ b/library/cpp/actors/prof/tag.cpp @@ -7,7 +7,7 @@ #if defined(PROFILE_MEMORY_ALLOCATIONS) #include <library/cpp/lfalloc/dbg_info/dbg_info.h> -#include <library/cpp/ytalloc/api/ytalloc.h> +#include <library/cpp/ytalloc/api/ytalloc.h> #endif #include <util/generic/singleton.h> diff --git a/library/cpp/actors/prof/ya.make b/library/cpp/actors/prof/ya.make index b5e2497563..246d1a46d9 100644 --- a/library/cpp/actors/prof/ya.make +++ b/library/cpp/actors/prof/ya.make @@ -19,7 +19,7 @@ IF (PROFILE_MEMORY_ALLOCATIONS) PEERDIR( library/cpp/malloc/api library/cpp/lfalloc/dbg_info - library/cpp/ytalloc/api + library/cpp/ytalloc/api ) ENDIF() diff --git a/library/cpp/testing/common/probe.h b/library/cpp/testing/common/probe.h index 19910979b5..84ea8a0678 100644 --- a/library/cpp/testing/common/probe.h +++ b/library/cpp/testing/common/probe.h @@ -1,7 +1,7 @@ #pragma once #include <util/system/yassert.h> - + namespace NTesting { //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/testing/gtest_extensions/probe.h b/library/cpp/testing/gtest_extensions/probe.h index 7d1fee83d3..a477189408 100644 --- a/library/cpp/testing/gtest_extensions/probe.h +++ b/library/cpp/testing/gtest_extensions/probe.h @@ -1,7 +1,7 @@ #pragma once #include <util/system/yassert.h> - + #include <library/cpp/testing/common/probe.h> #include <gtest/gtest.h> diff --git a/library/cpp/ya.make b/library/cpp/ya.make index 8c1193b007..2af6d597a1 100644 --- a/library/cpp/ya.make +++ b/library/cpp/ya.make @@ -416,7 +416,7 @@ RECURSE( yson/node/pybind yson_pull yson_pull/ut - yt + yt zipatch ) @@ -426,7 +426,7 @@ IF (OS_LINUX) balloc/aba_agri_test balloc_market/test balloc_market/aba_agri_test - ytalloc + ytalloc rseq ) ENDIF() diff --git a/library/cpp/yson/public.h b/library/cpp/yson/public.h index 1ed793592b..1b95a930e8 100644 --- a/library/cpp/yson/public.h +++ b/library/cpp/yson/public.h @@ -1,6 +1,6 @@ #pragma once -#include <library/cpp/yt/misc/enum.h> +#include <library/cpp/yt/misc/enum.h> #include <util/generic/yexception.h> #include <library/cpp/yt/yson_string/public.h> diff --git a/library/cpp/yson/ya.make b/library/cpp/yson/ya.make index c55a189b10..b689933bff 100644 --- a/library/cpp/yson/ya.make +++ b/library/cpp/yson/ya.make @@ -6,7 +6,7 @@ OWNER( ) PEERDIR( - library/cpp/yt/misc + library/cpp/yt/misc library/cpp/yt/yson ) diff --git a/library/cpp/yt/assert/assert.cpp b/library/cpp/yt/assert/assert.cpp index 095357cdfa..0c393c2511 100644 --- a/library/cpp/yt/assert/assert.cpp +++ b/library/cpp/yt/assert/assert.cpp @@ -1,29 +1,29 @@ -#include "assert.h" - -#include <util/system/yassert.h> -#include <util/system/compiler.h> - -namespace NYT::NDetail { - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void AssertTrapImpl( - TStringBuf trapType, - TStringBuf expr, - TStringBuf file, - int line, - TStringBuf function) -{ - // Map to Arcadia assert, poorly... - ::NPrivate::Panic( - ::NPrivate::TStaticBuf(file.data(), file.length()), - line, - function.data(), - expr.data(), - "%s", - trapType.data()); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NDetail +#include "assert.h" + +#include <util/system/yassert.h> +#include <util/system/compiler.h> + +namespace NYT::NDetail { + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK void AssertTrapImpl( + TStringBuf trapType, + TStringBuf expr, + TStringBuf file, + int line, + TStringBuf function) +{ + // Map to Arcadia assert, poorly... + ::NPrivate::Panic( + ::NPrivate::TStaticBuf(file.data(), file.length()), + line, + function.data(), + expr.data(), + "%s", + trapType.data()); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NDetail diff --git a/library/cpp/yt/assert/assert.h b/library/cpp/yt/assert/assert.h index 7a9e761a3a..40f1d5d829 100644 --- a/library/cpp/yt/assert/assert.h +++ b/library/cpp/yt/assert/assert.h @@ -1,76 +1,76 @@ -#pragma once - -#include <util/system/compiler.h> -#include <util/system/src_root.h> - -#include <util/generic/strbuf.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -namespace NDetail { - -[[noreturn]] -void AssertTrapImpl( - TStringBuf trapType, - TStringBuf expr, - TStringBuf file, - int line, - TStringBuf function); - -} // namespace NDetail - -#ifdef __GNUC__ - #define YT_BUILTIN_TRAP() __builtin_trap() -#else - #define YT_BUILTIN_TRAP() std::terminate() -#endif - -#define YT_ASSERT_TRAP(trapType, expr) \ - ::NYT::NDetail::AssertTrapImpl(TStringBuf(trapType), TStringBuf(expr), __SOURCE_FILE_IMPL__.As<TStringBuf>(), __LINE__, TStringBuf(__FUNCTION__)); \ - Y_UNREACHABLE() \ - -#ifdef NDEBUG - #define YT_ASSERT(expr) \ - do { \ - if (false) { \ - (void) (expr); \ - } \ - } while (false) -#else - #define YT_ASSERT(expr) \ - do { \ - if (Y_UNLIKELY(!(expr))) { \ - YT_ASSERT_TRAP("YT_ASSERT", #expr); \ - } \ - } while (false) -#endif - -//! Same as |YT_ASSERT| but evaluates and checks the expression in both release and debug mode. -#define YT_VERIFY(expr) \ - do { \ - if (Y_UNLIKELY(!(expr))) { \ - YT_ASSERT_TRAP("YT_VERIFY", #expr); \ - } \ - } while (false) - -//! Fatal error code marker. Abnormally terminates the current process. -#ifdef YT_COMPILING_UDF - #define YT_ABORT() __YT_BUILTIN_ABORT() -#else - #define YT_ABORT() \ - do { \ - YT_ASSERT_TRAP("YT_ABORT", ""); \ - } while (false) -#endif - -//! Unimplemented code marker. Abnormally terminates the current process. -#define YT_UNIMPLEMENTED() \ - do { \ - YT_ASSERT_TRAP("YT_UNIMPLEMENTED", ""); \ - } while (false) - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#pragma once + +#include <util/system/compiler.h> +#include <util/system/src_root.h> + +#include <util/generic/strbuf.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + +[[noreturn]] +void AssertTrapImpl( + TStringBuf trapType, + TStringBuf expr, + TStringBuf file, + int line, + TStringBuf function); + +} // namespace NDetail + +#ifdef __GNUC__ + #define YT_BUILTIN_TRAP() __builtin_trap() +#else + #define YT_BUILTIN_TRAP() std::terminate() +#endif + +#define YT_ASSERT_TRAP(trapType, expr) \ + ::NYT::NDetail::AssertTrapImpl(TStringBuf(trapType), TStringBuf(expr), __SOURCE_FILE_IMPL__.As<TStringBuf>(), __LINE__, TStringBuf(__FUNCTION__)); \ + Y_UNREACHABLE() \ + +#ifdef NDEBUG + #define YT_ASSERT(expr) \ + do { \ + if (false) { \ + (void) (expr); \ + } \ + } while (false) +#else + #define YT_ASSERT(expr) \ + do { \ + if (Y_UNLIKELY(!(expr))) { \ + YT_ASSERT_TRAP("YT_ASSERT", #expr); \ + } \ + } while (false) +#endif + +//! Same as |YT_ASSERT| but evaluates and checks the expression in both release and debug mode. +#define YT_VERIFY(expr) \ + do { \ + if (Y_UNLIKELY(!(expr))) { \ + YT_ASSERT_TRAP("YT_VERIFY", #expr); \ + } \ + } while (false) + +//! Fatal error code marker. Abnormally terminates the current process. +#ifdef YT_COMPILING_UDF + #define YT_ABORT() __YT_BUILTIN_ABORT() +#else + #define YT_ABORT() \ + do { \ + YT_ASSERT_TRAP("YT_ABORT", ""); \ + } while (false) +#endif + +//! Unimplemented code marker. Abnormally terminates the current process. +#define YT_UNIMPLEMENTED() \ + do { \ + YT_ASSERT_TRAP("YT_UNIMPLEMENTED", ""); \ + } while (false) + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/assert/ya.make b/library/cpp/yt/assert/ya.make index df74a4f1fa..19358ca018 100644 --- a/library/cpp/yt/assert/ya.make +++ b/library/cpp/yt/assert/ya.make @@ -1,9 +1,9 @@ -LIBRARY() - -OWNER(g:yt) - -SRCS( - assert.cpp -) - -END() +LIBRARY() + +OWNER(g:yt) + +SRCS( + assert.cpp +) + +END() diff --git a/library/cpp/yt/coding/unittests/varint_ut.cpp b/library/cpp/yt/coding/unittests/varint_ut.cpp index ed83ab5c92..8ebfdfbed8 100644 --- a/library/cpp/yt/coding/unittests/varint_ut.cpp +++ b/library/cpp/yt/coding/unittests/varint_ut.cpp @@ -1,134 +1,134 @@ -#include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/yt/coding/varint.h> - -#include <util/random/random.h> - -#include <util/string/escape.h> - -#include <tuple> - -namespace NYT { -namespace { - -using ::testing::Values; - -//////////////////////////////////////////////////////////////////////////////// - -class TWriteVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> > -{ }; - -TEST_P(TWriteVarIntTest, Serialization) -{ - ui64 value = std::get<0>(GetParam()); - TString rightAnswer = std::get<1>(GetParam()); - - TStringStream outputStream; - WriteVarUint64(&outputStream, value); - EXPECT_EQ(rightAnswer, outputStream.Str()); -} - -//////////////////////////////////////////////////////////////////////////////// - -class TReadVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> > -{ }; - -TEST_P(TReadVarIntTest, Serialization) -{ - ui64 rightAnswer = std::get<0>(GetParam()); - TString input = std::get<1>(GetParam()); - - TStringInput inputStream(input); - ui64 value; - ReadVarUint64(&inputStream, &value); - EXPECT_EQ(rightAnswer, value); -} - -TEST(TReadVarIntTest, Overflow) -{ - TString input("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 11); - TStringInput inputStream(input); - ui64 value; - EXPECT_ANY_THROW(ReadVarUint64(&inputStream, &value)); -} - -//////////////////////////////////////////////////////////////////////////////// - -auto ValuesForVarIntTests = Values( - // Simple cases. - std::make_tuple(0x0ull, TString("\x00", 1)), - std::make_tuple(0x1ull, TString("\x01", 1)), - std::make_tuple(0x2ull, TString("\x02", 1)), - std::make_tuple(0x3ull, TString("\x03", 1)), - std::make_tuple(0x4ull, TString("\x04", 1)), - - // The following "magic numbers" are critical points for varint encoding. - std::make_tuple((1ull << 7) - 1, TString("\x7f", 1)), - std::make_tuple((1ull << 7), TString("\x80\x01", 2)), - std::make_tuple((1ull << 14) - 1, TString("\xff\x7f", 2)), - std::make_tuple((1ull << 14), TString("\x80\x80\x01", 3)), - std::make_tuple((1ull << 21) - 1, TString("\xff\xff\x7f", 3)), - std::make_tuple((1ull << 21), TString("\x80\x80\x80\x01", 4)), - std::make_tuple((1ull << 28) - 1, TString("\xff\xff\xff\x7f", 4)), - std::make_tuple((1ull << 28), TString("\x80\x80\x80\x80\x01", 5)), - std::make_tuple((1ull << 35) - 1, TString("\xff\xff\xff\xff\x7f", 5)), - std::make_tuple((1ull << 35), TString("\x80\x80\x80\x80\x80\x01", 6)), - std::make_tuple((1ull << 42) - 1, TString("\xff\xff\xff\xff\xff\x7f", 6)), - std::make_tuple((1ull << 42), TString("\x80\x80\x80\x80\x80\x80\x01", 7)), - std::make_tuple((1ull << 49) - 1, TString("\xff\xff\xff\xff\xff\xff\x7f", 7)), - std::make_tuple((1ull << 49), TString("\x80\x80\x80\x80\x80\x80\x80\x01", 8)), - std::make_tuple((1ull << 56) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\x7f", 8)), - std::make_tuple((1ull << 56), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x01", 9)), - std::make_tuple((1ull << 63) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\xff\x7f", 9)), - std::make_tuple((1ull << 63), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 10)), - - // Boundary case. - std::make_tuple(static_cast<ui64>(-1), TString("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", 10)) -); - -INSTANTIATE_TEST_SUITE_P(ValueParametrized, TWriteVarIntTest, - ValuesForVarIntTests); - -INSTANTIATE_TEST_SUITE_P(ValueParametrized, TReadVarIntTest, - ValuesForVarIntTests); - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TVarInt32Test, RandomValues) -{ - srand(100500); // Set seed - const int numberOfValues = 10000; - - TStringStream stream; - for (int i = 0; i < numberOfValues; ++i) { - i32 expected = static_cast<i32>(RandomNumber<ui32>()); - WriteVarInt32(&stream, expected); - i32 actual; - ReadVarInt32(&stream, &actual); - EXPECT_EQ(expected, actual) - << "Encoded Variant: " << EscapeC(stream.Str()); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TVarInt64Test, RandomValues) -{ - srand(100500); // Set seed - const int numberOfValues = 10000; - - TStringStream stream; - for (int i = 0; i < numberOfValues; ++i) { - i64 expected = static_cast<i64>(RandomNumber<ui64>()); - WriteVarInt64(&stream, expected); - i64 actual; - ReadVarInt64(&stream, &actual); - EXPECT_EQ(expected, actual) - << "Encoded Variant: " << EscapeC(stream.Str()); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/yt/coding/varint.h> + +#include <util/random/random.h> + +#include <util/string/escape.h> + +#include <tuple> + +namespace NYT { +namespace { + +using ::testing::Values; + +//////////////////////////////////////////////////////////////////////////////// + +class TWriteVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> > +{ }; + +TEST_P(TWriteVarIntTest, Serialization) +{ + ui64 value = std::get<0>(GetParam()); + TString rightAnswer = std::get<1>(GetParam()); + + TStringStream outputStream; + WriteVarUint64(&outputStream, value); + EXPECT_EQ(rightAnswer, outputStream.Str()); +} + +//////////////////////////////////////////////////////////////////////////////// + +class TReadVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> > +{ }; + +TEST_P(TReadVarIntTest, Serialization) +{ + ui64 rightAnswer = std::get<0>(GetParam()); + TString input = std::get<1>(GetParam()); + + TStringInput inputStream(input); + ui64 value; + ReadVarUint64(&inputStream, &value); + EXPECT_EQ(rightAnswer, value); +} + +TEST(TReadVarIntTest, Overflow) +{ + TString input("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 11); + TStringInput inputStream(input); + ui64 value; + EXPECT_ANY_THROW(ReadVarUint64(&inputStream, &value)); +} + +//////////////////////////////////////////////////////////////////////////////// + +auto ValuesForVarIntTests = Values( + // Simple cases. + std::make_tuple(0x0ull, TString("\x00", 1)), + std::make_tuple(0x1ull, TString("\x01", 1)), + std::make_tuple(0x2ull, TString("\x02", 1)), + std::make_tuple(0x3ull, TString("\x03", 1)), + std::make_tuple(0x4ull, TString("\x04", 1)), + + // The following "magic numbers" are critical points for varint encoding. + std::make_tuple((1ull << 7) - 1, TString("\x7f", 1)), + std::make_tuple((1ull << 7), TString("\x80\x01", 2)), + std::make_tuple((1ull << 14) - 1, TString("\xff\x7f", 2)), + std::make_tuple((1ull << 14), TString("\x80\x80\x01", 3)), + std::make_tuple((1ull << 21) - 1, TString("\xff\xff\x7f", 3)), + std::make_tuple((1ull << 21), TString("\x80\x80\x80\x01", 4)), + std::make_tuple((1ull << 28) - 1, TString("\xff\xff\xff\x7f", 4)), + std::make_tuple((1ull << 28), TString("\x80\x80\x80\x80\x01", 5)), + std::make_tuple((1ull << 35) - 1, TString("\xff\xff\xff\xff\x7f", 5)), + std::make_tuple((1ull << 35), TString("\x80\x80\x80\x80\x80\x01", 6)), + std::make_tuple((1ull << 42) - 1, TString("\xff\xff\xff\xff\xff\x7f", 6)), + std::make_tuple((1ull << 42), TString("\x80\x80\x80\x80\x80\x80\x01", 7)), + std::make_tuple((1ull << 49) - 1, TString("\xff\xff\xff\xff\xff\xff\x7f", 7)), + std::make_tuple((1ull << 49), TString("\x80\x80\x80\x80\x80\x80\x80\x01", 8)), + std::make_tuple((1ull << 56) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\x7f", 8)), + std::make_tuple((1ull << 56), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x01", 9)), + std::make_tuple((1ull << 63) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\xff\x7f", 9)), + std::make_tuple((1ull << 63), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 10)), + + // Boundary case. + std::make_tuple(static_cast<ui64>(-1), TString("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", 10)) +); + +INSTANTIATE_TEST_SUITE_P(ValueParametrized, TWriteVarIntTest, + ValuesForVarIntTests); + +INSTANTIATE_TEST_SUITE_P(ValueParametrized, TReadVarIntTest, + ValuesForVarIntTests); + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TVarInt32Test, RandomValues) +{ + srand(100500); // Set seed + const int numberOfValues = 10000; + + TStringStream stream; + for (int i = 0; i < numberOfValues; ++i) { + i32 expected = static_cast<i32>(RandomNumber<ui32>()); + WriteVarInt32(&stream, expected); + i32 actual; + ReadVarInt32(&stream, &actual); + EXPECT_EQ(expected, actual) + << "Encoded Variant: " << EscapeC(stream.Str()); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TVarInt64Test, RandomValues) +{ + srand(100500); // Set seed + const int numberOfValues = 10000; + + TStringStream stream; + for (int i = 0; i < numberOfValues; ++i) { + i64 expected = static_cast<i64>(RandomNumber<ui64>()); + WriteVarInt64(&stream, expected); + i64 actual; + ReadVarInt64(&stream, &actual); + EXPECT_EQ(expected, actual) + << "Encoded Variant: " << EscapeC(stream.Str()); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/coding/unittests/ya.make b/library/cpp/yt/coding/unittests/ya.make index e0622db22d..23e4387fb2 100644 --- a/library/cpp/yt/coding/unittests/ya.make +++ b/library/cpp/yt/coding/unittests/ya.make @@ -1,15 +1,15 @@ -GTEST() - -OWNER(g:yt) - -SRCS( - zig_zag_ut.cpp - varint_ut.cpp -) - -PEERDIR( - library/cpp/yt/coding - library/cpp/testing/gtest -) - -END() +GTEST() + +OWNER(g:yt) + +SRCS( + zig_zag_ut.cpp + varint_ut.cpp +) + +PEERDIR( + library/cpp/yt/coding + library/cpp/testing/gtest +) + +END() diff --git a/library/cpp/yt/coding/unittests/zig_zag_ut.cpp b/library/cpp/yt/coding/unittests/zig_zag_ut.cpp index fae4e63064..ba092df287 100644 --- a/library/cpp/yt/coding/unittests/zig_zag_ut.cpp +++ b/library/cpp/yt/coding/unittests/zig_zag_ut.cpp @@ -1,57 +1,57 @@ -#include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/yt/coding/zig_zag.h> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TZigZagTest, Encode32) -{ - EXPECT_EQ(0u, ZigZagEncode32( 0)); - EXPECT_EQ(1u, ZigZagEncode32(-1)); - EXPECT_EQ(2u, ZigZagEncode32( 1)); - EXPECT_EQ(3u, ZigZagEncode32(-2)); - // ... - EXPECT_EQ(std::numeric_limits<ui32>::max() - 1, ZigZagEncode32(std::numeric_limits<i32>::max())); - EXPECT_EQ(std::numeric_limits<ui32>::max(), ZigZagEncode32(std::numeric_limits<i32>::min())); -} - -TEST(TZigZagTest, Decode32) -{ - EXPECT_EQ( 0, ZigZagDecode32(0)); - EXPECT_EQ(-1, ZigZagDecode32(1)); - EXPECT_EQ( 1, ZigZagDecode32(2)); - EXPECT_EQ(-2, ZigZagDecode32(3)); - // ... - EXPECT_EQ(std::numeric_limits<i32>::max(), ZigZagDecode32(std::numeric_limits<ui32>::max() - 1)); - EXPECT_EQ(std::numeric_limits<i32>::min(), ZigZagDecode32(std::numeric_limits<ui32>::max())); -} - -TEST(TZigZagTest, Encode64) -{ - EXPECT_EQ(0ull, ZigZagEncode64( 0)); - EXPECT_EQ(1ull, ZigZagEncode64(-1)); - EXPECT_EQ(2ull, ZigZagEncode64( 1)); - EXPECT_EQ(3ull, ZigZagEncode64(-2)); - // ... - EXPECT_EQ(std::numeric_limits<ui64>::max() - 1, ZigZagEncode64(std::numeric_limits<i64>::max())); - EXPECT_EQ(std::numeric_limits<ui64>::max(), ZigZagEncode64(std::numeric_limits<i64>::min())); -} - -TEST(TZigZagTest, Decode64) -{ - EXPECT_EQ(ZigZagDecode64(0), 0ll); - EXPECT_EQ(ZigZagDecode64(1), -1ll); - EXPECT_EQ(ZigZagDecode64(2), 1ll); - EXPECT_EQ(ZigZagDecode64(3), -2ll); - // ... - EXPECT_EQ(std::numeric_limits<i64>::max(), ZigZagDecode64(std::numeric_limits<ui64>::max() - 1)); - EXPECT_EQ(std::numeric_limits<i64>::min(), ZigZagDecode64(std::numeric_limits<ui64>::max())); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/yt/coding/zig_zag.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TZigZagTest, Encode32) +{ + EXPECT_EQ(0u, ZigZagEncode32( 0)); + EXPECT_EQ(1u, ZigZagEncode32(-1)); + EXPECT_EQ(2u, ZigZagEncode32( 1)); + EXPECT_EQ(3u, ZigZagEncode32(-2)); + // ... + EXPECT_EQ(std::numeric_limits<ui32>::max() - 1, ZigZagEncode32(std::numeric_limits<i32>::max())); + EXPECT_EQ(std::numeric_limits<ui32>::max(), ZigZagEncode32(std::numeric_limits<i32>::min())); +} + +TEST(TZigZagTest, Decode32) +{ + EXPECT_EQ( 0, ZigZagDecode32(0)); + EXPECT_EQ(-1, ZigZagDecode32(1)); + EXPECT_EQ( 1, ZigZagDecode32(2)); + EXPECT_EQ(-2, ZigZagDecode32(3)); + // ... + EXPECT_EQ(std::numeric_limits<i32>::max(), ZigZagDecode32(std::numeric_limits<ui32>::max() - 1)); + EXPECT_EQ(std::numeric_limits<i32>::min(), ZigZagDecode32(std::numeric_limits<ui32>::max())); +} + +TEST(TZigZagTest, Encode64) +{ + EXPECT_EQ(0ull, ZigZagEncode64( 0)); + EXPECT_EQ(1ull, ZigZagEncode64(-1)); + EXPECT_EQ(2ull, ZigZagEncode64( 1)); + EXPECT_EQ(3ull, ZigZagEncode64(-2)); + // ... + EXPECT_EQ(std::numeric_limits<ui64>::max() - 1, ZigZagEncode64(std::numeric_limits<i64>::max())); + EXPECT_EQ(std::numeric_limits<ui64>::max(), ZigZagEncode64(std::numeric_limits<i64>::min())); +} + +TEST(TZigZagTest, Decode64) +{ + EXPECT_EQ(ZigZagDecode64(0), 0ll); + EXPECT_EQ(ZigZagDecode64(1), -1ll); + EXPECT_EQ(ZigZagDecode64(2), 1ll); + EXPECT_EQ(ZigZagDecode64(3), -2ll); + // ... + EXPECT_EQ(std::numeric_limits<i64>::max(), ZigZagDecode64(std::numeric_limits<ui64>::max() - 1)); + EXPECT_EQ(std::numeric_limits<i64>::min(), ZigZagDecode64(std::numeric_limits<ui64>::max())); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/coding/varint-inl.h b/library/cpp/yt/coding/varint-inl.h index f0a09e9d30..c70b737af3 100644 --- a/library/cpp/yt/coding/varint-inl.h +++ b/library/cpp/yt/coding/varint-inl.h @@ -4,146 +4,146 @@ #include "varint.h" #endif -#include "zig_zag.h" - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -template <class TWriteCallback> +#include "zig_zag.h" + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class TWriteCallback> Y_FORCE_INLINE int WriteVarUint64Impl(TWriteCallback doWrite, ui64 value) -{ - bool stop = false; - int bytesWritten = 0; - while (!stop) { - ++bytesWritten; +{ + bool stop = false; + int bytesWritten = 0; + while (!stop) { + ++bytesWritten; ui8 byte = static_cast<ui8>(value | 0x80); - value >>= 7; - if (value == 0) { - stop = true; - byte &= 0x7F; - } - doWrite(byte); - } - return bytesWritten; -} - -// These are optimized versions of these Read/Write functions in protobuf/io/coded_stream.cc. + value >>= 7; + if (value == 0) { + stop = true; + byte &= 0x7F; + } + doWrite(byte); + } + return bytesWritten; +} + +// These are optimized versions of these Read/Write functions in protobuf/io/coded_stream.cc. Y_FORCE_INLINE int WriteVarUint64(IOutputStream* output, ui64 value) -{ +{ return WriteVarUint64Impl([&] (ui8 byte) { - output->Write(byte); - }, value); -} - + output->Write(byte); + }, value); +} + Y_FORCE_INLINE int WriteVarUint64(char* output, ui64 value) -{ +{ return WriteVarUint64Impl([&] (ui8 byte) { *output++ = byte; - }, value); -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class TOutput> + }, value); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class TOutput> Y_FORCE_INLINE int WriteVarUint32Impl(TOutput output, ui32 value) -{ +{ return WriteVarUint64(output, static_cast<ui64>(value)); -} - +} + Y_FORCE_INLINE int WriteVarUint32(IOutputStream* output, ui32 value) -{ +{ return WriteVarUint32Impl(output, value); -} - +} + Y_FORCE_INLINE int WriteVarUint32(char* output, ui32 value) -{ +{ return WriteVarUint32Impl(output, value); -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class TOutput> +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class TOutput> Y_FORCE_INLINE int WriteVarInt32Impl(TOutput output, i32 value) -{ +{ return WriteVarUint64(output, static_cast<ui64>(ZigZagEncode32(value))); -} - +} + Y_FORCE_INLINE int WriteVarInt32(IOutputStream* output, i32 value) -{ - return WriteVarInt32Impl(output, value); -} - +{ + return WriteVarInt32Impl(output, value); +} + Y_FORCE_INLINE int WriteVarInt32(char* output, i32 value) -{ - return WriteVarInt32Impl(output, value); -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class TOutput> +{ + return WriteVarInt32Impl(output, value); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class TOutput> Y_FORCE_INLINE int WriteVarInt64Impl(TOutput output, i64 value) -{ +{ return WriteVarUint64(output, static_cast<ui64>(ZigZagEncode64(value))); -} - +} + Y_FORCE_INLINE int WriteVarInt64(IOutputStream* output, i64 value) -{ - return WriteVarInt64Impl(output, value); -} - +{ + return WriteVarInt64Impl(output, value); +} + Y_FORCE_INLINE int WriteVarInt64(char* output, i64 value) -{ - return WriteVarInt64Impl(output, value); -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class TReadCallback> +{ + return WriteVarInt64Impl(output, value); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class TReadCallback> Y_FORCE_INLINE int ReadVarUint64Impl(TReadCallback doRead, ui64* value) -{ - size_t count = 0; - ui64 result = 0; - - ui8 byte; - do { - if (7 * count > 8 * sizeof(ui64) ) { - throw TSimpleException("Value is too big for varuint64"); - } - byte = doRead(); - result |= (static_cast<ui64> (byte & 0x7F)) << (7 * count); - ++count; - } while (byte & 0x80); - - *value = result; - return count; -} - +{ + size_t count = 0; + ui64 result = 0; + + ui8 byte; + do { + if (7 * count > 8 * sizeof(ui64) ) { + throw TSimpleException("Value is too big for varuint64"); + } + byte = doRead(); + result |= (static_cast<ui64> (byte & 0x7F)) << (7 * count); + ++count; + } while (byte & 0x80); + + *value = result; + return count; +} + Y_FORCE_INLINE int ReadVarUint64(IInputStream* input, ui64* value) -{ +{ return ReadVarUint64Impl([&] () { - char byte; - if (input->Read(&byte, 1) != 1) { - throw TSimpleException("Premature end of stream while reading varuint64"); - } - return byte; - }, value); -} - + char byte; + if (input->Read(&byte, 1) != 1) { + throw TSimpleException("Premature end of stream while reading varuint64"); + } + return byte; + }, value); +} + Y_FORCE_INLINE int ReadVarUint64(const char* input, ui64* value) -{ +{ return ReadVarUint64Impl([&] () { - char byte = *input; - ++input; - return byte; - }, value); -} - + char byte = *input; + ++input; + return byte; + }, value); +} + Y_FORCE_INLINE int ReadVarUint64(const char* input, const char* end, ui64* value) { return ReadVarUint64Impl([&] () { if (input == end) { - throw TSimpleException("Premature end of data while reading varuint64"); + throw TSimpleException("Premature end of data while reading varuint64"); } char byte = *input; ++input; @@ -151,90 +151,90 @@ Y_FORCE_INLINE int ReadVarUint64(const char* input, const char* end, ui64* value }, value); } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + template <class... Args> Y_FORCE_INLINE int ReadVarUint32Impl(ui32* value, Args... args) -{ - ui64 varInt; +{ + ui64 varInt; int bytesRead = ReadVarUint64(args..., &varInt); - if (varInt > std::numeric_limits<ui32>::max()) { - throw TSimpleException("Value is too big for varuint32"); - } - *value = static_cast<ui32>(varInt); - return bytesRead; -} - + if (varInt > std::numeric_limits<ui32>::max()) { + throw TSimpleException("Value is too big for varuint32"); + } + *value = static_cast<ui32>(varInt); + return bytesRead; +} + Y_FORCE_INLINE int ReadVarUint32(IInputStream* input, ui32* value) -{ +{ return ReadVarUint32Impl(value, input); -} - +} + Y_FORCE_INLINE int ReadVarUint32(const char* input, ui32* value) -{ +{ return ReadVarUint32Impl(value, input); -} - +} + Y_FORCE_INLINE int ReadVarUint32(const char* input, const char* end, ui32* value) { return ReadVarUint32Impl(value, input, end); } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + template <class... Args> Y_FORCE_INLINE int ReadVarInt32Impl(i32* value, Args... args) -{ - ui64 varInt; +{ + ui64 varInt; int bytesRead = ReadVarUint64(args..., &varInt); - if (varInt > std::numeric_limits<ui32>::max()) { - throw TSimpleException("Value is too big for varint32"); - } - *value = ZigZagDecode32(static_cast<ui32>(varInt)); - return bytesRead; -} - + if (varInt > std::numeric_limits<ui32>::max()) { + throw TSimpleException("Value is too big for varint32"); + } + *value = ZigZagDecode32(static_cast<ui32>(varInt)); + return bytesRead; +} + Y_FORCE_INLINE int ReadVarInt32(IInputStream* input, i32* value) -{ +{ return ReadVarInt32Impl(value, input); -} - +} + Y_FORCE_INLINE int ReadVarInt32(const char* input, i32* value) -{ +{ return ReadVarInt32Impl(value, input); -} - +} + Y_FORCE_INLINE int ReadVarInt32(const char* input, const char* end, i32* value) { return ReadVarInt32Impl(value, input, end); } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + template <class... Args> Y_FORCE_INLINE int ReadVarInt64Impl(i64* value, Args... args) -{ - ui64 varInt; +{ + ui64 varInt; int bytesRead = ReadVarUint64(args..., &varInt); - *value = ZigZagDecode64(varInt); - return bytesRead; -} - + *value = ZigZagDecode64(varInt); + return bytesRead; +} + Y_FORCE_INLINE int ReadVarInt64(IInputStream* input, i64* value) -{ +{ return ReadVarInt64Impl(value, input); -} - +} + Y_FORCE_INLINE int ReadVarInt64(const char* input, i64* value) -{ +{ return ReadVarInt64Impl(value, input); -} - +} + Y_FORCE_INLINE int ReadVarInt64(const char* input, const char* end, i64* value) { return ReadVarInt64Impl(value, input, end); } -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/coding/varint.h b/library/cpp/yt/coding/varint.h index c5399f8b06..78e7e5990c 100644 --- a/library/cpp/yt/coding/varint.h +++ b/library/cpp/yt/coding/varint.h @@ -1,23 +1,23 @@ #pragma once -#include <library/cpp/yt/exception/exception.h> - +#include <library/cpp/yt/exception/exception.h> + #include <util/system/defaults.h> -#include <util/stream/input.h> -#include <util/stream/output.h> +#include <util/stream/input.h> +#include <util/stream/output.h> namespace NYT { //////////////////////////////////////////////////////////////////////////////// -constexpr size_t MaxVarInt64Size = (8 * sizeof(ui64) - 1) / 7 + 1; -constexpr size_t MaxVarUint64Size = (8 * sizeof(ui64) - 1) / 7 + 1; +constexpr size_t MaxVarInt64Size = (8 * sizeof(ui64) - 1) / 7 + 1; +constexpr size_t MaxVarUint64Size = (8 * sizeof(ui64) - 1) / 7 + 1; -constexpr size_t MaxVarInt32Size = (8 * sizeof(ui32) - 1) / 7 + 1; -constexpr size_t MaxVarUint32Size = (8 * sizeof(ui32) - 1) / 7 + 1; +constexpr size_t MaxVarInt32Size = (8 * sizeof(ui32) - 1) / 7 + 1; +constexpr size_t MaxVarUint32Size = (8 * sizeof(ui32) - 1) / 7 + 1; -// Various functions to read/write varints. +// Various functions to read/write varints. // Returns the number of bytes written. int WriteVarUint64(IOutputStream* output, ui64 value); @@ -27,8 +27,8 @@ int WriteVarInt64(IOutputStream* output, i64 value); int WriteVarUint64(char* output, ui64 value); int WriteVarUint32(char* output, ui32 value); -int WriteVarInt32(char* output, i32 value); -int WriteVarInt64(char* output, i64 value); +int WriteVarInt32(char* output, i32 value); +int WriteVarInt64(char* output, i64 value); // Returns the number of bytes read. int ReadVarUint64(IInputStream* input, ui64* value); @@ -38,8 +38,8 @@ int ReadVarInt64(IInputStream* input, i64* value); int ReadVarUint64(const char* input, ui64* value); int ReadVarUint32(const char* input, ui32* value); -int ReadVarInt32(const char* input, i32* value); -int ReadVarInt64(const char* input, i64* value); +int ReadVarInt32(const char* input, i32* value); +int ReadVarInt64(const char* input, i64* value); // Throws exception if integer is not complete when `end' is reached. int ReadVarUint64(const char* input, const char* end, ui64* value); diff --git a/library/cpp/yt/coding/ya.make b/library/cpp/yt/coding/ya.make index 3dae919e57..ca7b97fbfb 100644 --- a/library/cpp/yt/coding/ya.make +++ b/library/cpp/yt/coding/ya.make @@ -1,12 +1,12 @@ -LIBRARY() - -SRCS( -) - -PEERDIR( - library/cpp/yt/exception -) - -END() - -RECURSE_FOR_TESTS(unittests) +LIBRARY() + +SRCS( +) + +PEERDIR( + library/cpp/yt/exception +) + +END() + +RECURSE_FOR_TESTS(unittests) diff --git a/library/cpp/yt/coding/zig_zag-inl.h b/library/cpp/yt/coding/zig_zag-inl.h index c611f7e1d4..67ad1f98b0 100644 --- a/library/cpp/yt/coding/zig_zag-inl.h +++ b/library/cpp/yt/coding/zig_zag-inl.h @@ -1,40 +1,40 @@ -#ifndef ZIG_ZAG_INL_H_ -#error "Direct inclusion of this file is not allowed, include zig_zag.h" -// For the sake of sane code completion. -#include "zig_zag.h" -#endif -#undef ZIG_ZAG_INL_H_ - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -inline ui32 ZigZagEncode32(i32 n) -{ - // Note: the right-shift must be arithmetic. - // Note: left shift must be unsigned because of overflow. - return (static_cast<ui32>(n) << 1) ^ static_cast<ui32>(n >> 31); -} - -inline i32 ZigZagDecode32(ui32 n) -{ - // Note: using unsigned types prevent undefined behavior. - return static_cast<i32>((n >> 1) ^ (~(n & 1) + 1)); -} - -inline ui64 ZigZagEncode64(i64 n) -{ - // Note: the right-shift must be arithmetic. - // Note: left shift must be unsigned because of overflow. - return (static_cast<ui64>(n) << 1) ^ static_cast<ui64>(n >> 63); -} - -inline i64 ZigZagDecode64(ui64 n) -{ - // Note: using unsigned types prevent undefined behavior. - return static_cast<i64>((n >> 1) ^ (~(n & 1) + 1)); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#ifndef ZIG_ZAG_INL_H_ +#error "Direct inclusion of this file is not allowed, include zig_zag.h" +// For the sake of sane code completion. +#include "zig_zag.h" +#endif +#undef ZIG_ZAG_INL_H_ + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +inline ui32 ZigZagEncode32(i32 n) +{ + // Note: the right-shift must be arithmetic. + // Note: left shift must be unsigned because of overflow. + return (static_cast<ui32>(n) << 1) ^ static_cast<ui32>(n >> 31); +} + +inline i32 ZigZagDecode32(ui32 n) +{ + // Note: using unsigned types prevent undefined behavior. + return static_cast<i32>((n >> 1) ^ (~(n & 1) + 1)); +} + +inline ui64 ZigZagEncode64(i64 n) +{ + // Note: the right-shift must be arithmetic. + // Note: left shift must be unsigned because of overflow. + return (static_cast<ui64>(n) << 1) ^ static_cast<ui64>(n >> 63); +} + +inline i64 ZigZagDecode64(ui64 n) +{ + // Note: using unsigned types prevent undefined behavior. + return static_cast<i64>((n >> 1) ^ (~(n & 1) + 1)); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/coding/zig_zag.h b/library/cpp/yt/coding/zig_zag.h index aa6d425a1c..19782704e7 100644 --- a/library/cpp/yt/coding/zig_zag.h +++ b/library/cpp/yt/coding/zig_zag.h @@ -1,24 +1,24 @@ #pragma once -#include <util/system/types.h> +#include <util/system/types.h> namespace NYT { //////////////////////////////////////////////////////////////////////////////// -// These Functions provide coding of integers with property: 0 <= f(x) <= 2 * |x| -// Actually taken 'as is' from protobuf/wire_format_lite.h +// These Functions provide coding of integers with property: 0 <= f(x) <= 2 * |x| +// Actually taken 'as is' from protobuf/wire_format_lite.h -ui32 ZigZagEncode32(i32 n); -i32 ZigZagDecode32(ui32 n); +ui32 ZigZagEncode32(i32 n); +i32 ZigZagDecode32(ui32 n); -ui64 ZigZagEncode64(i64 n); -i64 ZigZagDecode64(ui64 n); +ui64 ZigZagEncode64(i64 n); +i64 ZigZagDecode64(ui64 n); //////////////////////////////////////////////////////////////////////////////// } // namespace NYT - -#define ZIG_ZAG_INL_H_ -#include "zig_zag-inl.h" -#undef ZIG_ZAG_INL_H_ + +#define ZIG_ZAG_INL_H_ +#include "zig_zag-inl.h" +#undef ZIG_ZAG_INL_H_ diff --git a/library/cpp/yt/exception/exception.cpp b/library/cpp/yt/exception/exception.cpp index 1059d497e8..fee90ec2dd 100644 --- a/library/cpp/yt/exception/exception.cpp +++ b/library/cpp/yt/exception/exception.cpp @@ -1,48 +1,48 @@ -#include "exception.h" - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -TSimpleException::TSimpleException(TString message) - : Message_(std::move(message)) -{ } - -const TString& TSimpleException::GetMesage() const -{ - return Message_; -} - -const char* TSimpleException::what() const noexcept -{ - return Message_.c_str(); -} - -//////////////////////////////////////////////////////////////////////////////// - -TCompositeException::TCompositeException(TString message) - : TSimpleException(std::move(message)) - , What_(Message_) -{ } - -TCompositeException::TCompositeException( - const std::exception& exception, - TString message) - : TSimpleException(message) - , InnerException_(std::current_exception()) - , What_(message + "\n" + exception.what()) -{ } - -const std::exception_ptr& TCompositeException::GetInnerException() const -{ - return InnerException_; -} - -const char* TCompositeException::what() const noexcept -{ - return What_.c_str(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#include "exception.h" + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +TSimpleException::TSimpleException(TString message) + : Message_(std::move(message)) +{ } + +const TString& TSimpleException::GetMesage() const +{ + return Message_; +} + +const char* TSimpleException::what() const noexcept +{ + return Message_.c_str(); +} + +//////////////////////////////////////////////////////////////////////////////// + +TCompositeException::TCompositeException(TString message) + : TSimpleException(std::move(message)) + , What_(Message_) +{ } + +TCompositeException::TCompositeException( + const std::exception& exception, + TString message) + : TSimpleException(message) + , InnerException_(std::current_exception()) + , What_(message + "\n" + exception.what()) +{ } + +const std::exception_ptr& TCompositeException::GetInnerException() const +{ + return InnerException_; +} + +const char* TCompositeException::what() const noexcept +{ + return What_.c_str(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/exception/exception.h b/library/cpp/yt/exception/exception.h index 7d35637d60..9697c1d51f 100644 --- a/library/cpp/yt/exception/exception.h +++ b/library/cpp/yt/exception/exception.h @@ -1,45 +1,45 @@ -#pragma once - -#include <util/generic/string.h> - -#include <exception> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// -// These are poor man's versions of NYT::TErrorException to be used in -// a limited subset of core libraries that are needed to implement NYT::TError. - -class TSimpleException - : public std::exception -{ -public: - explicit TSimpleException(TString message); - - const TString& GetMesage() const; - const char* what() const noexcept override; - -protected: - const TString Message_; -}; - -class TCompositeException - : public TSimpleException -{ -public: - explicit TCompositeException(TString message); - TCompositeException( - const std::exception& exception, - TString message); - - const std::exception_ptr& GetInnerException() const; - const char* what() const noexcept override; - -private: - const std::exception_ptr InnerException_; - const TString What_; -}; - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#pragma once + +#include <util/generic/string.h> + +#include <exception> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// +// These are poor man's versions of NYT::TErrorException to be used in +// a limited subset of core libraries that are needed to implement NYT::TError. + +class TSimpleException + : public std::exception +{ +public: + explicit TSimpleException(TString message); + + const TString& GetMesage() const; + const char* what() const noexcept override; + +protected: + const TString Message_; +}; + +class TCompositeException + : public TSimpleException +{ +public: + explicit TCompositeException(TString message); + TCompositeException( + const std::exception& exception, + TString message); + + const std::exception_ptr& GetInnerException() const; + const char* what() const noexcept override; + +private: + const std::exception_ptr InnerException_; + const TString What_; +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/exception/ya.make b/library/cpp/yt/exception/ya.make index 0c89c31dc3..a93b31edd9 100644 --- a/library/cpp/yt/exception/ya.make +++ b/library/cpp/yt/exception/ya.make @@ -1,7 +1,7 @@ -LIBRARY() - -SRCS( - exception.cpp -) - -END() +LIBRARY() + +SRCS( + exception.cpp +) + +END() diff --git a/library/cpp/yt/malloc/malloc.cpp b/library/cpp/yt/malloc/malloc.cpp index 808afacdfb..e43a96f2ac 100644 --- a/library/cpp/yt/malloc/malloc.cpp +++ b/library/cpp/yt/malloc/malloc.cpp @@ -1,19 +1,19 @@ -#include "malloc.h" - -#include <util/system/compiler.h> - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK extern "C" size_t nallocx(size_t size, int /* flags */) noexcept -{ - return size; -} - -#ifndef _win_ -Y_WEAK extern "C" size_t malloc_usable_size(void* /* ptr */) noexcept -{ - return 0; -} -#endif - -//////////////////////////////////////////////////////////////////////////////// +#include "malloc.h" + +#include <util/system/compiler.h> + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK extern "C" size_t nallocx(size_t size, int /* flags */) noexcept +{ + return size; +} + +#ifndef _win_ +Y_WEAK extern "C" size_t malloc_usable_size(void* /* ptr */) noexcept +{ + return 0; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/malloc/malloc.h b/library/cpp/yt/malloc/malloc.h index b3c16d7849..592d4dbe29 100644 --- a/library/cpp/yt/malloc/malloc.h +++ b/library/cpp/yt/malloc/malloc.h @@ -1,8 +1,8 @@ -#include <cstddef> - -//////////////////////////////////////////////////////////////////////////////// - -extern "C" size_t malloc_usable_size(void* ptr) noexcept; -extern "C" size_t nallocx(size_t size, int flags) noexcept; - -//////////////////////////////////////////////////////////////////////////////// +#include <cstddef> + +//////////////////////////////////////////////////////////////////////////////// + +extern "C" size_t malloc_usable_size(void* ptr) noexcept; +extern "C" size_t nallocx(size_t size, int flags) noexcept; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/malloc/ya.make b/library/cpp/yt/malloc/ya.make index 0a07d93b36..8e36a95292 100644 --- a/library/cpp/yt/malloc/ya.make +++ b/library/cpp/yt/malloc/ya.make @@ -1,7 +1,7 @@ -LIBRARY() - -SRCS( - malloc.cpp -) - -END() +LIBRARY() + +SRCS( + malloc.cpp +) + +END() diff --git a/library/cpp/yt/memory/blob.cpp b/library/cpp/yt/memory/blob.cpp index 86000b033b..cfc2cf6dba 100644 --- a/library/cpp/yt/memory/blob.cpp +++ b/library/cpp/yt/memory/blob.cpp @@ -1,65 +1,65 @@ #include "blob.h" #include "ref.h" -#include <library/cpp/ytalloc/api/ytalloc.h> - +#include <library/cpp/ytalloc/api/ytalloc.h> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// -static constexpr size_t InitialBlobCapacity = 16; -static constexpr double BlobCapacityMultiplier = 1.5; +static constexpr size_t InitialBlobCapacity = 16; +static constexpr double BlobCapacityMultiplier = 1.5; TBlob::TBlob( TRefCountedTypeCookie tagCookie, size_t size, bool initiailizeStorage, - bool pageAligned) - : PageAligned_(pageAligned) + bool pageAligned) + : PageAligned_(pageAligned) { - SetTagCookie(tagCookie); + SetTagCookie(tagCookie); if (size == 0) { Reset(); } else { Allocate(std::max(size, InitialBlobCapacity)); - Size_ = size; + Size_ = size; if (initiailizeStorage) { - ::memset(Begin_, 0, Size_); + ::memset(Begin_, 0, Size_); } } } TBlob::TBlob( TRefCountedTypeCookie tagCookie, - TRef data, - bool pageAligned) - : PageAligned_(pageAligned) + TRef data, + bool pageAligned) + : PageAligned_(pageAligned) { - SetTagCookie(tagCookie); + SetTagCookie(tagCookie); Reset(); - Append(data); + Append(data); } TBlob::TBlob(const TBlob& other) - : PageAligned_(other.PageAligned_) + : PageAligned_(other.PageAligned_) { - SetTagCookie(other); + SetTagCookie(other); if (other.Size_ == 0) { Reset(); } else { Allocate(std::max(InitialBlobCapacity, other.Size_)); - ::memcpy(Begin_, other.Begin_, other.Size_); - Size_ = other.Size_; + ::memcpy(Begin_, other.Begin_, other.Size_); + Size_ = other.Size_; } } TBlob::TBlob(TBlob&& other) noexcept - : Begin_(other.Begin_) + : Begin_(other.Begin_) , Size_(other.Size_) , Capacity_(other.Capacity_) - , PageAligned_(other.PageAligned_) + , PageAligned_(other.PageAligned_) { - SetTagCookie(other); + SetTagCookie(other); other.Reset(); } @@ -88,7 +88,7 @@ void TBlob::Resize(size_t newSize, bool initializeStorage /*= true*/) Reallocate(newCapacity); } if (initializeStorage) { - ::memset(Begin_ + Size_, 0, newSize - Size_); + ::memset(Begin_ + Size_, 0, newSize - Size_); } } Size_ = newSize; @@ -114,66 +114,66 @@ TBlob& TBlob::operator = (TBlob&& rhs) noexcept void TBlob::Append(const void* data, size_t size) { - if (Size_ + size > Capacity_) { - Resize(Size_ + size, false); - ::memcpy(Begin_ + Size_ - size, data, size); - } else { - ::memcpy(Begin_ + Size_, data, size); - Size_ += size; - } + if (Size_ + size > Capacity_) { + Resize(Size_ + size, false); + ::memcpy(Begin_ + Size_ - size, data, size); + } else { + ::memcpy(Begin_ + Size_, data, size); + Size_ += size; + } } -void TBlob::Append(TRef ref) +void TBlob::Append(TRef ref) { Append(ref.Begin(), ref.Size()); } -void TBlob::Append(char ch) -{ - if (Size_ + 1 > Capacity_) { - Resize(Size_ + 1, false); - Begin_[Size_ - 1] = ch; - } else { - Begin_[Size_++] = ch; - } -} - +void TBlob::Append(char ch) +{ + if (Size_ + 1 > Capacity_) { + Resize(Size_ + 1, false); + Begin_[Size_ - 1] = ch; + } else { + Begin_[Size_++] = ch; + } +} + void TBlob::Reset() { - Begin_ = nullptr; + Begin_ = nullptr; Size_ = Capacity_ = 0; } -char* TBlob::DoAllocate(size_t size) -{ - return static_cast<char*>(PageAligned_ - ? NYTAlloc::AllocatePageAligned(size) - : NYTAlloc::Allocate(size)); -} - +char* TBlob::DoAllocate(size_t size) +{ + return static_cast<char*>(PageAligned_ + ? NYTAlloc::AllocatePageAligned(size) + : NYTAlloc::Allocate(size)); +} + void TBlob::Allocate(size_t newCapacity) { - YT_VERIFY(!Begin_); - Begin_ = DoAllocate(newCapacity); + YT_VERIFY(!Begin_); + Begin_ = DoAllocate(newCapacity); Capacity_ = newCapacity; #ifdef YT_ENABLE_REF_COUNTED_TRACKING - TRefCountedTrackerFacade::AllocateTagInstance(TagCookie_); - TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity); + TRefCountedTrackerFacade::AllocateTagInstance(TagCookie_); + TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity); #endif } void TBlob::Reallocate(size_t newCapacity) { - if (!Begin_) { + if (!Begin_) { Allocate(newCapacity); return; } - char* newBegin = DoAllocate(newCapacity); - ::memcpy(newBegin, Begin_, Size_); - NYTAlloc::FreeNonNull(Begin_); + char* newBegin = DoAllocate(newCapacity); + ::memcpy(newBegin, Begin_, Size_); + NYTAlloc::FreeNonNull(Begin_); #ifdef YT_ENABLE_REF_COUNTED_TRACKING - TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity); - TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_); + TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity); + TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_); #endif Begin_ = newBegin; Capacity_ = newCapacity; @@ -181,28 +181,28 @@ void TBlob::Reallocate(size_t newCapacity) void TBlob::Free() { - if (!Begin_) { + if (!Begin_) { return; } - NYTAlloc::FreeNonNull(Begin_); + NYTAlloc::FreeNonNull(Begin_); #ifdef YT_ENABLE_REF_COUNTED_TRACKING - TRefCountedTrackerFacade::FreeTagInstance(TagCookie_); - TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_); + TRefCountedTrackerFacade::FreeTagInstance(TagCookie_); + TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_); #endif - Reset(); + Reset(); } -void TBlob::SetTagCookie(TRefCountedTypeCookie tagCookie) +void TBlob::SetTagCookie(TRefCountedTypeCookie tagCookie) { #ifdef YT_ENABLE_REF_COUNTED_TRACKING - TagCookie_ = tagCookie; + TagCookie_ = tagCookie; #endif } - -void TBlob::SetTagCookie(const TBlob& other) + +void TBlob::SetTagCookie(const TBlob& other) { #ifdef YT_ENABLE_REF_COUNTED_TRACKING - TagCookie_ = other.TagCookie_; + TagCookie_ = other.TagCookie_; #endif } @@ -212,9 +212,9 @@ void swap(TBlob& left, TBlob& right) std::swap(left.Begin_, right.Begin_); std::swap(left.Size_, right.Size_); std::swap(left.Capacity_, right.Capacity_); - std::swap(left.PageAligned_, right.PageAligned_); + std::swap(left.PageAligned_, right.PageAligned_); #ifdef YT_ENABLE_REF_COUNTED_TRACKING - std::swap(left.TagCookie_, right.TagCookie_); + std::swap(left.TagCookie_, right.TagCookie_); #endif } } diff --git a/library/cpp/yt/memory/blob.h b/library/cpp/yt/memory/blob.h index 99441fb8c9..3490071848 100644 --- a/library/cpp/yt/memory/blob.h +++ b/library/cpp/yt/memory/blob.h @@ -1,6 +1,6 @@ #pragma once -#include "ref.h" +#include "ref.h" #include "ref_counted.h" namespace NYT { @@ -8,8 +8,8 @@ namespace NYT { //////////////////////////////////////////////////////////////////////////////// //! Default memory tag for TBlob. -struct TDefaultBlobTag -{ }; +struct TDefaultBlobTag +{ }; //! A home-grown optimized replacement for |std::vector<char>| suitable for carrying //! large chunks of data. @@ -21,48 +21,48 @@ class TBlob { public: //! Constructs a blob with a given size. - TBlob( - TRefCountedTypeCookie tagCookie, - size_t size, - bool initiailizeStorage = true, - bool pageAligned = false); + TBlob( + TRefCountedTypeCookie tagCookie, + size_t size, + bool initiailizeStorage = true, + bool pageAligned = false); //! Copies a chunk of memory into a new instance. - TBlob( - TRefCountedTypeCookie tagCookie, - TRef data, - bool pageAligned = false); + TBlob( + TRefCountedTypeCookie tagCookie, + TRef data, + bool pageAligned = false); //! Constructs an empty blob. template <class TTag = TDefaultBlobTag> - explicit TBlob(TTag tag = {}) - : TBlob(tag, 0, true, false) + explicit TBlob(TTag tag = {}) + : TBlob(tag, 0, true, false) { } //! Constructs a blob with a given size. template <class TTag> - explicit TBlob( - TTag, - size_t size, - bool initiailizeStorage = true, - bool pageAligned = false) - : TBlob( - GetRefCountedTypeCookie<TTag>(), - size, - initiailizeStorage, - pageAligned) + explicit TBlob( + TTag, + size_t size, + bool initiailizeStorage = true, + bool pageAligned = false) + : TBlob( + GetRefCountedTypeCookie<TTag>(), + size, + initiailizeStorage, + pageAligned) { } //! Copies a chunk of memory into a new instance. template <class TTag> - TBlob( - TTag, - TRef data, - bool pageAligned = false) - : TBlob( - GetRefCountedTypeCookie<TTag>(), - data, - pageAligned) + TBlob( + TTag, + TRef data, + bool pageAligned = false) + : TBlob( + GetRefCountedTypeCookie<TTag>(), + data, + pageAligned) { } //! Remind user about the tag argument. @@ -70,8 +70,8 @@ public: TBlob(i64 size, bool initiailizeStorage = true) = delete; TBlob(ui32 size, bool initiailizeStorage = true) = delete; TBlob(ui64 size, bool initiailizeStorage = true) = delete; - template <typename T, typename U> - TBlob(const T*, U) = delete; + template <typename T, typename U> + TBlob(const T*, U) = delete; //! Copies the data. TBlob(const TBlob& other); @@ -95,25 +95,25 @@ public: void Resize(size_t newSize, bool initializeStorage = true); //! Returns the start pointer. - Y_FORCE_INLINE const char* Begin() const + Y_FORCE_INLINE const char* Begin() const { return Begin_; } //! Returns the start pointer. - Y_FORCE_INLINE char* Begin() + Y_FORCE_INLINE char* Begin() { return Begin_; } //! Returns the end pointer. - Y_FORCE_INLINE const char* End() const + Y_FORCE_INLINE const char* End() const { return Begin_ + Size_; } //! Returns the end pointer. - Y_FORCE_INLINE char* End() + Y_FORCE_INLINE char* End() { return Begin_ + Size_; } @@ -125,49 +125,49 @@ public: } //! Returns the size. - Y_FORCE_INLINE size_t Size() const + Y_FORCE_INLINE size_t Size() const { return Size_; } //! Returns the capacity. - Y_FORCE_INLINE size_t Capacity() const + Y_FORCE_INLINE size_t Capacity() const { return Capacity_; } - //! Returns the TStringBuf instance for the occupied part of the blob. - Y_FORCE_INLINE TStringBuf ToStringBuf() const - { - return TStringBuf(Begin_, Size_); - } - - //! Returns the TRef instance for the occupied part of the blob. - Y_FORCE_INLINE TRef ToRef() const - { - return TRef(Begin_, Size_); - } - + //! Returns the TStringBuf instance for the occupied part of the blob. + Y_FORCE_INLINE TStringBuf ToStringBuf() const + { + return TStringBuf(Begin_, Size_); + } + + //! Returns the TRef instance for the occupied part of the blob. + Y_FORCE_INLINE TRef ToRef() const + { + return TRef(Begin_, Size_); + } + //! Provides by-value access to the underlying storage. - Y_FORCE_INLINE char operator [] (size_t index) const + Y_FORCE_INLINE char operator [] (size_t index) const { return Begin_[index]; } //! Provides by-ref access to the underlying storage. - Y_FORCE_INLINE char& operator [] (size_t index) + Y_FORCE_INLINE char& operator [] (size_t index) { return Begin_[index]; } //! Clears the instance but does not reclaim the memory. - Y_FORCE_INLINE void Clear() + Y_FORCE_INLINE void Clear() { Size_ = 0; } //! Returns |true| if size is zero. - Y_FORCE_INLINE bool IsEmpty() const + Y_FORCE_INLINE bool IsEmpty() const { return Size_ == 0; } @@ -182,35 +182,35 @@ public: void Append(const void* data, size_t size); //! Appends a chunk of memory to the end. - void Append(TRef ref); - - //! Appends a single char to the end. - void Append(char ch); + void Append(TRef ref); + //! Appends a single char to the end. + void Append(char ch); + //! Swaps the current and other instances void Swap(TBlob& other); - + friend void swap(TBlob& left, TBlob& right); private: - char* Begin_ = nullptr; - size_t Size_ = 0; - size_t Capacity_ = 0; - bool PageAligned_ = false; + char* Begin_ = nullptr; + size_t Size_ = 0; + size_t Capacity_ = 0; + bool PageAligned_ = false; #ifdef YT_ENABLE_REF_COUNTED_TRACKING - TRefCountedTypeCookie TagCookie_ = NullRefCountedTypeCookie; + TRefCountedTypeCookie TagCookie_ = NullRefCountedTypeCookie; #endif - char* DoAllocate(size_t newCapacity); + char* DoAllocate(size_t newCapacity); void Allocate(size_t newCapacity); void Reallocate(size_t newCapacity); void Free(); void Reset(); - void SetTagCookie(TRefCountedTypeCookie tagCookie); - void SetTagCookie(const TBlob& other); + void SetTagCookie(TRefCountedTypeCookie tagCookie); + void SetTagCookie(const TBlob& other); }; void swap(TBlob& left, TBlob& right); diff --git a/library/cpp/yt/memory/intrusive_ptr.h b/library/cpp/yt/memory/intrusive_ptr.h index 3dead7db1d..d40a71766f 100644 --- a/library/cpp/yt/memory/intrusive_ptr.h +++ b/library/cpp/yt/memory/intrusive_ptr.h @@ -1,29 +1,29 @@ -#pragma once - +#pragma once + #include "ref_counted.h" - -#include <util/generic/hash.h> + +#include <util/generic/hash.h> #include <util/generic/utility.h> #include <utility> #include <type_traits> -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + template <class T> class TIntrusivePtr { public: - typedef T TUnderlying; - + typedef T TUnderlying; + constexpr TIntrusivePtr() noexcept - { } - + { } + constexpr TIntrusivePtr(std::nullptr_t) noexcept - { } - + { } + //! Constructor from an unqualified reference. /*! * Note that this constructor could be racy due to unsynchronized operations @@ -33,22 +33,22 @@ public: * given the current amount of code written. */ TIntrusivePtr(T* obj, bool addReference = true) noexcept - : T_(obj) + : T_(obj) { if (T_ && addReference) { - Ref(T_); - } - } - + Ref(T_); + } + } + //! Copy constructor. TIntrusivePtr(const TIntrusivePtr& other) noexcept : T_(other.Get()) { - if (T_) { - Ref(T_); + if (T_) { + Ref(T_); } } - + //! Copy constructor with an upcast. template <class U, class = typename std::enable_if_t<std::is_convertible_v<U*, T*>>> TIntrusivePtr(const TIntrusivePtr<U>& other) noexcept @@ -57,16 +57,16 @@ public: static_assert( std::is_base_of_v<TRefCountedBase, T>, "Cast allowed only for types derived from TRefCountedBase"); - if (T_) { - Ref(T_); - } + if (T_) { + Ref(T_); + } } - + //! Move constructor. TIntrusivePtr(TIntrusivePtr&& other) noexcept : T_(other.Get()) { - other.T_ = nullptr; + other.T_ = nullptr; } //! Move constructor with an upcast. @@ -77,19 +77,19 @@ public: static_assert( std::is_base_of_v<TRefCountedBase, T>, "Cast allowed only for types derived from TRefCountedBase"); - other.T_ = nullptr; + other.T_ = nullptr; } //! Destructor. ~TIntrusivePtr() { - if (T_) { - Unref(T_); - } + if (T_) { + Unref(T_); + } } - + //! Copy assignment operator. - TIntrusivePtr& operator=(const TIntrusivePtr& other) noexcept + TIntrusivePtr& operator=(const TIntrusivePtr& other) noexcept { TIntrusivePtr(other).Swap(*this); return *this; @@ -97,7 +97,7 @@ public: //! Copy assignment operator with an upcast. template <class U> - TIntrusivePtr& operator=(const TIntrusivePtr<U>& other) noexcept + TIntrusivePtr& operator=(const TIntrusivePtr<U>& other) noexcept { static_assert( std::is_convertible_v<U*, T*>, @@ -118,7 +118,7 @@ public: //! Move assignment operator with an upcast. template <class U> - TIntrusivePtr& operator=(TIntrusivePtr<U>&& other) noexcept + TIntrusivePtr& operator=(TIntrusivePtr<U>&& other) noexcept { static_assert( std::is_convertible_v<U*, T*>, @@ -130,21 +130,21 @@ public: return *this; } - //! Drop the pointer. + //! Drop the pointer. void Reset() // noexcept { TIntrusivePtr().Swap(*this); } - //! Replace the pointer with a specified one. + //! Replace the pointer with a specified one. void Reset(T* p) // noexcept { TIntrusivePtr(p).Swap(*this); } - //! Returns the pointer. - T* Get() const noexcept - { + //! Returns the pointer. + T* Get() const noexcept + { return T_; } @@ -156,46 +156,46 @@ public: return p; } - T& operator*() const noexcept + T& operator*() const noexcept { - YT_ASSERT(T_); + YT_ASSERT(T_); return *T_; } - T* operator->() const noexcept + T* operator->() const noexcept { - YT_ASSERT(T_); + YT_ASSERT(T_); return T_; } - explicit operator bool() const noexcept - { + explicit operator bool() const noexcept + { return T_ != nullptr; - } - + } + //! Swap the pointer with the other one. - void Swap(TIntrusivePtr& r) noexcept - { + void Swap(TIntrusivePtr& r) noexcept + { DoSwap(T_, r.T_); } private: template <class U> friend class TIntrusivePtr; - - T* T_ = nullptr; -}; - -//////////////////////////////////////////////////////////////////////////////// - -//! Creates a strong pointer wrapper for a given raw pointer. -//! Compared to |TIntrusivePtr<T>::ctor|, type inference enables omitting |T|. + + T* T_ = nullptr; +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! Creates a strong pointer wrapper for a given raw pointer. +//! Compared to |TIntrusivePtr<T>::ctor|, type inference enables omitting |T|. template <class T> -TIntrusivePtr<T> MakeStrong(T* p) -{ - return TIntrusivePtr<T>(p); -} - +TIntrusivePtr<T> MakeStrong(T* p) +{ + return TIntrusivePtr<T>(p); +} + //! Tries to obtain an intrusive pointer for an object that may had //! already lost all of its references and, thus, is about to be deleted. /*! @@ -221,8 +221,8 @@ Y_FORCE_INLINE TIntrusivePtr<T> DangerousGetPtr(T* object) : TIntrusivePtr<T>(); } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + template <class T, class U> TIntrusivePtr<T> StaticPointerCast(const TIntrusivePtr<U>& ptr) { @@ -255,18 +255,18 @@ TIntrusivePtr<T> DynamicPointerCast(const TIntrusivePtr<U>& ptr) //////////////////////////////////////////////////////////////////////////////// +template <class T> +bool operator<(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<T>& rhs) +{ + return lhs.Get() < rhs.Get(); +} + template <class T> -bool operator<(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<T>& rhs) -{ - return lhs.Get() < rhs.Get(); -} - -template <class T> -bool operator>(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<T>& rhs) -{ - return lhs.Get() > rhs.Get(); -} - +bool operator>(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<T>& rhs) +{ + return lhs.Get() > rhs.Get(); +} + template <class T, class U> bool operator==(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<U>& rhs) { @@ -345,16 +345,16 @@ bool operator!=(const TIntrusivePtr<T>& lhs, std::nullptr_t) return nullptr != lhs.Get(); } -//////////////////////////////////////////////////////////////////////////////// - -} //namespace NYT - -//! A hasher for TIntrusivePtr. -template <class T> +//////////////////////////////////////////////////////////////////////////////// + +} //namespace NYT + +//! A hasher for TIntrusivePtr. +template <class T> struct THash<NYT::TIntrusivePtr<T>> -{ - Y_FORCE_INLINE size_t operator () (const NYT::TIntrusivePtr<T>& ptr) const - { - return THash<T*>()(ptr.Get()); - } -}; +{ + Y_FORCE_INLINE size_t operator () (const NYT::TIntrusivePtr<T>& ptr) const + { + return THash<T*>()(ptr.Get()); + } +}; diff --git a/library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h b/library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h index a68ec5ed6a..b6f261543b 100644 --- a/library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h +++ b/library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h @@ -1,43 +1,43 @@ -#ifndef LEAKY_REF_COUNTED_SINGLETON_INL_H_ -#error "Direct inclusion of this file is not allowed, include leaky_ref_counted_singleton.h" -// For the sake of sane code completion. -#include "leaky_ref_counted_singleton.h" -#endif - -#include "new.h" - -#include <atomic> -#include <mutex> - -#include <util/system/compiler.h> -#include <util/system/sanitizers.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -TIntrusivePtr<T> LeakyRefCountedSingleton() -{ - static std::atomic<T*> Ptr; - auto* ptr = Ptr.load(std::memory_order_acquire); - if (Y_LIKELY(ptr)) { - return ptr; - } - - static std::once_flag Initialized; - std::call_once(Initialized, [] { - auto ptr = New<T>(); - Ref(ptr.Get()); - Ptr.store(ptr.Get()); -#if defined(_asan_enabled_) - NSan::MarkAsIntentionallyLeaked(ptr.Get()); -#endif - }); - - return Ptr.load(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#ifndef LEAKY_REF_COUNTED_SINGLETON_INL_H_ +#error "Direct inclusion of this file is not allowed, include leaky_ref_counted_singleton.h" +// For the sake of sane code completion. +#include "leaky_ref_counted_singleton.h" +#endif + +#include "new.h" + +#include <atomic> +#include <mutex> + +#include <util/system/compiler.h> +#include <util/system/sanitizers.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +TIntrusivePtr<T> LeakyRefCountedSingleton() +{ + static std::atomic<T*> Ptr; + auto* ptr = Ptr.load(std::memory_order_acquire); + if (Y_LIKELY(ptr)) { + return ptr; + } + + static std::once_flag Initialized; + std::call_once(Initialized, [] { + auto ptr = New<T>(); + Ref(ptr.Get()); + Ptr.store(ptr.Get()); +#if defined(_asan_enabled_) + NSan::MarkAsIntentionallyLeaked(ptr.Get()); +#endif + }); + + return Ptr.load(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/memory/leaky_ref_counted_singleton.h b/library/cpp/yt/memory/leaky_ref_counted_singleton.h index 1d5761bd9d..93dbe7488a 100644 --- a/library/cpp/yt/memory/leaky_ref_counted_singleton.h +++ b/library/cpp/yt/memory/leaky_ref_counted_singleton.h @@ -1,18 +1,18 @@ -#pragma once - -#include "intrusive_ptr.h" - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -TIntrusivePtr<T> LeakyRefCountedSingleton(); - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT - -#define LEAKY_REF_COUNTED_SINGLETON_INL_H_ -#include "leaky_ref_counted_singleton-inl.h" -#undef LEAKY_REF_COUNTED_SINGLETON_INL_H_ +#pragma once + +#include "intrusive_ptr.h" + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +TIntrusivePtr<T> LeakyRefCountedSingleton(); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define LEAKY_REF_COUNTED_SINGLETON_INL_H_ +#include "leaky_ref_counted_singleton-inl.h" +#undef LEAKY_REF_COUNTED_SINGLETON_INL_H_ diff --git a/library/cpp/yt/memory/leaky_singleton-inl.h b/library/cpp/yt/memory/leaky_singleton-inl.h index 932747c921..4c7212e1be 100644 --- a/library/cpp/yt/memory/leaky_singleton-inl.h +++ b/library/cpp/yt/memory/leaky_singleton-inl.h @@ -1,34 +1,34 @@ -#ifndef LEAKY_SINGLETON_INL_H_ -#error "Direct inclusion of this file is not allowed, include leaky_singleton.h" -// For the sake of sane code completion. -#include "leaky_singleton.h" -#endif - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -TLeakyStorage<T>::TLeakyStorage() -{ - new (Get()) T(); -} - -template <class T> -T* TLeakyStorage<T>::Get() -{ - return reinterpret_cast<T*>(Buffer_); -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -T* LeakySingleton() -{ - static TLeakyStorage<T> Storage; - return Storage.Get(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#ifndef LEAKY_SINGLETON_INL_H_ +#error "Direct inclusion of this file is not allowed, include leaky_singleton.h" +// For the sake of sane code completion. +#include "leaky_singleton.h" +#endif + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +TLeakyStorage<T>::TLeakyStorage() +{ + new (Get()) T(); +} + +template <class T> +T* TLeakyStorage<T>::Get() +{ + return reinterpret_cast<T*>(Buffer_); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +T* LeakySingleton() +{ + static TLeakyStorage<T> Storage; + return Storage.Get(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/memory/leaky_singleton.h b/library/cpp/yt/memory/leaky_singleton.h index 03b5e51d78..df157f5574 100644 --- a/library/cpp/yt/memory/leaky_singleton.h +++ b/library/cpp/yt/memory/leaky_singleton.h @@ -4,31 +4,31 @@ namespace NYT { //////////////////////////////////////////////////////////////////////////////// +template <class T> +class TLeakyStorage +{ +public: + TLeakyStorage(); + + T* Get(); + +private: + alignas(T) char Buffer_[sizeof(T)]; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#define DECLARE_LEAKY_SINGLETON_FRIEND() \ + template <class T> \ + friend class ::NYT::TLeakyStorage; + template <class T> -class TLeakyStorage -{ -public: - TLeakyStorage(); - - T* Get(); - -private: - alignas(T) char Buffer_[sizeof(T)]; -}; - -//////////////////////////////////////////////////////////////////////////////// - -#define DECLARE_LEAKY_SINGLETON_FRIEND() \ - template <class T> \ - friend class ::NYT::TLeakyStorage; - -template <class T> -T* LeakySingleton(); +T* LeakySingleton(); //////////////////////////////////////////////////////////////////////////////// } // namespace NYT - -#define LEAKY_SINGLETON_INL_H_ -#include "leaky_singleton-inl.h" -#undef LEAKY_SINGLETON_INL_H_ + +#define LEAKY_SINGLETON_INL_H_ +#include "leaky_singleton-inl.h" +#undef LEAKY_SINGLETON_INL_H_ diff --git a/library/cpp/yt/memory/new-inl.h b/library/cpp/yt/memory/new-inl.h index 0a84818516..8458a0c367 100644 --- a/library/cpp/yt/memory/new-inl.h +++ b/library/cpp/yt/memory/new-inl.h @@ -4,7 +4,7 @@ #include "new.h" #endif -#include <library/cpp/ytalloc/api/ytalloc.h> +#include <library/cpp/ytalloc/api/ytalloc.h> namespace NYT { diff --git a/library/cpp/yt/memory/new.h b/library/cpp/yt/memory/new.h index 2db45e0465..d8a1db0df4 100644 --- a/library/cpp/yt/memory/new.h +++ b/library/cpp/yt/memory/new.h @@ -1,70 +1,70 @@ -#pragma once - +#pragma once + #include "intrusive_ptr.h" #include "ref_tracked.h" - -#include <library/cpp/yt/misc/source_location.h> - -#include <util/system/defaults.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -/*! - * \defgroup yt_new New<T> safe smart pointer constructors - * \ingroup yt_new - * - * This is collection of safe smart pointer constructors. - * - * \page yt_new_rationale Rationale - * New<T> function family was designed to prevent the following problem. - * Consider the following piece of code. - * - * \code - * class TFoo - * : public virtual TRefCounted - * { - * public: - * TFoo(); - * }; - * - * typedef TIntrusivePtr<TFoo> TFooPtr; - * - * void RegisterObject(TFooPtr foo) - * { - * ... - * } - * - * TFoo::TFoo() - * { - * // ... do something before - * RegisterObject(this); - * // ... do something after - * } - * \endcode - * - * What will happen on <tt>new TFoo()</tt> construction? After memory allocation - * the reference counter for newly created instance would be initialized to zero. - * Afterwards, the control goes to TFoo constructor. To invoke - * <tt>RegisterObject</tt> a new temporary smart pointer to the current instance - * have to be created effectively incrementing the reference counter (now one). - * After <tt>RegisterObject</tt> returns the control to the constructor - * the temporary pointer is destroyed effectively decrementing the reference - * counter to zero hence triggering object destruction during its initialization. - * - * To avoid this undefined behavior <tt>New<T></tt> was introduced. - * <tt>New<T></tt> holds a fake - * reference to the object during its construction effectively preventing - * premature destruction. - * - * \note An initialization like <tt>TIntrusivePtr<T> p = new T()</tt> - * would result in a dangling reference due to internals of #New<T> and - * #TRefCountedBase. - */ - -//////////////////////////////////////////////////////////////////////////////// - + +#include <library/cpp/yt/misc/source_location.h> + +#include <util/system/defaults.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +/*! + * \defgroup yt_new New<T> safe smart pointer constructors + * \ingroup yt_new + * + * This is collection of safe smart pointer constructors. + * + * \page yt_new_rationale Rationale + * New<T> function family was designed to prevent the following problem. + * Consider the following piece of code. + * + * \code + * class TFoo + * : public virtual TRefCounted + * { + * public: + * TFoo(); + * }; + * + * typedef TIntrusivePtr<TFoo> TFooPtr; + * + * void RegisterObject(TFooPtr foo) + * { + * ... + * } + * + * TFoo::TFoo() + * { + * // ... do something before + * RegisterObject(this); + * // ... do something after + * } + * \endcode + * + * What will happen on <tt>new TFoo()</tt> construction? After memory allocation + * the reference counter for newly created instance would be initialized to zero. + * Afterwards, the control goes to TFoo constructor. To invoke + * <tt>RegisterObject</tt> a new temporary smart pointer to the current instance + * have to be created effectively incrementing the reference counter (now one). + * After <tt>RegisterObject</tt> returns the control to the constructor + * the temporary pointer is destroyed effectively decrementing the reference + * counter to zero hence triggering object destruction during its initialization. + * + * To avoid this undefined behavior <tt>New<T></tt> was introduced. + * <tt>New<T></tt> holds a fake + * reference to the object during its construction effectively preventing + * premature destruction. + * + * \note An initialization like <tt>TIntrusivePtr<T> p = new T()</tt> + * would result in a dangling reference due to internals of #New<T> and + * #TRefCountedBase. + */ + +//////////////////////////////////////////////////////////////////////////////// + template <class T, class = void> struct THasAllocator { @@ -72,7 +72,7 @@ struct THasAllocator }; template <class T> -struct THasAllocator<T, std::void_t<typename T::TAllocator>> +struct THasAllocator<T, std::void_t<typename T::TAllocator>> { using TTrue = void; }; @@ -82,7 +82,7 @@ struct THasAllocator<T, std::void_t<typename T::TAllocator>> //! Allocates a new instance of |T|. template <class T, class... As, class = typename THasAllocator<T>::TFalse> TIntrusivePtr<T> New(As&&... args); - + template <class T, class... As, class = typename THasAllocator<T>::TTrue> TIntrusivePtr<T> New(typename T::TAllocator* allocator, As&&... args); @@ -101,26 +101,26 @@ TIntrusivePtr<T> NewWithDelete(const TDeleter& deleter, As&&... args); //! The allocation is additionally marked with #location. template <class T, class TTag, int Counter, class... As> TIntrusivePtr<T> NewWithLocation(const TSourceLocation& location, As&&... args); - + //! Enables calling #New and co for types with private ctors. #define DECLARE_NEW_FRIEND() \ template <class DECLARE_NEW_FRIEND_T> \ friend struct NYT::TRefCountedWrapper; - + //////////////////////////////////////////////////////////////////////////////// - + //! CRTP mixin enabling access to instance's extra space. template <class T> class TWithExtraSpace -{ +{ protected: const void* GetExtraSpacePtr() const; void* GetExtraSpacePtr(); }; - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT #define NEW_INL_H_ #include "new-inl.h" diff --git a/library/cpp/yt/memory/range.h b/library/cpp/yt/memory/range.h index 6c71aa9496..0c893c72ce 100644 --- a/library/cpp/yt/memory/range.h +++ b/library/cpp/yt/memory/range.h @@ -1,42 +1,42 @@ #pragma once -#include <library/cpp/yt/assert/assert.h> - -#include <library/cpp/yt/misc/hash.h> - +#include <library/cpp/yt/assert/assert.h> + +#include <library/cpp/yt/misc/hash.h> + #include <vector> -#include <array> -#include <optional> -#include <initializer_list> - -// For size_t. -#include <stddef.h> - -namespace google::protobuf { - -//////////////////////////////////////////////////////////////////////////////// -// Forward declarations - -template <class T> -class RepeatedField; - -template <class T> -class RepeatedPtrField; - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace google::protobuf - +#include <array> +#include <optional> +#include <initializer_list> + +// For size_t. +#include <stddef.h> + +namespace google::protobuf { + +//////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +template <class T> +class RepeatedField; + +template <class T> +class RepeatedPtrField; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace google::protobuf + namespace NYT { //////////////////////////////////////////////////////////////////////////////// -// Forward declarations - -template <class T, size_t N> -class TCompactVector; - -//////////////////////////////////////////////////////////////////////////////// +// Forward declarations +template <class T, size_t N> +class TCompactVector; + +//////////////////////////////////////////////////////////////////////////////// + //! TRange (inspired by TArrayRef from LLVM) /*! * Represents a constant reference to an array (zero or more elements @@ -93,28 +93,28 @@ public: //! Constructs a TRange from a C array. template <size_t N> - TRange(const T (&elements)[N]) - : Data_(elements) - , Length_(N) - { } - - //! Constructs a TRange from std::initializer_list. - TRange(std::initializer_list<T> elements) - : Data_(elements.begin()) - , Length_(elements.size()) - { } - - //! Constructs a TRange from std::array. - template <size_t N> - TRange(const std::array<T, N>& elements) - : Data_(elements.data()) + TRange(const T (&elements)[N]) + : Data_(elements) , Length_(N) { } - //! Constructs a TRange from std::optional. + //! Constructs a TRange from std::initializer_list. + TRange(std::initializer_list<T> elements) + : Data_(elements.begin()) + , Length_(elements.size()) + { } + + //! Constructs a TRange from std::array. + template <size_t N> + TRange(const std::array<T, N>& elements) + : Data_(elements.data()) + , Length_(N) + { } + + //! Constructs a TRange from std::optional. //! Range will contain 0-1 elements. - explicit TRange(const std::optional<T>& element) - : Data_(element ? &*element : nullptr) + explicit TRange(const std::optional<T>& element) + : Data_(element ? &*element : nullptr) , Length_(element ? 1 : 0) { } @@ -123,33 +123,33 @@ public: return Data_; } - // STL interop, for gcc. - const_iterator begin() const - { - return Begin(); - } - + // STL interop, for gcc. + const_iterator begin() const + { + return Begin(); + } + const_iterator End() const { return Data_ + Length_; } - // STL interop, for gcc. - const_iterator end() const - { - return End(); - } - + // STL interop, for gcc. + const_iterator end() const + { + return End(); + } + bool Empty() const { return Length_ == 0; } - bool empty() const - { - return Empty(); - } - + bool empty() const + { + return Empty(); + } + explicit operator bool() const { return Data_ != nullptr; @@ -167,24 +167,24 @@ public: const T& operator[](size_t index) const { - YT_ASSERT(index < Size()); + YT_ASSERT(index < Size()); return Data_[index]; } - const T& Front() const - { - YT_ASSERT(Length_ > 0); - return Data_[0]; - } - - const T& Back() const - { - YT_ASSERT(Length_ > 0); - return Data_[Length_ - 1]; - } - - + const T& Front() const + { + YT_ASSERT(Length_ > 0); + return Data_[0]; + } + + const T& Back() const + { + YT_ASSERT(Length_ > 0); + return Data_[Length_ - 1]; + } + + TRange<T> Slice(size_t startOffset, size_t endOffset) const { YT_ASSERT(startOffset <= endOffset && endOffset <= Size()); @@ -207,13 +207,13 @@ protected: // STL interop. template <class T> -typename TRange<T>::const_iterator begin(TRange<T> ref) +typename TRange<T>::const_iterator begin(TRange<T> ref) { return ref.Begin(); } template <class T> -typename TRange<T>::const_iterator end(TRange<T> ref) +typename TRange<T>::const_iterator end(TRange<T> ref) { return ref.End(); } @@ -241,13 +241,13 @@ TRange<T> MakeRange(const TCompactVector<T, N>& elements) return elements; } -//! "Copy-constructor". -template <class T> -TRange<T> MakeRange(TRange<T> range) -{ - return range; -} - +//! "Copy-constructor". +template <class T> +TRange<T> MakeRange(TRange<T> range) +{ + return range; +} + //! Constructs a TRange from an std::vector. template <class T> TRange<T> MakeRange(const std::vector<T>& elements) @@ -255,13 +255,13 @@ TRange<T> MakeRange(const std::vector<T>& elements) return elements; } -//! Constructs a TRange from an std::array. -template <class T, size_t N> -TRange<T> MakeRange(const std::array<T, N>& elements) -{ - return elements; -} - +//! Constructs a TRange from an std::array. +template <class T, size_t N> +TRange<T> MakeRange(const std::array<T, N>& elements) +{ + return elements; +} + //! Constructs a TRange from a C array. template <class T, size_t N> TRange<T> MakeRange(const T (& elements)[N]) @@ -269,27 +269,27 @@ TRange<T> MakeRange(const T (& elements)[N]) return TRange<T>(elements); } -//! Constructs a TRange from RepeatedField. -template <class T> -TRange<T> MakeRange(const google::protobuf::RepeatedField<T>& elements) -{ - return TRange<T>(elements.data(), elements.size()); -} - -//! Constructs a TRange from RepeatedPtrField. -template <class T> -TRange<const T*> MakeRange(const google::protobuf::RepeatedPtrField<T>& elements) -{ - return TRange<const T*>(elements.data(), elements.size()); -} - -template <class U, class T> -TRange<U> ReinterpretCastRange(TRange<T> range) -{ - static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); - return TRange<U>(reinterpret_cast<const U*>(range.Begin()), range.Size()); -}; - +//! Constructs a TRange from RepeatedField. +template <class T> +TRange<T> MakeRange(const google::protobuf::RepeatedField<T>& elements) +{ + return TRange<T>(elements.data(), elements.size()); +} + +//! Constructs a TRange from RepeatedPtrField. +template <class T> +TRange<const T*> MakeRange(const google::protobuf::RepeatedPtrField<T>& elements) +{ + return TRange<const T*>(elements.data(), elements.size()); +} + +template <class U, class T> +TRange<U> ReinterpretCastRange(TRange<T> range) +{ + static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); + return TRange<U>(reinterpret_cast<const U*>(range.Begin()), range.Size()); +}; + //////////////////////////////////////////////////////////////////////////////// // TMutableRange (inspired by TMutableArrayRef from LLVM) @@ -338,16 +338,16 @@ public: : TRange<T>(elements) { } - //! Constructs a TMutableRange from std::array. - template <size_t N> - TMutableRange(std::array<T, N>& elements) - : TRange<T>(elements.data(), N) - { } - - //! Construct a TMutableRange from an std::optional + //! Constructs a TMutableRange from std::array. + template <size_t N> + TMutableRange(std::array<T, N>& elements) + : TRange<T>(elements.data(), N) + { } + + //! Construct a TMutableRange from an std::optional //! Range will contain 0-1 elements. - explicit TMutableRange(std::optional<T>& optional) - : TRange<T>(optional) + explicit TMutableRange(std::optional<T>& optional) + : TRange<T>(optional) { } //! Constructs a TMutableRange from a C array. @@ -356,11 +356,11 @@ public: : TRange<T>(elements) { } - using TRange<T>::Begin; - using TRange<T>::End; - using TRange<T>::Front; - using TRange<T>::Back; - using TRange<T>::operator[]; + using TRange<T>::Begin; + using TRange<T>::End; + using TRange<T>::Front; + using TRange<T>::Back; + using TRange<T>::operator[]; iterator Begin() const { @@ -384,24 +384,24 @@ public: return End(); } - T& operator[](size_t index) - { - YT_ASSERT(index <= this->Size()); - return Begin()[index]; - } - - T& Front() - { - YT_ASSERT(this->Length_ > 0); - return Begin()[0]; - } - - T& Back() + T& operator[](size_t index) { - YT_ASSERT(this->Length_ > 0); - return Begin()[this->Length_ - 1]; + YT_ASSERT(index <= this->Size()); + return Begin()[index]; } + T& Front() + { + YT_ASSERT(this->Length_ > 0); + return Begin()[0]; + } + + T& Back() + { + YT_ASSERT(this->Length_ > 0); + return Begin()[this->Length_ - 1]; + } + TMutableRange<T> Slice(size_t startOffset, size_t endOffset) const { YT_ASSERT(startOffset <= endOffset && endOffset <= this->Size()); @@ -410,41 +410,41 @@ public: TMutableRange<T> Slice(T* begin, T* end) const { - YT_ASSERT(begin >= Begin()); - YT_ASSERT(end <= End()); + YT_ASSERT(begin >= Begin()); + YT_ASSERT(end <= End()); return TMutableRange<T>(begin, end); } }; // STL interop. template <class T> -typename TMutableRange<T>::iterator begin(TMutableRange<T> ref) +typename TMutableRange<T>::iterator begin(TMutableRange<T> ref) { return ref.Begin(); } template <class T> -typename TMutableRange<T>::iterator end(TMutableRange<T> ref) +typename TMutableRange<T>::iterator end(TMutableRange<T> ref) { return ref.End(); } //////////////////////////////////////////////////////////////////////////////// -//! Constructs a TMutableRange from a pointer and length. -template <class T> -TMutableRange<T> MakeMutableRange(T* data, size_t length) -{ - return TMutableRange<T>(data, length); -} - -//! Constructs a TMutableRange from a native range. -template <class T> -TMutableRange<T> MakeMutableRange(T* begin, T* end) -{ - return TMutableRange<T>(begin, end); -} - +//! Constructs a TMutableRange from a pointer and length. +template <class T> +TMutableRange<T> MakeMutableRange(T* data, size_t length) +{ + return TMutableRange<T>(data, length); +} + +//! Constructs a TMutableRange from a native range. +template <class T> +TMutableRange<T> MakeMutableRange(T* begin, T* end) +{ + return TMutableRange<T>(begin, end); +} + //! Constructs a TMutableRange from a TCompactVector. template <class T, size_t N> TMutableRange<T> MakeMutableRange(TCompactVector<T, N>& elements) @@ -452,58 +452,58 @@ TMutableRange<T> MakeMutableRange(TCompactVector<T, N>& elements) return elements; } -//! "Copy-constructor". -template <class T> -TMutableRange<T> MakeMutableRange(TMutableRange<T> range) -{ - return range; -} - -//! Constructs a TMutableRange from an std::vector. -template <class T> -TMutableRange<T> MakeMutableRange(std::vector<T>& elements) -{ - return elements; -} - -//! Constructs a TMutableRange from an std::array. -template <class T, size_t N> -TMutableRange<T> MakeMutableRange(std::array<T, N>& elements) -{ - return elements; -} - -//! Constructs a TMutableRange from a C array. -template <class T, size_t N> -TMutableRange<T> MakeMutableRange(T (& elements)[N]) -{ - return TMutableRange<T>(elements); -} - -//! Constructs a TMutableRange from RepeatedField. -template <class T> -TMutableRange<T> MakeMutableRange(google::protobuf::RepeatedField<T>& elements) -{ - return TMutableRange<T>(elements.data(), elements.size()); -} - -//! Constructs a TMutableRange from RepeatedPtrField. -template <class T> -TMutableRange<T*> MakeMutableRange(google::protobuf::RepeatedPtrField<T>& elements) -{ - return TMutableRange<const T*>(elements.data(), elements.size()); -} - -template <class U, class T> -TMutableRange<U> ReinterpretCastMutableRange(TMutableRange<T> range) -{ - static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); - return TMutableRange<U>(reinterpret_cast<U*>(range.Begin()), range.Size()); -} - -//////////////////////////////////////////////////////////////////////////////// - -// Mark TMutableRange and TMutableRange as PODs. +//! "Copy-constructor". +template <class T> +TMutableRange<T> MakeMutableRange(TMutableRange<T> range) +{ + return range; +} + +//! Constructs a TMutableRange from an std::vector. +template <class T> +TMutableRange<T> MakeMutableRange(std::vector<T>& elements) +{ + return elements; +} + +//! Constructs a TMutableRange from an std::array. +template <class T, size_t N> +TMutableRange<T> MakeMutableRange(std::array<T, N>& elements) +{ + return elements; +} + +//! Constructs a TMutableRange from a C array. +template <class T, size_t N> +TMutableRange<T> MakeMutableRange(T (& elements)[N]) +{ + return TMutableRange<T>(elements); +} + +//! Constructs a TMutableRange from RepeatedField. +template <class T> +TMutableRange<T> MakeMutableRange(google::protobuf::RepeatedField<T>& elements) +{ + return TMutableRange<T>(elements.data(), elements.size()); +} + +//! Constructs a TMutableRange from RepeatedPtrField. +template <class T> +TMutableRange<T*> MakeMutableRange(google::protobuf::RepeatedPtrField<T>& elements) +{ + return TMutableRange<const T*>(elements.data(), elements.size()); +} + +template <class U, class T> +TMutableRange<U> ReinterpretCastMutableRange(TMutableRange<T> range) +{ + static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); + return TMutableRange<U>(reinterpret_cast<U*>(range.Begin()), range.Size()); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Mark TMutableRange and TMutableRange as PODs. namespace NMpl { template <class T> @@ -540,17 +540,17 @@ struct hash<NYT::TRange<T>> } }; -template <class T> -struct hash<NYT::TMutableRange<T>> -{ - size_t operator()(const NYT::TMutableRange<T>& range) const - { - size_t result = 0; - for (const auto& element : range) { - NYT::HashCombine(result, element); - } - return result; - } -}; - - +template <class T> +struct hash<NYT::TMutableRange<T>> +{ + size_t operator()(const NYT::TMutableRange<T>& range) const + { + size_t result = 0; + for (const auto& element : range) { + NYT::HashCombine(result, element); + } + return result; + } +}; + + diff --git a/library/cpp/yt/memory/ref-inl.h b/library/cpp/yt/memory/ref-inl.h index 79be8356c5..6d11347527 100644 --- a/library/cpp/yt/memory/ref-inl.h +++ b/library/cpp/yt/memory/ref-inl.h @@ -1,517 +1,517 @@ -#ifndef REF_INL_H_ -#error "Direct inclusion of this file is not allowed, include ref.h" -// For the sake of sane code completion. -#include "ref.h" -#endif - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -namespace NDetail { - +#ifndef REF_INL_H_ +#error "Direct inclusion of this file is not allowed, include ref.h" +// For the sake of sane code completion. +#include "ref.h" +#endif + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + extern const char EmptyRefData[]; extern char MutableEmptyRefData[]; - -} // namespace NDetail - -//////////////////////////////////////////////////////////////////////////////// - -Y_FORCE_INLINE TRef::TRef(const void* data, size_t size) - : TRange<char>(static_cast<const char*>(data), size) -{ } - -Y_FORCE_INLINE TRef::TRef(const void* begin, const void* end) - : TRange<char>(static_cast<const char*>(begin), static_cast<const char*>(end)) -{ } - -Y_FORCE_INLINE TRef TRef::MakeEmpty() -{ - return TRef(NDetail::EmptyRefData, NDetail::EmptyRefData); -} - -Y_FORCE_INLINE TRef TRef::FromString(const TString& str) -{ - return FromStringBuf(str); -} - -Y_FORCE_INLINE TRef TRef::FromStringBuf(TStringBuf strBuf) -{ - return TRef(strBuf.data(), strBuf.length()); -} - -template <class T> -Y_FORCE_INLINE TRef TRef::FromPod(const T& data) -{ - static_assert(TTypeTraits<T>::IsPod || std::is_pod<T>::value, "T must be a pod-type."); - return TRef(&data, sizeof (data)); -} - -Y_FORCE_INLINE TRef TRef::Slice(size_t startOffset, size_t endOffset) const -{ - YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); - return TRef(Begin() + startOffset, endOffset - startOffset); -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_FORCE_INLINE TMutableRef::TMutableRef(void* data, size_t size) - : TMutableRange<char>(static_cast<char*>(data), size) -{ } - -Y_FORCE_INLINE TMutableRef::TMutableRef(void* begin, void* end) - : TMutableRange<char>(static_cast<char*>(begin), static_cast<char*>(end)) -{ } - -Y_FORCE_INLINE TMutableRef TMutableRef::MakeEmpty() -{ - return TMutableRef(NDetail::MutableEmptyRefData, NDetail::MutableEmptyRefData); -} - -Y_FORCE_INLINE TMutableRef::operator TRef() const -{ - return TRef(Begin(), Size()); -} - -template <class T> -Y_FORCE_INLINE TMutableRef TMutableRef::FromPod(T& data) -{ - static_assert(TTypeTraits<T>::IsPod || std::is_pod<T>::value, "T must be a pod-type."); - return TMutableRef(&data, sizeof (data)); -} - -Y_FORCE_INLINE TMutableRef TMutableRef::FromString(TString& str) -{ - // NB: begin() invokes CloneIfShared(). - return TMutableRef(str.begin(), str.length()); -} - -Y_FORCE_INLINE TMutableRef TMutableRef::Slice(size_t startOffset, size_t endOffset) const -{ - YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); - return TMutableRef(Begin() + startOffset, endOffset - startOffset); -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_FORCE_INLINE TSharedRef::TSharedRef(TRef ref, TSharedRange<char>::THolderPtr holder) - : TSharedRange<char>(ref, std::move(holder)) -{ } - -Y_FORCE_INLINE TSharedRef::TSharedRef(const void* data, size_t length, TSharedRange<char>::THolderPtr holder) - : TSharedRange<char>(static_cast<const char*>(data), length, std::move(holder)) -{ } - -Y_FORCE_INLINE TSharedRef::TSharedRef(const void* begin, const void* end, TSharedRange<char>::THolderPtr holder) - : TSharedRange<char>(static_cast<const char*>(begin), static_cast<const char*>(end), std::move(holder)) -{ } - -Y_FORCE_INLINE TSharedRef TSharedRef::MakeEmpty() -{ - return TSharedRef(TRef::MakeEmpty(), nullptr); -} - -Y_FORCE_INLINE TSharedRef::operator TRef() const -{ - return TRef(Begin(), Size()); -} - -template <class TTag> -Y_FORCE_INLINE TSharedRef TSharedRef::FromString(TString str) -{ - return FromString(std::move(str), GetRefCountedTypeCookie<TTag>()); -} - -Y_FORCE_INLINE TSharedRef TSharedRef::FromString(TString str) -{ - return FromString<TDefaultSharedBlobTag>(std::move(str)); -} - -template <class TTag> -Y_FORCE_INLINE TSharedRef TSharedRef::MakeCopy(TRef ref) -{ - return MakeCopy(ref, GetRefCountedTypeCookie<TTag>()); -} - -Y_FORCE_INLINE TSharedRef TSharedRef::Slice(size_t startOffset, size_t endOffset) const -{ - YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); - return TSharedRef(Begin() + startOffset, endOffset - startOffset, Holder_); -} - -Y_FORCE_INLINE TSharedRef TSharedRef::Slice(const void* begin, const void* end) const -{ - YT_ASSERT(begin >= Begin()); - YT_ASSERT(end <= End()); - return TSharedRef(begin, end, Holder_); -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(const TMutableRef& ref, TSharedMutableRange<char>::THolderPtr holder) - : TSharedMutableRange<char>(ref, std::move(holder)) -{ } - -Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(void* data, size_t length, TSharedMutableRange<char>::THolderPtr holder) - : TSharedMutableRange<char>(static_cast<char*>(data), length, std::move(holder)) -{ } - -Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(void* begin, void* end, TSharedMutableRange<char>::THolderPtr holder) - : TSharedMutableRange<char>(static_cast<char*>(begin), static_cast<char*>(end), std::move(holder)) -{ } - -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::MakeEmpty() -{ - return TSharedMutableRef(TMutableRef::MakeEmpty(), nullptr); -} - -Y_FORCE_INLINE TSharedMutableRef::operator TMutableRef() const -{ - return TMutableRef(Begin(), Size()); -} - -Y_FORCE_INLINE TSharedMutableRef::operator TSharedRef() const -{ - return TSharedRef(Begin(), Size(), Holder_); -} - -Y_FORCE_INLINE TSharedMutableRef::operator TRef() const -{ - return TRef(Begin(), Size()); -} - -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage) -{ - return Allocate<TDefaultSharedBlobTag>(size, initializeStorage); -} - -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage) -{ - return AllocatePageAligned<TDefaultSharedBlobTag>(size, initializeStorage); -} - -template <class TTag> -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::MakeCopy(TRef ref) -{ - return MakeCopy(ref, GetRefCountedTypeCookie<TTag>()); -} - -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Slice(size_t startOffset, size_t endOffset) const -{ - YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); - return TSharedMutableRef(Begin() + startOffset, endOffset - startOffset, Holder_); -} - -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Slice(void* begin, void* end) const -{ - YT_ASSERT(begin >= Begin()); - YT_ASSERT(end <= End()); - return TSharedMutableRef(begin, end, Holder_); -} - -template <class TTag> -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage) -{ - return Allocate(size, initializeStorage, GetRefCountedTypeCookie<TTag>()); -} - -template <class TTag> -Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage) -{ - return AllocatePageAligned(size, initializeStorage, GetRefCountedTypeCookie<TTag>()); -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_FORCE_INLINE size_t GetByteSize(TRef ref) -{ - return ref ? ref.Size() : 0; -} - -template <class T> -size_t GetByteSize(TRange<T> parts) -{ - size_t size = 0; - for (const auto& part : parts) { - size += part.Size(); - } - return size; -} - -template <class T> -size_t GetByteSize(const std::vector<T>& parts) -{ - return GetByteSize(MakeRange(parts)); -} - -//////////////////////////////////////////////////////////////////////////////// - -class TSharedRefArrayImpl - : public TRefCounted - , public TWithExtraSpace<TSharedRefArrayImpl> -{ -public: - TSharedRefArrayImpl( - size_t extraSpaceSize, - TRefCountedTypeCookie tagCookie, - size_t size) - : Size_(size) - , ExtraSpaceSize_(extraSpaceSize) - , TagCookie_(tagCookie) - { - for (size_t index = 0; index < Size_; ++index) { - new (MutableBegin() + index) TSharedRef(); - } - RegisterWithRefCountedTracker(); - } - - TSharedRefArrayImpl( - size_t extraSpaceSize, - TRefCountedTypeCookie tagCookie, - const TSharedRef& part) - : Size_(1) - , ExtraSpaceSize_(extraSpaceSize) - , TagCookie_(tagCookie) - { - new (MutableBegin()) TSharedRef(part); - RegisterWithRefCountedTracker(); - } - - TSharedRefArrayImpl( - size_t extraSpaceSize, - TRefCountedTypeCookie tagCookie, - TSharedRef&& part) - : Size_(1) - , ExtraSpaceSize_(extraSpaceSize) - , TagCookie_(tagCookie) - { - new (MutableBegin()) TSharedRef(std::move(part)); - RegisterWithRefCountedTracker(); - } - - template <class TParts> - TSharedRefArrayImpl( - size_t extraSpaceSize, - TRefCountedTypeCookie tagCookie, - const TParts& parts, - TSharedRefArray::TCopyParts) - : Size_(parts.size()) - , ExtraSpaceSize_(extraSpaceSize) - , TagCookie_(tagCookie) - { - for (size_t index = 0; index < Size_; ++index) { - new (MutableBegin() + index) TSharedRef(parts[index]); - } - RegisterWithRefCountedTracker(); - } - - template <class TParts> - TSharedRefArrayImpl( - size_t extraSpaceSize, - TRefCountedTypeCookie tagCookie, - TParts&& parts, - TSharedRefArray::TMoveParts) - : Size_(parts.size()) - , ExtraSpaceSize_(extraSpaceSize) - , TagCookie_(tagCookie) - { - for (size_t index = 0; index < Size_; ++index) { - new (MutableBegin() + index) TSharedRef(std::move(parts[index])); - } - RegisterWithRefCountedTracker(); - } - - ~TSharedRefArrayImpl() - { - for (size_t index = 0; index < Size_; ++index) { - auto& part = MutableBegin()[index]; - if (part.GetHolder() == this) { - part.Holder_.Release(); - } - part.TSharedRef::~TSharedRef(); - } - UnregisterFromRefCountedTracker(); - } - - - size_t Size() const - { - return Size_; - } - - bool Empty() const - { - return Size_ == 0; - } - - const TSharedRef& operator [] (size_t index) const - { - YT_ASSERT(index < Size()); - return Begin()[index]; - } - - - const TSharedRef* Begin() const - { - return static_cast<const TSharedRef*>(GetExtraSpacePtr()); - } - - const TSharedRef* End() const - { - return Begin() + Size_; - } - -private: - friend class TSharedRefArrayBuilder; - - const size_t Size_; - const size_t ExtraSpaceSize_; - const TRefCountedTypeCookie TagCookie_; - - - void RegisterWithRefCountedTracker() - { - TRefCountedTrackerFacade::AllocateTagInstance(TagCookie_); - TRefCountedTrackerFacade::AllocateSpace(TagCookie_, ExtraSpaceSize_); - } - - void UnregisterFromRefCountedTracker() - { - TRefCountedTrackerFacade::FreeTagInstance(TagCookie_); - TRefCountedTrackerFacade::FreeSpace(TagCookie_, ExtraSpaceSize_); - } - - - TSharedRef* MutableBegin() - { - return static_cast<TSharedRef*>(GetExtraSpacePtr()); - } - - TSharedRef* MutableEnd() - { - return MutableBegin() + Size_; - } - - char* GetBeginAllocationPtr() - { - return static_cast<char*>(static_cast<void*>(MutableEnd())); - } -}; - -DEFINE_REFCOUNTED_TYPE(TSharedRefArrayImpl) - -//////////////////////////////////////////////////////////////////////////////// - -struct TSharedRefArrayTag { }; - -Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TIntrusivePtr<TSharedRefArrayImpl> impl) - : Impl_(std::move(impl)) -{ } - -Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TSharedRefArray& other) - : Impl_(other.Impl_) -{ } - -Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TSharedRefArray&& other) noexcept - : Impl_(std::move(other.Impl_)) -{ } - -Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TSharedRef& part) - : Impl_(NewImpl(1, 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), part)) -{ } - -Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TSharedRef&& part) - : Impl_(NewImpl(1, 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), std::move(part))) -{ } - -template <class TParts> -Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TParts& parts, TSharedRefArray::TCopyParts) - : Impl_(NewImpl(parts.size(), 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), parts, TSharedRefArray::TCopyParts{})) -{ } - -template <class TParts> -Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TParts&& parts, TSharedRefArray::TMoveParts) - : Impl_(NewImpl(parts.size(), 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), std::move(parts), TSharedRefArray::TMoveParts{})) -{ } - -Y_FORCE_INLINE TSharedRefArray& TSharedRefArray::operator=(const TSharedRefArray& other) -{ - Impl_ = other.Impl_; - return *this; -} - -Y_FORCE_INLINE TSharedRefArray& TSharedRefArray::operator=(TSharedRefArray&& other) -{ - Impl_ = std::move(other.Impl_); - return *this; -} - -Y_FORCE_INLINE void TSharedRefArray::Reset() -{ - Impl_.Reset(); -} - -Y_FORCE_INLINE TSharedRefArray::operator bool() const -{ - return Impl_.operator bool(); -} - -Y_FORCE_INLINE size_t TSharedRefArray::Size() const -{ - return Impl_ ? Impl_->Size() : 0; -} - + +} // namespace NDetail + +//////////////////////////////////////////////////////////////////////////////// + +Y_FORCE_INLINE TRef::TRef(const void* data, size_t size) + : TRange<char>(static_cast<const char*>(data), size) +{ } + +Y_FORCE_INLINE TRef::TRef(const void* begin, const void* end) + : TRange<char>(static_cast<const char*>(begin), static_cast<const char*>(end)) +{ } + +Y_FORCE_INLINE TRef TRef::MakeEmpty() +{ + return TRef(NDetail::EmptyRefData, NDetail::EmptyRefData); +} + +Y_FORCE_INLINE TRef TRef::FromString(const TString& str) +{ + return FromStringBuf(str); +} + +Y_FORCE_INLINE TRef TRef::FromStringBuf(TStringBuf strBuf) +{ + return TRef(strBuf.data(), strBuf.length()); +} + +template <class T> +Y_FORCE_INLINE TRef TRef::FromPod(const T& data) +{ + static_assert(TTypeTraits<T>::IsPod || std::is_pod<T>::value, "T must be a pod-type."); + return TRef(&data, sizeof (data)); +} + +Y_FORCE_INLINE TRef TRef::Slice(size_t startOffset, size_t endOffset) const +{ + YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); + return TRef(Begin() + startOffset, endOffset - startOffset); +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_FORCE_INLINE TMutableRef::TMutableRef(void* data, size_t size) + : TMutableRange<char>(static_cast<char*>(data), size) +{ } + +Y_FORCE_INLINE TMutableRef::TMutableRef(void* begin, void* end) + : TMutableRange<char>(static_cast<char*>(begin), static_cast<char*>(end)) +{ } + +Y_FORCE_INLINE TMutableRef TMutableRef::MakeEmpty() +{ + return TMutableRef(NDetail::MutableEmptyRefData, NDetail::MutableEmptyRefData); +} + +Y_FORCE_INLINE TMutableRef::operator TRef() const +{ + return TRef(Begin(), Size()); +} + +template <class T> +Y_FORCE_INLINE TMutableRef TMutableRef::FromPod(T& data) +{ + static_assert(TTypeTraits<T>::IsPod || std::is_pod<T>::value, "T must be a pod-type."); + return TMutableRef(&data, sizeof (data)); +} + +Y_FORCE_INLINE TMutableRef TMutableRef::FromString(TString& str) +{ + // NB: begin() invokes CloneIfShared(). + return TMutableRef(str.begin(), str.length()); +} + +Y_FORCE_INLINE TMutableRef TMutableRef::Slice(size_t startOffset, size_t endOffset) const +{ + YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); + return TMutableRef(Begin() + startOffset, endOffset - startOffset); +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_FORCE_INLINE TSharedRef::TSharedRef(TRef ref, TSharedRange<char>::THolderPtr holder) + : TSharedRange<char>(ref, std::move(holder)) +{ } + +Y_FORCE_INLINE TSharedRef::TSharedRef(const void* data, size_t length, TSharedRange<char>::THolderPtr holder) + : TSharedRange<char>(static_cast<const char*>(data), length, std::move(holder)) +{ } + +Y_FORCE_INLINE TSharedRef::TSharedRef(const void* begin, const void* end, TSharedRange<char>::THolderPtr holder) + : TSharedRange<char>(static_cast<const char*>(begin), static_cast<const char*>(end), std::move(holder)) +{ } + +Y_FORCE_INLINE TSharedRef TSharedRef::MakeEmpty() +{ + return TSharedRef(TRef::MakeEmpty(), nullptr); +} + +Y_FORCE_INLINE TSharedRef::operator TRef() const +{ + return TRef(Begin(), Size()); +} + +template <class TTag> +Y_FORCE_INLINE TSharedRef TSharedRef::FromString(TString str) +{ + return FromString(std::move(str), GetRefCountedTypeCookie<TTag>()); +} + +Y_FORCE_INLINE TSharedRef TSharedRef::FromString(TString str) +{ + return FromString<TDefaultSharedBlobTag>(std::move(str)); +} + +template <class TTag> +Y_FORCE_INLINE TSharedRef TSharedRef::MakeCopy(TRef ref) +{ + return MakeCopy(ref, GetRefCountedTypeCookie<TTag>()); +} + +Y_FORCE_INLINE TSharedRef TSharedRef::Slice(size_t startOffset, size_t endOffset) const +{ + YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); + return TSharedRef(Begin() + startOffset, endOffset - startOffset, Holder_); +} + +Y_FORCE_INLINE TSharedRef TSharedRef::Slice(const void* begin, const void* end) const +{ + YT_ASSERT(begin >= Begin()); + YT_ASSERT(end <= End()); + return TSharedRef(begin, end, Holder_); +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(const TMutableRef& ref, TSharedMutableRange<char>::THolderPtr holder) + : TSharedMutableRange<char>(ref, std::move(holder)) +{ } + +Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(void* data, size_t length, TSharedMutableRange<char>::THolderPtr holder) + : TSharedMutableRange<char>(static_cast<char*>(data), length, std::move(holder)) +{ } + +Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(void* begin, void* end, TSharedMutableRange<char>::THolderPtr holder) + : TSharedMutableRange<char>(static_cast<char*>(begin), static_cast<char*>(end), std::move(holder)) +{ } + +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::MakeEmpty() +{ + return TSharedMutableRef(TMutableRef::MakeEmpty(), nullptr); +} + +Y_FORCE_INLINE TSharedMutableRef::operator TMutableRef() const +{ + return TMutableRef(Begin(), Size()); +} + +Y_FORCE_INLINE TSharedMutableRef::operator TSharedRef() const +{ + return TSharedRef(Begin(), Size(), Holder_); +} + +Y_FORCE_INLINE TSharedMutableRef::operator TRef() const +{ + return TRef(Begin(), Size()); +} + +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage) +{ + return Allocate<TDefaultSharedBlobTag>(size, initializeStorage); +} + +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage) +{ + return AllocatePageAligned<TDefaultSharedBlobTag>(size, initializeStorage); +} + +template <class TTag> +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::MakeCopy(TRef ref) +{ + return MakeCopy(ref, GetRefCountedTypeCookie<TTag>()); +} + +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Slice(size_t startOffset, size_t endOffset) const +{ + YT_ASSERT(endOffset >= startOffset && endOffset <= Size()); + return TSharedMutableRef(Begin() + startOffset, endOffset - startOffset, Holder_); +} + +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Slice(void* begin, void* end) const +{ + YT_ASSERT(begin >= Begin()); + YT_ASSERT(end <= End()); + return TSharedMutableRef(begin, end, Holder_); +} + +template <class TTag> +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage) +{ + return Allocate(size, initializeStorage, GetRefCountedTypeCookie<TTag>()); +} + +template <class TTag> +Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage) +{ + return AllocatePageAligned(size, initializeStorage, GetRefCountedTypeCookie<TTag>()); +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_FORCE_INLINE size_t GetByteSize(TRef ref) +{ + return ref ? ref.Size() : 0; +} + +template <class T> +size_t GetByteSize(TRange<T> parts) +{ + size_t size = 0; + for (const auto& part : parts) { + size += part.Size(); + } + return size; +} + +template <class T> +size_t GetByteSize(const std::vector<T>& parts) +{ + return GetByteSize(MakeRange(parts)); +} + +//////////////////////////////////////////////////////////////////////////////// + +class TSharedRefArrayImpl + : public TRefCounted + , public TWithExtraSpace<TSharedRefArrayImpl> +{ +public: + TSharedRefArrayImpl( + size_t extraSpaceSize, + TRefCountedTypeCookie tagCookie, + size_t size) + : Size_(size) + , ExtraSpaceSize_(extraSpaceSize) + , TagCookie_(tagCookie) + { + for (size_t index = 0; index < Size_; ++index) { + new (MutableBegin() + index) TSharedRef(); + } + RegisterWithRefCountedTracker(); + } + + TSharedRefArrayImpl( + size_t extraSpaceSize, + TRefCountedTypeCookie tagCookie, + const TSharedRef& part) + : Size_(1) + , ExtraSpaceSize_(extraSpaceSize) + , TagCookie_(tagCookie) + { + new (MutableBegin()) TSharedRef(part); + RegisterWithRefCountedTracker(); + } + + TSharedRefArrayImpl( + size_t extraSpaceSize, + TRefCountedTypeCookie tagCookie, + TSharedRef&& part) + : Size_(1) + , ExtraSpaceSize_(extraSpaceSize) + , TagCookie_(tagCookie) + { + new (MutableBegin()) TSharedRef(std::move(part)); + RegisterWithRefCountedTracker(); + } + + template <class TParts> + TSharedRefArrayImpl( + size_t extraSpaceSize, + TRefCountedTypeCookie tagCookie, + const TParts& parts, + TSharedRefArray::TCopyParts) + : Size_(parts.size()) + , ExtraSpaceSize_(extraSpaceSize) + , TagCookie_(tagCookie) + { + for (size_t index = 0; index < Size_; ++index) { + new (MutableBegin() + index) TSharedRef(parts[index]); + } + RegisterWithRefCountedTracker(); + } + + template <class TParts> + TSharedRefArrayImpl( + size_t extraSpaceSize, + TRefCountedTypeCookie tagCookie, + TParts&& parts, + TSharedRefArray::TMoveParts) + : Size_(parts.size()) + , ExtraSpaceSize_(extraSpaceSize) + , TagCookie_(tagCookie) + { + for (size_t index = 0; index < Size_; ++index) { + new (MutableBegin() + index) TSharedRef(std::move(parts[index])); + } + RegisterWithRefCountedTracker(); + } + + ~TSharedRefArrayImpl() + { + for (size_t index = 0; index < Size_; ++index) { + auto& part = MutableBegin()[index]; + if (part.GetHolder() == this) { + part.Holder_.Release(); + } + part.TSharedRef::~TSharedRef(); + } + UnregisterFromRefCountedTracker(); + } + + + size_t Size() const + { + return Size_; + } + + bool Empty() const + { + return Size_ == 0; + } + + const TSharedRef& operator [] (size_t index) const + { + YT_ASSERT(index < Size()); + return Begin()[index]; + } + + + const TSharedRef* Begin() const + { + return static_cast<const TSharedRef*>(GetExtraSpacePtr()); + } + + const TSharedRef* End() const + { + return Begin() + Size_; + } + +private: + friend class TSharedRefArrayBuilder; + + const size_t Size_; + const size_t ExtraSpaceSize_; + const TRefCountedTypeCookie TagCookie_; + + + void RegisterWithRefCountedTracker() + { + TRefCountedTrackerFacade::AllocateTagInstance(TagCookie_); + TRefCountedTrackerFacade::AllocateSpace(TagCookie_, ExtraSpaceSize_); + } + + void UnregisterFromRefCountedTracker() + { + TRefCountedTrackerFacade::FreeTagInstance(TagCookie_); + TRefCountedTrackerFacade::FreeSpace(TagCookie_, ExtraSpaceSize_); + } + + + TSharedRef* MutableBegin() + { + return static_cast<TSharedRef*>(GetExtraSpacePtr()); + } + + TSharedRef* MutableEnd() + { + return MutableBegin() + Size_; + } + + char* GetBeginAllocationPtr() + { + return static_cast<char*>(static_cast<void*>(MutableEnd())); + } +}; + +DEFINE_REFCOUNTED_TYPE(TSharedRefArrayImpl) + +//////////////////////////////////////////////////////////////////////////////// + +struct TSharedRefArrayTag { }; + +Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TIntrusivePtr<TSharedRefArrayImpl> impl) + : Impl_(std::move(impl)) +{ } + +Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TSharedRefArray& other) + : Impl_(other.Impl_) +{ } + +Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TSharedRefArray&& other) noexcept + : Impl_(std::move(other.Impl_)) +{ } + +Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TSharedRef& part) + : Impl_(NewImpl(1, 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), part)) +{ } + +Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TSharedRef&& part) + : Impl_(NewImpl(1, 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), std::move(part))) +{ } + +template <class TParts> +Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TParts& parts, TSharedRefArray::TCopyParts) + : Impl_(NewImpl(parts.size(), 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), parts, TSharedRefArray::TCopyParts{})) +{ } + +template <class TParts> +Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TParts&& parts, TSharedRefArray::TMoveParts) + : Impl_(NewImpl(parts.size(), 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), std::move(parts), TSharedRefArray::TMoveParts{})) +{ } + +Y_FORCE_INLINE TSharedRefArray& TSharedRefArray::operator=(const TSharedRefArray& other) +{ + Impl_ = other.Impl_; + return *this; +} + +Y_FORCE_INLINE TSharedRefArray& TSharedRefArray::operator=(TSharedRefArray&& other) +{ + Impl_ = std::move(other.Impl_); + return *this; +} + +Y_FORCE_INLINE void TSharedRefArray::Reset() +{ + Impl_.Reset(); +} + +Y_FORCE_INLINE TSharedRefArray::operator bool() const +{ + return Impl_.operator bool(); +} + +Y_FORCE_INLINE size_t TSharedRefArray::Size() const +{ + return Impl_ ? Impl_->Size() : 0; +} + Y_FORCE_INLINE size_t TSharedRefArray::size() const { return Impl_ ? Impl_->Size() : 0; } -Y_FORCE_INLINE bool TSharedRefArray::Empty() const -{ - return Impl_ ? Impl_->Empty() : true; -} - -Y_FORCE_INLINE const TSharedRef& TSharedRefArray::operator[](size_t index) const -{ - YT_ASSERT(Impl_); - return (*Impl_)[index]; -} - -Y_FORCE_INLINE const TSharedRef* TSharedRefArray::Begin() const -{ - return Impl_ ? Impl_->Begin() : nullptr; -} - -Y_FORCE_INLINE const TSharedRef* TSharedRefArray::End() const -{ - return Impl_ ? Impl_->End() : nullptr; -} - -template <class... As> -TSharedRefArrayImplPtr TSharedRefArray::NewImpl( - size_t size, - size_t poolCapacity, - TRefCountedTypeCookie tagCookie, - As&&... args) -{ - auto extraSpaceSize = sizeof (TSharedRef) * size + poolCapacity; - return NewWithExtraSpace<TSharedRefArrayImpl>( - extraSpaceSize, - extraSpaceSize, - tagCookie, - std::forward<As>(args)...); -} - -Y_FORCE_INLINE const TSharedRef* begin(const TSharedRefArray& array) -{ - return array.Begin(); -} - -Y_FORCE_INLINE const TSharedRef* end(const TSharedRefArray& array) -{ - return array.End(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +Y_FORCE_INLINE bool TSharedRefArray::Empty() const +{ + return Impl_ ? Impl_->Empty() : true; +} + +Y_FORCE_INLINE const TSharedRef& TSharedRefArray::operator[](size_t index) const +{ + YT_ASSERT(Impl_); + return (*Impl_)[index]; +} + +Y_FORCE_INLINE const TSharedRef* TSharedRefArray::Begin() const +{ + return Impl_ ? Impl_->Begin() : nullptr; +} + +Y_FORCE_INLINE const TSharedRef* TSharedRefArray::End() const +{ + return Impl_ ? Impl_->End() : nullptr; +} + +template <class... As> +TSharedRefArrayImplPtr TSharedRefArray::NewImpl( + size_t size, + size_t poolCapacity, + TRefCountedTypeCookie tagCookie, + As&&... args) +{ + auto extraSpaceSize = sizeof (TSharedRef) * size + poolCapacity; + return NewWithExtraSpace<TSharedRefArrayImpl>( + extraSpaceSize, + extraSpaceSize, + tagCookie, + std::forward<As>(args)...); +} + +Y_FORCE_INLINE const TSharedRef* begin(const TSharedRefArray& array) +{ + return array.Begin(); +} + +Y_FORCE_INLINE const TSharedRef* end(const TSharedRefArray& array) +{ + return array.End(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/memory/ref.cpp b/library/cpp/yt/memory/ref.cpp index e8ff42e976..18113e8570 100644 --- a/library/cpp/yt/memory/ref.cpp +++ b/library/cpp/yt/memory/ref.cpp @@ -1,25 +1,25 @@ #include "ref.h" -#include "blob.h" - -#include <library/cpp/ytalloc/api/ytalloc.h> - -#include <util/system/info.h> +#include "blob.h" +#include <library/cpp/ytalloc/api/ytalloc.h> + +#include <util/system/info.h> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// -namespace NDetail { - +namespace NDetail { + // N.B. We would prefer these arrays to be zero sized // but zero sized arrays are not supported in MSVC. const char EmptyRefData[1] = {0}; char MutableEmptyRefData[1] = {0}; - -} // namespace NDetail - -//////////////////////////////////////////////////////////////////////////////// - + +} // namespace NDetail + +//////////////////////////////////////////////////////////////////////////////// + class TBlobHolder : public TRefCounted { @@ -71,19 +71,19 @@ private: //////////////////////////////////////////////////////////////////////////////// -template <class TDerived> -class TAllocationHolderBase +template <class TDerived> +class TAllocationHolderBase : public TRefCounted { public: - TAllocationHolderBase(size_t size, TRefCountedTypeCookie cookie) + TAllocationHolderBase(size_t size, TRefCountedTypeCookie cookie) : Size_(size) #ifdef YT_ENABLE_REF_COUNTED_TRACKING , Cookie_(cookie) #endif - { } - - ~TAllocationHolderBase() + { } + + ~TAllocationHolderBase() { #ifdef YT_ENABLE_REF_COUNTED_TRACKING TRefCountedTrackerFacade::FreeTagInstance(Cookie_); @@ -93,25 +93,25 @@ public: TMutableRef GetRef() { - return TMutableRef(static_cast<TDerived*>(this)->GetBegin(), Size_); + return TMutableRef(static_cast<TDerived*>(this)->GetBegin(), Size_); } -protected: +protected: const size_t Size_; #ifdef YT_ENABLE_REF_COUNTED_TRACKING const TRefCountedTypeCookie Cookie_; #endif - - void Initialize(bool initializeStorage) - { - if (initializeStorage) { - ::memset(static_cast<TDerived*>(this)->GetBegin(), 0, Size_); - } -#ifdef YT_ENABLE_REF_COUNTED_TRACKING - TRefCountedTrackerFacade::AllocateTagInstance(Cookie_); - TRefCountedTrackerFacade::AllocateSpace(Cookie_, Size_); -#endif - } + + void Initialize(bool initializeStorage) + { + if (initializeStorage) { + ::memset(static_cast<TDerived*>(this)->GetBegin(), 0, Size_); + } +#ifdef YT_ENABLE_REF_COUNTED_TRACKING + TRefCountedTrackerFacade::AllocateTagInstance(Cookie_); + TRefCountedTrackerFacade::AllocateSpace(Cookie_, Size_); +#endif + } }; //////////////////////////////////////////////////////////////////////////////// @@ -119,171 +119,171 @@ protected: class TDefaultAllocationHolder : public TAllocationHolderBase<TDefaultAllocationHolder> , public TWithExtraSpace<TDefaultAllocationHolder> -{ -public: +{ +public: TDefaultAllocationHolder(size_t size, bool initializeStorage, TRefCountedTypeCookie cookie) - : TAllocationHolderBase(size, cookie) - { - Initialize(initializeStorage); - } - - char* GetBegin() - { - return static_cast<char*>(GetExtraSpacePtr()); - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -class TPageAlignedAllocationHolder - : public TAllocationHolderBase<TPageAlignedAllocationHolder> -{ -public: - TPageAlignedAllocationHolder(size_t size, bool initializeStorage, TRefCountedTypeCookie cookie) - : TAllocationHolderBase(size, cookie) - , Begin_(static_cast<char*>(NYTAlloc::AllocatePageAligned(size))) - { - Initialize(initializeStorage); - } - - ~TPageAlignedAllocationHolder() - { - NYTAlloc::Free(Begin_); - } - - char* GetBegin() - { - return Begin_; - } - -private: - char* const Begin_; -}; - -//////////////////////////////////////////////////////////////////////////////// - -TRef TRef::FromBlob(const TBlob& blob) -{ - return TRef(blob.Begin(), blob.Size()); -} - -bool TRef::AreBitwiseEqual(TRef lhs, TRef rhs) -{ - if (lhs.Size() != rhs.Size()) { - return false; - } - if (lhs.Size() == 0) { - return true; - } - return ::memcmp(lhs.Begin(), rhs.Begin(), lhs.Size()) == 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TMutableRef TMutableRef::FromBlob(TBlob& blob) -{ - return TMutableRef(blob.Begin(), blob.Size()); -} - -//////////////////////////////////////////////////////////////////////////////// - -TSharedRef TSharedRef::FromString(TString str, TRefCountedTypeCookie tagCookie) -{ - auto holder = New<TStringHolder>(std::move(str), tagCookie); + : TAllocationHolderBase(size, cookie) + { + Initialize(initializeStorage); + } + + char* GetBegin() + { + return static_cast<char*>(GetExtraSpacePtr()); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + +class TPageAlignedAllocationHolder + : public TAllocationHolderBase<TPageAlignedAllocationHolder> +{ +public: + TPageAlignedAllocationHolder(size_t size, bool initializeStorage, TRefCountedTypeCookie cookie) + : TAllocationHolderBase(size, cookie) + , Begin_(static_cast<char*>(NYTAlloc::AllocatePageAligned(size))) + { + Initialize(initializeStorage); + } + + ~TPageAlignedAllocationHolder() + { + NYTAlloc::Free(Begin_); + } + + char* GetBegin() + { + return Begin_; + } + +private: + char* const Begin_; +}; + +//////////////////////////////////////////////////////////////////////////////// + +TRef TRef::FromBlob(const TBlob& blob) +{ + return TRef(blob.Begin(), blob.Size()); +} + +bool TRef::AreBitwiseEqual(TRef lhs, TRef rhs) +{ + if (lhs.Size() != rhs.Size()) { + return false; + } + if (lhs.Size() == 0) { + return true; + } + return ::memcmp(lhs.Begin(), rhs.Begin(), lhs.Size()) == 0; +} + +//////////////////////////////////////////////////////////////////////////////// + +TMutableRef TMutableRef::FromBlob(TBlob& blob) +{ + return TMutableRef(blob.Begin(), blob.Size()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TSharedRef TSharedRef::FromString(TString str, TRefCountedTypeCookie tagCookie) +{ + auto holder = New<TStringHolder>(std::move(str), tagCookie); auto ref = TRef::FromString(holder->String()); - return TSharedRef(ref, std::move(holder)); -} - -TSharedRef TSharedRef::FromBlob(TBlob&& blob) -{ - auto ref = TRef::FromBlob(blob); - auto holder = New<TBlobHolder>(std::move(blob)); - return TSharedRef(ref, std::move(holder)); -} - -TSharedRef TSharedRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie) -{ - if (!ref) { - return {}; - } + return TSharedRef(ref, std::move(holder)); +} + +TSharedRef TSharedRef::FromBlob(TBlob&& blob) +{ + auto ref = TRef::FromBlob(blob); + auto holder = New<TBlobHolder>(std::move(blob)); + return TSharedRef(ref, std::move(holder)); +} + +TSharedRef TSharedRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie) +{ + if (!ref) { + return {}; + } if (ref.Empty()) { - return TSharedRef::MakeEmpty(); + return TSharedRef::MakeEmpty(); } auto result = TSharedMutableRef::Allocate(ref.Size(), false, tagCookie); ::memcpy(result.Begin(), ref.Begin(), ref.Size()); return result; -} - -std::vector<TSharedRef> TSharedRef::Split(size_t partSize) const -{ - YT_VERIFY(partSize > 0); - std::vector<TSharedRef> result; - result.reserve(Size() / partSize + 1); - auto sliceBegin = Begin(); - while (sliceBegin < End()) { - auto sliceEnd = sliceBegin + partSize; - if (sliceEnd < sliceBegin || sliceEnd > End()) { - sliceEnd = End(); - } - result.push_back(Slice(sliceBegin, sliceEnd)); - sliceBegin = sliceEnd; - } - return result; -} - -//////////////////////////////////////////////////////////////////////////////// - -TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie) -{ +} + +std::vector<TSharedRef> TSharedRef::Split(size_t partSize) const +{ + YT_VERIFY(partSize > 0); + std::vector<TSharedRef> result; + result.reserve(Size() / partSize + 1); + auto sliceBegin = Begin(); + while (sliceBegin < End()) { + auto sliceEnd = sliceBegin + partSize; + if (sliceEnd < sliceBegin || sliceEnd > End()) { + sliceEnd = End(); + } + result.push_back(Slice(sliceBegin, sliceEnd)); + sliceBegin = sliceEnd; + } + return result; +} + +//////////////////////////////////////////////////////////////////////////////// + +TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie) +{ auto holder = NewWithExtraSpace<TDefaultAllocationHolder>(size, size, initializeStorage, tagCookie); - auto ref = holder->GetRef(); - return TSharedMutableRef(ref, std::move(holder)); -} - -TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie) -{ - auto holder = New<TPageAlignedAllocationHolder>(size, initializeStorage, tagCookie); - auto ref = holder->GetRef(); - return TSharedMutableRef(ref, std::move(holder)); -} - -TSharedMutableRef TSharedMutableRef::FromBlob(TBlob&& blob) -{ - auto ref = TMutableRef::FromBlob(blob); - auto holder = New<TBlobHolder>(std::move(blob)); - return TSharedMutableRef(ref, std::move(holder)); -} - -TSharedMutableRef TSharedMutableRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie) -{ - if (!ref) { - return {}; - } + auto ref = holder->GetRef(); + return TSharedMutableRef(ref, std::move(holder)); +} + +TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie) +{ + auto holder = New<TPageAlignedAllocationHolder>(size, initializeStorage, tagCookie); + auto ref = holder->GetRef(); + return TSharedMutableRef(ref, std::move(holder)); +} + +TSharedMutableRef TSharedMutableRef::FromBlob(TBlob&& blob) +{ + auto ref = TMutableRef::FromBlob(blob); + auto holder = New<TBlobHolder>(std::move(blob)); + return TSharedMutableRef(ref, std::move(holder)); +} + +TSharedMutableRef TSharedMutableRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie) +{ + if (!ref) { + return {}; + } if (ref.Empty()) { - return TSharedMutableRef::MakeEmpty(); + return TSharedMutableRef::MakeEmpty(); } auto result = Allocate(ref.Size(), false, tagCookie); ::memcpy(result.Begin(), ref.Begin(), ref.Size()); return result; -} - +} + //////////////////////////////////////////////////////////////////////////////// -TString ToString(TRef ref) -{ +TString ToString(TRef ref) +{ return TString(ref.Begin(), ref.End()); -} - +} + TString ToString(const TMutableRef& ref) { return ToString(TRef(ref)); } -TString ToString(const TSharedRef& ref) -{ - return ToString(TRef(ref)); -} - +TString ToString(const TSharedRef& ref) +{ + return ToString(TRef(ref)); +} + TString ToString(const TSharedMutableRef& ref) { return ToString(TRef(ref)); @@ -298,23 +298,23 @@ size_t GetPageSize() size_t RoundUpToPage(size_t bytes) { static const size_t PageSize = NSystemInfo::GetPageSize(); - YT_ASSERT((PageSize & (PageSize - 1)) == 0); + YT_ASSERT((PageSize & (PageSize - 1)) == 0); return (bytes + PageSize - 1) & (~(PageSize - 1)); } -size_t GetByteSize(const TSharedRefArray& array) -{ - size_t size = 0; - if (array) { - for (const auto& part : array) { - size += part.Size(); - } - } - return size; -} - -//////////////////////////////////////////////////////////////////////////////// - +size_t GetByteSize(const TSharedRefArray& array) +{ + size_t size = 0; + if (array) { + for (const auto& part : array) { + size += part.Size(); + } + } + return size; +} + +//////////////////////////////////////////////////////////////////////////////// + i64 TSharedRefArray::ByteSize() const { i64 result = 0; @@ -326,53 +326,53 @@ i64 TSharedRefArray::ByteSize() const return result; } -std::vector<TSharedRef> TSharedRefArray::ToVector() const -{ - if (!Impl_) { - return {}; - } - - return std::vector<TSharedRef>(Begin(), End()); -} - -//////////////////////////////////////////////////////////////////////////////// - -TSharedRefArrayBuilder::TSharedRefArrayBuilder( - size_t size, - size_t poolCapacity, - TRefCountedTypeCookie tagCookie) - : AllocationCapacity_(poolCapacity) - , Impl_(TSharedRefArray::NewImpl( - size, - poolCapacity, - tagCookie, - size)) - , CurrentAllocationPtr_(Impl_->GetBeginAllocationPtr()) -{ } - -void TSharedRefArrayBuilder::Add(TSharedRef part) -{ - YT_ASSERT(CurrentPartIndex_ < Impl_->Size()); - Impl_->MutableBegin()[CurrentPartIndex_++] = std::move(part); -} - -TMutableRef TSharedRefArrayBuilder::AllocateAndAdd(size_t size) -{ - YT_ASSERT(CurrentPartIndex_ < Impl_->Size()); - YT_ASSERT(CurrentAllocationPtr_ + size <= Impl_->GetBeginAllocationPtr() + AllocationCapacity_); - TMutableRef ref(CurrentAllocationPtr_, size); - CurrentAllocationPtr_ += size; +std::vector<TSharedRef> TSharedRefArray::ToVector() const +{ + if (!Impl_) { + return {}; + } + + return std::vector<TSharedRef>(Begin(), End()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TSharedRefArrayBuilder::TSharedRefArrayBuilder( + size_t size, + size_t poolCapacity, + TRefCountedTypeCookie tagCookie) + : AllocationCapacity_(poolCapacity) + , Impl_(TSharedRefArray::NewImpl( + size, + poolCapacity, + tagCookie, + size)) + , CurrentAllocationPtr_(Impl_->GetBeginAllocationPtr()) +{ } + +void TSharedRefArrayBuilder::Add(TSharedRef part) +{ + YT_ASSERT(CurrentPartIndex_ < Impl_->Size()); + Impl_->MutableBegin()[CurrentPartIndex_++] = std::move(part); +} + +TMutableRef TSharedRefArrayBuilder::AllocateAndAdd(size_t size) +{ + YT_ASSERT(CurrentPartIndex_ < Impl_->Size()); + YT_ASSERT(CurrentAllocationPtr_ + size <= Impl_->GetBeginAllocationPtr() + AllocationCapacity_); + TMutableRef ref(CurrentAllocationPtr_, size); + CurrentAllocationPtr_ += size; TRefCountedPtr holder(Impl_.Get(), false); - TSharedRef sharedRef(ref, std::move(holder)); - Add(std::move(sharedRef)); - return ref; -} - -TSharedRefArray TSharedRefArrayBuilder::Finish() -{ - return TSharedRefArray(std::move(Impl_)); -} - -//////////////////////////////////////////////////////////////////////////////// - + TSharedRef sharedRef(ref, std::move(holder)); + Add(std::move(sharedRef)); + return ref; +} + +TSharedRefArray TSharedRefArrayBuilder::Finish() +{ + return TSharedRefArray(std::move(Impl_)); +} + +//////////////////////////////////////////////////////////////////////////////// + } // namespace NYT diff --git a/library/cpp/yt/memory/ref.h b/library/cpp/yt/memory/ref.h index 73d19d9013..9ad82a8258 100644 --- a/library/cpp/yt/memory/ref.h +++ b/library/cpp/yt/memory/ref.h @@ -1,53 +1,53 @@ #pragma once -#include "new.h" +#include "new.h" #include "range.h" -#include "shared_range.h" - -#include <type_traits> +#include "shared_range.h" +#include <type_traits> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// -// Forward declaration. -class TBlob; - +// Forward declaration. +class TBlob; + //! A non-owning reference to a range of memory. class TRef : public TRange<char> { public: //! Creates a null TRef. - TRef() = default; + TRef() = default; //! Creates a TRef for a given block of memory. - TRef(const void* data, size_t size); + TRef(const void* data, size_t size); //! Creates a TRef for a given range of memory. - TRef(const void* begin, const void* end); - - //! Creates an empty TRef. - static TRef MakeEmpty(); + TRef(const void* begin, const void* end); + + //! Creates an empty TRef. + static TRef MakeEmpty(); //! Creates a non-owning TRef for a given blob. - static TRef FromBlob(const TBlob& blob); + static TRef FromBlob(const TBlob& blob); //! Creates a non-owning TRef for a given string. - static TRef FromString(const TString& str); - - //! Creates a non-owning TRef for a given stringbuf. - static TRef FromStringBuf(TStringBuf strBuf); - + static TRef FromString(const TString& str); + + //! Creates a non-owning TRef for a given stringbuf. + static TRef FromStringBuf(TStringBuf strBuf); + //! Creates a non-owning TRef for a given pod structure. - template <class T> - static TRef FromPod(const T& data); + template <class T> + static TRef FromPod(const T& data); //! Creates a TRef for a part of existing range. - TRef Slice(size_t startOffset, size_t endOffset) const; + TRef Slice(size_t startOffset, size_t endOffset) const; //! Compares the content for bitwise equality. - static bool AreBitwiseEqual(TRef lhs, TRef rhs); + static bool AreBitwiseEqual(TRef lhs, TRef rhs); }; //////////////////////////////////////////////////////////////////////////////// @@ -61,107 +61,107 @@ public: //! Creates a null TMutableRef. //! Note empty TMutableRef is not the same as null TMutableRef. //! `operator bool` can be used to check if ref is nonnull. - TMutableRef() = default; + TMutableRef() = default; //! Creates a TMutableRef for a given block of memory. - TMutableRef(void* data, size_t size); + TMutableRef(void* data, size_t size); //! Creates a TMutableRef for a given range of memory. - TMutableRef(void* begin, void* end); - - //! Creates an empty TMutableRef. - static TMutableRef MakeEmpty(); + TMutableRef(void* begin, void* end); + //! Creates an empty TMutableRef. + static TMutableRef MakeEmpty(); + //! Converts a TMutableRef to TRef. - operator TRef() const; - + operator TRef() const; + //! Creates a non-owning TMutableRef for a given blob. - static TMutableRef FromBlob(TBlob& blob); + static TMutableRef FromBlob(TBlob& blob); //! Creates a non-owning TMutableRef for a given pod structure. template <class T> - static TMutableRef FromPod(T& data); - + static TMutableRef FromPod(T& data); + //! Creates a non-owning TMutableRef for a given string. //! Ensures that the string is not shared. - static TMutableRef FromString(TString& str); - + static TMutableRef FromString(TString& str); + //! Creates a TMutableRef for a part of existing range. - TMutableRef Slice(size_t startOffset, size_t endOffset) const; + TMutableRef Slice(size_t startOffset, size_t endOffset) const; }; //////////////////////////////////////////////////////////////////////////////// -//! Default tag type for memory blocks allocated via TSharedRef. -/*! +//! Default tag type for memory blocks allocated via TSharedRef. +/*! * Each newly allocated TSharedRef blob is associated with a tag type * that appears in ref-counted statistics. - */ -struct TDefaultSharedBlobTag { }; - -//! A reference to a range of memory with shared ownership. + */ +struct TDefaultSharedBlobTag { }; + +//! A reference to a range of memory with shared ownership. class TSharedRef : public TSharedRange<char> { public: //! Creates a null TSharedRef. - TSharedRef() = default; - + TSharedRef() = default; + //! Creates a TSharedRef with a given holder. - TSharedRef(TRef ref, THolderPtr holder); - + TSharedRef(TRef ref, THolderPtr holder); + //! Creates a TSharedRef from a pointer and length. - TSharedRef(const void* data, size_t length, THolderPtr holder); - - //! Creates a TSharedRef from a range. - TSharedRef(const void* begin, const void* end, THolderPtr holder); - - //! Creates an empty TSharedRef. - static TSharedRef MakeEmpty(); - + TSharedRef(const void* data, size_t length, THolderPtr holder); + + //! Creates a TSharedRef from a range. + TSharedRef(const void* begin, const void* end, THolderPtr holder); + + //! Creates an empty TSharedRef. + static TSharedRef MakeEmpty(); + //! Converts a TSharedRef to TRef. - operator TRef() const; - - + operator TRef() const; + + //! Creates a TSharedRef from a string. - //! Since strings are ref-counted, no data is copied. - //! The memory is marked with a given tag. - template <class TTag> - static TSharedRef FromString(TString str); - + //! Since strings are ref-counted, no data is copied. + //! The memory is marked with a given tag. + template <class TTag> + static TSharedRef FromString(TString str); + //! Creates a TSharedRef from a string. - //! Since strings are ref-counted, no data is copied. - //! The memory is marked with TDefaultSharedBlobTag. - static TSharedRef FromString(TString str); - + //! Since strings are ref-counted, no data is copied. + //! The memory is marked with TDefaultSharedBlobTag. + static TSharedRef FromString(TString str); + //! Creates a TSharedRef reference from a string. - //! Since strings are ref-counted, no data is copied. - //! The memory is marked with a given tag. - static TSharedRef FromString(TString str, TRefCountedTypeCookie tagCookie); - + //! Since strings are ref-counted, no data is copied. + //! The memory is marked with a given tag. + static TSharedRef FromString(TString str, TRefCountedTypeCookie tagCookie); + //! Creates a TSharedRef for a given blob taking ownership of its content. - static TSharedRef FromBlob(TBlob&& blob); + static TSharedRef FromBlob(TBlob&& blob); //! Creates a copy of a given TRef. //! The memory is marked with a given tag. - static TSharedRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie); + static TSharedRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie); //! Creates a copy of a given TRef. //! The memory is marked with a given tag. template <class TTag> - static TSharedRef MakeCopy(TRef ref); + static TSharedRef MakeCopy(TRef ref); //! Creates a TSharedRef for a part of existing range. - TSharedRef Slice(size_t startOffset, size_t endOffset) const; + TSharedRef Slice(size_t startOffset, size_t endOffset) const; //! Creates a TSharedRef for a part of existing range. - TSharedRef Slice(const void* begin, const void* end) const; + TSharedRef Slice(const void* begin, const void* end) const; //! Creates a vector of slices with specified size. - std::vector<TSharedRef> Split(size_t partSize) const; + std::vector<TSharedRef> Split(size_t partSize) const; private: - friend class TSharedRefArrayImpl; + friend class TSharedRefArrayImpl; }; //////////////////////////////////////////////////////////////////////////////// @@ -173,194 +173,194 @@ class TSharedMutableRef { public: //! Creates a null TSharedMutableRef. - TSharedMutableRef() = default; + TSharedMutableRef() = default; //! Creates a TSharedMutableRef with a given holder. - TSharedMutableRef(const TMutableRef& ref, THolderPtr holder); + TSharedMutableRef(const TMutableRef& ref, THolderPtr holder); //! Creates a TSharedMutableRef from a pointer and length. - TSharedMutableRef(void* data, size_t length, THolderPtr holder); + TSharedMutableRef(void* data, size_t length, THolderPtr holder); - //! Creates a TSharedMutableRef from a range. - TSharedMutableRef(void* begin, void* end, THolderPtr holder); - - //! Creates an empty TSharedMutableRef. - static TSharedMutableRef MakeEmpty(); + //! Creates a TSharedMutableRef from a range. + TSharedMutableRef(void* begin, void* end, THolderPtr holder); + //! Creates an empty TSharedMutableRef. + static TSharedMutableRef MakeEmpty(); + //! Converts a TSharedMutableRef to TMutableRef. - operator TMutableRef() const; + operator TMutableRef() const; //! Converts a TSharedMutableRef to TSharedRef. - operator TSharedRef() const; + operator TSharedRef() const; //! Converts a TSharedMutableRef to TRef. - operator TRef() const; + operator TRef() const; //! Allocates a new shared block of memory. //! The memory is marked with a given tag. template <class TTag> - static TSharedMutableRef Allocate(size_t size, bool initializeStorage = true); - + static TSharedMutableRef Allocate(size_t size, bool initializeStorage = true); + //! Allocates a new shared block of memory. //! The memory is marked with TDefaultSharedBlobTag. - static TSharedMutableRef Allocate(size_t size, bool initializeStorage = true); - + static TSharedMutableRef Allocate(size_t size, bool initializeStorage = true); + //! Allocates a new shared block of memory. //! The memory is marked with a given tag. - static TSharedMutableRef Allocate(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie); - - //! Allocates a new page aligned shared block of memory. - //! #size must be divisible by page size. - //! The memory is marked with a given tag. - template <class TTag> - static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage = true); - - //! Allocates a new page aligned shared block of memory. - //! #size must be divisible by page size. - //! The memory is marked with TDefaultSharedBlobTag. - static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage = true); - - //! Allocates a new page aligned shared block of memory. - //! #size must be divisible by page size. - //! The memory is marked with a given tag. - static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie); - + static TSharedMutableRef Allocate(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie); + + //! Allocates a new page aligned shared block of memory. + //! #size must be divisible by page size. + //! The memory is marked with a given tag. + template <class TTag> + static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage = true); + + //! Allocates a new page aligned shared block of memory. + //! #size must be divisible by page size. + //! The memory is marked with TDefaultSharedBlobTag. + static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage = true); + + //! Allocates a new page aligned shared block of memory. + //! #size must be divisible by page size. + //! The memory is marked with a given tag. + static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie); + //! Creates a TSharedMutableRef for the whole blob taking ownership of its content. - static TSharedMutableRef FromBlob(TBlob&& blob); - + static TSharedMutableRef FromBlob(TBlob&& blob); + //! Creates a copy of a given TRef. //! The memory is marked with a given tag. - static TSharedMutableRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie); - + static TSharedMutableRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie); + //! Creates a copy of a given TRef. //! The memory is marked with a given tag. template <class TTag> - static TSharedMutableRef MakeCopy(TRef ref); - + static TSharedMutableRef MakeCopy(TRef ref); + //! Creates a reference for a part of existing range. - TSharedMutableRef Slice(size_t startOffset, size_t endOffset) const; - + TSharedMutableRef Slice(size_t startOffset, size_t endOffset) const; + //! Creates a reference for a part of existing range. - TSharedMutableRef Slice(void* begin, void* end) const; -}; - -//////////////////////////////////////////////////////////////////////////////// - -DECLARE_REFCOUNTED_CLASS(TSharedRefArrayImpl) - -//! A smart-pointer to a ref-counted immutable sequence of TSharedRef-s. -class TSharedRefArray -{ -public: - TSharedRefArray() = default; - TSharedRefArray(const TSharedRefArray& other); - TSharedRefArray(TSharedRefArray&& other) noexcept; - - explicit TSharedRefArray(const TSharedRef& part); - explicit TSharedRefArray(TSharedRef&& part); - - struct TCopyParts - { }; - struct TMoveParts - { }; - - template <class TParts> - TSharedRefArray(const TParts& parts, TCopyParts); - template <class TParts> - TSharedRefArray(TParts&& parts, TMoveParts); - + TSharedMutableRef Slice(void* begin, void* end) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +DECLARE_REFCOUNTED_CLASS(TSharedRefArrayImpl) + +//! A smart-pointer to a ref-counted immutable sequence of TSharedRef-s. +class TSharedRefArray +{ +public: + TSharedRefArray() = default; + TSharedRefArray(const TSharedRefArray& other); + TSharedRefArray(TSharedRefArray&& other) noexcept; + + explicit TSharedRefArray(const TSharedRef& part); + explicit TSharedRefArray(TSharedRef&& part); + + struct TCopyParts + { }; + struct TMoveParts + { }; + + template <class TParts> + TSharedRefArray(const TParts& parts, TCopyParts); + template <class TParts> + TSharedRefArray(TParts&& parts, TMoveParts); + TSharedRefArray& operator = (const TSharedRefArray& other); TSharedRefArray& operator = (TSharedRefArray&& other); - - explicit operator bool() const; - + + explicit operator bool() const; + void Reset(); - size_t Size() const; + size_t Size() const; size_t size() const; i64 ByteSize() const; - bool Empty() const; - const TSharedRef& operator [] (size_t index) const; - - const TSharedRef* Begin() const; - const TSharedRef* End() const; - - std::vector<TSharedRef> ToVector() const; - -private: - friend class TSharedRefArrayBuilder; - - TSharedRefArrayImplPtr Impl_; - - explicit TSharedRefArray(TSharedRefArrayImplPtr impl); - - template <class... As> - static TSharedRefArrayImplPtr NewImpl( - size_t size, - size_t poolCapacity, - TRefCountedTypeCookie cookie, - As&&... args); + bool Empty() const; + const TSharedRef& operator [] (size_t index) const; + + const TSharedRef* Begin() const; + const TSharedRef* End() const; + + std::vector<TSharedRef> ToVector() const; + +private: + friend class TSharedRefArrayBuilder; + + TSharedRefArrayImplPtr Impl_; + + explicit TSharedRefArray(TSharedRefArrayImplPtr impl); + + template <class... As> + static TSharedRefArrayImplPtr NewImpl( + size_t size, + size_t poolCapacity, + TRefCountedTypeCookie cookie, + As&&... args); }; // STL interop. -const TSharedRef* begin(const TSharedRefArray& array); -const TSharedRef* end(const TSharedRefArray& array); - -//////////////////////////////////////////////////////////////////////////////// - -struct TDefaultSharedRefArrayBuilderTag { }; - -//! A helper for creating TSharedRefArray. -class TSharedRefArrayBuilder -{ -public: - //! Creates a builder instance. - /* - * The user must provide the total (resulting) part count in #size. - * - * Additionally, the user may request a certain memory pool of size #poolCapacity - * to be created. Parts occupiying space in the above pool are created with #AllocateAndAdd - * calls. - * - * The pool (if any) and the array are created within a single memory allocation tagged with - * #tagCookie. - * - * If less than #size parts are added, the trailing ones are null. - */ - explicit TSharedRefArrayBuilder( - size_t size, - size_t poolCapacity = 0, - TRefCountedTypeCookie tagCookie = GetRefCountedTypeCookie<TDefaultSharedRefArrayBuilderTag>()); - - //! Adds an existing TSharedRef part to the constructed array. - void Add(TSharedRef part); - - //! Allocates #size memory from the pool and adds a part to the constuctured array. - /*! - * The resulting TMutableRef enables the user to fill the just-created part appropriately. - * The total sum of #size during all #AllocateAndAll calls must now exceed #allocationCapacity - * passed to the ctor. - * - * The memory is being claimed from the pool contiguously; the user must - * take care of the alignment issues on its own. - */ - TMutableRef AllocateAndAdd(size_t size); - - //! Finalizes the construction; returns the constructed TSharedRefArray. - TSharedRefArray Finish(); - -private: - const size_t AllocationCapacity_; - TSharedRefArrayImplPtr Impl_; - char* CurrentAllocationPtr_; - size_t CurrentPartIndex_ = 0; -}; - - +const TSharedRef* begin(const TSharedRefArray& array); +const TSharedRef* end(const TSharedRefArray& array); + //////////////////////////////////////////////////////////////////////////////// -TString ToString(TRef ref); +struct TDefaultSharedRefArrayBuilderTag { }; + +//! A helper for creating TSharedRefArray. +class TSharedRefArrayBuilder +{ +public: + //! Creates a builder instance. + /* + * The user must provide the total (resulting) part count in #size. + * + * Additionally, the user may request a certain memory pool of size #poolCapacity + * to be created. Parts occupiying space in the above pool are created with #AllocateAndAdd + * calls. + * + * The pool (if any) and the array are created within a single memory allocation tagged with + * #tagCookie. + * + * If less than #size parts are added, the trailing ones are null. + */ + explicit TSharedRefArrayBuilder( + size_t size, + size_t poolCapacity = 0, + TRefCountedTypeCookie tagCookie = GetRefCountedTypeCookie<TDefaultSharedRefArrayBuilderTag>()); + + //! Adds an existing TSharedRef part to the constructed array. + void Add(TSharedRef part); + + //! Allocates #size memory from the pool and adds a part to the constuctured array. + /*! + * The resulting TMutableRef enables the user to fill the just-created part appropriately. + * The total sum of #size during all #AllocateAndAll calls must now exceed #allocationCapacity + * passed to the ctor. + * + * The memory is being claimed from the pool contiguously; the user must + * take care of the alignment issues on its own. + */ + TMutableRef AllocateAndAdd(size_t size); + + //! Finalizes the construction; returns the constructed TSharedRefArray. + TSharedRefArray Finish(); + +private: + const size_t AllocationCapacity_; + TSharedRefArrayImplPtr Impl_; + char* CurrentAllocationPtr_; + size_t CurrentPartIndex_ = 0; +}; + + +//////////////////////////////////////////////////////////////////////////////// + +TString ToString(TRef ref); TString ToString(const TMutableRef& ref); TString ToString(const TSharedRef& ref); TString ToString(const TSharedMutableRef& ref); @@ -368,17 +368,17 @@ TString ToString(const TSharedMutableRef& ref); size_t GetPageSize(); size_t RoundUpToPage(size_t bytes); -size_t GetByteSize(TRef ref); -size_t GetByteSize(const TSharedRefArray& array); -template <class T> -size_t GetByteSize(TRange<T> parts); +size_t GetByteSize(TRef ref); +size_t GetByteSize(const TSharedRefArray& array); template <class T> -size_t GetByteSize(const std::vector<T>& parts); +size_t GetByteSize(TRange<T> parts); +template <class T> +size_t GetByteSize(const std::vector<T>& parts); //////////////////////////////////////////////////////////////////////////////// } // namespace NYT -#define REF_INL_H_ -#include "ref-inl.h" -#undef REF_INL_H_ +#define REF_INL_H_ +#include "ref-inl.h" +#undef REF_INL_H_ diff --git a/library/cpp/yt/memory/ref_counted-inl.h b/library/cpp/yt/memory/ref_counted-inl.h index e6d64fec18..1e5eb937b5 100644 --- a/library/cpp/yt/memory/ref_counted-inl.h +++ b/library/cpp/yt/memory/ref_counted-inl.h @@ -47,7 +47,7 @@ using TDeleter = void (*)(void*); void ScheduleObjectDeletion(void* ptr, TDeleter deleter); template <class T> -struct TMemoryReleaser<T, std::enable_if_t<T::EnableHazard>> +struct TMemoryReleaser<T, std::enable_if_t<T::EnableHazard>> { static void Do(void* ptr, uint16_t offset) { @@ -94,7 +94,7 @@ Y_FORCE_INLINE bool TRefCounter::Unref() const // See http://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html#boost_atomic.usage_examples.example_reference_counters // auto oldStrongCount = StrongCount_.fetch_sub(1, std::memory_order_release); - YT_ASSERT(oldStrongCount > 0); + YT_ASSERT(oldStrongCount > 0); if (oldStrongCount == 1) { StrongCount_.load(std::memory_order_acquire); return true; diff --git a/library/cpp/yt/memory/ref_counted.h b/library/cpp/yt/memory/ref_counted.h index b683615b83..fd5d69439d 100644 --- a/library/cpp/yt/memory/ref_counted.h +++ b/library/cpp/yt/memory/ref_counted.h @@ -1,17 +1,17 @@ -#pragma once +#pragma once + +#include <library/cpp/yt/misc/port.h> -#include <library/cpp/yt/misc/port.h> - -#include <library/cpp/yt/assert/assert.h> - -#include <library/cpp/ytalloc/api/ytalloc.h> +#include <library/cpp/yt/assert/assert.h> + +#include <library/cpp/ytalloc/api/ytalloc.h> #include <atomic> -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + //! A technical base class for ref-counted objects and promise states. class TRefCountedBase { @@ -20,30 +20,30 @@ public: // Make destructor protected virtual ~TRefCountedBase() noexcept = default; - + virtual void DestroyRefCounted() = 0; - + private: - TRefCountedBase(const TRefCountedBase&) = delete; - TRefCountedBase(TRefCountedBase&&) = delete; - + TRefCountedBase(const TRefCountedBase&) = delete; + TRefCountedBase(TRefCountedBase&&) = delete; + TRefCountedBase& operator=(const TRefCountedBase&) = delete; TRefCountedBase& operator=(TRefCountedBase&&) = delete; -}; - -//////////////////////////////////////////////////////////////////////////////// - +}; + +//////////////////////////////////////////////////////////////////////////////// + template <class T, class = void> struct TFreeMemory -{ +{ static void Do(void* ptr) { NYTAlloc::FreeNonNull(ptr); } }; - + template <class T> -struct TFreeMemory<T, std::void_t<typename T::TAllocator>> +struct TFreeMemory<T, std::void_t<typename T::TAllocator>> { static void Do(void* ptr) { @@ -51,17 +51,17 @@ struct TFreeMemory<T, std::void_t<typename T::TAllocator>> TAllocator::Free(ptr); } }; - + //////////////////////////////////////////////////////////////////////////////// -class TRefCounter +class TRefCounter { -public: +public: //! Returns current number of strong references to the object. - /*! + /*! * Note that you should never ever use this method in production code. * This method is mainly for debugging purposes. - */ + */ int GetRefCount() const noexcept; //! Increments the strong reference counter. diff --git a/library/cpp/yt/memory/ref_tracked.h b/library/cpp/yt/memory/ref_tracked.h index 75c1eb5985..554f433f2f 100644 --- a/library/cpp/yt/memory/ref_tracked.h +++ b/library/cpp/yt/memory/ref_tracked.h @@ -1,7 +1,7 @@ #pragma once -#include <library/cpp/yt/misc/port.h> -#include <library/cpp/yt/misc/source_location.h> +#include <library/cpp/yt/misc/port.h> +#include <library/cpp/yt/misc/source_location.h> #include <util/system/defaults.h> @@ -78,26 +78,26 @@ public: #ifdef YT_ENABLE_REF_COUNTED_TRACKING TRefTracked() { - auto cookie = GetRefCountedTypeCookie<T>(); - TRefCountedTrackerFacade::AllocateInstance(cookie); + auto cookie = GetRefCountedTypeCookie<T>(); + TRefCountedTrackerFacade::AllocateInstance(cookie); } - TRefTracked(const TRefTracked&) + TRefTracked(const TRefTracked&) { auto cookie = GetRefCountedTypeCookie<T>(); - TRefCountedTrackerFacade::AllocateInstance(cookie); + TRefCountedTrackerFacade::AllocateInstance(cookie); } - TRefTracked(TRefTracked&&) + TRefTracked(TRefTracked&&) { auto cookie = GetRefCountedTypeCookie<T>(); - TRefCountedTrackerFacade::AllocateInstance(cookie); + TRefCountedTrackerFacade::AllocateInstance(cookie); } ~TRefTracked() { - auto cookie = GetRefCountedTypeCookie<T>(); - TRefCountedTrackerFacade::FreeInstance(cookie); + auto cookie = GetRefCountedTypeCookie<T>(); + TRefCountedTrackerFacade::FreeInstance(cookie); } #endif }; diff --git a/library/cpp/yt/memory/shared_range.h b/library/cpp/yt/memory/shared_range.h index 9841d7a0df..81a1266ff1 100644 --- a/library/cpp/yt/memory/shared_range.h +++ b/library/cpp/yt/memory/shared_range.h @@ -1,48 +1,48 @@ -#pragma once - -#include "intrusive_ptr.h" +#pragma once + +#include "intrusive_ptr.h" #include "range.h" #include "ref_counted.h" - -#include <library/cpp/yt/assert/assert.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - + +#include <library/cpp/yt/assert/assert.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + template <class T, size_t N> class TCompactVector; -//! TRange with ownership semantics. -template <class T> -class TSharedRange - : public TRange<T> -{ -public: +//! TRange with ownership semantics. +template <class T> +class TSharedRange + : public TRange<T> +{ +public: using THolderPtr = TRefCountedPtr; - + //! Constructs a null TSharedRange. - TSharedRange() - { } - - //! Constructs a TSharedRange from TRange. - TSharedRange(TRange<T> range, THolderPtr holder) - : TRange<T>(range) - , Holder_(std::move(holder)) - { } - - //! Constructs a TSharedRange from a pointer and length. - TSharedRange(const T* data, size_t length, THolderPtr holder) - : TRange<T>(data, length) - , Holder_(std::move(holder)) - { } - - //! Constructs a TSharedRange from a range. - TSharedRange(const T* begin, const T* end, THolderPtr holder) - : TRange<T>(begin, end) - , Holder_(std::move(holder)) - { } - + TSharedRange() + { } + + //! Constructs a TSharedRange from TRange. + TSharedRange(TRange<T> range, THolderPtr holder) + : TRange<T>(range) + , Holder_(std::move(holder)) + { } + + //! Constructs a TSharedRange from a pointer and length. + TSharedRange(const T* data, size_t length, THolderPtr holder) + : TRange<T>(data, length) + , Holder_(std::move(holder)) + { } + + //! Constructs a TSharedRange from a range. + TSharedRange(const T* begin, const T* end, THolderPtr holder) + : TRange<T>(begin, end) + , Holder_(std::move(holder)) + { } + //! Constructs a TSharedRange from a TCompactVector. template <size_t N> TSharedRange(const TCompactVector<T, N>& elements, THolderPtr holder) @@ -50,99 +50,99 @@ public: , Holder_(std::move(holder)) { } - //! Constructs a TSharedRange from an std::vector. - TSharedRange(const std::vector<T>& elements, THolderPtr holder) - : TRange<T>(elements) - , Holder_(std::move(holder)) - { } - - //! Constructs a TSharedRange from a C array. - template <size_t N> - TSharedRange(const T (& elements)[N], THolderPtr holder) - : TRange<T>(elements) - , Holder_(std::move(holder)) - { } - - - void Reset() - { - TRange<T>::Data_ = nullptr; - TRange<T>::Length_ = 0; - Holder_.Reset(); - } - - TSharedRange<T> Slice(size_t startOffset, size_t endOffset) const - { - YT_ASSERT(startOffset <= this->Size()); - YT_ASSERT(endOffset >= startOffset && endOffset <= this->Size()); - return TSharedRange<T>(this->Begin() + startOffset, endOffset - startOffset, Holder_); - } - - TSharedRange<T> Slice(const T* begin, const T* end) const - { - YT_ASSERT(begin >= this->Begin()); - YT_ASSERT(end <= this->End()); - return TSharedRange<T>(begin, end, Holder_); - } - - const THolderPtr& GetHolder() const - { - return Holder_; - } - + //! Constructs a TSharedRange from an std::vector. + TSharedRange(const std::vector<T>& elements, THolderPtr holder) + : TRange<T>(elements) + , Holder_(std::move(holder)) + { } + + //! Constructs a TSharedRange from a C array. + template <size_t N> + TSharedRange(const T (& elements)[N], THolderPtr holder) + : TRange<T>(elements) + , Holder_(std::move(holder)) + { } + + + void Reset() + { + TRange<T>::Data_ = nullptr; + TRange<T>::Length_ = 0; + Holder_.Reset(); + } + + TSharedRange<T> Slice(size_t startOffset, size_t endOffset) const + { + YT_ASSERT(startOffset <= this->Size()); + YT_ASSERT(endOffset >= startOffset && endOffset <= this->Size()); + return TSharedRange<T>(this->Begin() + startOffset, endOffset - startOffset, Holder_); + } + + TSharedRange<T> Slice(const T* begin, const T* end) const + { + YT_ASSERT(begin >= this->Begin()); + YT_ASSERT(end <= this->End()); + return TSharedRange<T>(begin, end, Holder_); + } + + const THolderPtr& GetHolder() const + { + return Holder_; + } + THolderPtr&& ReleaseHolder() { return std::move(Holder_); } -protected: - THolderPtr Holder_; - -}; - -//////////////////////////////////////////////////////////////////////////////// - -//! Constructs a combined holder instance by taking ownership of a given list of holders. -template <class... THolders> +protected: + THolderPtr Holder_; + +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! Constructs a combined holder instance by taking ownership of a given list of holders. +template <class... THolders> TRefCountedPtr MakeCompositeHolder(THolders&&... holders) -{ - struct THolder - : public TRefCounted - { - std::tuple<typename std::decay<THolders>::type...> Holders; - }; - - auto holder = New<THolder>(); - holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...); - return holder; -} - -template <class T, class TContainer, class... THolders> -TSharedRange<T> DoMakeSharedRange(TContainer&& elements, THolders&&... holders) -{ - struct THolder - : public TRefCounted - { - typename std::decay<TContainer>::type Elements; - std::tuple<typename std::decay<THolders>::type...> Holders; - }; - - auto holder = New<THolder>(); - holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...); - holder->Elements = std::forward<TContainer>(elements); - - auto range = MakeRange<T>(holder->Elements); - +{ + struct THolder + : public TRefCounted + { + std::tuple<typename std::decay<THolders>::type...> Holders; + }; + + auto holder = New<THolder>(); + holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...); + return holder; +} + +template <class T, class TContainer, class... THolders> +TSharedRange<T> DoMakeSharedRange(TContainer&& elements, THolders&&... holders) +{ + struct THolder + : public TRefCounted + { + typename std::decay<TContainer>::type Elements; + std::tuple<typename std::decay<THolders>::type...> Holders; + }; + + auto holder = New<THolder>(); + holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...); + holder->Elements = std::forward<TContainer>(elements); + + auto range = MakeRange<T>(holder->Elements); + return TSharedRange<T>(range, std::move(holder)); -} - -//! Constructs a TSharedRange by taking ownership of an std::vector. -template <class T, class... THolders> -TSharedRange<T> MakeSharedRange(std::vector<T>&& elements, THolders&&... holders) -{ - return DoMakeSharedRange<T>(std::move(elements), std::forward<THolders>(holders)...); -} - +} + +//! Constructs a TSharedRange by taking ownership of an std::vector. +template <class T, class... THolders> +TSharedRange<T> MakeSharedRange(std::vector<T>&& elements, THolders&&... holders) +{ + return DoMakeSharedRange<T>(std::move(elements), std::forward<THolders>(holders)...); +} + //! Constructs a TSharedRange by taking ownership of an TCompactVector. template <class T, size_t N, class... THolders> TSharedRange<T> MakeSharedRange(TCompactVector<T, N>&& elements, THolders&&... holders) @@ -150,65 +150,65 @@ TSharedRange<T> MakeSharedRange(TCompactVector<T, N>&& elements, THolders&&... h return DoMakeSharedRange<T>(std::move(elements), std::forward<THolders>(holders)...); } -//! Constructs a TSharedRange by copying an std::vector. -template <class T, class... THolders> -TSharedRange<T> MakeSharedRange(const std::vector<T>& elements, THolders&&... holders) -{ - return DoMakeSharedRange<T>(elements, std::forward<THolders>(holders)...); -} - -template <class T, class... THolders> -TSharedRange<T> MakeSharedRange(TRange<T> range, THolders&&... holders) -{ - return TSharedRange<T>(range, MakeCompositeHolder(std::forward<THolders>(holders)...)); -} - +//! Constructs a TSharedRange by copying an std::vector. +template <class T, class... THolders> +TSharedRange<T> MakeSharedRange(const std::vector<T>& elements, THolders&&... holders) +{ + return DoMakeSharedRange<T>(elements, std::forward<THolders>(holders)...); +} + +template <class T, class... THolders> +TSharedRange<T> MakeSharedRange(TRange<T> range, THolders&&... holders) +{ + return TSharedRange<T>(range, MakeCompositeHolder(std::forward<THolders>(holders)...)); +} + template <class T, class THolder> TSharedRange<T> MakeSharedRange(TRange<T> range, TIntrusivePtr<THolder> holder) { return TSharedRange<T>(range, std::move(holder)); } -template <class U, class T> -TSharedRange<U> ReinterpretCastRange(const TSharedRange<T>& range) -{ - static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); - return TSharedRange<U>(reinterpret_cast<const U*>(range.Begin()), range.Size(), range.GetHolder()); -}; - -//////////////////////////////////////////////////////////////////////////////// - -//! TMutableRange with ownership semantics. -//! Use with caution :) -template <class T> -class TSharedMutableRange - : public TMutableRange<T> -{ -public: +template <class U, class T> +TSharedRange<U> ReinterpretCastRange(const TSharedRange<T>& range) +{ + static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); + return TSharedRange<U>(reinterpret_cast<const U*>(range.Begin()), range.Size(), range.GetHolder()); +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! TMutableRange with ownership semantics. +//! Use with caution :) +template <class T> +class TSharedMutableRange + : public TMutableRange<T> +{ +public: using THolderPtr = TRefCountedPtr; - - //! Constructs a null TSharedMutableRange. - TSharedMutableRange() - { } - - //! Constructs a TSharedMutableRange from TMutableRange. - TSharedMutableRange(TMutableRange<T> range, THolderPtr holder) - : TMutableRange<T>(range) - , Holder_(std::move(holder)) - { } - - //! Constructs a TSharedMutableRange from a pointer and length. - TSharedMutableRange(T* data, size_t length, THolderPtr holder) - : TMutableRange<T>(data, length) - , Holder_(std::move(holder)) - { } - - //! Constructs a TSharedMutableRange from a range. - TSharedMutableRange(T* begin, T* end, THolderPtr holder) - : TMutableRange<T>(begin, end) - , Holder_(std::move(holder)) - { } - + + //! Constructs a null TSharedMutableRange. + TSharedMutableRange() + { } + + //! Constructs a TSharedMutableRange from TMutableRange. + TSharedMutableRange(TMutableRange<T> range, THolderPtr holder) + : TMutableRange<T>(range) + , Holder_(std::move(holder)) + { } + + //! Constructs a TSharedMutableRange from a pointer and length. + TSharedMutableRange(T* data, size_t length, THolderPtr holder) + : TMutableRange<T>(data, length) + , Holder_(std::move(holder)) + { } + + //! Constructs a TSharedMutableRange from a range. + TSharedMutableRange(T* begin, T* end, THolderPtr holder) + : TMutableRange<T>(begin, end) + , Holder_(std::move(holder)) + { } + //! Constructs a TSharedMutableRange from a TCompactVector. template <size_t N> TSharedMutableRange(TCompactVector<T, N>& elements, THolderPtr holder) @@ -216,82 +216,82 @@ public: , Holder_(std::move(holder)) { } - //! Constructs a TSharedMutableRange from an std::vector. - TSharedMutableRange(std::vector<T>& elements, THolderPtr holder) - : TMutableRange<T>(elements) - , Holder_(std::move(holder)) - { } - - //! Constructs a TSharedMutableRange from a C array. - template <size_t N> - TSharedMutableRange(T (& elements)[N], THolderPtr holder) - : TMutableRange<T>(elements) - , Holder_(std::move(holder)) - { } - - - void Reset() - { - TRange<T>::Data_ = nullptr; - TRange<T>::Length_ = 0; - Holder_.Reset(); - } - - TSharedMutableRange<T> Slice(size_t startOffset, size_t endOffset) const - { - YT_ASSERT(startOffset <= this->Size()); - YT_ASSERT(endOffset >= startOffset && endOffset <= this->Size()); - return TSharedMutableRange<T>(this->Begin() + startOffset, endOffset - startOffset, Holder_); - } - - TSharedMutableRange<T> Slice(T* begin, T* end) const - { - YT_ASSERT(begin >= this->Begin()); - YT_ASSERT(end <= this->End()); - return TSharedMutableRange<T>(begin, end, Holder_); - } - - THolderPtr GetHolder() const - { - return Holder_; - } - + //! Constructs a TSharedMutableRange from an std::vector. + TSharedMutableRange(std::vector<T>& elements, THolderPtr holder) + : TMutableRange<T>(elements) + , Holder_(std::move(holder)) + { } + + //! Constructs a TSharedMutableRange from a C array. + template <size_t N> + TSharedMutableRange(T (& elements)[N], THolderPtr holder) + : TMutableRange<T>(elements) + , Holder_(std::move(holder)) + { } + + + void Reset() + { + TRange<T>::Data_ = nullptr; + TRange<T>::Length_ = 0; + Holder_.Reset(); + } + + TSharedMutableRange<T> Slice(size_t startOffset, size_t endOffset) const + { + YT_ASSERT(startOffset <= this->Size()); + YT_ASSERT(endOffset >= startOffset && endOffset <= this->Size()); + return TSharedMutableRange<T>(this->Begin() + startOffset, endOffset - startOffset, Holder_); + } + + TSharedMutableRange<T> Slice(T* begin, T* end) const + { + YT_ASSERT(begin >= this->Begin()); + YT_ASSERT(end <= this->End()); + return TSharedMutableRange<T>(begin, end, Holder_); + } + + THolderPtr GetHolder() const + { + return Holder_; + } + THolderPtr&& ReleaseHolder() { return std::move(Holder_); } -protected: - THolderPtr Holder_; - -}; - -template <class T, class TContainer, class... THolders> -TSharedMutableRange<T> DoMakeSharedMutableRange(TContainer&& elements, THolders&&... holders) -{ - struct THolder - : public TRefCounted - { - typename std::decay<TContainer>::type Elements; - std::tuple<typename std::decay<THolders>::type...> Holders; - }; - - auto holder = New<THolder>(); - holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...); - holder->Elements = std::forward<TContainer>(elements); - - auto range = TMutableRange<T>(holder->Elements); - - return TSharedMutableRange<T>(range, holder); -} - -//! Constructs a TSharedMutableRange by taking ownership of an std::vector. -template <class T, class... THolders> -TSharedMutableRange<T> MakeSharedMutableRange(std::vector<T>&& elements, THolders&&... holders) -{ - return DoMakeSharedMutableRange<T>(std::move(elements), std::forward<THolders>(holders)...); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +protected: + THolderPtr Holder_; + +}; + +template <class T, class TContainer, class... THolders> +TSharedMutableRange<T> DoMakeSharedMutableRange(TContainer&& elements, THolders&&... holders) +{ + struct THolder + : public TRefCounted + { + typename std::decay<TContainer>::type Elements; + std::tuple<typename std::decay<THolders>::type...> Holders; + }; + + auto holder = New<THolder>(); + holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...); + holder->Elements = std::forward<TContainer>(elements); + + auto range = TMutableRange<T>(holder->Elements); + + return TSharedMutableRange<T>(range, holder); +} + +//! Constructs a TSharedMutableRange by taking ownership of an std::vector. +template <class T, class... THolders> +TSharedMutableRange<T> MakeSharedMutableRange(std::vector<T>&& elements, THolders&&... holders) +{ + return DoMakeSharedMutableRange<T>(std::move(elements), std::forward<THolders>(holders)...); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp b/library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp index 622bed0eb0..abd55e7661 100644 --- a/library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp +++ b/library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp @@ -1,485 +1,485 @@ #include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/yt/memory/new.h> -#include <library/cpp/yt/memory/ref_counted.h> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -using ::testing::IsNull; -using ::testing::NotNull; -using ::testing::InSequence; -using ::testing::MockFunction; -using ::testing::StrictMock; - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary types and functions. -//////////////////////////////////////////////////////////////////////////////// - -// This object tracks number of increments and decrements -// to the reference counter (see traits specialization below). -struct TIntricateObject - : private TNonCopyable -{ - int Increments = 0; - int Decrements = 0; - int Zeros = 0; - - void Ref() - { - ++Increments; - } - - void Unref() - { - ++Decrements; - if (Increments == Decrements) { - ++Zeros; - } - } -}; - -typedef TIntrusivePtr<TIntricateObject> TIntricateObjectPtr; - -void Ref(TIntricateObject* obj) -{ - obj->Ref(); -} - -void Unref(TIntricateObject* obj) -{ - obj->Unref(); -} - -MATCHER_P3(HasRefCounts, increments, decrements, zeros, - "Reference counter " \ - "was incremented " + ::testing::PrintToString(increments) + " times, " + - "was decremented " + ::testing::PrintToString(decrements) + " times, " + - "vanished to zero " + ::testing::PrintToString(zeros) + " times") -{ - Y_UNUSED(result_listener); - return - arg.Increments == increments && - arg.Decrements == decrements && - arg.Zeros == zeros; -} - -void PrintTo(const TIntricateObject& arg, ::std::ostream* os) -{ + +#include <library/cpp/yt/memory/new.h> +#include <library/cpp/yt/memory/ref_counted.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +using ::testing::IsNull; +using ::testing::NotNull; +using ::testing::InSequence; +using ::testing::MockFunction; +using ::testing::StrictMock; + +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary types and functions. +//////////////////////////////////////////////////////////////////////////////// + +// This object tracks number of increments and decrements +// to the reference counter (see traits specialization below). +struct TIntricateObject + : private TNonCopyable +{ + int Increments = 0; + int Decrements = 0; + int Zeros = 0; + + void Ref() + { + ++Increments; + } + + void Unref() + { + ++Decrements; + if (Increments == Decrements) { + ++Zeros; + } + } +}; + +typedef TIntrusivePtr<TIntricateObject> TIntricateObjectPtr; + +void Ref(TIntricateObject* obj) +{ + obj->Ref(); +} + +void Unref(TIntricateObject* obj) +{ + obj->Unref(); +} + +MATCHER_P3(HasRefCounts, increments, decrements, zeros, + "Reference counter " \ + "was incremented " + ::testing::PrintToString(increments) + " times, " + + "was decremented " + ::testing::PrintToString(decrements) + " times, " + + "vanished to zero " + ::testing::PrintToString(zeros) + " times") +{ + Y_UNUSED(result_listener); + return + arg.Increments == increments && + arg.Decrements == decrements && + arg.Zeros == zeros; +} + +void PrintTo(const TIntricateObject& arg, ::std::ostream* os) +{ *os << arg.Increments << " increments, " << arg.Decrements << " decrements and " << arg.Zeros << " times vanished"; -} - -// This is an object which creates intrusive pointers to the self -// during its construction. -class TObjectWithSelfPointers - : public TRefCounted -{ -public: - explicit TObjectWithSelfPointers(IOutputStream* output) - : Output_(output) - { - *Output_ << "Cb"; - - for (int i = 0; i < 3; ++i) { - *Output_ << '!'; - TIntrusivePtr<TObjectWithSelfPointers> ptr(this); - } - - *Output_ << "Ca"; - } - - virtual ~TObjectWithSelfPointers() - { - *Output_ << 'D'; - } - -private: - IOutputStream* const Output_; - -}; - -// This is a simple object with simple reference counting. -class TObjectWithSimpleRC - : public TRefCounted -{ -public: - explicit TObjectWithSimpleRC(IOutputStream* output) - : Output_(output) - { - *Output_ << 'C'; - } - - virtual ~TObjectWithSimpleRC() - { - *Output_ << 'D'; - } - - void DoSomething() - { - *Output_ << '!'; - } - -private: - IOutputStream* const Output_; - -}; - -// This is a simple object with full-fledged reference counting. -class TObjectWithFullRC - : public TRefCounted -{ -public: - explicit TObjectWithFullRC(IOutputStream* output) - : Output_(output) - { - *Output_ << 'C'; - } - - virtual ~TObjectWithFullRC() - { - *Output_ << 'D'; - } - - void DoSomething() - { - *Output_ << '!'; - } - -private: - IOutputStream* const Output_; - -}; - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TIntrusivePtrTest, Empty) -{ - TIntricateObjectPtr emptyPointer; - EXPECT_EQ(nullptr, emptyPointer.Get()); -} - -TEST(TIntrusivePtrTest, Basic) -{ - TIntricateObject object; - - EXPECT_THAT(object, HasRefCounts(0, 0, 0)); - - { - TIntricateObjectPtr owningPointer(&object); - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - EXPECT_EQ(&object, owningPointer.Get()); - } - - EXPECT_THAT(object, HasRefCounts(1, 1, 1)); - - { - TIntricateObjectPtr nonOwningPointer(&object, false); - EXPECT_THAT(object, HasRefCounts(1, 1, 1)); - EXPECT_EQ(&object, nonOwningPointer.Get()); - } - - EXPECT_THAT(object, HasRefCounts(1, 2, 1)); -} - -TEST(TIntrusivePtrTest, ResetToNull) -{ - TIntricateObject object; - TIntricateObjectPtr ptr(&object); - - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - EXPECT_EQ(&object, ptr.Get()); - - ptr.Reset(); - - EXPECT_THAT(object, HasRefCounts(1, 1, 1)); - EXPECT_EQ(nullptr, ptr.Get()); -} - -TEST(TIntrusivePtrTest, ResetToOtherObject) -{ - TIntricateObject firstObject; - TIntricateObject secondObject; - - TIntricateObjectPtr ptr(&firstObject); - - EXPECT_THAT(firstObject, HasRefCounts(1, 0, 0)); - EXPECT_THAT(secondObject, HasRefCounts(0, 0, 0)); - EXPECT_EQ(&firstObject, ptr.Get()); - - ptr.Reset(&secondObject); - - EXPECT_THAT(firstObject, HasRefCounts(1, 1, 1)); - EXPECT_THAT(secondObject, HasRefCounts(1, 0, 0)); - EXPECT_EQ(&secondObject, ptr.Get()); -} - -TEST(TIntrusivePtrTest, CopySemantics) -{ - TIntricateObject object; - - TIntricateObjectPtr foo(&object); - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - - { - TIntricateObjectPtr bar(foo); - EXPECT_THAT(object, HasRefCounts(2, 0, 0)); - EXPECT_EQ(&object, foo.Get()); - EXPECT_EQ(&object, bar.Get()); - } - - EXPECT_THAT(object, HasRefCounts(2, 1, 0)); - - { - TIntricateObjectPtr bar; - bar = foo; - - EXPECT_THAT(object, HasRefCounts(3, 1, 0)); - EXPECT_EQ(&object, foo.Get()); - EXPECT_EQ(&object, bar.Get()); - } - - EXPECT_THAT(object, HasRefCounts(3, 2, 0)); -} - -TEST(TIntrusivePtrTest, MoveSemantics) -{ - TIntricateObject object; - - TIntricateObjectPtr foo(&object); - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - - { - TIntricateObjectPtr bar(std::move(foo)); - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - EXPECT_THAT(foo.Get(), IsNull()); - EXPECT_EQ(&object, bar.Get()); - } - - EXPECT_THAT(object, HasRefCounts(1, 1, 1)); - foo.Reset(&object); - EXPECT_THAT(object, HasRefCounts(2, 1, 1)); - - { - TIntricateObjectPtr bar; - bar = std::move(foo); - EXPECT_THAT(object, HasRefCounts(2, 1, 1)); - EXPECT_THAT(foo.Get(), IsNull()); - EXPECT_EQ(&object, bar.Get()); - } -} - -TEST(TIntrusivePtrTest, Swap) -{ - TIntricateObject object; - - TIntricateObjectPtr foo(&object); - TIntricateObjectPtr bar; - - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - EXPECT_THAT(foo.Get(), NotNull()); - EXPECT_THAT(bar.Get(), IsNull()); - - foo.Swap(bar); - - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - EXPECT_THAT(foo.Get(), IsNull()); - EXPECT_THAT(bar.Get(), NotNull()); - - foo.Swap(bar); - - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - EXPECT_THAT(foo.Get(), NotNull()); - EXPECT_THAT(bar.Get(), IsNull()); -} - -TEST(TIntrusivePtrTest, UpCast) -{ - //! This is a simple typical reference-counted object. - class TSimpleObject - : public TRefCounted - { }; - - //! This is a simple inherited reference-counted object. - class TAnotherObject - : public TSimpleObject - { }; - - auto foo = New<TSimpleObject>(); - auto bar = New<TAnotherObject>(); - auto baz = New<TAnotherObject>(); - - foo = baz; - - EXPECT_TRUE(foo == baz); -} - -TEST(TIntrusivePtrTest, DownCast) -{ - class TBaseObject - : public TRefCounted - { }; - - class TDerivedObject - : public TBaseObject - { }; - - //! This is a simple inherited reference-counted object. - class TAnotherObject - : public TBaseObject - { }; - - TIntrusivePtr<TBaseObject> foo = New<TDerivedObject>(); - TIntrusivePtr<TBaseObject> bar = New<TAnotherObject>(); - { - auto baz = StaticPointerCast<TDerivedObject>(foo); - EXPECT_TRUE(foo == baz); - } - { - auto baz = StaticPointerCast<TDerivedObject>(TIntrusivePtr<TBaseObject>{foo}); - EXPECT_TRUE(foo == baz); - } - { - auto baz = DynamicPointerCast<TDerivedObject>(foo); - EXPECT_TRUE(foo == baz); - } - { - auto baz = DynamicPointerCast<TDerivedObject>(bar); - EXPECT_TRUE(nullptr == baz); - } - { - auto baz = ConstPointerCast<const TBaseObject>(foo); - EXPECT_TRUE(foo.Get() == baz.Get()); - } - { - auto baz = ConstPointerCast<const TBaseObject>(TIntrusivePtr<TBaseObject>{foo}); - EXPECT_TRUE(foo.Get() == baz.Get()); - } -} - -TEST(TIntrusivePtrTest, UnspecifiedBoolType) -{ - TIntricateObject object; - - TIntricateObjectPtr foo; - TIntricateObjectPtr bar(&object); - - EXPECT_FALSE(foo); - EXPECT_TRUE(bar); -} - -TEST(TIntrusivePtrTest, ObjectIsNotDestroyedPrematurely) -{ - TStringStream output; - New<TObjectWithSelfPointers>(&output); - - // TObject... appends symbols to the output; see definitions. - EXPECT_STREQ("Cb!!!CaD", output.Str().c_str()); -} - -TEST(TIntrusivePtrTest, EqualityOperator) -{ - TIntricateObject object, anotherObject; - - TIntricateObjectPtr emptyPointer; - TIntricateObjectPtr somePointer(&object); - TIntricateObjectPtr samePointer(&object); - TIntricateObjectPtr anotherPointer(&anotherObject); - - EXPECT_FALSE(somePointer == emptyPointer); - EXPECT_FALSE(samePointer == emptyPointer); - - EXPECT_TRUE(somePointer != emptyPointer); - EXPECT_TRUE(samePointer != emptyPointer); - - EXPECT_TRUE(somePointer == samePointer); - - EXPECT_TRUE(&object == somePointer); - EXPECT_TRUE(&object == samePointer); - - EXPECT_FALSE(somePointer == anotherPointer); - EXPECT_TRUE(somePointer != anotherPointer); - - EXPECT_TRUE(&anotherObject == anotherPointer); -} - -TEST(TIntrusivePtrTest, Reset) -{ - TIntricateObject object; - TIntricateObjectPtr pointer(&object); - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); - EXPECT_EQ(&object, pointer.Release()); - EXPECT_THAT(object, HasRefCounts(1, 0, 0)); -} - -TEST(TIntrusivePtrTest, CompareWithNullptr) -{ - TIntricateObjectPtr pointer1; - EXPECT_TRUE(nullptr == pointer1); - EXPECT_FALSE(nullptr != pointer1); - TIntricateObject object; - TIntricateObjectPtr pointer2(&object); - EXPECT_TRUE(pointer2 != nullptr); - EXPECT_FALSE(pointer2 == nullptr); -} - - -template <class T> -void TestIntrusivePtrBehavior() -{ - typedef TIntrusivePtr<T> TMyPtr; - - TStringStream output; - { - TMyPtr ptr(New<T>(&output)); - { - TMyPtr anotherPtr(ptr); - anotherPtr->DoSomething(); - } - { - TMyPtr anotherPtr(ptr); - anotherPtr->DoSomething(); - } - ptr->DoSomething(); - } - - // TObject... appends symbols to the output; see definitions. - EXPECT_STREQ("C!!!D", output.Str().c_str()); -} - -TEST(TIntrusivePtrTest, SimpleRCBehaviour) -{ - TestIntrusivePtrBehavior<TObjectWithSimpleRC>(); -} - -TEST(TIntrusivePtrTest, FullRCBehaviour) -{ - TestIntrusivePtrBehavior<TObjectWithFullRC>(); -} - -TEST(TIntrusivePtrTest, ObjectAlignment) -{ - struct TObject - : public TRefCounted - { - alignas(64) ui64 Data; - }; - - struct TPODObject final - { - alignas(64) ui64 Data; - }; - - auto foo = New<TObject>(); - auto bar = New<TPODObject>(); - - EXPECT_TRUE(reinterpret_cast<uintptr_t>(foo.Get()) % 64 == 0); - EXPECT_TRUE(reinterpret_cast<uintptr_t>(bar.Get()) % 64 == 0); -} - +} + +// This is an object which creates intrusive pointers to the self +// during its construction. +class TObjectWithSelfPointers + : public TRefCounted +{ +public: + explicit TObjectWithSelfPointers(IOutputStream* output) + : Output_(output) + { + *Output_ << "Cb"; + + for (int i = 0; i < 3; ++i) { + *Output_ << '!'; + TIntrusivePtr<TObjectWithSelfPointers> ptr(this); + } + + *Output_ << "Ca"; + } + + virtual ~TObjectWithSelfPointers() + { + *Output_ << 'D'; + } + +private: + IOutputStream* const Output_; + +}; + +// This is a simple object with simple reference counting. +class TObjectWithSimpleRC + : public TRefCounted +{ +public: + explicit TObjectWithSimpleRC(IOutputStream* output) + : Output_(output) + { + *Output_ << 'C'; + } + + virtual ~TObjectWithSimpleRC() + { + *Output_ << 'D'; + } + + void DoSomething() + { + *Output_ << '!'; + } + +private: + IOutputStream* const Output_; + +}; + +// This is a simple object with full-fledged reference counting. +class TObjectWithFullRC + : public TRefCounted +{ +public: + explicit TObjectWithFullRC(IOutputStream* output) + : Output_(output) + { + *Output_ << 'C'; + } + + virtual ~TObjectWithFullRC() + { + *Output_ << 'D'; + } + + void DoSomething() + { + *Output_ << '!'; + } + +private: + IOutputStream* const Output_; + +}; + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TIntrusivePtrTest, Empty) +{ + TIntricateObjectPtr emptyPointer; + EXPECT_EQ(nullptr, emptyPointer.Get()); +} + +TEST(TIntrusivePtrTest, Basic) +{ + TIntricateObject object; + + EXPECT_THAT(object, HasRefCounts(0, 0, 0)); + + { + TIntricateObjectPtr owningPointer(&object); + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + EXPECT_EQ(&object, owningPointer.Get()); + } + + EXPECT_THAT(object, HasRefCounts(1, 1, 1)); + + { + TIntricateObjectPtr nonOwningPointer(&object, false); + EXPECT_THAT(object, HasRefCounts(1, 1, 1)); + EXPECT_EQ(&object, nonOwningPointer.Get()); + } + + EXPECT_THAT(object, HasRefCounts(1, 2, 1)); +} + +TEST(TIntrusivePtrTest, ResetToNull) +{ + TIntricateObject object; + TIntricateObjectPtr ptr(&object); + + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + EXPECT_EQ(&object, ptr.Get()); + + ptr.Reset(); + + EXPECT_THAT(object, HasRefCounts(1, 1, 1)); + EXPECT_EQ(nullptr, ptr.Get()); +} + +TEST(TIntrusivePtrTest, ResetToOtherObject) +{ + TIntricateObject firstObject; + TIntricateObject secondObject; + + TIntricateObjectPtr ptr(&firstObject); + + EXPECT_THAT(firstObject, HasRefCounts(1, 0, 0)); + EXPECT_THAT(secondObject, HasRefCounts(0, 0, 0)); + EXPECT_EQ(&firstObject, ptr.Get()); + + ptr.Reset(&secondObject); + + EXPECT_THAT(firstObject, HasRefCounts(1, 1, 1)); + EXPECT_THAT(secondObject, HasRefCounts(1, 0, 0)); + EXPECT_EQ(&secondObject, ptr.Get()); +} + +TEST(TIntrusivePtrTest, CopySemantics) +{ + TIntricateObject object; + + TIntricateObjectPtr foo(&object); + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + + { + TIntricateObjectPtr bar(foo); + EXPECT_THAT(object, HasRefCounts(2, 0, 0)); + EXPECT_EQ(&object, foo.Get()); + EXPECT_EQ(&object, bar.Get()); + } + + EXPECT_THAT(object, HasRefCounts(2, 1, 0)); + + { + TIntricateObjectPtr bar; + bar = foo; + + EXPECT_THAT(object, HasRefCounts(3, 1, 0)); + EXPECT_EQ(&object, foo.Get()); + EXPECT_EQ(&object, bar.Get()); + } + + EXPECT_THAT(object, HasRefCounts(3, 2, 0)); +} + +TEST(TIntrusivePtrTest, MoveSemantics) +{ + TIntricateObject object; + + TIntricateObjectPtr foo(&object); + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + + { + TIntricateObjectPtr bar(std::move(foo)); + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + EXPECT_THAT(foo.Get(), IsNull()); + EXPECT_EQ(&object, bar.Get()); + } + + EXPECT_THAT(object, HasRefCounts(1, 1, 1)); + foo.Reset(&object); + EXPECT_THAT(object, HasRefCounts(2, 1, 1)); + + { + TIntricateObjectPtr bar; + bar = std::move(foo); + EXPECT_THAT(object, HasRefCounts(2, 1, 1)); + EXPECT_THAT(foo.Get(), IsNull()); + EXPECT_EQ(&object, bar.Get()); + } +} + +TEST(TIntrusivePtrTest, Swap) +{ + TIntricateObject object; + + TIntricateObjectPtr foo(&object); + TIntricateObjectPtr bar; + + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + EXPECT_THAT(foo.Get(), NotNull()); + EXPECT_THAT(bar.Get(), IsNull()); + + foo.Swap(bar); + + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + EXPECT_THAT(foo.Get(), IsNull()); + EXPECT_THAT(bar.Get(), NotNull()); + + foo.Swap(bar); + + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + EXPECT_THAT(foo.Get(), NotNull()); + EXPECT_THAT(bar.Get(), IsNull()); +} + +TEST(TIntrusivePtrTest, UpCast) +{ + //! This is a simple typical reference-counted object. + class TSimpleObject + : public TRefCounted + { }; + + //! This is a simple inherited reference-counted object. + class TAnotherObject + : public TSimpleObject + { }; + + auto foo = New<TSimpleObject>(); + auto bar = New<TAnotherObject>(); + auto baz = New<TAnotherObject>(); + + foo = baz; + + EXPECT_TRUE(foo == baz); +} + +TEST(TIntrusivePtrTest, DownCast) +{ + class TBaseObject + : public TRefCounted + { }; + + class TDerivedObject + : public TBaseObject + { }; + + //! This is a simple inherited reference-counted object. + class TAnotherObject + : public TBaseObject + { }; + + TIntrusivePtr<TBaseObject> foo = New<TDerivedObject>(); + TIntrusivePtr<TBaseObject> bar = New<TAnotherObject>(); + { + auto baz = StaticPointerCast<TDerivedObject>(foo); + EXPECT_TRUE(foo == baz); + } + { + auto baz = StaticPointerCast<TDerivedObject>(TIntrusivePtr<TBaseObject>{foo}); + EXPECT_TRUE(foo == baz); + } + { + auto baz = DynamicPointerCast<TDerivedObject>(foo); + EXPECT_TRUE(foo == baz); + } + { + auto baz = DynamicPointerCast<TDerivedObject>(bar); + EXPECT_TRUE(nullptr == baz); + } + { + auto baz = ConstPointerCast<const TBaseObject>(foo); + EXPECT_TRUE(foo.Get() == baz.Get()); + } + { + auto baz = ConstPointerCast<const TBaseObject>(TIntrusivePtr<TBaseObject>{foo}); + EXPECT_TRUE(foo.Get() == baz.Get()); + } +} + +TEST(TIntrusivePtrTest, UnspecifiedBoolType) +{ + TIntricateObject object; + + TIntricateObjectPtr foo; + TIntricateObjectPtr bar(&object); + + EXPECT_FALSE(foo); + EXPECT_TRUE(bar); +} + +TEST(TIntrusivePtrTest, ObjectIsNotDestroyedPrematurely) +{ + TStringStream output; + New<TObjectWithSelfPointers>(&output); + + // TObject... appends symbols to the output; see definitions. + EXPECT_STREQ("Cb!!!CaD", output.Str().c_str()); +} + +TEST(TIntrusivePtrTest, EqualityOperator) +{ + TIntricateObject object, anotherObject; + + TIntricateObjectPtr emptyPointer; + TIntricateObjectPtr somePointer(&object); + TIntricateObjectPtr samePointer(&object); + TIntricateObjectPtr anotherPointer(&anotherObject); + + EXPECT_FALSE(somePointer == emptyPointer); + EXPECT_FALSE(samePointer == emptyPointer); + + EXPECT_TRUE(somePointer != emptyPointer); + EXPECT_TRUE(samePointer != emptyPointer); + + EXPECT_TRUE(somePointer == samePointer); + + EXPECT_TRUE(&object == somePointer); + EXPECT_TRUE(&object == samePointer); + + EXPECT_FALSE(somePointer == anotherPointer); + EXPECT_TRUE(somePointer != anotherPointer); + + EXPECT_TRUE(&anotherObject == anotherPointer); +} + +TEST(TIntrusivePtrTest, Reset) +{ + TIntricateObject object; + TIntricateObjectPtr pointer(&object); + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); + EXPECT_EQ(&object, pointer.Release()); + EXPECT_THAT(object, HasRefCounts(1, 0, 0)); +} + +TEST(TIntrusivePtrTest, CompareWithNullptr) +{ + TIntricateObjectPtr pointer1; + EXPECT_TRUE(nullptr == pointer1); + EXPECT_FALSE(nullptr != pointer1); + TIntricateObject object; + TIntricateObjectPtr pointer2(&object); + EXPECT_TRUE(pointer2 != nullptr); + EXPECT_FALSE(pointer2 == nullptr); +} + + +template <class T> +void TestIntrusivePtrBehavior() +{ + typedef TIntrusivePtr<T> TMyPtr; + + TStringStream output; + { + TMyPtr ptr(New<T>(&output)); + { + TMyPtr anotherPtr(ptr); + anotherPtr->DoSomething(); + } + { + TMyPtr anotherPtr(ptr); + anotherPtr->DoSomething(); + } + ptr->DoSomething(); + } + + // TObject... appends symbols to the output; see definitions. + EXPECT_STREQ("C!!!D", output.Str().c_str()); +} + +TEST(TIntrusivePtrTest, SimpleRCBehaviour) +{ + TestIntrusivePtrBehavior<TObjectWithSimpleRC>(); +} + +TEST(TIntrusivePtrTest, FullRCBehaviour) +{ + TestIntrusivePtrBehavior<TObjectWithFullRC>(); +} + +TEST(TIntrusivePtrTest, ObjectAlignment) +{ + struct TObject + : public TRefCounted + { + alignas(64) ui64 Data; + }; + + struct TPODObject final + { + alignas(64) ui64 Data; + }; + + auto foo = New<TObject>(); + auto bar = New<TPODObject>(); + + EXPECT_TRUE(reinterpret_cast<uintptr_t>(foo.Get()) % 64 == 0); + EXPECT_TRUE(reinterpret_cast<uintptr_t>(bar.Get()) % 64 == 0); +} + TEST(TIntrusivePtrTest, InitStruct) { struct TObj1 final @@ -556,7 +556,7 @@ TEST(TIntrusivePtrTest, InitStruct) New<TObj6>(1, 2); } -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/memory/unittests/weak_ptr_ut.cpp b/library/cpp/yt/memory/unittests/weak_ptr_ut.cpp index 180c16b5ca..2a420e8315 100644 --- a/library/cpp/yt/memory/unittests/weak_ptr_ut.cpp +++ b/library/cpp/yt/memory/unittests/weak_ptr_ut.cpp @@ -1,358 +1,358 @@ #include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/yt/memory/new.h> -#include <library/cpp/yt/memory/weak_ptr.h> - + +#include <library/cpp/yt/memory/new.h> +#include <library/cpp/yt/memory/weak_ptr.h> + #include <array> - -namespace NYT { -namespace { - -using ::testing::IsNull; -using ::testing::NotNull; -using ::testing::InSequence; -using ::testing::MockFunction; -using ::testing::StrictMock; - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary types and functions. -//////////////////////////////////////////////////////////////////////////////// - -static int ConstructorShadowState = 0; -static int DestructorShadowState = 0; - -void ResetShadowState() -{ - ConstructorShadowState = 0; - DestructorShadowState = 0; -} - -class TIntricateObject - : public TRefCounted -{ -public: - TIntricateObject() - { - ++ConstructorShadowState; - } - - virtual ~TIntricateObject() - { - ++DestructorShadowState; - } - - // Prevent the counter from destruction by holding an additional - // reference to the counter. - void LockCounter() - { - WeakRef(); - } - - // Release an additional reference to the reference counter acquired by - // #LockCounter(). - void UnlockCounter() - { - WeakUnref(); - } - -private: - // Explicitly non-copyable. - TIntricateObject(const TIntricateObject&); - TIntricateObject(TIntricateObject&&); - TIntricateObject& operator=(const TIntricateObject&); - TIntricateObject& operator=(TIntricateObject&&); -}; - -typedef TIntrusivePtr<TIntricateObject> TIntricateObjectPtr; -typedef TWeakPtr<TIntricateObject> TIntricateObjectWkPtr; - -class TDerivedIntricateObject - : public TIntricateObject -{ -private: - // Payload. + +namespace NYT { +namespace { + +using ::testing::IsNull; +using ::testing::NotNull; +using ::testing::InSequence; +using ::testing::MockFunction; +using ::testing::StrictMock; + +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary types and functions. +//////////////////////////////////////////////////////////////////////////////// + +static int ConstructorShadowState = 0; +static int DestructorShadowState = 0; + +void ResetShadowState() +{ + ConstructorShadowState = 0; + DestructorShadowState = 0; +} + +class TIntricateObject + : public TRefCounted +{ +public: + TIntricateObject() + { + ++ConstructorShadowState; + } + + virtual ~TIntricateObject() + { + ++DestructorShadowState; + } + + // Prevent the counter from destruction by holding an additional + // reference to the counter. + void LockCounter() + { + WeakRef(); + } + + // Release an additional reference to the reference counter acquired by + // #LockCounter(). + void UnlockCounter() + { + WeakUnref(); + } + +private: + // Explicitly non-copyable. + TIntricateObject(const TIntricateObject&); + TIntricateObject(TIntricateObject&&); + TIntricateObject& operator=(const TIntricateObject&); + TIntricateObject& operator=(TIntricateObject&&); +}; + +typedef TIntrusivePtr<TIntricateObject> TIntricateObjectPtr; +typedef TWeakPtr<TIntricateObject> TIntricateObjectWkPtr; + +class TDerivedIntricateObject + : public TIntricateObject +{ +private: + // Payload. [[maybe_unused]] std::array<char, 32> Payload; -}; - -typedef TIntrusivePtr<TDerivedIntricateObject> TDerivedIntricateObjectPtr; -typedef TWeakPtr<TDerivedIntricateObject> TDerivedIntricateObjectWkPtr; - -MATCHER_P2(HasRefCounts, strongRefs, weakRefs, - "The object has " - + ::testing::PrintToString(strongRefs) + " strong and " - + ::testing::PrintToString(weakRefs) + " weak references") -{ - Y_UNUSED(result_listener); - return - arg.GetRefCount() == strongRefs && - arg.GetWeakRefCount() == weakRefs; -} - -template <class T> -void PrintExtrinsicRefCounted(const T& arg, ::std::ostream* os) -{ +}; + +typedef TIntrusivePtr<TDerivedIntricateObject> TDerivedIntricateObjectPtr; +typedef TWeakPtr<TDerivedIntricateObject> TDerivedIntricateObjectWkPtr; + +MATCHER_P2(HasRefCounts, strongRefs, weakRefs, + "The object has " + + ::testing::PrintToString(strongRefs) + " strong and " + + ::testing::PrintToString(weakRefs) + " weak references") +{ + Y_UNUSED(result_listener); + return + arg.GetRefCount() == strongRefs && + arg.GetWeakRefCount() == weakRefs; +} + +template <class T> +void PrintExtrinsicRefCounted(const T& arg, ::std::ostream* os) +{ *os << arg.GetRefCount() << " strong and " << arg.GetWeakRefCount() << " weak references"; -} - -void PrintTo(const TIntricateObject& arg, ::std::ostream* os) -{ - PrintExtrinsicRefCounted(arg, os); -} - -//////////////////////////////////////////////////////////////////////////////// - -class TWeakPtrTest - : public ::testing::Test -{ -public: - virtual void SetUp() - { - ResetShadowState(); - } -}; - -TEST_F(TWeakPtrTest, Empty) -{ - TIntricateObjectWkPtr emptyPointer; - EXPECT_EQ(TIntricateObjectPtr(), emptyPointer.Lock()); -} - -TEST_F(TWeakPtrTest, Basic) -{ - TIntricateObjectPtr object = New<TIntricateObject>(); - TIntricateObject* objectPtr = object.Get(); - - EXPECT_THAT(*object, HasRefCounts(1, 1)); - - { - TIntricateObjectWkPtr ptr(objectPtr); - EXPECT_THAT(*object, HasRefCounts(1, 2)); - EXPECT_EQ(object, ptr.Lock()); - } - - EXPECT_THAT(*object, HasRefCounts(1, 1)); - - { - TIntricateObjectWkPtr ptr(object); - EXPECT_THAT(*object, HasRefCounts(1, 2)); - EXPECT_EQ(object, ptr.Lock()); - } - - EXPECT_THAT(*object, HasRefCounts(1, 1)); - - object.Reset(); - - EXPECT_EQ(1, ConstructorShadowState); - EXPECT_EQ(1, DestructorShadowState); -} - -TEST_F(TWeakPtrTest, ResetToNull) -{ - TIntricateObjectPtr object = New<TIntricateObject>(); - TIntricateObjectWkPtr ptr(object); - - EXPECT_THAT(*object, HasRefCounts(1, 2)); - EXPECT_EQ(object, ptr.Lock()); - - ptr.Reset(); - - EXPECT_THAT(*object, HasRefCounts(1, 1)); - EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock()); -} - -TEST_F(TWeakPtrTest, ResetToOtherObject) -{ - TIntricateObjectPtr firstObject = New<TIntricateObject>(); - TIntricateObjectPtr secondObject = New<TIntricateObject>(); - - { - TIntricateObjectWkPtr ptr(firstObject); - - EXPECT_THAT(*firstObject, HasRefCounts(1, 2)); - EXPECT_THAT(*secondObject, HasRefCounts(1, 1)); - EXPECT_EQ(firstObject, ptr.Lock()); - - ptr.Reset(secondObject); - - EXPECT_THAT(*firstObject, HasRefCounts(1, 1)); - EXPECT_THAT(*secondObject, HasRefCounts(1, 2)); - EXPECT_EQ(secondObject, ptr.Lock()); - } - - TIntricateObject* firstObjectPtr = firstObject.Get(); - TIntricateObject* secondObjectPtr = secondObject.Get(); - - { - TIntricateObjectWkPtr ptr(firstObjectPtr); - - EXPECT_THAT(*firstObject, HasRefCounts(1, 2)); - EXPECT_THAT(*secondObject, HasRefCounts(1, 1)); - EXPECT_EQ(firstObject, ptr.Lock()); - - ptr.Reset(secondObjectPtr); - - EXPECT_THAT(*firstObject, HasRefCounts(1, 1)); - EXPECT_THAT(*secondObject, HasRefCounts(1, 2)); - EXPECT_EQ(secondObject, ptr.Lock()); - } -} - -TEST_F(TWeakPtrTest, CopySemantics) -{ - TIntricateObjectPtr object = New<TIntricateObject>(); - TIntricateObjectWkPtr foo(object); - - { - EXPECT_THAT(*object, HasRefCounts(1, 2)); - TIntricateObjectWkPtr bar(foo); - EXPECT_THAT(*object, HasRefCounts(1, 3)); - - EXPECT_EQ(object, foo.Lock()); - EXPECT_EQ(object, bar.Lock()); - } - - { - EXPECT_THAT(*object, HasRefCounts(1, 2)); - TIntricateObjectWkPtr bar; - bar = foo; - EXPECT_THAT(*object, HasRefCounts(1, 3)); - - EXPECT_EQ(object, foo.Lock()); - EXPECT_EQ(object, bar.Lock()); - } -} - -TEST_F(TWeakPtrTest, MoveSemantics) -{ - TIntricateObjectPtr object = New<TIntricateObject>(); - TIntricateObjectWkPtr foo(object); - - { - EXPECT_THAT(*object, HasRefCounts(1, 2)); - TIntricateObjectWkPtr bar(std::move(foo)); - EXPECT_THAT(*object, HasRefCounts(1, 2)); - - EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); - EXPECT_EQ(object, bar.Lock()); - } - - foo.Reset(object); - - { - EXPECT_THAT(*object, HasRefCounts(1, 2)); - TIntricateObjectWkPtr bar; - bar = std::move(foo); - EXPECT_THAT(*object, HasRefCounts(1, 2)); - - EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); - EXPECT_EQ(object, bar.Lock()); - } -} - -TEST_F(TWeakPtrTest, OutOfScope) -{ - TIntricateObjectWkPtr ptr; - - EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock()); - { - TIntricateObjectPtr object = New<TIntricateObject>(); - ptr = object; - EXPECT_EQ(object, ptr.Lock()); - } - EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock()); -} - -TEST_F(TWeakPtrTest, OutOfNestedScope) -{ - TIntricateObjectWkPtr foo; - - EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); - { - TIntricateObjectPtr object = New<TIntricateObject>(); - foo = object; - - EXPECT_EQ(object, foo.Lock()); - { - TIntricateObjectWkPtr bar; - bar = object; - - EXPECT_EQ(object, bar.Lock()); - } - EXPECT_EQ(object, foo.Lock()); - } - EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); - - EXPECT_EQ(1, ConstructorShadowState); - EXPECT_EQ(1, DestructorShadowState); -} - -TEST_F(TWeakPtrTest, IsExpired) -{ - TIntricateObjectWkPtr ptr; - - EXPECT_TRUE(ptr.IsExpired()); - { - TIntricateObjectPtr object = New<TIntricateObject>(); - ptr = object; - EXPECT_FALSE(ptr.IsExpired()); - } - EXPECT_TRUE(ptr.IsExpired()); -} - -TEST_F(TWeakPtrTest, UpCast) -{ - TDerivedIntricateObjectPtr object = New<TDerivedIntricateObject>(); - TIntricateObjectWkPtr ptr = object; - - EXPECT_EQ(object.Get(), ptr.Lock().Get()); -} - -class TIntricateObjectVirtual - : public virtual TRefCounted -{ -public: - TIntricateObjectVirtual() - { - ++ConstructorShadowState; - } - - virtual ~TIntricateObjectVirtual() - { - ++DestructorShadowState; - } - - // Prevent the counter from destruction by holding an additional - // reference to the counter. - void LockCounter() - { - WeakRef(); - } - - // Release an additional reference to the reference counter acquired by - // #LockCounter(). - void UnlockCounter() - { - WeakUnref(); - } - -private: - // Explicitly non-copyable. - TIntricateObjectVirtual(const TIntricateObjectVirtual&); - TIntricateObjectVirtual(TIntricateObjectVirtual&&); - TIntricateObjectVirtual& operator=(const TIntricateObjectVirtual&); - TIntricateObjectVirtual& operator=(TIntricateObjectVirtual&&); -}; - -TEST_F(TWeakPtrTest, VirtualBase) -{ - auto object = New<TIntricateObjectVirtual>(); - TWeakPtr<TIntricateObjectVirtual> ptr = object; - - object.Reset(); - ptr.Reset(); -} - +} + +void PrintTo(const TIntricateObject& arg, ::std::ostream* os) +{ + PrintExtrinsicRefCounted(arg, os); +} + +//////////////////////////////////////////////////////////////////////////////// + +class TWeakPtrTest + : public ::testing::Test +{ +public: + virtual void SetUp() + { + ResetShadowState(); + } +}; + +TEST_F(TWeakPtrTest, Empty) +{ + TIntricateObjectWkPtr emptyPointer; + EXPECT_EQ(TIntricateObjectPtr(), emptyPointer.Lock()); +} + +TEST_F(TWeakPtrTest, Basic) +{ + TIntricateObjectPtr object = New<TIntricateObject>(); + TIntricateObject* objectPtr = object.Get(); + + EXPECT_THAT(*object, HasRefCounts(1, 1)); + + { + TIntricateObjectWkPtr ptr(objectPtr); + EXPECT_THAT(*object, HasRefCounts(1, 2)); + EXPECT_EQ(object, ptr.Lock()); + } + + EXPECT_THAT(*object, HasRefCounts(1, 1)); + + { + TIntricateObjectWkPtr ptr(object); + EXPECT_THAT(*object, HasRefCounts(1, 2)); + EXPECT_EQ(object, ptr.Lock()); + } + + EXPECT_THAT(*object, HasRefCounts(1, 1)); + + object.Reset(); + + EXPECT_EQ(1, ConstructorShadowState); + EXPECT_EQ(1, DestructorShadowState); +} + +TEST_F(TWeakPtrTest, ResetToNull) +{ + TIntricateObjectPtr object = New<TIntricateObject>(); + TIntricateObjectWkPtr ptr(object); + + EXPECT_THAT(*object, HasRefCounts(1, 2)); + EXPECT_EQ(object, ptr.Lock()); + + ptr.Reset(); + + EXPECT_THAT(*object, HasRefCounts(1, 1)); + EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock()); +} + +TEST_F(TWeakPtrTest, ResetToOtherObject) +{ + TIntricateObjectPtr firstObject = New<TIntricateObject>(); + TIntricateObjectPtr secondObject = New<TIntricateObject>(); + + { + TIntricateObjectWkPtr ptr(firstObject); + + EXPECT_THAT(*firstObject, HasRefCounts(1, 2)); + EXPECT_THAT(*secondObject, HasRefCounts(1, 1)); + EXPECT_EQ(firstObject, ptr.Lock()); + + ptr.Reset(secondObject); + + EXPECT_THAT(*firstObject, HasRefCounts(1, 1)); + EXPECT_THAT(*secondObject, HasRefCounts(1, 2)); + EXPECT_EQ(secondObject, ptr.Lock()); + } + + TIntricateObject* firstObjectPtr = firstObject.Get(); + TIntricateObject* secondObjectPtr = secondObject.Get(); + + { + TIntricateObjectWkPtr ptr(firstObjectPtr); + + EXPECT_THAT(*firstObject, HasRefCounts(1, 2)); + EXPECT_THAT(*secondObject, HasRefCounts(1, 1)); + EXPECT_EQ(firstObject, ptr.Lock()); + + ptr.Reset(secondObjectPtr); + + EXPECT_THAT(*firstObject, HasRefCounts(1, 1)); + EXPECT_THAT(*secondObject, HasRefCounts(1, 2)); + EXPECT_EQ(secondObject, ptr.Lock()); + } +} + +TEST_F(TWeakPtrTest, CopySemantics) +{ + TIntricateObjectPtr object = New<TIntricateObject>(); + TIntricateObjectWkPtr foo(object); + + { + EXPECT_THAT(*object, HasRefCounts(1, 2)); + TIntricateObjectWkPtr bar(foo); + EXPECT_THAT(*object, HasRefCounts(1, 3)); + + EXPECT_EQ(object, foo.Lock()); + EXPECT_EQ(object, bar.Lock()); + } + + { + EXPECT_THAT(*object, HasRefCounts(1, 2)); + TIntricateObjectWkPtr bar; + bar = foo; + EXPECT_THAT(*object, HasRefCounts(1, 3)); + + EXPECT_EQ(object, foo.Lock()); + EXPECT_EQ(object, bar.Lock()); + } +} + +TEST_F(TWeakPtrTest, MoveSemantics) +{ + TIntricateObjectPtr object = New<TIntricateObject>(); + TIntricateObjectWkPtr foo(object); + + { + EXPECT_THAT(*object, HasRefCounts(1, 2)); + TIntricateObjectWkPtr bar(std::move(foo)); + EXPECT_THAT(*object, HasRefCounts(1, 2)); + + EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); + EXPECT_EQ(object, bar.Lock()); + } + + foo.Reset(object); + + { + EXPECT_THAT(*object, HasRefCounts(1, 2)); + TIntricateObjectWkPtr bar; + bar = std::move(foo); + EXPECT_THAT(*object, HasRefCounts(1, 2)); + + EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); + EXPECT_EQ(object, bar.Lock()); + } +} + +TEST_F(TWeakPtrTest, OutOfScope) +{ + TIntricateObjectWkPtr ptr; + + EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock()); + { + TIntricateObjectPtr object = New<TIntricateObject>(); + ptr = object; + EXPECT_EQ(object, ptr.Lock()); + } + EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock()); +} + +TEST_F(TWeakPtrTest, OutOfNestedScope) +{ + TIntricateObjectWkPtr foo; + + EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); + { + TIntricateObjectPtr object = New<TIntricateObject>(); + foo = object; + + EXPECT_EQ(object, foo.Lock()); + { + TIntricateObjectWkPtr bar; + bar = object; + + EXPECT_EQ(object, bar.Lock()); + } + EXPECT_EQ(object, foo.Lock()); + } + EXPECT_EQ(TIntricateObjectPtr(), foo.Lock()); + + EXPECT_EQ(1, ConstructorShadowState); + EXPECT_EQ(1, DestructorShadowState); +} + +TEST_F(TWeakPtrTest, IsExpired) +{ + TIntricateObjectWkPtr ptr; + + EXPECT_TRUE(ptr.IsExpired()); + { + TIntricateObjectPtr object = New<TIntricateObject>(); + ptr = object; + EXPECT_FALSE(ptr.IsExpired()); + } + EXPECT_TRUE(ptr.IsExpired()); +} + +TEST_F(TWeakPtrTest, UpCast) +{ + TDerivedIntricateObjectPtr object = New<TDerivedIntricateObject>(); + TIntricateObjectWkPtr ptr = object; + + EXPECT_EQ(object.Get(), ptr.Lock().Get()); +} + +class TIntricateObjectVirtual + : public virtual TRefCounted +{ +public: + TIntricateObjectVirtual() + { + ++ConstructorShadowState; + } + + virtual ~TIntricateObjectVirtual() + { + ++DestructorShadowState; + } + + // Prevent the counter from destruction by holding an additional + // reference to the counter. + void LockCounter() + { + WeakRef(); + } + + // Release an additional reference to the reference counter acquired by + // #LockCounter(). + void UnlockCounter() + { + WeakUnref(); + } + +private: + // Explicitly non-copyable. + TIntricateObjectVirtual(const TIntricateObjectVirtual&); + TIntricateObjectVirtual(TIntricateObjectVirtual&&); + TIntricateObjectVirtual& operator=(const TIntricateObjectVirtual&); + TIntricateObjectVirtual& operator=(TIntricateObjectVirtual&&); +}; + +TEST_F(TWeakPtrTest, VirtualBase) +{ + auto object = New<TIntricateObjectVirtual>(); + TWeakPtr<TIntricateObjectVirtual> ptr = object; + + object.Reset(); + ptr.Reset(); +} + #if 0 class TSlowlyDyingObject : public TRefCounted @@ -379,55 +379,55 @@ void PrintTo(const TSlowlyDyingObject& arg, ::std::ostream* os) typedef TIntrusivePtr<TSlowlyDyingObject> TSlowlyDyingObjectPtr; typedef TWeakPtr<TSlowlyDyingObject> TSlowlyDyingObjectWkPtr; -static void* AsynchronousDeleter(void* param) -{ - TSlowlyDyingObjectPtr* indirectObject = - reinterpret_cast<TSlowlyDyingObjectPtr*>(param); - indirectObject->Reset(); - return nullptr; -} - -std::unique_ptr<NThreading::TEvent> DeathEvent; - -TEST_F(TWeakPtrTest, DISABLED_AcquisionOfSlowlyDyingObject) -{ - DeathEvent.reset(new NThreading::TEvent()); - - TSlowlyDyingObjectPtr object = New<TSlowlyDyingObject>(); - TSlowlyDyingObjectWkPtr ptr(object); - - TSlowlyDyingObject* objectPtr = object.Get(); - - EXPECT_EQ(object, ptr.Lock()); - EXPECT_THAT(*objectPtr, HasRefCounts(1, 2)); - - ASSERT_EQ(1, ConstructorShadowState); - ASSERT_EQ(0, DestructorShadowState); - - // Kick off object deletion in the background. - TThread thread(&AsynchronousDeleter, &object); - thread.Start(); - Sleep(TDuration::Seconds(0.100)); - - ASSERT_EQ(1, ConstructorShadowState); - ASSERT_EQ(1, DestructorShadowState); - - EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock()); - EXPECT_THAT(*objectPtr, HasRefCounts(0, 2)); - - // Finalize object destruction. - DeathEvent->NotifyAll(); - thread.Join(); - - ASSERT_EQ(1, ConstructorShadowState); - ASSERT_EQ(2, DestructorShadowState); - - EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock()); -} - +static void* AsynchronousDeleter(void* param) +{ + TSlowlyDyingObjectPtr* indirectObject = + reinterpret_cast<TSlowlyDyingObjectPtr*>(param); + indirectObject->Reset(); + return nullptr; +} + +std::unique_ptr<NThreading::TEvent> DeathEvent; + +TEST_F(TWeakPtrTest, DISABLED_AcquisionOfSlowlyDyingObject) +{ + DeathEvent.reset(new NThreading::TEvent()); + + TSlowlyDyingObjectPtr object = New<TSlowlyDyingObject>(); + TSlowlyDyingObjectWkPtr ptr(object); + + TSlowlyDyingObject* objectPtr = object.Get(); + + EXPECT_EQ(object, ptr.Lock()); + EXPECT_THAT(*objectPtr, HasRefCounts(1, 2)); + + ASSERT_EQ(1, ConstructorShadowState); + ASSERT_EQ(0, DestructorShadowState); + + // Kick off object deletion in the background. + TThread thread(&AsynchronousDeleter, &object); + thread.Start(); + Sleep(TDuration::Seconds(0.100)); + + ASSERT_EQ(1, ConstructorShadowState); + ASSERT_EQ(1, DestructorShadowState); + + EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock()); + EXPECT_THAT(*objectPtr, HasRefCounts(0, 2)); + + // Finalize object destruction. + DeathEvent->NotifyAll(); + thread.Join(); + + ASSERT_EQ(1, ConstructorShadowState); + ASSERT_EQ(2, DestructorShadowState); + + EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock()); +} + #endif -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/memory/unittests/ya.make b/library/cpp/yt/memory/unittests/ya.make index f09ad7d0c9..da95290172 100644 --- a/library/cpp/yt/memory/unittests/ya.make +++ b/library/cpp/yt/memory/unittests/ya.make @@ -13,7 +13,7 @@ SRCS( PEERDIR( library/cpp/testing/gtest - library/cpp/yt/memory + library/cpp/yt/memory ) END() diff --git a/library/cpp/yt/memory/weak_ptr.h b/library/cpp/yt/memory/weak_ptr.h index 25a242bb8a..b8b7152933 100644 --- a/library/cpp/yt/memory/weak_ptr.h +++ b/library/cpp/yt/memory/weak_ptr.h @@ -2,8 +2,8 @@ #include "ref_counted.h" -#include <util/generic/hash.h> - +#include <util/generic/hash.h> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// @@ -12,12 +12,12 @@ template <class T> class TWeakPtr { public: - typedef T TUnderlying; + typedef T TUnderlying; //! Empty constructor. - TWeakPtr() = default; - - TWeakPtr(std::nullptr_t) + TWeakPtr() = default; + + TWeakPtr(std::nullptr_t) { } //! Constructor from an unqualified reference. @@ -25,7 +25,7 @@ public: * Note that this constructor could be racy due to unsynchronized operations * on the object and on the counter. */ - explicit TWeakPtr(T* p) noexcept + explicit TWeakPtr(T* p) noexcept : T_(p) { @@ -110,7 +110,7 @@ public: } //! Copy assignment operator. - TWeakPtr& operator=(const TWeakPtr& other) noexcept + TWeakPtr& operator=(const TWeakPtr& other) noexcept { TWeakPtr(other).Swap(*this); return *this; @@ -118,7 +118,7 @@ public: //! Copy assignment operator with an upcast. template <class U> - TWeakPtr& operator=(const TWeakPtr<U>& other) noexcept + TWeakPtr& operator=(const TWeakPtr<U>& other) noexcept { static_assert( std::is_convertible_v<U*, T*>, @@ -136,7 +136,7 @@ public: //! Move assignment operator with an upcast. template <class U> - TWeakPtr& operator=(TWeakPtr<U>&& other) noexcept + TWeakPtr& operator=(TWeakPtr<U>&& other) noexcept { static_assert( std::is_convertible_v<U*, T*>, @@ -177,7 +177,7 @@ public: } //! Acquire a strong reference to the pointee and return a strong pointer. - TIntrusivePtr<T> Lock() const noexcept + TIntrusivePtr<T> Lock() const noexcept { return T_ && RefCounter()->TryRef() ? TIntrusivePtr<T>(T_, false) @@ -209,10 +209,10 @@ private: template <class U> friend class TWeakPtr; - template <class U> + template <class U> friend struct ::THash; - T* T_ = nullptr; + T* T_ = nullptr; #if defined(_tsan_enabled_) const TRefCounter* RefCounter_ = nullptr; @@ -230,22 +230,22 @@ private: //////////////////////////////////////////////////////////////////////////////// -//! Creates a weak pointer wrapper for a given raw pointer. -//! Compared to |TWeakPtr<T>::ctor|, type inference enables omitting |T|. -template <class T> -TWeakPtr<T> MakeWeak(T* p) -{ - return TWeakPtr<T>(p); -} - -//! Creates a weak pointer wrapper for a given intrusive pointer. -//! Compared to |TWeakPtr<T>::ctor|, type inference enables omitting |T|. +//! Creates a weak pointer wrapper for a given raw pointer. +//! Compared to |TWeakPtr<T>::ctor|, type inference enables omitting |T|. template <class T> -TWeakPtr<T> MakeWeak(const TIntrusivePtr<T>& p) -{ - return TWeakPtr<T>(p); -} - +TWeakPtr<T> MakeWeak(T* p) +{ + return TWeakPtr<T>(p); +} + +//! Creates a weak pointer wrapper for a given intrusive pointer. +//! Compared to |TWeakPtr<T>::ctor|, type inference enables omitting |T|. +template <class T> +TWeakPtr<T> MakeWeak(const TIntrusivePtr<T>& p) +{ + return TWeakPtr<T>(p); +} + //! A helper for acquiring weak pointer for pointee, resetting intrusive pointer and then //! returning the pointee reference count using the acquired weak pointer. //! This helper is designed for best effort in checking that the object is not leaked after @@ -265,10 +265,10 @@ int ResetAndGetResidualRefCount(TIntrusivePtr<T>& pointer) } } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + // TODO(sandello): Kill comparsions. -template <class T> +template <class T> bool operator<(const TWeakPtr<T>& lhs, const TWeakPtr<T>& rhs) { return lhs.Lock().Get() < rhs.Lock().Get(); @@ -301,14 +301,14 @@ bool operator!=(const TWeakPtr<T>& lhs, const TWeakPtr<U>& rhs) //////////////////////////////////////////////////////////////////////////////// } // namespace NYT - - -//! A hasher for TWeakPtr. -template <class T> + + +//! A hasher for TWeakPtr. +template <class T> struct THash<NYT::TWeakPtr<T>> -{ - size_t operator () (const NYT::TWeakPtr<T>& ptr) const - { +{ + size_t operator () (const NYT::TWeakPtr<T>& ptr) const + { return THash<const NYT::TRefCountedBase*>()(ptr.T_); - } -}; + } +}; diff --git a/library/cpp/yt/memory/ya.make b/library/cpp/yt/memory/ya.make index a925c714ee..07a2501fa1 100644 --- a/library/cpp/yt/memory/ya.make +++ b/library/cpp/yt/memory/ya.make @@ -3,14 +3,14 @@ LIBRARY() OWNER(g:yt) SRCS( - blob.cpp - ref.cpp + blob.cpp + ref.cpp ref_tracked.cpp ) PEERDIR( - library/cpp/yt/assert - library/cpp/yt/misc + library/cpp/yt/assert + library/cpp/yt/misc library/cpp/ytalloc/api ) @@ -20,8 +20,8 @@ CHECK_DEPENDENT_DIRS( contrib library util - library/cpp/yt/assert - library/cpp/yt/misc + library/cpp/yt/assert + library/cpp/yt/misc ) END() diff --git a/library/cpp/yt/misc/cast-inl.h b/library/cpp/yt/misc/cast-inl.h index 1920b7c0b7..78884df637 100644 --- a/library/cpp/yt/misc/cast-inl.h +++ b/library/cpp/yt/misc/cast-inl.h @@ -4,9 +4,9 @@ #include "cast.h" #endif -#include <util/string/cast.h> -#include <util/string/printf.h> - +#include <util/string/cast.h> +#include <util/string/printf.h> + #include <type_traits> namespace NYT { @@ -39,29 +39,29 @@ typename std::enable_if<std::is_unsigned<T>::value && std::is_unsigned<S>::value return value <= std::numeric_limits<T>::max(); } -template <class T> -TString FormatInvalidCastValue(T value) -{ - return ::ToString(value); -} - -inline TString FormatInvalidCastValue(signed char value) -{ - return TString("'") + value + TString("'"); -} - -inline TString FormatInvalidCastValue(unsigned char value) -{ - return TString("'") + value + TString("'"); -} - -#ifdef __cpp_char8_t -inline TString FormatInvalidCastValue(char8_t value) -{ - return FormatInvalidCastValue(static_cast<unsigned char>(value)); -} -#endif - +template <class T> +TString FormatInvalidCastValue(T value) +{ + return ::ToString(value); +} + +inline TString FormatInvalidCastValue(signed char value) +{ + return TString("'") + value + TString("'"); +} + +inline TString FormatInvalidCastValue(unsigned char value) +{ + return TString("'") + value + TString("'"); +} + +#ifdef __cpp_char8_t +inline TString FormatInvalidCastValue(char8_t value) +{ + return FormatInvalidCastValue(static_cast<unsigned char>(value)); +} +#endif + } // namespace NDetail template <class T, class S> @@ -79,8 +79,8 @@ T CheckedIntegralCast(S value) { T result; if (!TryIntegralCast<T>(value, &result)) { - throw TSimpleException(Sprintf("Argument value %s is out of expected range", - NDetail::FormatInvalidCastValue(value).c_str())); + throw TSimpleException(Sprintf("Argument value %s is out of expected range", + NDetail::FormatInvalidCastValue(value).c_str())); } return result; } @@ -101,9 +101,9 @@ T CheckedEnumCast(S value) { T result; if (!TryEnumCast<T>(value, &result)) { - throw TSimpleException(Sprintf("Invalid value %d of enum type %s", - static_cast<int>(value), - TEnumTraits<T>::GetTypeName().data())); + throw TSimpleException(Sprintf("Invalid value %d of enum type %s", + static_cast<int>(value), + TEnumTraits<T>::GetTypeName().data())); } return result; } diff --git a/library/cpp/yt/misc/cast.h b/library/cpp/yt/misc/cast.h index c7565c9e6d..5adb3553e9 100644 --- a/library/cpp/yt/misc/cast.h +++ b/library/cpp/yt/misc/cast.h @@ -1,7 +1,7 @@ #pragma once -#include <library/cpp/yt/exception/exception.h> - +#include <library/cpp/yt/exception/exception.h> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// @@ -12,8 +12,8 @@ bool TryIntegralCast(S value, T* result); template <class T, class S> T CheckedIntegralCast(S value); -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + template <class T, class S> bool TryEnumCast(S value, T* result); diff --git a/library/cpp/yt/misc/enum-inl.h b/library/cpp/yt/misc/enum-inl.h index 59ef704775..7666181aa2 100644 --- a/library/cpp/yt/misc/enum-inl.h +++ b/library/cpp/yt/misc/enum-inl.h @@ -1,41 +1,41 @@ -#pragma once -#ifndef ENUM_INL_H_ -#error "Direct inclusion of this file is not allowed, include enum.h" -// For the sake of sane code completion. -#include "enum.h" -#endif - -#include <util/string/printf.h> -#include <util/string/cast.h> - +#pragma once +#ifndef ENUM_INL_H_ +#error "Direct inclusion of this file is not allowed, include enum.h" +// For the sake of sane code completion. +#include "enum.h" +#endif + +#include <util/string/printf.h> +#include <util/string/cast.h> + #include <algorithm> -#include <stdexcept> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -#define ENUM__CLASS(name, underlyingType, seq) \ - enum class name : underlyingType \ - { \ - PP_FOR_EACH(ENUM__DOMAIN_ITEM, seq) \ - }; - -#define ENUM__DOMAIN_ITEM(item) \ - PP_IF( \ - PP_IS_SEQUENCE(item), \ - ENUM__DOMAIN_ITEM_SEQ, \ - ENUM__DOMAIN_ITEM_ATOMIC \ - )(item)() - -#define ENUM__DOMAIN_ITEM_ATOMIC(item) \ - item PP_COMMA - -#define ENUM__DOMAIN_ITEM_SEQ(seq) \ - PP_ELEMENT(seq, 0) = PP_ELEMENT(seq, 1) PP_COMMA - -//////////////////////////////////////////////////////////////////////////////// - +#include <stdexcept> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +#define ENUM__CLASS(name, underlyingType, seq) \ + enum class name : underlyingType \ + { \ + PP_FOR_EACH(ENUM__DOMAIN_ITEM, seq) \ + }; + +#define ENUM__DOMAIN_ITEM(item) \ + PP_IF( \ + PP_IS_SEQUENCE(item), \ + ENUM__DOMAIN_ITEM_SEQ, \ + ENUM__DOMAIN_ITEM_ATOMIC \ + )(item)() + +#define ENUM__DOMAIN_ITEM_ATOMIC(item) \ + item PP_COMMA + +#define ENUM__DOMAIN_ITEM_SEQ(seq) \ + PP_ELEMENT(seq, 0) = PP_ELEMENT(seq, 1) PP_COMMA + +//////////////////////////////////////////////////////////////////////////////// + namespace NDetail { template <typename TValues> @@ -55,15 +55,15 @@ static constexpr bool AreValuesDistinct(const TValues& values) //////////////////////////////////////////////////////////////////////////////// -#define ENUM__BEGIN_TRAITS(name, underlyingType, isBit, isStringSerializable, seq) \ - struct TEnumTraitsImpl_##name \ - { \ - using TType = name; \ - using TUnderlying = underlyingType; \ - [[maybe_unused]] static constexpr bool IsBitEnum = isBit; \ - [[maybe_unused]] static constexpr bool IsStringSerializableEnum = isStringSerializable; \ - [[maybe_unused]] static constexpr int DomainSize = PP_COUNT(seq); \ - \ +#define ENUM__BEGIN_TRAITS(name, underlyingType, isBit, isStringSerializable, seq) \ + struct TEnumTraitsImpl_##name \ + { \ + using TType = name; \ + using TUnderlying = underlyingType; \ + [[maybe_unused]] static constexpr bool IsBitEnum = isBit; \ + [[maybe_unused]] static constexpr bool IsStringSerializableEnum = isStringSerializable; \ + [[maybe_unused]] static constexpr int DomainSize = PP_COUNT(seq); \ + \ static constexpr std::array<TStringBuf, DomainSize> Names{{ \ PP_FOR_EACH(ENUM__GET_DOMAIN_NAMES_ITEM, seq) \ }}; \ @@ -71,95 +71,95 @@ static constexpr bool AreValuesDistinct(const TValues& values) PP_FOR_EACH(ENUM__GET_DOMAIN_VALUES_ITEM, seq) \ }}; \ \ - static TStringBuf GetTypeName() \ - { \ + static TStringBuf GetTypeName() \ + { \ static constexpr TStringBuf typeName = PP_STRINGIZE(name); \ - return typeName; \ - } \ - \ - static const TStringBuf* FindLiteralByValue(TType value) \ - { \ + return typeName; \ + } \ + \ + static const TStringBuf* FindLiteralByValue(TType value) \ + { \ for (int i = 0; i < DomainSize; ++i) { \ if (Values[i] == value) { \ return &Names[i]; \ } \ } \ - return nullptr; \ - } \ - \ - static bool FindValueByLiteral(TStringBuf literal, TType* result) \ - { \ + return nullptr; \ + } \ + \ + static bool FindValueByLiteral(TStringBuf literal, TType* result) \ + { \ for (int i = 0; i < DomainSize; ++i) { \ if (Names[i] == literal) { \ *result = Values[i]; \ return true; \ } \ } \ - return false; \ - } \ - \ - static const std::array<TStringBuf, DomainSize>& GetDomainNames() \ - { \ + return false; \ + } \ + \ + static const std::array<TStringBuf, DomainSize>& GetDomainNames() \ + { \ return Names; \ - } \ - \ - static const std::array<TType, DomainSize>& GetDomainValues() \ - { \ + } \ + \ + static const std::array<TType, DomainSize>& GetDomainValues() \ + { \ return Values; \ - } \ - \ - static TType FromString(TStringBuf str) \ - { \ - TType value; \ - if (!FindValueByLiteral(str, &value)) { \ - throw ::NYT::TSimpleException(Sprintf("Error parsing %s value %s", \ - PP_STRINGIZE(name), \ - TString(str).Quote().c_str()).c_str()); \ - } \ - return value; \ - } - -#define ENUM__GET_DOMAIN_VALUES_ITEM(item) \ - PP_IF( \ - PP_IS_SEQUENCE(item), \ - ENUM__GET_DOMAIN_VALUES_ITEM_SEQ, \ - ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC \ - )(item) - -#define ENUM__GET_DOMAIN_VALUES_ITEM_SEQ(seq) \ - ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(PP_ELEMENT(seq, 0)) - -#define ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(item) \ - TType::item, - -#define ENUM__GET_DOMAIN_NAMES_ITEM(item) \ - PP_IF( \ - PP_IS_SEQUENCE(item), \ - ENUM__GET_DOMAIN_NAMES_ITEM_SEQ, \ - ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC \ - )(item) - -#define ENUM__GET_DOMAIN_NAMES_ITEM_SEQ(seq) \ - ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(PP_ELEMENT(seq, 0)) - -#define ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(item) \ + } \ + \ + static TType FromString(TStringBuf str) \ + { \ + TType value; \ + if (!FindValueByLiteral(str, &value)) { \ + throw ::NYT::TSimpleException(Sprintf("Error parsing %s value %s", \ + PP_STRINGIZE(name), \ + TString(str).Quote().c_str()).c_str()); \ + } \ + return value; \ + } + +#define ENUM__GET_DOMAIN_VALUES_ITEM(item) \ + PP_IF( \ + PP_IS_SEQUENCE(item), \ + ENUM__GET_DOMAIN_VALUES_ITEM_SEQ, \ + ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC \ + )(item) + +#define ENUM__GET_DOMAIN_VALUES_ITEM_SEQ(seq) \ + ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(PP_ELEMENT(seq, 0)) + +#define ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(item) \ + TType::item, + +#define ENUM__GET_DOMAIN_NAMES_ITEM(item) \ + PP_IF( \ + PP_IS_SEQUENCE(item), \ + ENUM__GET_DOMAIN_NAMES_ITEM_SEQ, \ + ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC \ + )(item) + +#define ENUM__GET_DOMAIN_NAMES_ITEM_SEQ(seq) \ + ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(PP_ELEMENT(seq, 0)) + +#define ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(item) \ TStringBuf(PP_STRINGIZE(item)), - + #define ENUM__DECOMPOSE \ - static std::vector<TType> Decompose(TType value) \ - { \ - std::vector<TType> result; \ + static std::vector<TType> Decompose(TType value) \ + { \ + std::vector<TType> result; \ for (int i = 0; i < DomainSize; ++i) { \ if (static_cast<TUnderlying>(value) & static_cast<TUnderlying>(Values[i])) { \ result.push_back(Values[i]); \ } \ } \ - return result; \ - } - + return result; \ + } + #define ENUM__MINMAX \ static constexpr TType GetMinValue() \ - { \ + { \ static_assert(!Values.empty()); \ return *std::min_element(std::begin(Values), std::end(Values)); \ } \ @@ -174,212 +174,212 @@ static constexpr bool AreValuesDistinct(const TValues& values) static_assert(::NYT::NDetail::AreValuesDistinct(Values), \ "Enumeration " #name " contains duplicate values"); -#define ENUM__END_TRAITS(name) \ - }; \ - \ +#define ENUM__END_TRAITS(name) \ + }; \ + \ [[maybe_unused]] inline TEnumTraitsImpl_##name GetEnumTraitsImpl(name) \ - { \ - return TEnumTraitsImpl_##name(); \ - } \ + { \ + return TEnumTraitsImpl_##name(); \ + } \ \ - using ::ToString; \ + using ::ToString; \ [[maybe_unused]] inline TString ToString(name value) \ - { \ - return ::NYT::TEnumTraits<name>::ToString(value); \ - } - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -std::vector<T> TEnumTraits<T, true>::Decompose(T value) -{ - return TImpl::Decompose(value); -} - -template <class T> -T TEnumTraits<T, true>::FromString(TStringBuf str) -{ - return TImpl::FromString(str); -} - -template <class T> -TString TEnumTraits<T, true>::ToString(TType value) -{ - TString result; - const auto* literal = FindLiteralByValue(value); - if (literal) { - result = *literal; - } else { - result = GetTypeName(); - result += "("; - result += ::ToString(static_cast<TUnderlying>(value)); - result += ")"; - } - return result; -} - -template <class T> -auto TEnumTraits<T, true>::GetDomainValues() -> const std::array<T, DomainSize>& -{ - return TImpl::GetDomainValues(); -} - -template <class T> -auto TEnumTraits<T, true>::GetDomainNames() -> const std::array<TStringBuf, DomainSize>& -{ - return TImpl::GetDomainNames(); -} - -template <class T> -constexpr T TEnumTraits<T, true>::GetMaxValue() -{ - return TImpl::GetMaxValue(); -} - -template <class T> -constexpr T TEnumTraits<T, true>::GetMinValue() -{ - return TImpl::GetMinValue(); -} - -template <class T> -bool TEnumTraits<T, true>::FindValueByLiteral(TStringBuf literal, TType* result) -{ - return TImpl::FindValueByLiteral(literal, result); -} - -template <class T> -const TStringBuf* TEnumTraits<T, true>::FindLiteralByValue(TType value) -{ - return TImpl::FindLiteralByValue(value); -} - -template <class T> -TStringBuf TEnumTraits<T, true>::GetTypeName() -{ - return TImpl::GetTypeName(); -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class E, class T, E Min, E Max> -TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector() - : Items_{} -{ } - -template <class E, class T, E Min, E Max> -TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector(std::initializer_list<T> elements) - : Items_{} -{ - Y_ASSERT(std::distance(elements.begin(), elements.end()) <= N); - size_t index = 0; - for (const auto& element : elements) { - Items_[index++] = element; - } -} - -template <class E, class T, E Min, E Max> -T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) -{ - Y_ASSERT(index >= Min && index <= Max); - return Items_[static_cast<TUnderlying>(index) - static_cast<TUnderlying>(Min)]; -} - -template <class E, class T, E Min, E Max> -const T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) const -{ - return const_cast<TEnumIndexedVector&>(*this)[index]; -} - -template <class E, class T, E Min, E Max> -T* TEnumIndexedVector<E, T, Min, Max>::begin() -{ - return Items_.data(); -} - -template <class E, class T, E Min, E Max> -const T* TEnumIndexedVector<E, T, Min, Max>::begin() const -{ - return Items_.data(); -} - -template <class E, class T, E Min, E Max> -T* TEnumIndexedVector<E, T, Min, Max>::end() -{ - return begin() + N; -} - -template <class E, class T, E Min, E Max> -const T* TEnumIndexedVector<E, T, Min, Max>::end() const -{ - return begin() + N; -} - -template <class E, class T, E Min, E Max> -bool TEnumIndexedVector<E, T, Min, Max>::IsDomainValue(E value) -{ - return value >= Min && value <= Max; -} - -//////////////////////////////////////////////////////////////////////////////// - -#define ENUM__BINARY_BITWISE_OPERATOR(T, assignOp, op) \ + { \ + return ::NYT::TEnumTraits<name>::ToString(value); \ + } + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +std::vector<T> TEnumTraits<T, true>::Decompose(T value) +{ + return TImpl::Decompose(value); +} + +template <class T> +T TEnumTraits<T, true>::FromString(TStringBuf str) +{ + return TImpl::FromString(str); +} + +template <class T> +TString TEnumTraits<T, true>::ToString(TType value) +{ + TString result; + const auto* literal = FindLiteralByValue(value); + if (literal) { + result = *literal; + } else { + result = GetTypeName(); + result += "("; + result += ::ToString(static_cast<TUnderlying>(value)); + result += ")"; + } + return result; +} + +template <class T> +auto TEnumTraits<T, true>::GetDomainValues() -> const std::array<T, DomainSize>& +{ + return TImpl::GetDomainValues(); +} + +template <class T> +auto TEnumTraits<T, true>::GetDomainNames() -> const std::array<TStringBuf, DomainSize>& +{ + return TImpl::GetDomainNames(); +} + +template <class T> +constexpr T TEnumTraits<T, true>::GetMaxValue() +{ + return TImpl::GetMaxValue(); +} + +template <class T> +constexpr T TEnumTraits<T, true>::GetMinValue() +{ + return TImpl::GetMinValue(); +} + +template <class T> +bool TEnumTraits<T, true>::FindValueByLiteral(TStringBuf literal, TType* result) +{ + return TImpl::FindValueByLiteral(literal, result); +} + +template <class T> +const TStringBuf* TEnumTraits<T, true>::FindLiteralByValue(TType value) +{ + return TImpl::FindLiteralByValue(value); +} + +template <class T> +TStringBuf TEnumTraits<T, true>::GetTypeName() +{ + return TImpl::GetTypeName(); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class E, class T, E Min, E Max> +TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector() + : Items_{} +{ } + +template <class E, class T, E Min, E Max> +TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector(std::initializer_list<T> elements) + : Items_{} +{ + Y_ASSERT(std::distance(elements.begin(), elements.end()) <= N); + size_t index = 0; + for (const auto& element : elements) { + Items_[index++] = element; + } +} + +template <class E, class T, E Min, E Max> +T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) +{ + Y_ASSERT(index >= Min && index <= Max); + return Items_[static_cast<TUnderlying>(index) - static_cast<TUnderlying>(Min)]; +} + +template <class E, class T, E Min, E Max> +const T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) const +{ + return const_cast<TEnumIndexedVector&>(*this)[index]; +} + +template <class E, class T, E Min, E Max> +T* TEnumIndexedVector<E, T, Min, Max>::begin() +{ + return Items_.data(); +} + +template <class E, class T, E Min, E Max> +const T* TEnumIndexedVector<E, T, Min, Max>::begin() const +{ + return Items_.data(); +} + +template <class E, class T, E Min, E Max> +T* TEnumIndexedVector<E, T, Min, Max>::end() +{ + return begin() + N; +} + +template <class E, class T, E Min, E Max> +const T* TEnumIndexedVector<E, T, Min, Max>::end() const +{ + return begin() + N; +} + +template <class E, class T, E Min, E Max> +bool TEnumIndexedVector<E, T, Min, Max>::IsDomainValue(E value) +{ + return value >= Min && value <= Max; +} + +//////////////////////////////////////////////////////////////////////////////// + +#define ENUM__BINARY_BITWISE_OPERATOR(T, assignOp, op) \ [[maybe_unused]] inline constexpr T operator op (T lhs, T rhs) \ - { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - return T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \ - } \ - \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + return T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \ + } \ + \ [[maybe_unused]] inline T& operator assignOp (T& lhs, T rhs) \ - { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - lhs = T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \ - return lhs; \ - } - -#define ENUM__UNARY_BITWISE_OPERATOR(T, op) \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + lhs = T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \ + return lhs; \ + } + +#define ENUM__UNARY_BITWISE_OPERATOR(T, op) \ [[maybe_unused]] inline constexpr T operator op (T value) \ - { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - return T(op static_cast<TUnderlying>(value)); \ - } - -#define ENUM__BIT_SHIFT_OPERATOR(T, assignOp, op) \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + return T(op static_cast<TUnderlying>(value)); \ + } + +#define ENUM__BIT_SHIFT_OPERATOR(T, assignOp, op) \ [[maybe_unused]] inline constexpr T operator op (T lhs, size_t rhs) \ - { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - return T(static_cast<TUnderlying>(lhs) op rhs); \ - } \ - \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + return T(static_cast<TUnderlying>(lhs) op rhs); \ + } \ + \ [[maybe_unused]] inline T& operator assignOp (T& lhs, size_t rhs) \ - { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - lhs = T(static_cast<TUnderlying>(lhs) op rhs); \ - return lhs; \ - } - -#define ENUM__BITWISE_OPS(name) \ - ENUM__BINARY_BITWISE_OPERATOR(name, &=, &) \ - ENUM__BINARY_BITWISE_OPERATOR(name, |=, | ) \ - ENUM__BINARY_BITWISE_OPERATOR(name, ^=, ^) \ - ENUM__UNARY_BITWISE_OPERATOR(name, ~) \ - ENUM__BIT_SHIFT_OPERATOR(name, <<=, << ) \ - ENUM__BIT_SHIFT_OPERATOR(name, >>=, >> ) - -//////////////////////////////////////////////////////////////////////////////// - + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + lhs = T(static_cast<TUnderlying>(lhs) op rhs); \ + return lhs; \ + } + +#define ENUM__BITWISE_OPS(name) \ + ENUM__BINARY_BITWISE_OPERATOR(name, &=, &) \ + ENUM__BINARY_BITWISE_OPERATOR(name, |=, | ) \ + ENUM__BINARY_BITWISE_OPERATOR(name, ^=, ^) \ + ENUM__UNARY_BITWISE_OPERATOR(name, ~) \ + ENUM__BIT_SHIFT_OPERATOR(name, <<=, << ) \ + ENUM__BIT_SHIFT_OPERATOR(name, >>=, >> ) + +//////////////////////////////////////////////////////////////////////////////// + template <typename E, typename> bool Any(E value) -{ - return static_cast<typename TEnumTraits<E>::TUnderlying>(value) != 0; -} - +{ + return static_cast<typename TEnumTraits<E>::TUnderlying>(value) != 0; +} + template <class E, typename> bool None(E value) -{ - return static_cast<typename TEnumTraits<E>::TUnderlying>(value) == 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +{ + return static_cast<typename TEnumTraits<E>::TUnderlying>(value) == 0; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/enum.h b/library/cpp/yt/misc/enum.h index 894364aa43..b30d20dbe0 100644 --- a/library/cpp/yt/misc/enum.h +++ b/library/cpp/yt/misc/enum.h @@ -1,113 +1,113 @@ -#pragma once - -#include "preprocessor.h" - -#include <util/generic/strbuf.h> - -#include <stdexcept> -#include <type_traits> -#include <array> -#include <vector> - -#include <library/cpp/yt/exception/exception.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// -/* - * Smart enumerations augment C++ enum classes with a bunch of reflection - * capabilities accessible via TEnumTraits class specialization. - * - * Please refer to the unit test for an actual example of usage - * (unittests/enum_ut.cpp). - */ - +#pragma once + +#include "preprocessor.h" + +#include <util/generic/strbuf.h> + +#include <stdexcept> +#include <type_traits> +#include <array> +#include <vector> + +#include <library/cpp/yt/exception/exception.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// +/* + * Smart enumerations augment C++ enum classes with a bunch of reflection + * capabilities accessible via TEnumTraits class specialization. + * + * Please refer to the unit test for an actual example of usage + * (unittests/enum_ut.cpp). + */ + // Actual overload must be provided with defines DEFINE_ENUM_XXX (see below). template <class T> void GetEnumTraitsImpl(T); -template < - class T, +template < + class T, bool = std::is_enum<T>::value && !std::is_convertible<T, int>::value && !std::is_same<void, decltype(GetEnumTraitsImpl(T()))>::value -> -struct TEnumTraits -{ - static constexpr bool IsEnum = false; - static constexpr bool IsBitEnum = false; - static constexpr bool IsStringSerializableEnum = false; -}; - -template <class T> -struct TEnumTraits<T, true> -{ - using TImpl = decltype(GetEnumTraitsImpl(T())); - using TType = T; - using TUnderlying = typename TImpl::TUnderlying; - - static constexpr bool IsEnum = true; - static constexpr bool IsBitEnum = TImpl::IsBitEnum; - static constexpr bool IsStringSerializableEnum = TImpl::IsStringSerializableEnum; - - static constexpr int DomainSize = TImpl::DomainSize; - - static TStringBuf GetTypeName(); - - static const TStringBuf* FindLiteralByValue(TType value); - static bool FindValueByLiteral(TStringBuf literal, TType* result); - - static const std::array<TStringBuf, DomainSize>& GetDomainNames(); - static const std::array<TType, DomainSize>& GetDomainValues(); - - static TType FromString(TStringBuf str); - static TString ToString(TType value); - - // For non-bit enums only. - static constexpr TType GetMinValue(); - static constexpr TType GetMaxValue(); - - // For bit enums only. - static std::vector<TType> Decompose(TType value); - - // LLVM SmallDenseMap interop. - // This should only be used for enums whose underlying type has big enough range - // (see getEmptyKey and getTombstoneKey functions). - struct TDenseMapInfo - { - static inline TType getEmptyKey() - { - return static_cast<TType>(-1); - } - - static inline TType getTombstoneKey() - { - return static_cast<TType>(-2); - } - - static unsigned getHashValue(const TType& key) - { - return static_cast<unsigned>(key) * 37U; - } - - static bool isEqual(const TType& lhs, const TType& rhs) - { - return lhs == rhs; - } - }; -}; - -//////////////////////////////////////////////////////////////////////////////// - -//! Defines a smart enumeration with a specific underlying type. -/*! - * \param name Enumeration name. - * \param seq Enumeration domain encoded as a <em>sequence</em>. - * \param underlyingType Underlying type. - */ -#define DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \ +> +struct TEnumTraits +{ + static constexpr bool IsEnum = false; + static constexpr bool IsBitEnum = false; + static constexpr bool IsStringSerializableEnum = false; +}; + +template <class T> +struct TEnumTraits<T, true> +{ + using TImpl = decltype(GetEnumTraitsImpl(T())); + using TType = T; + using TUnderlying = typename TImpl::TUnderlying; + + static constexpr bool IsEnum = true; + static constexpr bool IsBitEnum = TImpl::IsBitEnum; + static constexpr bool IsStringSerializableEnum = TImpl::IsStringSerializableEnum; + + static constexpr int DomainSize = TImpl::DomainSize; + + static TStringBuf GetTypeName(); + + static const TStringBuf* FindLiteralByValue(TType value); + static bool FindValueByLiteral(TStringBuf literal, TType* result); + + static const std::array<TStringBuf, DomainSize>& GetDomainNames(); + static const std::array<TType, DomainSize>& GetDomainValues(); + + static TType FromString(TStringBuf str); + static TString ToString(TType value); + + // For non-bit enums only. + static constexpr TType GetMinValue(); + static constexpr TType GetMaxValue(); + + // For bit enums only. + static std::vector<TType> Decompose(TType value); + + // LLVM SmallDenseMap interop. + // This should only be used for enums whose underlying type has big enough range + // (see getEmptyKey and getTombstoneKey functions). + struct TDenseMapInfo + { + static inline TType getEmptyKey() + { + return static_cast<TType>(-1); + } + + static inline TType getTombstoneKey() + { + return static_cast<TType>(-2); + } + + static unsigned getHashValue(const TType& key) + { + return static_cast<unsigned>(key) * 37U; + } + + static bool isEqual(const TType& lhs, const TType& rhs) + { + return lhs == rhs; + } + }; +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! Defines a smart enumeration with a specific underlying type. +/*! + * \param name Enumeration name. + * \param seq Enumeration domain encoded as a <em>sequence</em>. + * \param underlyingType Underlying type. + */ +#define DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ + ENUM__CLASS(name, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \ ENUM__MINMAX \ ENUM__VALIDATE_UNIQUE(name) \ ENUM__END_TRAITS(name) @@ -118,26 +118,26 @@ struct TEnumTraits<T, true> ENUM__CLASS(name, underlyingType, seq) \ ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \ ENUM__MINMAX \ - ENUM__END_TRAITS(name) - -//! Defines a smart enumeration with the default |int| underlying type. -#define DEFINE_ENUM(name, seq) \ - DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq) - -//! Defines a smart enumeration with a specific underlying type. -/*! - * \param name Enumeration name. - * \param seq Enumeration domain encoded as a <em>sequence</em>. - * \param underlyingType Underlying type. - */ -#define DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \ + ENUM__END_TRAITS(name) + +//! Defines a smart enumeration with the default |int| underlying type. +#define DEFINE_ENUM(name, seq) \ + DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq) + +//! Defines a smart enumeration with a specific underlying type. +/*! + * \param name Enumeration name. + * \param seq Enumeration domain encoded as a <em>sequence</em>. + * \param underlyingType Underlying type. + */ +#define DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ + ENUM__CLASS(name, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \ ENUM__DECOMPOSE \ ENUM__VALIDATE_UNIQUE(name) \ - ENUM__END_TRAITS(name) \ - ENUM__BITWISE_OPS(name) - + ENUM__END_TRAITS(name) \ + ENUM__BITWISE_OPS(name) + //! Defines a smart enumeration with a specific underlying type. //! Duplicate enumeration values are allowed. /*! @@ -152,23 +152,23 @@ struct TEnumTraits<T, true> ENUM__END_TRAITS(name) \ ENUM__BITWISE_OPS(name) -//! Defines a smart enumeration with the default |unsigned| underlying type. -/*! - * \param name Enumeration name. - * \param seq Enumeration domain encoded as a <em>sequence</em>. - */ -#define DEFINE_BIT_ENUM(name, seq) \ - DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, unsigned, seq) - -//! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute. -/*! - * \param name Enumeration name. - * \param seq Enumeration domain encoded as a <em>sequence</em>. - * \param underlyingType Underlying type. - */ -#define DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \ +//! Defines a smart enumeration with the default |unsigned| underlying type. +/*! + * \param name Enumeration name. + * \param seq Enumeration domain encoded as a <em>sequence</em>. + */ +#define DEFINE_BIT_ENUM(name, seq) \ + DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, unsigned, seq) + +//! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute. +/*! + * \param name Enumeration name. + * \param seq Enumeration domain encoded as a <em>sequence</em>. + * \param underlyingType Underlying type. + */ +#define DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ + ENUM__CLASS(name, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \ ENUM__MINMAX \ ENUM__VALIDATE_UNIQUE(name) \ ENUM__END_TRAITS(name) \ @@ -179,65 +179,65 @@ struct TEnumTraits<T, true> ENUM__CLASS(name, underlyingType, seq) \ ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \ ENUM__MINMAX \ - ENUM__END_TRAITS(name) - -//! Defines a smart enumeration with the default |int| underlying type and IsStringSerializable attribute. -#define DEFINE_STRING_SERIALIZABLE_ENUM(name, seq) \ - DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq) - -//////////////////////////////////////////////////////////////////////////////// - -//! A statically sized vector with elements of type |T| indexed by -//! the items of enumeration type |E|. -/*! - * Items are value-initialized on construction. - */ -template < - class E, - class T, - E Min = TEnumTraits<E>::GetMinValue(), - E Max = TEnumTraits<E>::GetMaxValue() -> -class TEnumIndexedVector -{ -public: - using TIndex = E; - using TValue = T; - - TEnumIndexedVector(); - TEnumIndexedVector(std::initializer_list<T> elements); - - T& operator[] (E index); - const T& operator[] (E index) const; - - // STL interop. - T* begin(); - const T* begin() const; - T* end(); - const T* end() const; - - static bool IsDomainValue(E value); - -private: - using TUnderlying = typename TEnumTraits<E>::TUnderlying; - static constexpr int N = static_cast<TUnderlying>(Max) - static_cast<TUnderlying>(Min) + 1; - std::array<T, N> Items_; -}; - -//////////////////////////////////////////////////////////////////////////////// - -//! Returns |true| iff the enumeration value is not bitwise zero. + ENUM__END_TRAITS(name) + +//! Defines a smart enumeration with the default |int| underlying type and IsStringSerializable attribute. +#define DEFINE_STRING_SERIALIZABLE_ENUM(name, seq) \ + DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq) + +//////////////////////////////////////////////////////////////////////////////// + +//! A statically sized vector with elements of type |T| indexed by +//! the items of enumeration type |E|. +/*! + * Items are value-initialized on construction. + */ +template < + class E, + class T, + E Min = TEnumTraits<E>::GetMinValue(), + E Max = TEnumTraits<E>::GetMaxValue() +> +class TEnumIndexedVector +{ +public: + using TIndex = E; + using TValue = T; + + TEnumIndexedVector(); + TEnumIndexedVector(std::initializer_list<T> elements); + + T& operator[] (E index); + const T& operator[] (E index) const; + + // STL interop. + T* begin(); + const T* begin() const; + T* end(); + const T* end() const; + + static bool IsDomainValue(E value); + +private: + using TUnderlying = typename TEnumTraits<E>::TUnderlying; + static constexpr int N = static_cast<TUnderlying>(Max) - static_cast<TUnderlying>(Min) + 1; + std::array<T, N> Items_; +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! Returns |true| iff the enumeration value is not bitwise zero. template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>> bool Any(E value); - -//! Returns |true| iff the enumeration value is bitwise zero. + +//! Returns |true| iff the enumeration value is bitwise zero. template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>> bool None(E value); - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT - -#define ENUM_INL_H_ -#include "enum-inl.h" -#undef ENUM_INL_H_ + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define ENUM_INL_H_ +#include "enum-inl.h" +#undef ENUM_INL_H_ diff --git a/library/cpp/yt/misc/guid-inl.h b/library/cpp/yt/misc/guid-inl.h index 2d94b5701b..3f0768cca2 100644 --- a/library/cpp/yt/misc/guid-inl.h +++ b/library/cpp/yt/misc/guid-inl.h @@ -1,76 +1,76 @@ -#ifndef GUID_INL_H_ -#error "Direct inclusion of this file is not allowed, include guid.h" +#ifndef GUID_INL_H_ +#error "Direct inclusion of this file is not allowed, include guid.h" // For the sake of sane code completion. #include "guid.h" -#endif - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -Y_FORCE_INLINE constexpr TGuid::TGuid() - : Parts32{} -{ } - -Y_FORCE_INLINE constexpr TGuid::TGuid(ui32 part0, ui32 part1, ui32 part2, ui32 part3) - : Parts32{part0, part1, part2, part3} -{ } - -Y_FORCE_INLINE constexpr TGuid::TGuid(ui64 part0, ui64 part1) - : Parts64{part0, part1} -{ } - -Y_FORCE_INLINE bool TGuid::IsEmpty() const -{ - return Parts64[0] == 0 && Parts64[1] == 0; -} - -Y_FORCE_INLINE TGuid::operator bool() const +#endif + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +Y_FORCE_INLINE constexpr TGuid::TGuid() + : Parts32{} +{ } + +Y_FORCE_INLINE constexpr TGuid::TGuid(ui32 part0, ui32 part1, ui32 part2, ui32 part3) + : Parts32{part0, part1, part2, part3} +{ } + +Y_FORCE_INLINE constexpr TGuid::TGuid(ui64 part0, ui64 part1) + : Parts64{part0, part1} +{ } + +Y_FORCE_INLINE bool TGuid::IsEmpty() const +{ + return Parts64[0] == 0 && Parts64[1] == 0; +} + +Y_FORCE_INLINE TGuid::operator bool() const { return !IsEmpty(); } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + Y_FORCE_INLINE bool operator == (TGuid lhs, TGuid rhs) -{ - return lhs.Parts64[0] == rhs.Parts64[0] && - lhs.Parts64[1] == rhs.Parts64[1]; -} - +{ + return lhs.Parts64[0] == rhs.Parts64[0] && + lhs.Parts64[1] == rhs.Parts64[1]; +} + Y_FORCE_INLINE bool operator != (TGuid lhs, TGuid rhs) -{ - return !(lhs == rhs); -} - +{ + return !(lhs == rhs); +} + Y_FORCE_INLINE bool operator < (TGuid lhs, TGuid rhs) -{ -#ifdef __GNUC__ - ui64 lhs0 = __builtin_bswap64(lhs.Parts64[0]); - ui64 rhs0 = __builtin_bswap64(rhs.Parts64[0]); - if (lhs0 < rhs0) { - return true; - } - if (lhs0 > rhs0) { - return false; - } - ui64 lhs1 = __builtin_bswap64(lhs.Parts64[1]); - ui64 rhs1 = __builtin_bswap64(rhs.Parts64[1]); - return lhs1 < rhs1; -#else - return memcmp(&lhs, &rhs, sizeof(TGuid)) < 0; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT - +{ +#ifdef __GNUC__ + ui64 lhs0 = __builtin_bswap64(lhs.Parts64[0]); + ui64 rhs0 = __builtin_bswap64(rhs.Parts64[0]); + if (lhs0 < rhs0) { + return true; + } + if (lhs0 > rhs0) { + return false; + } + ui64 lhs1 = __builtin_bswap64(lhs.Parts64[1]); + ui64 rhs1 = __builtin_bswap64(rhs.Parts64[1]); + return lhs1 < rhs1; +#else + return memcmp(&lhs, &rhs, sizeof(TGuid)) < 0; +#endif +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + Y_FORCE_INLINE size_t THash<NYT::TGuid>::operator()(const NYT::TGuid& guid) const -{ - const size_t p = 1000000009; // prime number - return guid.Parts32[0] + - guid.Parts32[1] * p + - guid.Parts32[2] * p * p + - guid.Parts32[3] * p * p * p; -} +{ + const size_t p = 1000000009; // prime number + return guid.Parts32[0] + + guid.Parts32[1] * p + + guid.Parts32[2] * p * p + + guid.Parts32[3] * p * p * p; +} diff --git a/library/cpp/yt/misc/guid.cpp b/library/cpp/yt/misc/guid.cpp index 882787d7a2..f08ca7c99f 100644 --- a/library/cpp/yt/misc/guid.cpp +++ b/library/cpp/yt/misc/guid.cpp @@ -1,13 +1,13 @@ -#include "guid.h" - -#include <util/random/random.h> - -#include <util/string/printf.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - +#include "guid.h" + +#include <util/random/random.h> + +#include <util/string/printf.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + namespace { const ui8 HexDigits1[16] = { @@ -37,23 +37,23 @@ const ui16 HexDigits2[256] = { //////////////////////////////////////////////////////////////////////////////// -TGuid TGuid::Create() -{ - return TGuid(RandomNumber<ui64>(), RandomNumber<ui64>()); -} - -TGuid TGuid::FromString(TStringBuf str) -{ - TGuid guid; - if (!FromString(str, &guid)) { - throw TSimpleException(Sprintf("Error parsing GUID \"%s\"", - TString(str).c_str())); - } - return guid; -} - -bool TGuid::FromString(TStringBuf str, TGuid* result) -{ +TGuid TGuid::Create() +{ + return TGuid(RandomNumber<ui64>(), RandomNumber<ui64>()); +} + +TGuid TGuid::FromString(TStringBuf str) +{ + TGuid guid; + if (!FromString(str, &guid)) { + throw TSimpleException(Sprintf("Error parsing GUID \"%s\"", + TString(str).c_str())); + } + return guid; +} + +bool TGuid::FromString(TStringBuf str, TGuid* result) +{ size_t partId = 3; ui64 partValue = 0; bool isEmptyPart = true; @@ -93,18 +93,18 @@ bool TGuid::FromString(TStringBuf str, TGuid* result) } if (partId != 0 || isEmptyPart) { // x-y or x-y-z- - return false; - } + return false; + } result->Parts32[partId] = static_cast<ui32>(partValue); - return true; -} - + return true; +} + TGuid TGuid::FromStringHex32(TStringBuf str) { TGuid guid; if (!FromStringHex32(str, &guid)) { - throw TSimpleException(Sprintf("Error parsing Hex32 GUID \"%s\"", - TString(str).c_str())); + throw TSimpleException(Sprintf("Error parsing Hex32 GUID \"%s\"", + TString(str).c_str())); } return guid; } @@ -131,7 +131,7 @@ bool TGuid::FromStringHex32(TStringBuf str, TGuid* result) } return digit; }; - + for (size_t j = 0; j < 16; ++j) { result->ReversedParts8[15 - j] = parseChar() * 16 + parseChar(); } @@ -198,6 +198,6 @@ char* WriteGuidToBuffer(char* ptr, TGuid value) return ptr; } -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/guid.h b/library/cpp/yt/misc/guid.h index ec4ba3526a..1517c006ed 100644 --- a/library/cpp/yt/misc/guid.h +++ b/library/cpp/yt/misc/guid.h @@ -1,14 +1,14 @@ -#pragma once - +#pragma once + #include <util/generic/string.h> -#include <util/generic/typetraits.h> - -#include <library/cpp/yt/exception/exception.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - +#include <util/generic/typetraits.h> + +#include <library/cpp/yt/exception/exception.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + //! TGuid is 16-byte value that might be interpreted as four little-endian 32-bit integers or two 64-bit little-endian integers. /*! * *-------------------------*-------------------------* @@ -35,75 +35,75 @@ namespace NYT { * 34 is byte [9] * ff is byte [15] */ -struct TGuid -{ - union - { - ui32 Parts32[4]; - ui64 Parts64[2]; +struct TGuid +{ + union + { + ui32 Parts32[4]; + ui64 Parts64[2]; ui8 ReversedParts8[16]; - }; - - //! Constructs a null (zero) guid. - constexpr TGuid(); - - //! Constructs guid from parts. - constexpr TGuid(ui32 part0, ui32 part1, ui32 part2, ui32 part3); - - //! Constructs guid from parts. - constexpr TGuid(ui64 part0, ui64 part1); - - //! Copies an existing guid. - TGuid(const TGuid& other) = default; - - //! Checks if TGuid is zero. - bool IsEmpty() const; - + }; + + //! Constructs a null (zero) guid. + constexpr TGuid(); + + //! Constructs guid from parts. + constexpr TGuid(ui32 part0, ui32 part1, ui32 part2, ui32 part3); + + //! Constructs guid from parts. + constexpr TGuid(ui64 part0, ui64 part1); + + //! Copies an existing guid. + TGuid(const TGuid& other) = default; + + //! Checks if TGuid is zero. + bool IsEmpty() const; + //! Converts TGuid to bool, returns |false| iff TGuid is zero. explicit operator bool() const; - //! Creates a new instance. - static TGuid Create(); - - //! Parses guid from TStringBuf, throws an exception if something went wrong. - static TGuid FromString(TStringBuf str); - - //! Parses guid from TStringBuf, returns |true| if everything was ok. - static bool FromString(TStringBuf str, TGuid* guid); + //! Creates a new instance. + static TGuid Create(); + + //! Parses guid from TStringBuf, throws an exception if something went wrong. + static TGuid FromString(TStringBuf str); + + //! Parses guid from TStringBuf, returns |true| if everything was ok. + static bool FromString(TStringBuf str, TGuid* guid); //! Same as FromString, but expects exactly 32 hex digits without dashes. static TGuid FromStringHex32(TStringBuf str); //! Same as TryFromString, but expects exactly 32 hex digits without dashes. static bool FromStringHex32(TStringBuf str, TGuid* guid); -}; - +}; + bool operator == (TGuid lhs, TGuid rhs); bool operator != (TGuid lhs, TGuid rhs); bool operator < (TGuid lhs, TGuid rhs); - -//////////////////////////////////////////////////////////////////////////////// - -constexpr int MaxGuidStringSize = 4 * 8 + 3; + +//////////////////////////////////////////////////////////////////////////////// + +constexpr int MaxGuidStringSize = 4 * 8 + 3; char* WriteGuidToBuffer(char* ptr, TGuid value); //////////////////////////////////////////////////////////////////////////////// -} // namespace NYT - -//////////////////////////////////////////////////////////////////////////////// - -Y_DECLARE_PODTYPE(NYT::TGuid); - -//! A hasher for TGuid. -template <> +} // namespace NYT + +//////////////////////////////////////////////////////////////////////////////// + +Y_DECLARE_PODTYPE(NYT::TGuid); + +//! A hasher for TGuid. +template <> struct THash<NYT::TGuid> -{ - size_t operator()(const NYT::TGuid& guid) const; -}; - -//////////////////////////////////////////////////////////////////////////////// - -#define GUID_INL_H_ -#include "guid-inl.h" -#undef GUID_INL_H_ +{ + size_t operator()(const NYT::TGuid& guid) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#define GUID_INL_H_ +#include "guid-inl.h" +#undef GUID_INL_H_ diff --git a/library/cpp/yt/misc/hash-inl.h b/library/cpp/yt/misc/hash-inl.h index 46eeefe620..0b8873c2d3 100644 --- a/library/cpp/yt/misc/hash-inl.h +++ b/library/cpp/yt/misc/hash-inl.h @@ -1,47 +1,47 @@ -#ifndef HASH_INL_H_ -#error "Direct inclusion of this file is not allowed, include hash.h" +#ifndef HASH_INL_H_ +#error "Direct inclusion of this file is not allowed, include hash.h" // For the sake of sane code completion. #include "hash.h" -#endif - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -inline void HashCombine(size_t& h, size_t k) -{ - static_assert(sizeof(size_t) == 8, "size_t must be 64 bit."); - - const size_t m = 0xc6a4a7935bd1e995ULL; - const int r = 47; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; -} - -template <class T> -void HashCombine(size_t& h, const T& k) -{ - HashCombine(h, THash<T>()(k)); -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class TElement, class TUnderlying> -TRandomizedHash<TElement, TUnderlying>::TRandomizedHash() - : Seed_(RandomNumber<size_t>()) -{ } - -template <class TElement, class TUnderlying> -size_t TRandomizedHash<TElement, TUnderlying>::operator ()(const TElement& element) const -{ - return Underlying_(element) + Seed_; -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#endif + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +inline void HashCombine(size_t& h, size_t k) +{ + static_assert(sizeof(size_t) == 8, "size_t must be 64 bit."); + + const size_t m = 0xc6a4a7935bd1e995ULL; + const int r = 47; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; +} + +template <class T> +void HashCombine(size_t& h, const T& k) +{ + HashCombine(h, THash<T>()(k)); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class TElement, class TUnderlying> +TRandomizedHash<TElement, TUnderlying>::TRandomizedHash() + : Seed_(RandomNumber<size_t>()) +{ } + +template <class TElement, class TUnderlying> +size_t TRandomizedHash<TElement, TUnderlying>::operator ()(const TElement& element) const +{ + return Underlying_(element) + Seed_; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/hash.h b/library/cpp/yt/misc/hash.h index 2fecf89506..ec03732999 100644 --- a/library/cpp/yt/misc/hash.h +++ b/library/cpp/yt/misc/hash.h @@ -1,31 +1,31 @@ -#pragma once - -#include <util/generic/hash.h> - +#pragma once + +#include <util/generic/hash.h> + #include <util/random/random.h> -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -//! Updates #h with #k. -//! Cf. |boost::hash_combine|. -void HashCombine(size_t& h, size_t k); - -//! Updates #h with the hash of #k. -//! Cf. |boost::hash_combine|. -template <class T> -void HashCombine(size_t& h, const T& k); - -//////////////////////////////////////////////////////////////////////////////// +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +//! Updates #h with #k. +//! Cf. |boost::hash_combine|. +void HashCombine(size_t& h, size_t k); + +//! Updates #h with the hash of #k. +//! Cf. |boost::hash_combine|. +template <class T> +void HashCombine(size_t& h, const T& k); + +//////////////////////////////////////////////////////////////////////////////// //! Provides a hasher that randomizes the results of another one. template <class TElement, class TUnderlying = ::THash<TElement>> class TRandomizedHash { public: - TRandomizedHash(); - size_t operator () (const TElement& element) const; + TRandomizedHash(); + size_t operator () (const TElement& element) const; private: size_t Seed_; @@ -33,10 +33,10 @@ private: }; -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + } // namespace NYT -#define HASH_INL_H_ -#include "hash-inl.h" -#undef HASH_INL_H_ +#define HASH_INL_H_ +#include "hash-inl.h" +#undef HASH_INL_H_ diff --git a/library/cpp/yt/misc/port.h b/library/cpp/yt/misc/port.h index b24ac50995..894a485b5a 100644 --- a/library/cpp/yt/misc/port.h +++ b/library/cpp/yt/misc/port.h @@ -2,69 +2,69 @@ #include <util/system/platform.h> -// Check platform bitness. +// Check platform bitness. #if !defined(_64_) - #error YT requires 64-bit platform -#endif - -// This define enables tracking of reference-counted objects to provide -// various insightful information on memory usage and object creation patterns. -#define YT_ENABLE_REF_COUNTED_TRACKING - + #error YT requires 64-bit platform +#endif + +// This define enables tracking of reference-counted objects to provide +// various insightful information on memory usage and object creation patterns. +#define YT_ENABLE_REF_COUNTED_TRACKING + // This define enables logging with TRACE level. You can still disable trace logging // for particular TU by discarding this macro identifier. #define YT_ENABLE_TRACE_LOGGING -#ifndef NDEBUG - // This define enables thread affinity check -- a user-defined verification ensuring - // that some functions are called from particular threads. - #define YT_ENABLE_THREAD_AFFINITY_CHECK - - // This define enables tracking of BIND callbacks location. - #define YT_ENABLE_BIND_LOCATION_TRACKING - - // This define enables checking that all required protobuf fields are present - // during serialization. - #define YT_VALIDATE_REQUIRED_PROTO_FIELDS - - // Detects deadlocks caused by recursive acquisitions of (non-recursive) spin locks. - #define YT_ENABLE_SPIN_LOCK_OWNERSHIP_TRACKING -#endif - -// Configure SSE usage. +#ifndef NDEBUG + // This define enables thread affinity check -- a user-defined verification ensuring + // that some functions are called from particular threads. + #define YT_ENABLE_THREAD_AFFINITY_CHECK + + // This define enables tracking of BIND callbacks location. + #define YT_ENABLE_BIND_LOCATION_TRACKING + + // This define enables checking that all required protobuf fields are present + // during serialization. + #define YT_VALIDATE_REQUIRED_PROTO_FIELDS + + // Detects deadlocks caused by recursive acquisitions of (non-recursive) spin locks. + #define YT_ENABLE_SPIN_LOCK_OWNERSHIP_TRACKING +#endif + +// Configure SSE usage. #ifdef SSE42_ENABLED - #define YT_USE_SSE42 -#endif - -#ifdef _win_ - // Someone above has defined this by including one of Windows headers. - #undef GetMessage - #undef Yield - - // For protobuf-generated files: - // C4125: decimal digit terminates octal escape sequence - #pragma warning (disable: 4125) - // C4505: unreferenced local function has been removed - #pragma warning (disable : 4505) - // C4121: alignment of a member was sensitive to packing - #pragma warning (disable: 4121) - // C4503: decorated name length exceeded, name was truncated - #pragma warning (disable : 4503) - // C4714: function marked as __forceinline not inlined - #pragma warning (disable: 4714) - // C4250: inherits via dominance - #pragma warning (disable: 4250) -#endif - -#if defined(__GNUC__) || defined(__clang__) - #define PER_THREAD __thread - #define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) + #define YT_USE_SSE42 +#endif + +#ifdef _win_ + // Someone above has defined this by including one of Windows headers. + #undef GetMessage + #undef Yield + + // For protobuf-generated files: + // C4125: decimal digit terminates octal escape sequence + #pragma warning (disable: 4125) + // C4505: unreferenced local function has been removed + #pragma warning (disable : 4505) + // C4121: alignment of a member was sensitive to packing + #pragma warning (disable: 4121) + // C4503: decorated name length exceeded, name was truncated + #pragma warning (disable : 4503) + // C4714: function marked as __forceinline not inlined + #pragma warning (disable: 4714) + // C4250: inherits via dominance + #pragma warning (disable: 4250) +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define PER_THREAD __thread + #define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) // Prevent GCC from throwing out functions in release builds. #define ATTRIBUTE_USED __attribute__((used)) -#elif defined(_MSC_VER) - #define PER_THREAD __declspec(thread) - #define ATTRIBUTE_NO_SANITIZE_ADDRESS +#elif defined(_MSC_VER) + #define PER_THREAD __declspec(thread) + #define ATTRIBUTE_NO_SANITIZE_ADDRESS #define ATTRIBUTE_USED -#else - #error Unsupported compiler -#endif +#else + #error Unsupported compiler +#endif diff --git a/library/cpp/yt/misc/preprocessor-gen.h b/library/cpp/yt/misc/preprocessor-gen.h index b809941bcd..912216330a 100644 --- a/library/cpp/yt/misc/preprocessor-gen.h +++ b/library/cpp/yt/misc/preprocessor-gen.h @@ -1,125 +1,125 @@ -#pragma once - -// WARNING: This file was auto-generated. -// Please, consider incorporating any changes into the generator. - -// Generated on Wed Dec 9 14:20:20 2015. - - -/*! - \internal -*/ - -#ifndef PREPROCESSOR_GEN_H_ -#error "Direct inclusion of this file is not allowed, include preprocessor.h" -// For the sake of sane code completion. -#include "preprocessor.h" -#endif -#undef PREPROCESSOR_GEN_H_ - -//////////////////////////////////////////////////////////////////////////////// -#define PP_COUNT_IMPL(...) PP_CONCAT(PP_COUNT_CONST_, \ - PP_COUNT_IMPL_0 __VA_ARGS__) -#define PP_COUNT_CONST_PP_COUNT_IMPL_0 0 -#define PP_COUNT_CONST_PP_COUNT_IMPL_1 1 -#define PP_COUNT_CONST_PP_COUNT_IMPL_2 2 -#define PP_COUNT_CONST_PP_COUNT_IMPL_3 3 -#define PP_COUNT_CONST_PP_COUNT_IMPL_4 4 -#define PP_COUNT_CONST_PP_COUNT_IMPL_5 5 -#define PP_COUNT_CONST_PP_COUNT_IMPL_6 6 -#define PP_COUNT_CONST_PP_COUNT_IMPL_7 7 -#define PP_COUNT_CONST_PP_COUNT_IMPL_8 8 -#define PP_COUNT_CONST_PP_COUNT_IMPL_9 9 -#define PP_COUNT_CONST_PP_COUNT_IMPL_10 10 -#define PP_COUNT_CONST_PP_COUNT_IMPL_11 11 -#define PP_COUNT_CONST_PP_COUNT_IMPL_12 12 -#define PP_COUNT_CONST_PP_COUNT_IMPL_13 13 -#define PP_COUNT_CONST_PP_COUNT_IMPL_14 14 -#define PP_COUNT_CONST_PP_COUNT_IMPL_15 15 -#define PP_COUNT_CONST_PP_COUNT_IMPL_16 16 -#define PP_COUNT_CONST_PP_COUNT_IMPL_17 17 -#define PP_COUNT_CONST_PP_COUNT_IMPL_18 18 -#define PP_COUNT_CONST_PP_COUNT_IMPL_19 19 -#define PP_COUNT_CONST_PP_COUNT_IMPL_20 20 -#define PP_COUNT_CONST_PP_COUNT_IMPL_21 21 -#define PP_COUNT_CONST_PP_COUNT_IMPL_22 22 -#define PP_COUNT_CONST_PP_COUNT_IMPL_23 23 -#define PP_COUNT_CONST_PP_COUNT_IMPL_24 24 -#define PP_COUNT_CONST_PP_COUNT_IMPL_25 25 -#define PP_COUNT_CONST_PP_COUNT_IMPL_26 26 -#define PP_COUNT_CONST_PP_COUNT_IMPL_27 27 -#define PP_COUNT_CONST_PP_COUNT_IMPL_28 28 -#define PP_COUNT_CONST_PP_COUNT_IMPL_29 29 -#define PP_COUNT_CONST_PP_COUNT_IMPL_30 30 -#define PP_COUNT_CONST_PP_COUNT_IMPL_31 31 -#define PP_COUNT_CONST_PP_COUNT_IMPL_32 32 -#define PP_COUNT_CONST_PP_COUNT_IMPL_33 33 -#define PP_COUNT_CONST_PP_COUNT_IMPL_34 34 -#define PP_COUNT_CONST_PP_COUNT_IMPL_35 35 -#define PP_COUNT_CONST_PP_COUNT_IMPL_36 36 -#define PP_COUNT_CONST_PP_COUNT_IMPL_37 37 -#define PP_COUNT_CONST_PP_COUNT_IMPL_38 38 -#define PP_COUNT_CONST_PP_COUNT_IMPL_39 39 -#define PP_COUNT_CONST_PP_COUNT_IMPL_40 40 -#define PP_COUNT_CONST_PP_COUNT_IMPL_41 41 -#define PP_COUNT_CONST_PP_COUNT_IMPL_42 42 -#define PP_COUNT_CONST_PP_COUNT_IMPL_43 43 -#define PP_COUNT_CONST_PP_COUNT_IMPL_44 44 -#define PP_COUNT_CONST_PP_COUNT_IMPL_45 45 -#define PP_COUNT_CONST_PP_COUNT_IMPL_46 46 -#define PP_COUNT_CONST_PP_COUNT_IMPL_47 47 -#define PP_COUNT_CONST_PP_COUNT_IMPL_48 48 -#define PP_COUNT_CONST_PP_COUNT_IMPL_49 49 -#define PP_COUNT_CONST_PP_COUNT_IMPL_50 50 -#define PP_COUNT_CONST_PP_COUNT_IMPL_51 51 -#define PP_COUNT_CONST_PP_COUNT_IMPL_52 52 -#define PP_COUNT_CONST_PP_COUNT_IMPL_53 53 -#define PP_COUNT_CONST_PP_COUNT_IMPL_54 54 -#define PP_COUNT_CONST_PP_COUNT_IMPL_55 55 -#define PP_COUNT_CONST_PP_COUNT_IMPL_56 56 -#define PP_COUNT_CONST_PP_COUNT_IMPL_57 57 -#define PP_COUNT_CONST_PP_COUNT_IMPL_58 58 -#define PP_COUNT_CONST_PP_COUNT_IMPL_59 59 -#define PP_COUNT_CONST_PP_COUNT_IMPL_60 60 -#define PP_COUNT_CONST_PP_COUNT_IMPL_61 61 -#define PP_COUNT_CONST_PP_COUNT_IMPL_62 62 -#define PP_COUNT_CONST_PP_COUNT_IMPL_63 63 -#define PP_COUNT_CONST_PP_COUNT_IMPL_64 64 -#define PP_COUNT_CONST_PP_COUNT_IMPL_65 65 -#define PP_COUNT_CONST_PP_COUNT_IMPL_66 66 -#define PP_COUNT_CONST_PP_COUNT_IMPL_67 67 -#define PP_COUNT_CONST_PP_COUNT_IMPL_68 68 -#define PP_COUNT_CONST_PP_COUNT_IMPL_69 69 -#define PP_COUNT_CONST_PP_COUNT_IMPL_70 70 -#define PP_COUNT_CONST_PP_COUNT_IMPL_71 71 -#define PP_COUNT_CONST_PP_COUNT_IMPL_72 72 -#define PP_COUNT_CONST_PP_COUNT_IMPL_73 73 -#define PP_COUNT_CONST_PP_COUNT_IMPL_74 74 -#define PP_COUNT_CONST_PP_COUNT_IMPL_75 75 -#define PP_COUNT_CONST_PP_COUNT_IMPL_76 76 -#define PP_COUNT_CONST_PP_COUNT_IMPL_77 77 -#define PP_COUNT_CONST_PP_COUNT_IMPL_78 78 -#define PP_COUNT_CONST_PP_COUNT_IMPL_79 79 -#define PP_COUNT_CONST_PP_COUNT_IMPL_80 80 -#define PP_COUNT_CONST_PP_COUNT_IMPL_81 81 -#define PP_COUNT_CONST_PP_COUNT_IMPL_82 82 -#define PP_COUNT_CONST_PP_COUNT_IMPL_83 83 -#define PP_COUNT_CONST_PP_COUNT_IMPL_84 84 -#define PP_COUNT_CONST_PP_COUNT_IMPL_85 85 -#define PP_COUNT_CONST_PP_COUNT_IMPL_86 86 -#define PP_COUNT_CONST_PP_COUNT_IMPL_87 87 -#define PP_COUNT_CONST_PP_COUNT_IMPL_88 88 -#define PP_COUNT_CONST_PP_COUNT_IMPL_89 89 -#define PP_COUNT_CONST_PP_COUNT_IMPL_90 90 -#define PP_COUNT_CONST_PP_COUNT_IMPL_91 91 -#define PP_COUNT_CONST_PP_COUNT_IMPL_92 92 -#define PP_COUNT_CONST_PP_COUNT_IMPL_93 93 -#define PP_COUNT_CONST_PP_COUNT_IMPL_94 94 -#define PP_COUNT_CONST_PP_COUNT_IMPL_95 95 -#define PP_COUNT_CONST_PP_COUNT_IMPL_96 96 -#define PP_COUNT_CONST_PP_COUNT_IMPL_97 97 -#define PP_COUNT_CONST_PP_COUNT_IMPL_98 98 -#define PP_COUNT_CONST_PP_COUNT_IMPL_99 99 +#pragma once + +// WARNING: This file was auto-generated. +// Please, consider incorporating any changes into the generator. + +// Generated on Wed Dec 9 14:20:20 2015. + + +/*! + \internal +*/ + +#ifndef PREPROCESSOR_GEN_H_ +#error "Direct inclusion of this file is not allowed, include preprocessor.h" +// For the sake of sane code completion. +#include "preprocessor.h" +#endif +#undef PREPROCESSOR_GEN_H_ + +//////////////////////////////////////////////////////////////////////////////// +#define PP_COUNT_IMPL(...) PP_CONCAT(PP_COUNT_CONST_, \ + PP_COUNT_IMPL_0 __VA_ARGS__) +#define PP_COUNT_CONST_PP_COUNT_IMPL_0 0 +#define PP_COUNT_CONST_PP_COUNT_IMPL_1 1 +#define PP_COUNT_CONST_PP_COUNT_IMPL_2 2 +#define PP_COUNT_CONST_PP_COUNT_IMPL_3 3 +#define PP_COUNT_CONST_PP_COUNT_IMPL_4 4 +#define PP_COUNT_CONST_PP_COUNT_IMPL_5 5 +#define PP_COUNT_CONST_PP_COUNT_IMPL_6 6 +#define PP_COUNT_CONST_PP_COUNT_IMPL_7 7 +#define PP_COUNT_CONST_PP_COUNT_IMPL_8 8 +#define PP_COUNT_CONST_PP_COUNT_IMPL_9 9 +#define PP_COUNT_CONST_PP_COUNT_IMPL_10 10 +#define PP_COUNT_CONST_PP_COUNT_IMPL_11 11 +#define PP_COUNT_CONST_PP_COUNT_IMPL_12 12 +#define PP_COUNT_CONST_PP_COUNT_IMPL_13 13 +#define PP_COUNT_CONST_PP_COUNT_IMPL_14 14 +#define PP_COUNT_CONST_PP_COUNT_IMPL_15 15 +#define PP_COUNT_CONST_PP_COUNT_IMPL_16 16 +#define PP_COUNT_CONST_PP_COUNT_IMPL_17 17 +#define PP_COUNT_CONST_PP_COUNT_IMPL_18 18 +#define PP_COUNT_CONST_PP_COUNT_IMPL_19 19 +#define PP_COUNT_CONST_PP_COUNT_IMPL_20 20 +#define PP_COUNT_CONST_PP_COUNT_IMPL_21 21 +#define PP_COUNT_CONST_PP_COUNT_IMPL_22 22 +#define PP_COUNT_CONST_PP_COUNT_IMPL_23 23 +#define PP_COUNT_CONST_PP_COUNT_IMPL_24 24 +#define PP_COUNT_CONST_PP_COUNT_IMPL_25 25 +#define PP_COUNT_CONST_PP_COUNT_IMPL_26 26 +#define PP_COUNT_CONST_PP_COUNT_IMPL_27 27 +#define PP_COUNT_CONST_PP_COUNT_IMPL_28 28 +#define PP_COUNT_CONST_PP_COUNT_IMPL_29 29 +#define PP_COUNT_CONST_PP_COUNT_IMPL_30 30 +#define PP_COUNT_CONST_PP_COUNT_IMPL_31 31 +#define PP_COUNT_CONST_PP_COUNT_IMPL_32 32 +#define PP_COUNT_CONST_PP_COUNT_IMPL_33 33 +#define PP_COUNT_CONST_PP_COUNT_IMPL_34 34 +#define PP_COUNT_CONST_PP_COUNT_IMPL_35 35 +#define PP_COUNT_CONST_PP_COUNT_IMPL_36 36 +#define PP_COUNT_CONST_PP_COUNT_IMPL_37 37 +#define PP_COUNT_CONST_PP_COUNT_IMPL_38 38 +#define PP_COUNT_CONST_PP_COUNT_IMPL_39 39 +#define PP_COUNT_CONST_PP_COUNT_IMPL_40 40 +#define PP_COUNT_CONST_PP_COUNT_IMPL_41 41 +#define PP_COUNT_CONST_PP_COUNT_IMPL_42 42 +#define PP_COUNT_CONST_PP_COUNT_IMPL_43 43 +#define PP_COUNT_CONST_PP_COUNT_IMPL_44 44 +#define PP_COUNT_CONST_PP_COUNT_IMPL_45 45 +#define PP_COUNT_CONST_PP_COUNT_IMPL_46 46 +#define PP_COUNT_CONST_PP_COUNT_IMPL_47 47 +#define PP_COUNT_CONST_PP_COUNT_IMPL_48 48 +#define PP_COUNT_CONST_PP_COUNT_IMPL_49 49 +#define PP_COUNT_CONST_PP_COUNT_IMPL_50 50 +#define PP_COUNT_CONST_PP_COUNT_IMPL_51 51 +#define PP_COUNT_CONST_PP_COUNT_IMPL_52 52 +#define PP_COUNT_CONST_PP_COUNT_IMPL_53 53 +#define PP_COUNT_CONST_PP_COUNT_IMPL_54 54 +#define PP_COUNT_CONST_PP_COUNT_IMPL_55 55 +#define PP_COUNT_CONST_PP_COUNT_IMPL_56 56 +#define PP_COUNT_CONST_PP_COUNT_IMPL_57 57 +#define PP_COUNT_CONST_PP_COUNT_IMPL_58 58 +#define PP_COUNT_CONST_PP_COUNT_IMPL_59 59 +#define PP_COUNT_CONST_PP_COUNT_IMPL_60 60 +#define PP_COUNT_CONST_PP_COUNT_IMPL_61 61 +#define PP_COUNT_CONST_PP_COUNT_IMPL_62 62 +#define PP_COUNT_CONST_PP_COUNT_IMPL_63 63 +#define PP_COUNT_CONST_PP_COUNT_IMPL_64 64 +#define PP_COUNT_CONST_PP_COUNT_IMPL_65 65 +#define PP_COUNT_CONST_PP_COUNT_IMPL_66 66 +#define PP_COUNT_CONST_PP_COUNT_IMPL_67 67 +#define PP_COUNT_CONST_PP_COUNT_IMPL_68 68 +#define PP_COUNT_CONST_PP_COUNT_IMPL_69 69 +#define PP_COUNT_CONST_PP_COUNT_IMPL_70 70 +#define PP_COUNT_CONST_PP_COUNT_IMPL_71 71 +#define PP_COUNT_CONST_PP_COUNT_IMPL_72 72 +#define PP_COUNT_CONST_PP_COUNT_IMPL_73 73 +#define PP_COUNT_CONST_PP_COUNT_IMPL_74 74 +#define PP_COUNT_CONST_PP_COUNT_IMPL_75 75 +#define PP_COUNT_CONST_PP_COUNT_IMPL_76 76 +#define PP_COUNT_CONST_PP_COUNT_IMPL_77 77 +#define PP_COUNT_CONST_PP_COUNT_IMPL_78 78 +#define PP_COUNT_CONST_PP_COUNT_IMPL_79 79 +#define PP_COUNT_CONST_PP_COUNT_IMPL_80 80 +#define PP_COUNT_CONST_PP_COUNT_IMPL_81 81 +#define PP_COUNT_CONST_PP_COUNT_IMPL_82 82 +#define PP_COUNT_CONST_PP_COUNT_IMPL_83 83 +#define PP_COUNT_CONST_PP_COUNT_IMPL_84 84 +#define PP_COUNT_CONST_PP_COUNT_IMPL_85 85 +#define PP_COUNT_CONST_PP_COUNT_IMPL_86 86 +#define PP_COUNT_CONST_PP_COUNT_IMPL_87 87 +#define PP_COUNT_CONST_PP_COUNT_IMPL_88 88 +#define PP_COUNT_CONST_PP_COUNT_IMPL_89 89 +#define PP_COUNT_CONST_PP_COUNT_IMPL_90 90 +#define PP_COUNT_CONST_PP_COUNT_IMPL_91 91 +#define PP_COUNT_CONST_PP_COUNT_IMPL_92 92 +#define PP_COUNT_CONST_PP_COUNT_IMPL_93 93 +#define PP_COUNT_CONST_PP_COUNT_IMPL_94 94 +#define PP_COUNT_CONST_PP_COUNT_IMPL_95 95 +#define PP_COUNT_CONST_PP_COUNT_IMPL_96 96 +#define PP_COUNT_CONST_PP_COUNT_IMPL_97 97 +#define PP_COUNT_CONST_PP_COUNT_IMPL_98 98 +#define PP_COUNT_CONST_PP_COUNT_IMPL_99 99 #define PP_COUNT_CONST_PP_COUNT_IMPL_100 100 #define PP_COUNT_CONST_PP_COUNT_IMPL_101 101 #define PP_COUNT_CONST_PP_COUNT_IMPL_102 102 @@ -220,106 +220,106 @@ #define PP_COUNT_CONST_PP_COUNT_IMPL_197 197 #define PP_COUNT_CONST_PP_COUNT_IMPL_198 198 #define PP_COUNT_CONST_PP_COUNT_IMPL_199 199 -#define PP_COUNT_IMPL_0(_) PP_COUNT_IMPL_1 -#define PP_COUNT_IMPL_1(_) PP_COUNT_IMPL_2 -#define PP_COUNT_IMPL_2(_) PP_COUNT_IMPL_3 -#define PP_COUNT_IMPL_3(_) PP_COUNT_IMPL_4 -#define PP_COUNT_IMPL_4(_) PP_COUNT_IMPL_5 -#define PP_COUNT_IMPL_5(_) PP_COUNT_IMPL_6 -#define PP_COUNT_IMPL_6(_) PP_COUNT_IMPL_7 -#define PP_COUNT_IMPL_7(_) PP_COUNT_IMPL_8 -#define PP_COUNT_IMPL_8(_) PP_COUNT_IMPL_9 -#define PP_COUNT_IMPL_9(_) PP_COUNT_IMPL_10 -#define PP_COUNT_IMPL_10(_) PP_COUNT_IMPL_11 -#define PP_COUNT_IMPL_11(_) PP_COUNT_IMPL_12 -#define PP_COUNT_IMPL_12(_) PP_COUNT_IMPL_13 -#define PP_COUNT_IMPL_13(_) PP_COUNT_IMPL_14 -#define PP_COUNT_IMPL_14(_) PP_COUNT_IMPL_15 -#define PP_COUNT_IMPL_15(_) PP_COUNT_IMPL_16 -#define PP_COUNT_IMPL_16(_) PP_COUNT_IMPL_17 -#define PP_COUNT_IMPL_17(_) PP_COUNT_IMPL_18 -#define PP_COUNT_IMPL_18(_) PP_COUNT_IMPL_19 -#define PP_COUNT_IMPL_19(_) PP_COUNT_IMPL_20 -#define PP_COUNT_IMPL_20(_) PP_COUNT_IMPL_21 -#define PP_COUNT_IMPL_21(_) PP_COUNT_IMPL_22 -#define PP_COUNT_IMPL_22(_) PP_COUNT_IMPL_23 -#define PP_COUNT_IMPL_23(_) PP_COUNT_IMPL_24 -#define PP_COUNT_IMPL_24(_) PP_COUNT_IMPL_25 -#define PP_COUNT_IMPL_25(_) PP_COUNT_IMPL_26 -#define PP_COUNT_IMPL_26(_) PP_COUNT_IMPL_27 -#define PP_COUNT_IMPL_27(_) PP_COUNT_IMPL_28 -#define PP_COUNT_IMPL_28(_) PP_COUNT_IMPL_29 -#define PP_COUNT_IMPL_29(_) PP_COUNT_IMPL_30 -#define PP_COUNT_IMPL_30(_) PP_COUNT_IMPL_31 -#define PP_COUNT_IMPL_31(_) PP_COUNT_IMPL_32 -#define PP_COUNT_IMPL_32(_) PP_COUNT_IMPL_33 -#define PP_COUNT_IMPL_33(_) PP_COUNT_IMPL_34 -#define PP_COUNT_IMPL_34(_) PP_COUNT_IMPL_35 -#define PP_COUNT_IMPL_35(_) PP_COUNT_IMPL_36 -#define PP_COUNT_IMPL_36(_) PP_COUNT_IMPL_37 -#define PP_COUNT_IMPL_37(_) PP_COUNT_IMPL_38 -#define PP_COUNT_IMPL_38(_) PP_COUNT_IMPL_39 -#define PP_COUNT_IMPL_39(_) PP_COUNT_IMPL_40 -#define PP_COUNT_IMPL_40(_) PP_COUNT_IMPL_41 -#define PP_COUNT_IMPL_41(_) PP_COUNT_IMPL_42 -#define PP_COUNT_IMPL_42(_) PP_COUNT_IMPL_43 -#define PP_COUNT_IMPL_43(_) PP_COUNT_IMPL_44 -#define PP_COUNT_IMPL_44(_) PP_COUNT_IMPL_45 -#define PP_COUNT_IMPL_45(_) PP_COUNT_IMPL_46 -#define PP_COUNT_IMPL_46(_) PP_COUNT_IMPL_47 -#define PP_COUNT_IMPL_47(_) PP_COUNT_IMPL_48 -#define PP_COUNT_IMPL_48(_) PP_COUNT_IMPL_49 -#define PP_COUNT_IMPL_49(_) PP_COUNT_IMPL_50 -#define PP_COUNT_IMPL_50(_) PP_COUNT_IMPL_51 -#define PP_COUNT_IMPL_51(_) PP_COUNT_IMPL_52 -#define PP_COUNT_IMPL_52(_) PP_COUNT_IMPL_53 -#define PP_COUNT_IMPL_53(_) PP_COUNT_IMPL_54 -#define PP_COUNT_IMPL_54(_) PP_COUNT_IMPL_55 -#define PP_COUNT_IMPL_55(_) PP_COUNT_IMPL_56 -#define PP_COUNT_IMPL_56(_) PP_COUNT_IMPL_57 -#define PP_COUNT_IMPL_57(_) PP_COUNT_IMPL_58 -#define PP_COUNT_IMPL_58(_) PP_COUNT_IMPL_59 -#define PP_COUNT_IMPL_59(_) PP_COUNT_IMPL_60 -#define PP_COUNT_IMPL_60(_) PP_COUNT_IMPL_61 -#define PP_COUNT_IMPL_61(_) PP_COUNT_IMPL_62 -#define PP_COUNT_IMPL_62(_) PP_COUNT_IMPL_63 -#define PP_COUNT_IMPL_63(_) PP_COUNT_IMPL_64 -#define PP_COUNT_IMPL_64(_) PP_COUNT_IMPL_65 -#define PP_COUNT_IMPL_65(_) PP_COUNT_IMPL_66 -#define PP_COUNT_IMPL_66(_) PP_COUNT_IMPL_67 -#define PP_COUNT_IMPL_67(_) PP_COUNT_IMPL_68 -#define PP_COUNT_IMPL_68(_) PP_COUNT_IMPL_69 -#define PP_COUNT_IMPL_69(_) PP_COUNT_IMPL_70 -#define PP_COUNT_IMPL_70(_) PP_COUNT_IMPL_71 -#define PP_COUNT_IMPL_71(_) PP_COUNT_IMPL_72 -#define PP_COUNT_IMPL_72(_) PP_COUNT_IMPL_73 -#define PP_COUNT_IMPL_73(_) PP_COUNT_IMPL_74 -#define PP_COUNT_IMPL_74(_) PP_COUNT_IMPL_75 -#define PP_COUNT_IMPL_75(_) PP_COUNT_IMPL_76 -#define PP_COUNT_IMPL_76(_) PP_COUNT_IMPL_77 -#define PP_COUNT_IMPL_77(_) PP_COUNT_IMPL_78 -#define PP_COUNT_IMPL_78(_) PP_COUNT_IMPL_79 -#define PP_COUNT_IMPL_79(_) PP_COUNT_IMPL_80 -#define PP_COUNT_IMPL_80(_) PP_COUNT_IMPL_81 -#define PP_COUNT_IMPL_81(_) PP_COUNT_IMPL_82 -#define PP_COUNT_IMPL_82(_) PP_COUNT_IMPL_83 -#define PP_COUNT_IMPL_83(_) PP_COUNT_IMPL_84 -#define PP_COUNT_IMPL_84(_) PP_COUNT_IMPL_85 -#define PP_COUNT_IMPL_85(_) PP_COUNT_IMPL_86 -#define PP_COUNT_IMPL_86(_) PP_COUNT_IMPL_87 -#define PP_COUNT_IMPL_87(_) PP_COUNT_IMPL_88 -#define PP_COUNT_IMPL_88(_) PP_COUNT_IMPL_89 -#define PP_COUNT_IMPL_89(_) PP_COUNT_IMPL_90 -#define PP_COUNT_IMPL_90(_) PP_COUNT_IMPL_91 -#define PP_COUNT_IMPL_91(_) PP_COUNT_IMPL_92 -#define PP_COUNT_IMPL_92(_) PP_COUNT_IMPL_93 -#define PP_COUNT_IMPL_93(_) PP_COUNT_IMPL_94 -#define PP_COUNT_IMPL_94(_) PP_COUNT_IMPL_95 -#define PP_COUNT_IMPL_95(_) PP_COUNT_IMPL_96 -#define PP_COUNT_IMPL_96(_) PP_COUNT_IMPL_97 -#define PP_COUNT_IMPL_97(_) PP_COUNT_IMPL_98 -#define PP_COUNT_IMPL_98(_) PP_COUNT_IMPL_99 -#define PP_COUNT_IMPL_99(_) PP_COUNT_IMPL_100 +#define PP_COUNT_IMPL_0(_) PP_COUNT_IMPL_1 +#define PP_COUNT_IMPL_1(_) PP_COUNT_IMPL_2 +#define PP_COUNT_IMPL_2(_) PP_COUNT_IMPL_3 +#define PP_COUNT_IMPL_3(_) PP_COUNT_IMPL_4 +#define PP_COUNT_IMPL_4(_) PP_COUNT_IMPL_5 +#define PP_COUNT_IMPL_5(_) PP_COUNT_IMPL_6 +#define PP_COUNT_IMPL_6(_) PP_COUNT_IMPL_7 +#define PP_COUNT_IMPL_7(_) PP_COUNT_IMPL_8 +#define PP_COUNT_IMPL_8(_) PP_COUNT_IMPL_9 +#define PP_COUNT_IMPL_9(_) PP_COUNT_IMPL_10 +#define PP_COUNT_IMPL_10(_) PP_COUNT_IMPL_11 +#define PP_COUNT_IMPL_11(_) PP_COUNT_IMPL_12 +#define PP_COUNT_IMPL_12(_) PP_COUNT_IMPL_13 +#define PP_COUNT_IMPL_13(_) PP_COUNT_IMPL_14 +#define PP_COUNT_IMPL_14(_) PP_COUNT_IMPL_15 +#define PP_COUNT_IMPL_15(_) PP_COUNT_IMPL_16 +#define PP_COUNT_IMPL_16(_) PP_COUNT_IMPL_17 +#define PP_COUNT_IMPL_17(_) PP_COUNT_IMPL_18 +#define PP_COUNT_IMPL_18(_) PP_COUNT_IMPL_19 +#define PP_COUNT_IMPL_19(_) PP_COUNT_IMPL_20 +#define PP_COUNT_IMPL_20(_) PP_COUNT_IMPL_21 +#define PP_COUNT_IMPL_21(_) PP_COUNT_IMPL_22 +#define PP_COUNT_IMPL_22(_) PP_COUNT_IMPL_23 +#define PP_COUNT_IMPL_23(_) PP_COUNT_IMPL_24 +#define PP_COUNT_IMPL_24(_) PP_COUNT_IMPL_25 +#define PP_COUNT_IMPL_25(_) PP_COUNT_IMPL_26 +#define PP_COUNT_IMPL_26(_) PP_COUNT_IMPL_27 +#define PP_COUNT_IMPL_27(_) PP_COUNT_IMPL_28 +#define PP_COUNT_IMPL_28(_) PP_COUNT_IMPL_29 +#define PP_COUNT_IMPL_29(_) PP_COUNT_IMPL_30 +#define PP_COUNT_IMPL_30(_) PP_COUNT_IMPL_31 +#define PP_COUNT_IMPL_31(_) PP_COUNT_IMPL_32 +#define PP_COUNT_IMPL_32(_) PP_COUNT_IMPL_33 +#define PP_COUNT_IMPL_33(_) PP_COUNT_IMPL_34 +#define PP_COUNT_IMPL_34(_) PP_COUNT_IMPL_35 +#define PP_COUNT_IMPL_35(_) PP_COUNT_IMPL_36 +#define PP_COUNT_IMPL_36(_) PP_COUNT_IMPL_37 +#define PP_COUNT_IMPL_37(_) PP_COUNT_IMPL_38 +#define PP_COUNT_IMPL_38(_) PP_COUNT_IMPL_39 +#define PP_COUNT_IMPL_39(_) PP_COUNT_IMPL_40 +#define PP_COUNT_IMPL_40(_) PP_COUNT_IMPL_41 +#define PP_COUNT_IMPL_41(_) PP_COUNT_IMPL_42 +#define PP_COUNT_IMPL_42(_) PP_COUNT_IMPL_43 +#define PP_COUNT_IMPL_43(_) PP_COUNT_IMPL_44 +#define PP_COUNT_IMPL_44(_) PP_COUNT_IMPL_45 +#define PP_COUNT_IMPL_45(_) PP_COUNT_IMPL_46 +#define PP_COUNT_IMPL_46(_) PP_COUNT_IMPL_47 +#define PP_COUNT_IMPL_47(_) PP_COUNT_IMPL_48 +#define PP_COUNT_IMPL_48(_) PP_COUNT_IMPL_49 +#define PP_COUNT_IMPL_49(_) PP_COUNT_IMPL_50 +#define PP_COUNT_IMPL_50(_) PP_COUNT_IMPL_51 +#define PP_COUNT_IMPL_51(_) PP_COUNT_IMPL_52 +#define PP_COUNT_IMPL_52(_) PP_COUNT_IMPL_53 +#define PP_COUNT_IMPL_53(_) PP_COUNT_IMPL_54 +#define PP_COUNT_IMPL_54(_) PP_COUNT_IMPL_55 +#define PP_COUNT_IMPL_55(_) PP_COUNT_IMPL_56 +#define PP_COUNT_IMPL_56(_) PP_COUNT_IMPL_57 +#define PP_COUNT_IMPL_57(_) PP_COUNT_IMPL_58 +#define PP_COUNT_IMPL_58(_) PP_COUNT_IMPL_59 +#define PP_COUNT_IMPL_59(_) PP_COUNT_IMPL_60 +#define PP_COUNT_IMPL_60(_) PP_COUNT_IMPL_61 +#define PP_COUNT_IMPL_61(_) PP_COUNT_IMPL_62 +#define PP_COUNT_IMPL_62(_) PP_COUNT_IMPL_63 +#define PP_COUNT_IMPL_63(_) PP_COUNT_IMPL_64 +#define PP_COUNT_IMPL_64(_) PP_COUNT_IMPL_65 +#define PP_COUNT_IMPL_65(_) PP_COUNT_IMPL_66 +#define PP_COUNT_IMPL_66(_) PP_COUNT_IMPL_67 +#define PP_COUNT_IMPL_67(_) PP_COUNT_IMPL_68 +#define PP_COUNT_IMPL_68(_) PP_COUNT_IMPL_69 +#define PP_COUNT_IMPL_69(_) PP_COUNT_IMPL_70 +#define PP_COUNT_IMPL_70(_) PP_COUNT_IMPL_71 +#define PP_COUNT_IMPL_71(_) PP_COUNT_IMPL_72 +#define PP_COUNT_IMPL_72(_) PP_COUNT_IMPL_73 +#define PP_COUNT_IMPL_73(_) PP_COUNT_IMPL_74 +#define PP_COUNT_IMPL_74(_) PP_COUNT_IMPL_75 +#define PP_COUNT_IMPL_75(_) PP_COUNT_IMPL_76 +#define PP_COUNT_IMPL_76(_) PP_COUNT_IMPL_77 +#define PP_COUNT_IMPL_77(_) PP_COUNT_IMPL_78 +#define PP_COUNT_IMPL_78(_) PP_COUNT_IMPL_79 +#define PP_COUNT_IMPL_79(_) PP_COUNT_IMPL_80 +#define PP_COUNT_IMPL_80(_) PP_COUNT_IMPL_81 +#define PP_COUNT_IMPL_81(_) PP_COUNT_IMPL_82 +#define PP_COUNT_IMPL_82(_) PP_COUNT_IMPL_83 +#define PP_COUNT_IMPL_83(_) PP_COUNT_IMPL_84 +#define PP_COUNT_IMPL_84(_) PP_COUNT_IMPL_85 +#define PP_COUNT_IMPL_85(_) PP_COUNT_IMPL_86 +#define PP_COUNT_IMPL_86(_) PP_COUNT_IMPL_87 +#define PP_COUNT_IMPL_87(_) PP_COUNT_IMPL_88 +#define PP_COUNT_IMPL_88(_) PP_COUNT_IMPL_89 +#define PP_COUNT_IMPL_89(_) PP_COUNT_IMPL_90 +#define PP_COUNT_IMPL_90(_) PP_COUNT_IMPL_91 +#define PP_COUNT_IMPL_91(_) PP_COUNT_IMPL_92 +#define PP_COUNT_IMPL_92(_) PP_COUNT_IMPL_93 +#define PP_COUNT_IMPL_93(_) PP_COUNT_IMPL_94 +#define PP_COUNT_IMPL_94(_) PP_COUNT_IMPL_95 +#define PP_COUNT_IMPL_95(_) PP_COUNT_IMPL_96 +#define PP_COUNT_IMPL_96(_) PP_COUNT_IMPL_97 +#define PP_COUNT_IMPL_97(_) PP_COUNT_IMPL_98 +#define PP_COUNT_IMPL_98(_) PP_COUNT_IMPL_99 +#define PP_COUNT_IMPL_99(_) PP_COUNT_IMPL_100 #define PP_COUNT_IMPL_100(_) PP_COUNT_IMPL_101 #define PP_COUNT_IMPL_101(_) PP_COUNT_IMPL_102 #define PP_COUNT_IMPL_102(_) PP_COUNT_IMPL_103 @@ -420,110 +420,110 @@ #define PP_COUNT_IMPL_197(_) PP_COUNT_IMPL_198 #define PP_COUNT_IMPL_198(_) PP_COUNT_IMPL_199 #define PP_COUNT_IMPL_199(_) PP_COUNT_IMPL_200 - -//////////////////////////////////////////////////////////////////////////////// -#define PP_KILL_IMPL(seq, index) PP_CONCAT(PP_KILL_IMPL_, index) seq -#define PP_KILL_IMPL_0 -#define PP_KILL_IMPL_1(_) PP_KILL_IMPL_0 -#define PP_KILL_IMPL_2(_) PP_KILL_IMPL_1 -#define PP_KILL_IMPL_3(_) PP_KILL_IMPL_2 -#define PP_KILL_IMPL_4(_) PP_KILL_IMPL_3 -#define PP_KILL_IMPL_5(_) PP_KILL_IMPL_4 -#define PP_KILL_IMPL_6(_) PP_KILL_IMPL_5 -#define PP_KILL_IMPL_7(_) PP_KILL_IMPL_6 -#define PP_KILL_IMPL_8(_) PP_KILL_IMPL_7 -#define PP_KILL_IMPL_9(_) PP_KILL_IMPL_8 -#define PP_KILL_IMPL_10(_) PP_KILL_IMPL_9 -#define PP_KILL_IMPL_11(_) PP_KILL_IMPL_10 -#define PP_KILL_IMPL_12(_) PP_KILL_IMPL_11 -#define PP_KILL_IMPL_13(_) PP_KILL_IMPL_12 -#define PP_KILL_IMPL_14(_) PP_KILL_IMPL_13 -#define PP_KILL_IMPL_15(_) PP_KILL_IMPL_14 -#define PP_KILL_IMPL_16(_) PP_KILL_IMPL_15 -#define PP_KILL_IMPL_17(_) PP_KILL_IMPL_16 -#define PP_KILL_IMPL_18(_) PP_KILL_IMPL_17 -#define PP_KILL_IMPL_19(_) PP_KILL_IMPL_18 -#define PP_KILL_IMPL_20(_) PP_KILL_IMPL_19 -#define PP_KILL_IMPL_21(_) PP_KILL_IMPL_20 -#define PP_KILL_IMPL_22(_) PP_KILL_IMPL_21 -#define PP_KILL_IMPL_23(_) PP_KILL_IMPL_22 -#define PP_KILL_IMPL_24(_) PP_KILL_IMPL_23 -#define PP_KILL_IMPL_25(_) PP_KILL_IMPL_24 -#define PP_KILL_IMPL_26(_) PP_KILL_IMPL_25 -#define PP_KILL_IMPL_27(_) PP_KILL_IMPL_26 -#define PP_KILL_IMPL_28(_) PP_KILL_IMPL_27 -#define PP_KILL_IMPL_29(_) PP_KILL_IMPL_28 -#define PP_KILL_IMPL_30(_) PP_KILL_IMPL_29 -#define PP_KILL_IMPL_31(_) PP_KILL_IMPL_30 -#define PP_KILL_IMPL_32(_) PP_KILL_IMPL_31 -#define PP_KILL_IMPL_33(_) PP_KILL_IMPL_32 -#define PP_KILL_IMPL_34(_) PP_KILL_IMPL_33 -#define PP_KILL_IMPL_35(_) PP_KILL_IMPL_34 -#define PP_KILL_IMPL_36(_) PP_KILL_IMPL_35 -#define PP_KILL_IMPL_37(_) PP_KILL_IMPL_36 -#define PP_KILL_IMPL_38(_) PP_KILL_IMPL_37 -#define PP_KILL_IMPL_39(_) PP_KILL_IMPL_38 -#define PP_KILL_IMPL_40(_) PP_KILL_IMPL_39 -#define PP_KILL_IMPL_41(_) PP_KILL_IMPL_40 -#define PP_KILL_IMPL_42(_) PP_KILL_IMPL_41 -#define PP_KILL_IMPL_43(_) PP_KILL_IMPL_42 -#define PP_KILL_IMPL_44(_) PP_KILL_IMPL_43 -#define PP_KILL_IMPL_45(_) PP_KILL_IMPL_44 -#define PP_KILL_IMPL_46(_) PP_KILL_IMPL_45 -#define PP_KILL_IMPL_47(_) PP_KILL_IMPL_46 -#define PP_KILL_IMPL_48(_) PP_KILL_IMPL_47 -#define PP_KILL_IMPL_49(_) PP_KILL_IMPL_48 -#define PP_KILL_IMPL_50(_) PP_KILL_IMPL_49 -#define PP_KILL_IMPL_51(_) PP_KILL_IMPL_50 -#define PP_KILL_IMPL_52(_) PP_KILL_IMPL_51 -#define PP_KILL_IMPL_53(_) PP_KILL_IMPL_52 -#define PP_KILL_IMPL_54(_) PP_KILL_IMPL_53 -#define PP_KILL_IMPL_55(_) PP_KILL_IMPL_54 -#define PP_KILL_IMPL_56(_) PP_KILL_IMPL_55 -#define PP_KILL_IMPL_57(_) PP_KILL_IMPL_56 -#define PP_KILL_IMPL_58(_) PP_KILL_IMPL_57 -#define PP_KILL_IMPL_59(_) PP_KILL_IMPL_58 -#define PP_KILL_IMPL_60(_) PP_KILL_IMPL_59 -#define PP_KILL_IMPL_61(_) PP_KILL_IMPL_60 -#define PP_KILL_IMPL_62(_) PP_KILL_IMPL_61 -#define PP_KILL_IMPL_63(_) PP_KILL_IMPL_62 -#define PP_KILL_IMPL_64(_) PP_KILL_IMPL_63 -#define PP_KILL_IMPL_65(_) PP_KILL_IMPL_64 -#define PP_KILL_IMPL_66(_) PP_KILL_IMPL_65 -#define PP_KILL_IMPL_67(_) PP_KILL_IMPL_66 -#define PP_KILL_IMPL_68(_) PP_KILL_IMPL_67 -#define PP_KILL_IMPL_69(_) PP_KILL_IMPL_68 -#define PP_KILL_IMPL_70(_) PP_KILL_IMPL_69 -#define PP_KILL_IMPL_71(_) PP_KILL_IMPL_70 -#define PP_KILL_IMPL_72(_) PP_KILL_IMPL_71 -#define PP_KILL_IMPL_73(_) PP_KILL_IMPL_72 -#define PP_KILL_IMPL_74(_) PP_KILL_IMPL_73 -#define PP_KILL_IMPL_75(_) PP_KILL_IMPL_74 -#define PP_KILL_IMPL_76(_) PP_KILL_IMPL_75 -#define PP_KILL_IMPL_77(_) PP_KILL_IMPL_76 -#define PP_KILL_IMPL_78(_) PP_KILL_IMPL_77 -#define PP_KILL_IMPL_79(_) PP_KILL_IMPL_78 -#define PP_KILL_IMPL_80(_) PP_KILL_IMPL_79 -#define PP_KILL_IMPL_81(_) PP_KILL_IMPL_80 -#define PP_KILL_IMPL_82(_) PP_KILL_IMPL_81 -#define PP_KILL_IMPL_83(_) PP_KILL_IMPL_82 -#define PP_KILL_IMPL_84(_) PP_KILL_IMPL_83 -#define PP_KILL_IMPL_85(_) PP_KILL_IMPL_84 -#define PP_KILL_IMPL_86(_) PP_KILL_IMPL_85 -#define PP_KILL_IMPL_87(_) PP_KILL_IMPL_86 -#define PP_KILL_IMPL_88(_) PP_KILL_IMPL_87 -#define PP_KILL_IMPL_89(_) PP_KILL_IMPL_88 -#define PP_KILL_IMPL_90(_) PP_KILL_IMPL_89 -#define PP_KILL_IMPL_91(_) PP_KILL_IMPL_90 -#define PP_KILL_IMPL_92(_) PP_KILL_IMPL_91 -#define PP_KILL_IMPL_93(_) PP_KILL_IMPL_92 -#define PP_KILL_IMPL_94(_) PP_KILL_IMPL_93 -#define PP_KILL_IMPL_95(_) PP_KILL_IMPL_94 -#define PP_KILL_IMPL_96(_) PP_KILL_IMPL_95 -#define PP_KILL_IMPL_97(_) PP_KILL_IMPL_96 -#define PP_KILL_IMPL_98(_) PP_KILL_IMPL_97 -#define PP_KILL_IMPL_99(_) PP_KILL_IMPL_98 -#define PP_KILL_IMPL_100(_) PP_KILL_IMPL_99 + +//////////////////////////////////////////////////////////////////////////////// +#define PP_KILL_IMPL(seq, index) PP_CONCAT(PP_KILL_IMPL_, index) seq +#define PP_KILL_IMPL_0 +#define PP_KILL_IMPL_1(_) PP_KILL_IMPL_0 +#define PP_KILL_IMPL_2(_) PP_KILL_IMPL_1 +#define PP_KILL_IMPL_3(_) PP_KILL_IMPL_2 +#define PP_KILL_IMPL_4(_) PP_KILL_IMPL_3 +#define PP_KILL_IMPL_5(_) PP_KILL_IMPL_4 +#define PP_KILL_IMPL_6(_) PP_KILL_IMPL_5 +#define PP_KILL_IMPL_7(_) PP_KILL_IMPL_6 +#define PP_KILL_IMPL_8(_) PP_KILL_IMPL_7 +#define PP_KILL_IMPL_9(_) PP_KILL_IMPL_8 +#define PP_KILL_IMPL_10(_) PP_KILL_IMPL_9 +#define PP_KILL_IMPL_11(_) PP_KILL_IMPL_10 +#define PP_KILL_IMPL_12(_) PP_KILL_IMPL_11 +#define PP_KILL_IMPL_13(_) PP_KILL_IMPL_12 +#define PP_KILL_IMPL_14(_) PP_KILL_IMPL_13 +#define PP_KILL_IMPL_15(_) PP_KILL_IMPL_14 +#define PP_KILL_IMPL_16(_) PP_KILL_IMPL_15 +#define PP_KILL_IMPL_17(_) PP_KILL_IMPL_16 +#define PP_KILL_IMPL_18(_) PP_KILL_IMPL_17 +#define PP_KILL_IMPL_19(_) PP_KILL_IMPL_18 +#define PP_KILL_IMPL_20(_) PP_KILL_IMPL_19 +#define PP_KILL_IMPL_21(_) PP_KILL_IMPL_20 +#define PP_KILL_IMPL_22(_) PP_KILL_IMPL_21 +#define PP_KILL_IMPL_23(_) PP_KILL_IMPL_22 +#define PP_KILL_IMPL_24(_) PP_KILL_IMPL_23 +#define PP_KILL_IMPL_25(_) PP_KILL_IMPL_24 +#define PP_KILL_IMPL_26(_) PP_KILL_IMPL_25 +#define PP_KILL_IMPL_27(_) PP_KILL_IMPL_26 +#define PP_KILL_IMPL_28(_) PP_KILL_IMPL_27 +#define PP_KILL_IMPL_29(_) PP_KILL_IMPL_28 +#define PP_KILL_IMPL_30(_) PP_KILL_IMPL_29 +#define PP_KILL_IMPL_31(_) PP_KILL_IMPL_30 +#define PP_KILL_IMPL_32(_) PP_KILL_IMPL_31 +#define PP_KILL_IMPL_33(_) PP_KILL_IMPL_32 +#define PP_KILL_IMPL_34(_) PP_KILL_IMPL_33 +#define PP_KILL_IMPL_35(_) PP_KILL_IMPL_34 +#define PP_KILL_IMPL_36(_) PP_KILL_IMPL_35 +#define PP_KILL_IMPL_37(_) PP_KILL_IMPL_36 +#define PP_KILL_IMPL_38(_) PP_KILL_IMPL_37 +#define PP_KILL_IMPL_39(_) PP_KILL_IMPL_38 +#define PP_KILL_IMPL_40(_) PP_KILL_IMPL_39 +#define PP_KILL_IMPL_41(_) PP_KILL_IMPL_40 +#define PP_KILL_IMPL_42(_) PP_KILL_IMPL_41 +#define PP_KILL_IMPL_43(_) PP_KILL_IMPL_42 +#define PP_KILL_IMPL_44(_) PP_KILL_IMPL_43 +#define PP_KILL_IMPL_45(_) PP_KILL_IMPL_44 +#define PP_KILL_IMPL_46(_) PP_KILL_IMPL_45 +#define PP_KILL_IMPL_47(_) PP_KILL_IMPL_46 +#define PP_KILL_IMPL_48(_) PP_KILL_IMPL_47 +#define PP_KILL_IMPL_49(_) PP_KILL_IMPL_48 +#define PP_KILL_IMPL_50(_) PP_KILL_IMPL_49 +#define PP_KILL_IMPL_51(_) PP_KILL_IMPL_50 +#define PP_KILL_IMPL_52(_) PP_KILL_IMPL_51 +#define PP_KILL_IMPL_53(_) PP_KILL_IMPL_52 +#define PP_KILL_IMPL_54(_) PP_KILL_IMPL_53 +#define PP_KILL_IMPL_55(_) PP_KILL_IMPL_54 +#define PP_KILL_IMPL_56(_) PP_KILL_IMPL_55 +#define PP_KILL_IMPL_57(_) PP_KILL_IMPL_56 +#define PP_KILL_IMPL_58(_) PP_KILL_IMPL_57 +#define PP_KILL_IMPL_59(_) PP_KILL_IMPL_58 +#define PP_KILL_IMPL_60(_) PP_KILL_IMPL_59 +#define PP_KILL_IMPL_61(_) PP_KILL_IMPL_60 +#define PP_KILL_IMPL_62(_) PP_KILL_IMPL_61 +#define PP_KILL_IMPL_63(_) PP_KILL_IMPL_62 +#define PP_KILL_IMPL_64(_) PP_KILL_IMPL_63 +#define PP_KILL_IMPL_65(_) PP_KILL_IMPL_64 +#define PP_KILL_IMPL_66(_) PP_KILL_IMPL_65 +#define PP_KILL_IMPL_67(_) PP_KILL_IMPL_66 +#define PP_KILL_IMPL_68(_) PP_KILL_IMPL_67 +#define PP_KILL_IMPL_69(_) PP_KILL_IMPL_68 +#define PP_KILL_IMPL_70(_) PP_KILL_IMPL_69 +#define PP_KILL_IMPL_71(_) PP_KILL_IMPL_70 +#define PP_KILL_IMPL_72(_) PP_KILL_IMPL_71 +#define PP_KILL_IMPL_73(_) PP_KILL_IMPL_72 +#define PP_KILL_IMPL_74(_) PP_KILL_IMPL_73 +#define PP_KILL_IMPL_75(_) PP_KILL_IMPL_74 +#define PP_KILL_IMPL_76(_) PP_KILL_IMPL_75 +#define PP_KILL_IMPL_77(_) PP_KILL_IMPL_76 +#define PP_KILL_IMPL_78(_) PP_KILL_IMPL_77 +#define PP_KILL_IMPL_79(_) PP_KILL_IMPL_78 +#define PP_KILL_IMPL_80(_) PP_KILL_IMPL_79 +#define PP_KILL_IMPL_81(_) PP_KILL_IMPL_80 +#define PP_KILL_IMPL_82(_) PP_KILL_IMPL_81 +#define PP_KILL_IMPL_83(_) PP_KILL_IMPL_82 +#define PP_KILL_IMPL_84(_) PP_KILL_IMPL_83 +#define PP_KILL_IMPL_85(_) PP_KILL_IMPL_84 +#define PP_KILL_IMPL_86(_) PP_KILL_IMPL_85 +#define PP_KILL_IMPL_87(_) PP_KILL_IMPL_86 +#define PP_KILL_IMPL_88(_) PP_KILL_IMPL_87 +#define PP_KILL_IMPL_89(_) PP_KILL_IMPL_88 +#define PP_KILL_IMPL_90(_) PP_KILL_IMPL_89 +#define PP_KILL_IMPL_91(_) PP_KILL_IMPL_90 +#define PP_KILL_IMPL_92(_) PP_KILL_IMPL_91 +#define PP_KILL_IMPL_93(_) PP_KILL_IMPL_92 +#define PP_KILL_IMPL_94(_) PP_KILL_IMPL_93 +#define PP_KILL_IMPL_95(_) PP_KILL_IMPL_94 +#define PP_KILL_IMPL_96(_) PP_KILL_IMPL_95 +#define PP_KILL_IMPL_97(_) PP_KILL_IMPL_96 +#define PP_KILL_IMPL_98(_) PP_KILL_IMPL_97 +#define PP_KILL_IMPL_99(_) PP_KILL_IMPL_98 +#define PP_KILL_IMPL_100(_) PP_KILL_IMPL_99 #define PP_KILL_IMPL_101(_) PP_KILL_IMPL_100 #define PP_KILL_IMPL_102(_) PP_KILL_IMPL_101 #define PP_KILL_IMPL_103(_) PP_KILL_IMPL_102 @@ -624,114 +624,114 @@ #define PP_KILL_IMPL_198(_) PP_KILL_IMPL_197 #define PP_KILL_IMPL_199(_) PP_KILL_IMPL_198 #define PP_KILL_IMPL_200(_) PP_KILL_IMPL_199 - -//////////////////////////////////////////////////////////////////////////////// -#define PP_ELEMENT_IMPL(seq, \ - index) PP_ELEMENT_IMPL_A((PP_CONCAT(PP_ELEMENT_IMPL_, index) seq)) -#define PP_ELEMENT_IMPL_A(x) PP_ELEMENT_IMPL_C(PP_ELEMENT_IMPL_B x) -#define PP_ELEMENT_IMPL_B(x, _) x -#define PP_ELEMENT_IMPL_C(x) x -#define PP_ELEMENT_IMPL_0(x) x, PP_NIL -#define PP_ELEMENT_IMPL_1(_) PP_ELEMENT_IMPL_0 -#define PP_ELEMENT_IMPL_2(_) PP_ELEMENT_IMPL_1 -#define PP_ELEMENT_IMPL_3(_) PP_ELEMENT_IMPL_2 -#define PP_ELEMENT_IMPL_4(_) PP_ELEMENT_IMPL_3 -#define PP_ELEMENT_IMPL_5(_) PP_ELEMENT_IMPL_4 -#define PP_ELEMENT_IMPL_6(_) PP_ELEMENT_IMPL_5 -#define PP_ELEMENT_IMPL_7(_) PP_ELEMENT_IMPL_6 -#define PP_ELEMENT_IMPL_8(_) PP_ELEMENT_IMPL_7 -#define PP_ELEMENT_IMPL_9(_) PP_ELEMENT_IMPL_8 -#define PP_ELEMENT_IMPL_10(_) PP_ELEMENT_IMPL_9 -#define PP_ELEMENT_IMPL_11(_) PP_ELEMENT_IMPL_10 -#define PP_ELEMENT_IMPL_12(_) PP_ELEMENT_IMPL_11 -#define PP_ELEMENT_IMPL_13(_) PP_ELEMENT_IMPL_12 -#define PP_ELEMENT_IMPL_14(_) PP_ELEMENT_IMPL_13 -#define PP_ELEMENT_IMPL_15(_) PP_ELEMENT_IMPL_14 -#define PP_ELEMENT_IMPL_16(_) PP_ELEMENT_IMPL_15 -#define PP_ELEMENT_IMPL_17(_) PP_ELEMENT_IMPL_16 -#define PP_ELEMENT_IMPL_18(_) PP_ELEMENT_IMPL_17 -#define PP_ELEMENT_IMPL_19(_) PP_ELEMENT_IMPL_18 -#define PP_ELEMENT_IMPL_20(_) PP_ELEMENT_IMPL_19 -#define PP_ELEMENT_IMPL_21(_) PP_ELEMENT_IMPL_20 -#define PP_ELEMENT_IMPL_22(_) PP_ELEMENT_IMPL_21 -#define PP_ELEMENT_IMPL_23(_) PP_ELEMENT_IMPL_22 -#define PP_ELEMENT_IMPL_24(_) PP_ELEMENT_IMPL_23 -#define PP_ELEMENT_IMPL_25(_) PP_ELEMENT_IMPL_24 -#define PP_ELEMENT_IMPL_26(_) PP_ELEMENT_IMPL_25 -#define PP_ELEMENT_IMPL_27(_) PP_ELEMENT_IMPL_26 -#define PP_ELEMENT_IMPL_28(_) PP_ELEMENT_IMPL_27 -#define PP_ELEMENT_IMPL_29(_) PP_ELEMENT_IMPL_28 -#define PP_ELEMENT_IMPL_30(_) PP_ELEMENT_IMPL_29 -#define PP_ELEMENT_IMPL_31(_) PP_ELEMENT_IMPL_30 -#define PP_ELEMENT_IMPL_32(_) PP_ELEMENT_IMPL_31 -#define PP_ELEMENT_IMPL_33(_) PP_ELEMENT_IMPL_32 -#define PP_ELEMENT_IMPL_34(_) PP_ELEMENT_IMPL_33 -#define PP_ELEMENT_IMPL_35(_) PP_ELEMENT_IMPL_34 -#define PP_ELEMENT_IMPL_36(_) PP_ELEMENT_IMPL_35 -#define PP_ELEMENT_IMPL_37(_) PP_ELEMENT_IMPL_36 -#define PP_ELEMENT_IMPL_38(_) PP_ELEMENT_IMPL_37 -#define PP_ELEMENT_IMPL_39(_) PP_ELEMENT_IMPL_38 -#define PP_ELEMENT_IMPL_40(_) PP_ELEMENT_IMPL_39 -#define PP_ELEMENT_IMPL_41(_) PP_ELEMENT_IMPL_40 -#define PP_ELEMENT_IMPL_42(_) PP_ELEMENT_IMPL_41 -#define PP_ELEMENT_IMPL_43(_) PP_ELEMENT_IMPL_42 -#define PP_ELEMENT_IMPL_44(_) PP_ELEMENT_IMPL_43 -#define PP_ELEMENT_IMPL_45(_) PP_ELEMENT_IMPL_44 -#define PP_ELEMENT_IMPL_46(_) PP_ELEMENT_IMPL_45 -#define PP_ELEMENT_IMPL_47(_) PP_ELEMENT_IMPL_46 -#define PP_ELEMENT_IMPL_48(_) PP_ELEMENT_IMPL_47 -#define PP_ELEMENT_IMPL_49(_) PP_ELEMENT_IMPL_48 -#define PP_ELEMENT_IMPL_50(_) PP_ELEMENT_IMPL_49 -#define PP_ELEMENT_IMPL_51(_) PP_ELEMENT_IMPL_50 -#define PP_ELEMENT_IMPL_52(_) PP_ELEMENT_IMPL_51 -#define PP_ELEMENT_IMPL_53(_) PP_ELEMENT_IMPL_52 -#define PP_ELEMENT_IMPL_54(_) PP_ELEMENT_IMPL_53 -#define PP_ELEMENT_IMPL_55(_) PP_ELEMENT_IMPL_54 -#define PP_ELEMENT_IMPL_56(_) PP_ELEMENT_IMPL_55 -#define PP_ELEMENT_IMPL_57(_) PP_ELEMENT_IMPL_56 -#define PP_ELEMENT_IMPL_58(_) PP_ELEMENT_IMPL_57 -#define PP_ELEMENT_IMPL_59(_) PP_ELEMENT_IMPL_58 -#define PP_ELEMENT_IMPL_60(_) PP_ELEMENT_IMPL_59 -#define PP_ELEMENT_IMPL_61(_) PP_ELEMENT_IMPL_60 -#define PP_ELEMENT_IMPL_62(_) PP_ELEMENT_IMPL_61 -#define PP_ELEMENT_IMPL_63(_) PP_ELEMENT_IMPL_62 -#define PP_ELEMENT_IMPL_64(_) PP_ELEMENT_IMPL_63 -#define PP_ELEMENT_IMPL_65(_) PP_ELEMENT_IMPL_64 -#define PP_ELEMENT_IMPL_66(_) PP_ELEMENT_IMPL_65 -#define PP_ELEMENT_IMPL_67(_) PP_ELEMENT_IMPL_66 -#define PP_ELEMENT_IMPL_68(_) PP_ELEMENT_IMPL_67 -#define PP_ELEMENT_IMPL_69(_) PP_ELEMENT_IMPL_68 -#define PP_ELEMENT_IMPL_70(_) PP_ELEMENT_IMPL_69 -#define PP_ELEMENT_IMPL_71(_) PP_ELEMENT_IMPL_70 -#define PP_ELEMENT_IMPL_72(_) PP_ELEMENT_IMPL_71 -#define PP_ELEMENT_IMPL_73(_) PP_ELEMENT_IMPL_72 -#define PP_ELEMENT_IMPL_74(_) PP_ELEMENT_IMPL_73 -#define PP_ELEMENT_IMPL_75(_) PP_ELEMENT_IMPL_74 -#define PP_ELEMENT_IMPL_76(_) PP_ELEMENT_IMPL_75 -#define PP_ELEMENT_IMPL_77(_) PP_ELEMENT_IMPL_76 -#define PP_ELEMENT_IMPL_78(_) PP_ELEMENT_IMPL_77 -#define PP_ELEMENT_IMPL_79(_) PP_ELEMENT_IMPL_78 -#define PP_ELEMENT_IMPL_80(_) PP_ELEMENT_IMPL_79 -#define PP_ELEMENT_IMPL_81(_) PP_ELEMENT_IMPL_80 -#define PP_ELEMENT_IMPL_82(_) PP_ELEMENT_IMPL_81 -#define PP_ELEMENT_IMPL_83(_) PP_ELEMENT_IMPL_82 -#define PP_ELEMENT_IMPL_84(_) PP_ELEMENT_IMPL_83 -#define PP_ELEMENT_IMPL_85(_) PP_ELEMENT_IMPL_84 -#define PP_ELEMENT_IMPL_86(_) PP_ELEMENT_IMPL_85 -#define PP_ELEMENT_IMPL_87(_) PP_ELEMENT_IMPL_86 -#define PP_ELEMENT_IMPL_88(_) PP_ELEMENT_IMPL_87 -#define PP_ELEMENT_IMPL_89(_) PP_ELEMENT_IMPL_88 -#define PP_ELEMENT_IMPL_90(_) PP_ELEMENT_IMPL_89 -#define PP_ELEMENT_IMPL_91(_) PP_ELEMENT_IMPL_90 -#define PP_ELEMENT_IMPL_92(_) PP_ELEMENT_IMPL_91 -#define PP_ELEMENT_IMPL_93(_) PP_ELEMENT_IMPL_92 -#define PP_ELEMENT_IMPL_94(_) PP_ELEMENT_IMPL_93 -#define PP_ELEMENT_IMPL_95(_) PP_ELEMENT_IMPL_94 -#define PP_ELEMENT_IMPL_96(_) PP_ELEMENT_IMPL_95 -#define PP_ELEMENT_IMPL_97(_) PP_ELEMENT_IMPL_96 -#define PP_ELEMENT_IMPL_98(_) PP_ELEMENT_IMPL_97 -#define PP_ELEMENT_IMPL_99(_) PP_ELEMENT_IMPL_98 -#define PP_ELEMENT_IMPL_100(_) PP_ELEMENT_IMPL_99 + +//////////////////////////////////////////////////////////////////////////////// +#define PP_ELEMENT_IMPL(seq, \ + index) PP_ELEMENT_IMPL_A((PP_CONCAT(PP_ELEMENT_IMPL_, index) seq)) +#define PP_ELEMENT_IMPL_A(x) PP_ELEMENT_IMPL_C(PP_ELEMENT_IMPL_B x) +#define PP_ELEMENT_IMPL_B(x, _) x +#define PP_ELEMENT_IMPL_C(x) x +#define PP_ELEMENT_IMPL_0(x) x, PP_NIL +#define PP_ELEMENT_IMPL_1(_) PP_ELEMENT_IMPL_0 +#define PP_ELEMENT_IMPL_2(_) PP_ELEMENT_IMPL_1 +#define PP_ELEMENT_IMPL_3(_) PP_ELEMENT_IMPL_2 +#define PP_ELEMENT_IMPL_4(_) PP_ELEMENT_IMPL_3 +#define PP_ELEMENT_IMPL_5(_) PP_ELEMENT_IMPL_4 +#define PP_ELEMENT_IMPL_6(_) PP_ELEMENT_IMPL_5 +#define PP_ELEMENT_IMPL_7(_) PP_ELEMENT_IMPL_6 +#define PP_ELEMENT_IMPL_8(_) PP_ELEMENT_IMPL_7 +#define PP_ELEMENT_IMPL_9(_) PP_ELEMENT_IMPL_8 +#define PP_ELEMENT_IMPL_10(_) PP_ELEMENT_IMPL_9 +#define PP_ELEMENT_IMPL_11(_) PP_ELEMENT_IMPL_10 +#define PP_ELEMENT_IMPL_12(_) PP_ELEMENT_IMPL_11 +#define PP_ELEMENT_IMPL_13(_) PP_ELEMENT_IMPL_12 +#define PP_ELEMENT_IMPL_14(_) PP_ELEMENT_IMPL_13 +#define PP_ELEMENT_IMPL_15(_) PP_ELEMENT_IMPL_14 +#define PP_ELEMENT_IMPL_16(_) PP_ELEMENT_IMPL_15 +#define PP_ELEMENT_IMPL_17(_) PP_ELEMENT_IMPL_16 +#define PP_ELEMENT_IMPL_18(_) PP_ELEMENT_IMPL_17 +#define PP_ELEMENT_IMPL_19(_) PP_ELEMENT_IMPL_18 +#define PP_ELEMENT_IMPL_20(_) PP_ELEMENT_IMPL_19 +#define PP_ELEMENT_IMPL_21(_) PP_ELEMENT_IMPL_20 +#define PP_ELEMENT_IMPL_22(_) PP_ELEMENT_IMPL_21 +#define PP_ELEMENT_IMPL_23(_) PP_ELEMENT_IMPL_22 +#define PP_ELEMENT_IMPL_24(_) PP_ELEMENT_IMPL_23 +#define PP_ELEMENT_IMPL_25(_) PP_ELEMENT_IMPL_24 +#define PP_ELEMENT_IMPL_26(_) PP_ELEMENT_IMPL_25 +#define PP_ELEMENT_IMPL_27(_) PP_ELEMENT_IMPL_26 +#define PP_ELEMENT_IMPL_28(_) PP_ELEMENT_IMPL_27 +#define PP_ELEMENT_IMPL_29(_) PP_ELEMENT_IMPL_28 +#define PP_ELEMENT_IMPL_30(_) PP_ELEMENT_IMPL_29 +#define PP_ELEMENT_IMPL_31(_) PP_ELEMENT_IMPL_30 +#define PP_ELEMENT_IMPL_32(_) PP_ELEMENT_IMPL_31 +#define PP_ELEMENT_IMPL_33(_) PP_ELEMENT_IMPL_32 +#define PP_ELEMENT_IMPL_34(_) PP_ELEMENT_IMPL_33 +#define PP_ELEMENT_IMPL_35(_) PP_ELEMENT_IMPL_34 +#define PP_ELEMENT_IMPL_36(_) PP_ELEMENT_IMPL_35 +#define PP_ELEMENT_IMPL_37(_) PP_ELEMENT_IMPL_36 +#define PP_ELEMENT_IMPL_38(_) PP_ELEMENT_IMPL_37 +#define PP_ELEMENT_IMPL_39(_) PP_ELEMENT_IMPL_38 +#define PP_ELEMENT_IMPL_40(_) PP_ELEMENT_IMPL_39 +#define PP_ELEMENT_IMPL_41(_) PP_ELEMENT_IMPL_40 +#define PP_ELEMENT_IMPL_42(_) PP_ELEMENT_IMPL_41 +#define PP_ELEMENT_IMPL_43(_) PP_ELEMENT_IMPL_42 +#define PP_ELEMENT_IMPL_44(_) PP_ELEMENT_IMPL_43 +#define PP_ELEMENT_IMPL_45(_) PP_ELEMENT_IMPL_44 +#define PP_ELEMENT_IMPL_46(_) PP_ELEMENT_IMPL_45 +#define PP_ELEMENT_IMPL_47(_) PP_ELEMENT_IMPL_46 +#define PP_ELEMENT_IMPL_48(_) PP_ELEMENT_IMPL_47 +#define PP_ELEMENT_IMPL_49(_) PP_ELEMENT_IMPL_48 +#define PP_ELEMENT_IMPL_50(_) PP_ELEMENT_IMPL_49 +#define PP_ELEMENT_IMPL_51(_) PP_ELEMENT_IMPL_50 +#define PP_ELEMENT_IMPL_52(_) PP_ELEMENT_IMPL_51 +#define PP_ELEMENT_IMPL_53(_) PP_ELEMENT_IMPL_52 +#define PP_ELEMENT_IMPL_54(_) PP_ELEMENT_IMPL_53 +#define PP_ELEMENT_IMPL_55(_) PP_ELEMENT_IMPL_54 +#define PP_ELEMENT_IMPL_56(_) PP_ELEMENT_IMPL_55 +#define PP_ELEMENT_IMPL_57(_) PP_ELEMENT_IMPL_56 +#define PP_ELEMENT_IMPL_58(_) PP_ELEMENT_IMPL_57 +#define PP_ELEMENT_IMPL_59(_) PP_ELEMENT_IMPL_58 +#define PP_ELEMENT_IMPL_60(_) PP_ELEMENT_IMPL_59 +#define PP_ELEMENT_IMPL_61(_) PP_ELEMENT_IMPL_60 +#define PP_ELEMENT_IMPL_62(_) PP_ELEMENT_IMPL_61 +#define PP_ELEMENT_IMPL_63(_) PP_ELEMENT_IMPL_62 +#define PP_ELEMENT_IMPL_64(_) PP_ELEMENT_IMPL_63 +#define PP_ELEMENT_IMPL_65(_) PP_ELEMENT_IMPL_64 +#define PP_ELEMENT_IMPL_66(_) PP_ELEMENT_IMPL_65 +#define PP_ELEMENT_IMPL_67(_) PP_ELEMENT_IMPL_66 +#define PP_ELEMENT_IMPL_68(_) PP_ELEMENT_IMPL_67 +#define PP_ELEMENT_IMPL_69(_) PP_ELEMENT_IMPL_68 +#define PP_ELEMENT_IMPL_70(_) PP_ELEMENT_IMPL_69 +#define PP_ELEMENT_IMPL_71(_) PP_ELEMENT_IMPL_70 +#define PP_ELEMENT_IMPL_72(_) PP_ELEMENT_IMPL_71 +#define PP_ELEMENT_IMPL_73(_) PP_ELEMENT_IMPL_72 +#define PP_ELEMENT_IMPL_74(_) PP_ELEMENT_IMPL_73 +#define PP_ELEMENT_IMPL_75(_) PP_ELEMENT_IMPL_74 +#define PP_ELEMENT_IMPL_76(_) PP_ELEMENT_IMPL_75 +#define PP_ELEMENT_IMPL_77(_) PP_ELEMENT_IMPL_76 +#define PP_ELEMENT_IMPL_78(_) PP_ELEMENT_IMPL_77 +#define PP_ELEMENT_IMPL_79(_) PP_ELEMENT_IMPL_78 +#define PP_ELEMENT_IMPL_80(_) PP_ELEMENT_IMPL_79 +#define PP_ELEMENT_IMPL_81(_) PP_ELEMENT_IMPL_80 +#define PP_ELEMENT_IMPL_82(_) PP_ELEMENT_IMPL_81 +#define PP_ELEMENT_IMPL_83(_) PP_ELEMENT_IMPL_82 +#define PP_ELEMENT_IMPL_84(_) PP_ELEMENT_IMPL_83 +#define PP_ELEMENT_IMPL_85(_) PP_ELEMENT_IMPL_84 +#define PP_ELEMENT_IMPL_86(_) PP_ELEMENT_IMPL_85 +#define PP_ELEMENT_IMPL_87(_) PP_ELEMENT_IMPL_86 +#define PP_ELEMENT_IMPL_88(_) PP_ELEMENT_IMPL_87 +#define PP_ELEMENT_IMPL_89(_) PP_ELEMENT_IMPL_88 +#define PP_ELEMENT_IMPL_90(_) PP_ELEMENT_IMPL_89 +#define PP_ELEMENT_IMPL_91(_) PP_ELEMENT_IMPL_90 +#define PP_ELEMENT_IMPL_92(_) PP_ELEMENT_IMPL_91 +#define PP_ELEMENT_IMPL_93(_) PP_ELEMENT_IMPL_92 +#define PP_ELEMENT_IMPL_94(_) PP_ELEMENT_IMPL_93 +#define PP_ELEMENT_IMPL_95(_) PP_ELEMENT_IMPL_94 +#define PP_ELEMENT_IMPL_96(_) PP_ELEMENT_IMPL_95 +#define PP_ELEMENT_IMPL_97(_) PP_ELEMENT_IMPL_96 +#define PP_ELEMENT_IMPL_98(_) PP_ELEMENT_IMPL_97 +#define PP_ELEMENT_IMPL_99(_) PP_ELEMENT_IMPL_98 +#define PP_ELEMENT_IMPL_100(_) PP_ELEMENT_IMPL_99 #define PP_ELEMENT_IMPL_101(_) PP_ELEMENT_IMPL_100 #define PP_ELEMENT_IMPL_102(_) PP_ELEMENT_IMPL_101 #define PP_ELEMENT_IMPL_103(_) PP_ELEMENT_IMPL_102 @@ -832,217 +832,217 @@ #define PP_ELEMENT_IMPL_198(_) PP_ELEMENT_IMPL_197 #define PP_ELEMENT_IMPL_199(_) PP_ELEMENT_IMPL_198 #define PP_ELEMENT_IMPL_200(_) PP_ELEMENT_IMPL_199 - -//////////////////////////////////////////////////////////////////////////////// -#define PP_HEAD_IMPL(seq) PP_ELEMENT_IMPL(seq, 0) - -//////////////////////////////////////////////////////////////////////////////// -#define PP_TAIL_IMPL(seq) PP_KILL_IMPL(seq, 1) - -//////////////////////////////////////////////////////////////////////////////// -#define PP_FOR_EACH_IMPL(what, seq) PP_CONCAT(PP_FOR_EACH_IMPL_, \ - PP_COUNT(seq))(what, seq) -#define PP_FOR_EACH_IMPL_0(what, seq) -#define PP_FOR_EACH_IMPL_1(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_0(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_2(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_1(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_3(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_2(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_4(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_3(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_5(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_4(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_6(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_5(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_7(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_6(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_8(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_7(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_9(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_8(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_10(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_9(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_11(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_10(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_12(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_11(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_13(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_12(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_14(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_13(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_15(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_14(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_16(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_15(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_17(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_16(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_18(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_17(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_19(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_18(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_20(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_19(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_21(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_20(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_22(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_21(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_23(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_22(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_24(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_23(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_25(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_24(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_26(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_25(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_27(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_26(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_28(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_27(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_29(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_28(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_30(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_29(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_31(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_30(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_32(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_31(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_33(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_32(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_34(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_33(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_35(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_34(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_36(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_35(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_37(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_36(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_38(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_37(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_39(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_38(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_40(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_39(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_41(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_40(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_42(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_41(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_43(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_42(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_44(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_43(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_45(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_44(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_46(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_45(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_47(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_46(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_48(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_47(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_49(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_48(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_50(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_49(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_51(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_50(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_52(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_51(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_53(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_52(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_54(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_53(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_55(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_54(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_56(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_55(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_57(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_56(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_58(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_57(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_59(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_58(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_60(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_59(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_61(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_60(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_62(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_61(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_63(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_62(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_64(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_63(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_65(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_64(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_66(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_65(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_67(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_66(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_68(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_67(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_69(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_68(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_70(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_69(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_71(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_70(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_72(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_71(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_73(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_72(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_74(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_73(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_75(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_74(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_76(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_75(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_77(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_76(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_78(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_77(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_79(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_78(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_80(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_79(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_81(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_80(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_82(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_81(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_83(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_82(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_84(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_83(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_85(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_84(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_86(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_85(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_87(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_86(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_88(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_87(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_89(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_88(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_90(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_89(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_91(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_90(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_92(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_91(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_93(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_92(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_94(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_93(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_95(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_94(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_96(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_95(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_97(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_96(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_98(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_97(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_99(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_98(what, PP_TAIL(seq)) -#define PP_FOR_EACH_IMPL_100(what, \ - seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_99(what, PP_TAIL(seq)) + +//////////////////////////////////////////////////////////////////////////////// +#define PP_HEAD_IMPL(seq) PP_ELEMENT_IMPL(seq, 0) + +//////////////////////////////////////////////////////////////////////////////// +#define PP_TAIL_IMPL(seq) PP_KILL_IMPL(seq, 1) + +//////////////////////////////////////////////////////////////////////////////// +#define PP_FOR_EACH_IMPL(what, seq) PP_CONCAT(PP_FOR_EACH_IMPL_, \ + PP_COUNT(seq))(what, seq) +#define PP_FOR_EACH_IMPL_0(what, seq) +#define PP_FOR_EACH_IMPL_1(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_0(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_2(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_1(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_3(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_2(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_4(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_3(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_5(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_4(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_6(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_5(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_7(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_6(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_8(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_7(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_9(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_8(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_10(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_9(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_11(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_10(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_12(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_11(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_13(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_12(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_14(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_13(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_15(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_14(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_16(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_15(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_17(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_16(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_18(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_17(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_19(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_18(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_20(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_19(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_21(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_20(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_22(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_21(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_23(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_22(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_24(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_23(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_25(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_24(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_26(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_25(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_27(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_26(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_28(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_27(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_29(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_28(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_30(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_29(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_31(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_30(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_32(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_31(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_33(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_32(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_34(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_33(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_35(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_34(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_36(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_35(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_37(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_36(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_38(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_37(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_39(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_38(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_40(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_39(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_41(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_40(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_42(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_41(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_43(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_42(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_44(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_43(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_45(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_44(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_46(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_45(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_47(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_46(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_48(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_47(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_49(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_48(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_50(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_49(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_51(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_50(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_52(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_51(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_53(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_52(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_54(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_53(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_55(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_54(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_56(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_55(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_57(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_56(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_58(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_57(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_59(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_58(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_60(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_59(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_61(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_60(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_62(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_61(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_63(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_62(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_64(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_63(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_65(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_64(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_66(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_65(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_67(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_66(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_68(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_67(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_69(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_68(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_70(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_69(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_71(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_70(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_72(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_71(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_73(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_72(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_74(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_73(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_75(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_74(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_76(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_75(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_77(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_76(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_78(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_77(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_79(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_78(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_80(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_79(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_81(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_80(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_82(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_81(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_83(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_82(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_84(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_83(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_85(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_84(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_86(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_85(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_87(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_86(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_88(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_87(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_89(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_88(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_90(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_89(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_91(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_90(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_92(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_91(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_93(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_92(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_94(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_93(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_95(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_94(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_96(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_95(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_97(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_96(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_98(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_97(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_99(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_98(what, PP_TAIL(seq)) +#define PP_FOR_EACH_IMPL_100(what, \ + seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_99(what, PP_TAIL(seq)) #define PP_FOR_EACH_IMPL_101(what, \ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_100(what, PP_TAIL(seq)) #define PP_FOR_EACH_IMPL_102(what, \ @@ -1243,7 +1243,7 @@ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_198(what, PP_TAIL(seq)) #define PP_FOR_EACH_IMPL_200(what, \ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_199(what, PP_TAIL(seq)) -//////////////////////////////////////////////////////////////////////////////// -/*! - \endinternal -*/ +//////////////////////////////////////////////////////////////////////////////// +/*! + \endinternal +*/ diff --git a/library/cpp/yt/misc/preprocessor-gen.h.pump b/library/cpp/yt/misc/preprocessor-gen.h.pump index 0f178ae37e..7e3517fdd1 100644 --- a/library/cpp/yt/misc/preprocessor-gen.h.pump +++ b/library/cpp/yt/misc/preprocessor-gen.h.pump @@ -1,70 +1,70 @@ -#pragma once - -$$ Please, use Pump to convert this source file to valid C++ header. -$$ Note that lines in this file could be longer than 80 symbols. +#pragma once + +$$ Please, use Pump to convert this source file to valid C++ header. +$$ Note that lines in this file could be longer than 80 symbols. $var n = 199 -$range i 0..n - -/*! - \internal -*/ - -#ifndef PREPROCESSOR_GEN_H_ -#error "Direct inclusion of this file is not allowed, include preprocessor.h" -// For the sake of sane code completion. -#include "preprocessor.h" -#endif -#undef PREPROCESSOR_GEN_H_ - -//////////////////////////////////////////////////////////////////////////////// -#define PP_COUNT_IMPL(...) PP_CONCAT(PP_COUNT_CONST_, PP_COUNT_IMPL_0 __VA_ARGS__) - -$for i [[ -#define PP_COUNT_CONST_PP_COUNT_IMPL_$i $i - -]] - -$for i [[ -#define PP_COUNT_IMPL_$i(_) PP_COUNT_IMPL_$(i+1) - -]] - -//////////////////////////////////////////////////////////////////////////////// -#define PP_KILL_IMPL(seq, index) PP_CONCAT(PP_KILL_IMPL_, index) seq -#define PP_KILL_IMPL_0 - -$for i [[ -#define PP_KILL_IMPL_$(i+1)(_) PP_KILL_IMPL_$i - -]] - -//////////////////////////////////////////////////////////////////////////////// -#define PP_ELEMENT_IMPL(seq, index) PP_ELEMENT_IMPL_A((PP_CONCAT(PP_ELEMENT_IMPL_, index) seq)) -#define PP_ELEMENT_IMPL_A(x) PP_ELEMENT_IMPL_C(PP_ELEMENT_IMPL_B x) -#define PP_ELEMENT_IMPL_B(x, _) x -#define PP_ELEMENT_IMPL_C(x) x -#define PP_ELEMENT_IMPL_0(x) x, PP_NIL - -$for i [[ -#define PP_ELEMENT_IMPL_$(i+1)(_) PP_ELEMENT_IMPL_$i - -]] - -//////////////////////////////////////////////////////////////////////////////// -#define PP_HEAD_IMPL(seq) PP_ELEMENT_IMPL(seq, 0) - -//////////////////////////////////////////////////////////////////////////////// -#define PP_TAIL_IMPL(seq) PP_KILL_IMPL(seq, 1) - -//////////////////////////////////////////////////////////////////////////////// -#define PP_FOR_EACH_IMPL(what, seq) PP_CONCAT(PP_FOR_EACH_IMPL_, PP_COUNT(seq))(what, seq) -#define PP_FOR_EACH_IMPL_0(what, seq) - -$for i [[ -#define PP_FOR_EACH_IMPL_$(i+1)(what, seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_$i(what, PP_TAIL(seq)) - -]] -//////////////////////////////////////////////////////////////////////////////// -/*! - \endinternal -*/ +$range i 0..n + +/*! + \internal +*/ + +#ifndef PREPROCESSOR_GEN_H_ +#error "Direct inclusion of this file is not allowed, include preprocessor.h" +// For the sake of sane code completion. +#include "preprocessor.h" +#endif +#undef PREPROCESSOR_GEN_H_ + +//////////////////////////////////////////////////////////////////////////////// +#define PP_COUNT_IMPL(...) PP_CONCAT(PP_COUNT_CONST_, PP_COUNT_IMPL_0 __VA_ARGS__) + +$for i [[ +#define PP_COUNT_CONST_PP_COUNT_IMPL_$i $i + +]] + +$for i [[ +#define PP_COUNT_IMPL_$i(_) PP_COUNT_IMPL_$(i+1) + +]] + +//////////////////////////////////////////////////////////////////////////////// +#define PP_KILL_IMPL(seq, index) PP_CONCAT(PP_KILL_IMPL_, index) seq +#define PP_KILL_IMPL_0 + +$for i [[ +#define PP_KILL_IMPL_$(i+1)(_) PP_KILL_IMPL_$i + +]] + +//////////////////////////////////////////////////////////////////////////////// +#define PP_ELEMENT_IMPL(seq, index) PP_ELEMENT_IMPL_A((PP_CONCAT(PP_ELEMENT_IMPL_, index) seq)) +#define PP_ELEMENT_IMPL_A(x) PP_ELEMENT_IMPL_C(PP_ELEMENT_IMPL_B x) +#define PP_ELEMENT_IMPL_B(x, _) x +#define PP_ELEMENT_IMPL_C(x) x +#define PP_ELEMENT_IMPL_0(x) x, PP_NIL + +$for i [[ +#define PP_ELEMENT_IMPL_$(i+1)(_) PP_ELEMENT_IMPL_$i + +]] + +//////////////////////////////////////////////////////////////////////////////// +#define PP_HEAD_IMPL(seq) PP_ELEMENT_IMPL(seq, 0) + +//////////////////////////////////////////////////////////////////////////////// +#define PP_TAIL_IMPL(seq) PP_KILL_IMPL(seq, 1) + +//////////////////////////////////////////////////////////////////////////////// +#define PP_FOR_EACH_IMPL(what, seq) PP_CONCAT(PP_FOR_EACH_IMPL_, PP_COUNT(seq))(what, seq) +#define PP_FOR_EACH_IMPL_0(what, seq) + +$for i [[ +#define PP_FOR_EACH_IMPL_$(i+1)(what, seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_$i(what, PP_TAIL(seq)) + +]] +//////////////////////////////////////////////////////////////////////////////// +/*! + \endinternal +*/ diff --git a/library/cpp/yt/misc/preprocessor.h b/library/cpp/yt/misc/preprocessor.h index 9afd3ae902..1372d6534f 100644 --- a/library/cpp/yt/misc/preprocessor.h +++ b/library/cpp/yt/misc/preprocessor.h @@ -1,124 +1,124 @@ -#pragma once - -/*! - * \file preprocesor.h - * \brief Preprocessor metaprogramming macroses - */ - -#if !defined(_MSC_VER) && !defined(__GNUC__) -# error Your compiler is not currently supported. -#endif - -/*! - * \defgroup yt_pp Preprocessor metaprogramming macroses - * \ingroup yt_commons - * - * This is collection of macro definitions for various metaprogramming tasks - * with the preprocessor. - * - * \{ - * - * \page yt_pp_sequences Sequences - * Everything revolves around the concept of a \em sequence. A typical - * sequence is encoded like <tt>(1)(2)(3)...</tt>. Internally this allows - * to apply some macro to the every element in the sequence (see #PP_FOR_EACH). - * - * Note that sequences can be nested, i. e. <tt>((1)(2)(3))(a)(b)(c)</tt> - * - * \page yt_pp_examples Examples - * Please refer to the unit test for an actual example of usage - * (unittests/preprocessor_ut.cpp). - * - */ - -//! Concatenates two tokens. -#define PP_CONCAT(x, y) PP_CONCAT_A(x, y) -//! \cond Implementation -#define PP_CONCAT_A(x, y) PP_CONCAT_B(x, y) -#define PP_CONCAT_B(x, y) x ## y -//! \endcond - -//! Transforms token into the string forcing argument expansion. -#define PP_STRINGIZE(x) PP_STRINGIZE_A(x) -//! \cond Implementation -#define PP_STRINGIZE_A(x) PP_STRINGIZE_B(x) -#define PP_STRINGIZE_B(x) #x -//! \endcond - -//! \cond Implementation -#define PP_LEFT_PARENTHESIS ( -#define PP_RIGHT_PARENTHESIS ) -#define PP_COMMA() , -#define PP_EMPTY() -//! \endcond - -//! Performs (non-lazy) conditional expansion. -/*! - * \param cond Condition; should expands to either \c PP_TRUE or \c PP_FALSE. - * \param _then Expansion result in case when \c cond holds. - * \param _else Expansion result in case when \c cond does not hold. - */ -#define PP_IF(cond, _then, _else) PP_CONCAT(PP_IF_, cond)(_then, _else) -//! \cond Implementation -#define PP_IF_PP_TRUE(x, y) x -#define PP_IF_PP_FALSE(x, y) y -//! \endcond - -//! Tests whether supplied argument can be treated as a sequence -//! (i. e. <tt>()()()...</tt>) -#define PP_IS_SEQUENCE(arg) PP_CONCAT(PP_IS_SEQUENCE_B_, PP_COUNT((PP_NIL PP_IS_SEQUENCE_A arg PP_NIL))) -//! \cond Implementation -#define PP_IS_SEQUENCE_A(_) PP_RIGHT_PARENTHESIS PP_LEFT_PARENTHESIS -#define PP_IS_SEQUENCE_B_1 PP_FALSE -#define PP_IS_SEQUENCE_B_2 PP_TRUE -//! \endcond - -//! Computes the number of elements in the sequence. -#define PP_COUNT(...) PP_COUNT_IMPL(__VA_ARGS__) - -//! Removes first \c n elements from the sequence. -#define PP_KILL(seq, n) PP_KILL_IMPL(seq, n) - -//! Extracts the head of the sequence. -/*! For example, \code PP_HEAD((0)(1)(2)(3)) == 0 \endcode - */ -#define PP_HEAD(...) PP_HEAD_IMPL(__VA_ARGS__) - -//! Extracts the tail of the sequence. -/*! For example, \code PP_TAIL((0)(1)(2)(3)) == (1)(2)(3) \endcode - */ -#define PP_TAIL(...) PP_TAIL_IMPL(__VA_ARGS__) - -//! Extracts the element with the specified index from the sequence. -/*! For example, \code PP_ELEMENT((0)(1)(2)(3), 1) == 1 \endcode - */ -#define PP_ELEMENT(seq, index) PP_ELEMENT_IMPL(seq, index) - -//! Applies the macro to every member of the sequence. -/*! For example, - * \code - * #define MyFunctor(x) +x+ - * PP_FOR_EACH(MyFunctor, (0)(1)(2)(3)) == +0+ +1+ +2+ +3+ - * \encode - */ -#define PP_FOR_EACH(what, seq) PP_FOR_EACH_IMPL(what, seq) - -//! Declares an anonymous variable. -#ifdef __COUNTER__ -#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __COUNTER__) -#else -#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __LINE__) -#endif - -//! Insert prefix based on presence of additional arguments. -#define PP_ONE_OR_NONE(a, ...) PP_THIRD(a, ## __VA_ARGS__, a) -#define PP_THIRD(a, b, ...) __VA_ARGS__ - -//! \cond Implementation -#define PREPROCESSOR_GEN_H_ -#include "preprocessor-gen.h" -#undef PREPROCESSOR_GEN_H_ -//! \endcond - -/*! \} */ - +#pragma once + +/*! + * \file preprocesor.h + * \brief Preprocessor metaprogramming macroses + */ + +#if !defined(_MSC_VER) && !defined(__GNUC__) +# error Your compiler is not currently supported. +#endif + +/*! + * \defgroup yt_pp Preprocessor metaprogramming macroses + * \ingroup yt_commons + * + * This is collection of macro definitions for various metaprogramming tasks + * with the preprocessor. + * + * \{ + * + * \page yt_pp_sequences Sequences + * Everything revolves around the concept of a \em sequence. A typical + * sequence is encoded like <tt>(1)(2)(3)...</tt>. Internally this allows + * to apply some macro to the every element in the sequence (see #PP_FOR_EACH). + * + * Note that sequences can be nested, i. e. <tt>((1)(2)(3))(a)(b)(c)</tt> + * + * \page yt_pp_examples Examples + * Please refer to the unit test for an actual example of usage + * (unittests/preprocessor_ut.cpp). + * + */ + +//! Concatenates two tokens. +#define PP_CONCAT(x, y) PP_CONCAT_A(x, y) +//! \cond Implementation +#define PP_CONCAT_A(x, y) PP_CONCAT_B(x, y) +#define PP_CONCAT_B(x, y) x ## y +//! \endcond + +//! Transforms token into the string forcing argument expansion. +#define PP_STRINGIZE(x) PP_STRINGIZE_A(x) +//! \cond Implementation +#define PP_STRINGIZE_A(x) PP_STRINGIZE_B(x) +#define PP_STRINGIZE_B(x) #x +//! \endcond + +//! \cond Implementation +#define PP_LEFT_PARENTHESIS ( +#define PP_RIGHT_PARENTHESIS ) +#define PP_COMMA() , +#define PP_EMPTY() +//! \endcond + +//! Performs (non-lazy) conditional expansion. +/*! + * \param cond Condition; should expands to either \c PP_TRUE or \c PP_FALSE. + * \param _then Expansion result in case when \c cond holds. + * \param _else Expansion result in case when \c cond does not hold. + */ +#define PP_IF(cond, _then, _else) PP_CONCAT(PP_IF_, cond)(_then, _else) +//! \cond Implementation +#define PP_IF_PP_TRUE(x, y) x +#define PP_IF_PP_FALSE(x, y) y +//! \endcond + +//! Tests whether supplied argument can be treated as a sequence +//! (i. e. <tt>()()()...</tt>) +#define PP_IS_SEQUENCE(arg) PP_CONCAT(PP_IS_SEQUENCE_B_, PP_COUNT((PP_NIL PP_IS_SEQUENCE_A arg PP_NIL))) +//! \cond Implementation +#define PP_IS_SEQUENCE_A(_) PP_RIGHT_PARENTHESIS PP_LEFT_PARENTHESIS +#define PP_IS_SEQUENCE_B_1 PP_FALSE +#define PP_IS_SEQUENCE_B_2 PP_TRUE +//! \endcond + +//! Computes the number of elements in the sequence. +#define PP_COUNT(...) PP_COUNT_IMPL(__VA_ARGS__) + +//! Removes first \c n elements from the sequence. +#define PP_KILL(seq, n) PP_KILL_IMPL(seq, n) + +//! Extracts the head of the sequence. +/*! For example, \code PP_HEAD((0)(1)(2)(3)) == 0 \endcode + */ +#define PP_HEAD(...) PP_HEAD_IMPL(__VA_ARGS__) + +//! Extracts the tail of the sequence. +/*! For example, \code PP_TAIL((0)(1)(2)(3)) == (1)(2)(3) \endcode + */ +#define PP_TAIL(...) PP_TAIL_IMPL(__VA_ARGS__) + +//! Extracts the element with the specified index from the sequence. +/*! For example, \code PP_ELEMENT((0)(1)(2)(3), 1) == 1 \endcode + */ +#define PP_ELEMENT(seq, index) PP_ELEMENT_IMPL(seq, index) + +//! Applies the macro to every member of the sequence. +/*! For example, + * \code + * #define MyFunctor(x) +x+ + * PP_FOR_EACH(MyFunctor, (0)(1)(2)(3)) == +0+ +1+ +2+ +3+ + * \encode + */ +#define PP_FOR_EACH(what, seq) PP_FOR_EACH_IMPL(what, seq) + +//! Declares an anonymous variable. +#ifdef __COUNTER__ +#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __COUNTER__) +#else +#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __LINE__) +#endif + +//! Insert prefix based on presence of additional arguments. +#define PP_ONE_OR_NONE(a, ...) PP_THIRD(a, ## __VA_ARGS__, a) +#define PP_THIRD(a, b, ...) __VA_ARGS__ + +//! \cond Implementation +#define PREPROCESSOR_GEN_H_ +#include "preprocessor-gen.h" +#undef PREPROCESSOR_GEN_H_ +//! \endcond + +/*! \} */ + diff --git a/library/cpp/yt/misc/property.h b/library/cpp/yt/misc/property.h index bef8024ae1..1bf1f1dfb6 100644 --- a/library/cpp/yt/misc/property.h +++ b/library/cpp/yt/misc/property.h @@ -8,40 +8,40 @@ public: \ type& name(); \ const type& name() const; -//! Defines a trivial public read-write property that is passed by reference. -//! All arguments after name are used as default value (via braced-init-list). -#define DEFINE_BYREF_RW_PROPERTY(type, name, ...) \ -protected: \ - type name##_ { __VA_ARGS__ }; \ +//! Defines a trivial public read-write property that is passed by reference. +//! All arguments after name are used as default value (via braced-init-list). +#define DEFINE_BYREF_RW_PROPERTY(type, name, ...) \ +protected: \ + type name##_ { __VA_ARGS__ }; \ \ public: \ - Y_FORCE_INLINE type& name() \ + Y_FORCE_INLINE type& name() \ { \ return name##_; \ } \ \ - Y_FORCE_INLINE const type& name() const \ - { \ - return name##_; \ - } - -//! Defines a trivial public read-write property that is passed by reference -//! and is not inline-initialized. -#define DEFINE_BYREF_RW_PROPERTY_NO_INIT(type, name) \ -protected: \ - type name##_; \ - \ -public: \ - Y_FORCE_INLINE type& name() \ - { \ - return name##_; \ - } \ - \ - Y_FORCE_INLINE const type& name() const \ + Y_FORCE_INLINE const type& name() const \ { \ return name##_; \ } +//! Defines a trivial public read-write property that is passed by reference +//! and is not inline-initialized. +#define DEFINE_BYREF_RW_PROPERTY_NO_INIT(type, name) \ +protected: \ + type name##_; \ + \ +public: \ + Y_FORCE_INLINE type& name() \ + { \ + return name##_; \ + } \ + \ + Y_FORCE_INLINE const type& name() const \ + { \ + return name##_; \ + } + //! Forwards a trivial public read-write property that is passed by reference. #define DELEGATE_BYREF_RW_PROPERTY(declaringType, type, name, delegateTo) \ type& declaringType::name() \ @@ -59,32 +59,32 @@ public: \ //! Declares a trivial public read-only property that is passed by reference. #define DECLARE_BYREF_RO_PROPERTY(type, name) \ public: \ - const type& name() const; - -//! Defines a trivial public read-only property that is passed by reference. -//! All arguments after name are used as default value (via braced-init-list). -#define DEFINE_BYREF_RO_PROPERTY(type, name, ...) \ -protected: \ - type name##_ { __VA_ARGS__ }; \ - \ -public: \ - Y_FORCE_INLINE const type& name() const \ - { \ - return name##_; \ - } - -//! Defines a trivial public read-only property that is passed by reference -//! and is not inline-initialized. -#define DEFINE_BYREF_RO_PROPERTY_NO_INIT(type, name) \ -protected: \ - type name##_; \ - \ -public: \ - Y_FORCE_INLINE const type& name() const \ - { \ - return name##_; \ - } + const type& name() const; +//! Defines a trivial public read-only property that is passed by reference. +//! All arguments after name are used as default value (via braced-init-list). +#define DEFINE_BYREF_RO_PROPERTY(type, name, ...) \ +protected: \ + type name##_ { __VA_ARGS__ }; \ + \ +public: \ + Y_FORCE_INLINE const type& name() const \ + { \ + return name##_; \ + } + +//! Defines a trivial public read-only property that is passed by reference +//! and is not inline-initialized. +#define DEFINE_BYREF_RO_PROPERTY_NO_INIT(type, name) \ +protected: \ + type name##_; \ + \ +public: \ + Y_FORCE_INLINE const type& name() const \ + { \ + return name##_; \ + } + //! Forwards a trivial public read-only property that is passed by reference. #define DELEGATE_BYREF_RO_PROPERTY(declaringType, type, name, delegateTo) \ const type& declaringType::name() const \ @@ -98,21 +98,21 @@ public: \ #define DECLARE_BYVAL_RW_PROPERTY(type, name) \ public: \ type Get##name() const; \ - void Set##name(type value); + void Set##name(type value); -//! Defines a trivial public read-write property that is passed by value. -//! All arguments after name are used as default value (via braced-init-list). -#define DEFINE_BYVAL_RW_PROPERTY(type, name, ...) \ -protected: \ - type name##_ { __VA_ARGS__ }; \ +//! Defines a trivial public read-write property that is passed by value. +//! All arguments after name are used as default value (via braced-init-list). +#define DEFINE_BYVAL_RW_PROPERTY(type, name, ...) \ +protected: \ + type name##_ { __VA_ARGS__ }; \ \ public: \ - Y_FORCE_INLINE type Get##name() const \ + Y_FORCE_INLINE type Get##name() const \ { \ return name##_; \ } \ \ - Y_FORCE_INLINE void Set##name(type value) \ + Y_FORCE_INLINE void Set##name(type value) \ { \ name##_ = value; \ } \ @@ -139,24 +139,24 @@ public: \ name##_ = value; \ return std::move(*this); \ } \ - -//! Defines a trivial public read-write property that is passed by value -//! and is not inline-initialized. -#define DEFINE_BYVAL_RW_PROPERTY_NO_INIT(type, name, ...) \ -protected: \ - type name##_; \ - \ -public: \ - Y_FORCE_INLINE type Get##name() const \ - { \ - return name##_; \ - } \ - \ - Y_FORCE_INLINE void Set##name(type value) \ - { \ - name##_ = value; \ - } \ - + +//! Defines a trivial public read-write property that is passed by value +//! and is not inline-initialized. +#define DEFINE_BYVAL_RW_PROPERTY_NO_INIT(type, name, ...) \ +protected: \ + type name##_; \ + \ +public: \ + Y_FORCE_INLINE type Get##name() const \ + { \ + return name##_; \ + } \ + \ + Y_FORCE_INLINE void Set##name(type value) \ + { \ + name##_ = value; \ + } \ + //! Forwards a trivial public read-write property that is passed by value. #define DELEGATE_BYVAL_RW_PROPERTY(declaringType, type, name, delegateTo) \ type declaringType::Get##name() const \ @@ -164,7 +164,7 @@ public: \ return (delegateTo).Get##name(); \ } \ \ - void declaringType::Set##name(type value) \ + void declaringType::Set##name(type value) \ { \ (delegateTo).Set##name(value); \ } @@ -176,31 +176,31 @@ public: \ public: \ type Get##name() const; -//! Defines a trivial public read-only property that is passed by value. -//! All arguments after name are used as default value (via braced-init-list). -#define DEFINE_BYVAL_RO_PROPERTY(type, name, ...) \ -protected: \ - type name##_ { __VA_ARGS__ }; \ - \ -public: \ - Y_FORCE_INLINE type Get##name() const \ - { \ - return name##_; \ - } - - -//! Defines a trivial public read-only property that is passed by value -//! and is not inline-initialized. -#define DEFINE_BYVAL_RO_PROPERTY_NO_INIT(type, name) \ -protected: \ - type name##_; \ - \ -public: \ - Y_FORCE_INLINE type Get##name() const \ - { \ - return name##_; \ - } - +//! Defines a trivial public read-only property that is passed by value. +//! All arguments after name are used as default value (via braced-init-list). +#define DEFINE_BYVAL_RO_PROPERTY(type, name, ...) \ +protected: \ + type name##_ { __VA_ARGS__ }; \ + \ +public: \ + Y_FORCE_INLINE type Get##name() const \ + { \ + return name##_; \ + } + + +//! Defines a trivial public read-only property that is passed by value +//! and is not inline-initialized. +#define DEFINE_BYVAL_RO_PROPERTY_NO_INIT(type, name) \ +protected: \ + type name##_; \ + \ +public: \ + Y_FORCE_INLINE type Get##name() const \ + { \ + return name##_; \ + } + //! Forwards a trivial public read-only property that is passed by value. #define DELEGATE_BYVAL_RO_PROPERTY(declaringType, type, name, delegateTo) \ type declaringType::Get##name() \ diff --git a/library/cpp/yt/misc/source_location.cpp b/library/cpp/yt/misc/source_location.cpp index 8d22d43636..c632378050 100644 --- a/library/cpp/yt/misc/source_location.cpp +++ b/library/cpp/yt/misc/source_location.cpp @@ -1,54 +1,54 @@ -#include "source_location.h" - -#include <string.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -const char* TSourceLocation::GetFileName() const -{ - return FileName_; -} - -int TSourceLocation::GetLine() const -{ - return Line_; -} - -bool TSourceLocation::IsValid() const -{ - return FileName_ != nullptr; -} - -bool TSourceLocation::operator<(const TSourceLocation& other) const -{ - const char* fileName = FileName_ ? FileName_ : ""; - const char* otherFileName = other.FileName_ ? other.FileName_ : ""; - int fileNameResult = strcmp(fileName, otherFileName); - if (fileNameResult != 0) { +#include "source_location.h" + +#include <string.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +const char* TSourceLocation::GetFileName() const +{ + return FileName_; +} + +int TSourceLocation::GetLine() const +{ + return Line_; +} + +bool TSourceLocation::IsValid() const +{ + return FileName_ != nullptr; +} + +bool TSourceLocation::operator<(const TSourceLocation& other) const +{ + const char* fileName = FileName_ ? FileName_ : ""; + const char* otherFileName = other.FileName_ ? other.FileName_ : ""; + int fileNameResult = strcmp(fileName, otherFileName); + if (fileNameResult != 0) { return fileNameResult < 0; - } - - if (Line_ < other.Line_) { - return true; - } - if (Line_ > other.Line_) { - return false; - } - - return false; -} - -bool TSourceLocation::operator==(const TSourceLocation& other) const -{ - const char* fileName = FileName_ ? FileName_ : ""; - const char* otherFileName = other.FileName_ ? other.FileName_ : ""; - return - strcmp(fileName, otherFileName) == 0 && - Line_ == other.Line_; -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT + } + + if (Line_ < other.Line_) { + return true; + } + if (Line_ > other.Line_) { + return false; + } + + return false; +} + +bool TSourceLocation::operator==(const TSourceLocation& other) const +{ + const char* fileName = FileName_ ? FileName_ : ""; + const char* otherFileName = other.FileName_ ? other.FileName_ : ""; + return + strcmp(fileName, otherFileName) == 0 && + Line_ == other.Line_; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/source_location.h b/library/cpp/yt/misc/source_location.h index 84213eea70..b59896fcdd 100644 --- a/library/cpp/yt/misc/source_location.h +++ b/library/cpp/yt/misc/source_location.h @@ -1,38 +1,38 @@ -#pragma once - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -class TSourceLocation -{ -public: - TSourceLocation() - : FileName_(nullptr) - , Line_(-1) - { } - - TSourceLocation(const char* fileName, int line) - : FileName_(fileName) - , Line_(line) - { } - - const char* GetFileName() const; - int GetLine() const; - bool IsValid() const; - - bool operator<(const TSourceLocation& other) const; - bool operator==(const TSourceLocation& other) const; - -private: - const char* FileName_; - int Line_; - -}; - -//! Defines a macro to record the current source location. -#define FROM_HERE ::NYT::TSourceLocation(__FILE__, __LINE__) - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#pragma once + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +class TSourceLocation +{ +public: + TSourceLocation() + : FileName_(nullptr) + , Line_(-1) + { } + + TSourceLocation(const char* fileName, int line) + : FileName_(fileName) + , Line_(line) + { } + + const char* GetFileName() const; + int GetLine() const; + bool IsValid() const; + + bool operator<(const TSourceLocation& other) const; + bool operator==(const TSourceLocation& other) const; + +private: + const char* FileName_; + int Line_; + +}; + +//! Defines a macro to record the current source location. +#define FROM_HERE ::NYT::TSourceLocation(__FILE__, __LINE__) + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/unittests/enum_ut.cpp b/library/cpp/yt/misc/unittests/enum_ut.cpp index 6af11b04dc..0ee906d2ae 100644 --- a/library/cpp/yt/misc/unittests/enum_ut.cpp +++ b/library/cpp/yt/misc/unittests/enum_ut.cpp @@ -1,250 +1,250 @@ #include <library/cpp/testing/gtest/gtest.h> - + #include <library/cpp/yt/misc/enum.h> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -DEFINE_ENUM(ESimple, - (X) - (Y) - (Z) -); - -DEFINE_ENUM(EColor, - ((Red) (10)) - ((Green)(20)) - ((Blue) (30)) - (Black) - (White) -); - -DEFINE_BIT_ENUM(EFlag, - ((_1)(0x0001)) - ((_2)(0x0002)) - ((_3)(0x0004)) - ((_4)(0x0008)) -); - -DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(EMultipleNames, int, - (A1) - ((A2)(0)) - (B) - (C) - ((D1)(100)) - ((D2)(100)) -); - -//////////////////////////////////////////////////////////////////////////////// - -template <class T, size_t N> -std::vector<T> ToVector(std::array<T, N> array) -{ - return std::vector<T>(array.begin(), array.end()); -} - -TEST(TEnumTest, Domain) -{ - EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize); - std::vector<ESimple> v { - ESimple::X, - ESimple::Y, - ESimple::Z - }; - EXPECT_EQ(v, ToVector(TEnumTraits<ESimple>::GetDomainValues())); - EXPECT_EQ(ESimple::X, TEnumTraits<ESimple>::GetMinValue()); - EXPECT_EQ(ESimple::Z, TEnumTraits<ESimple>::GetMaxValue()); -} - -TEST(TEnumTest, Basic) -{ - EXPECT_EQ(0, static_cast<int>(ESimple::X)); - EXPECT_EQ(1, static_cast<int>(ESimple::Y)); - EXPECT_EQ(2, static_cast<int>(ESimple::Z)); - - EXPECT_EQ(0, static_cast<int>(EColor( ))); - EXPECT_EQ(5, static_cast<int>(EColor(5))); - - EXPECT_EQ(10, static_cast<int>(EColor::Red )); - EXPECT_EQ(20, static_cast<int>(EColor::Green)); - EXPECT_EQ(30, static_cast<int>(EColor::Blue )); - EXPECT_EQ(31, static_cast<int>(EColor::Black)); - EXPECT_EQ(32, static_cast<int>(EColor::White)); -} - -TEST(TEnumTest, ToString) -{ - EXPECT_EQ("EColor(0)", ToString(EColor( ))); - EXPECT_EQ("EColor(5)", ToString(EColor(5))); - - EXPECT_EQ("Red", ToString(EColor(EColor::Red ))); - EXPECT_EQ("Green", ToString(EColor::Green)); - EXPECT_EQ("Blue", ToString(EColor(EColor::Blue ))); - EXPECT_EQ("Black", ToString(EColor::Black)); - EXPECT_EQ("White", ToString(EColor::White)); -} - -TEST(TEnumTest, FromString) -{ - EXPECT_EQ(EColor::Red , TEnumTraits<EColor>::FromString("Red" )); - EXPECT_EQ(EColor::Green, TEnumTraits<EColor>::FromString("Green")); - EXPECT_EQ(EColor::Blue , TEnumTraits<EColor>::FromString("Blue" )); - EXPECT_EQ(EColor::Black, TEnumTraits<EColor>::FromString("Black")); - EXPECT_EQ(EColor::White, TEnumTraits<EColor>::FromString("White")); - - EXPECT_THROW(TEnumTraits<EColor>::FromString("Pink"), std::exception); - - EColor color; - bool returnValue; - - returnValue = TEnumTraits<EColor>::FindValueByLiteral("Red", &color); - EXPECT_EQ(EColor::Red, color); - EXPECT_TRUE(returnValue); - - returnValue = TEnumTraits<EColor>::FindValueByLiteral("Pink", &color); - EXPECT_EQ(EColor::Red, color); - EXPECT_FALSE(returnValue); -} - -TEST(TEnumTest, Ordering) -{ - ESimple a(ESimple::X); - ESimple b(ESimple::Y); - ESimple c(ESimple::Y); - ESimple d(ESimple::Z); - - EXPECT_FALSE(a < a); EXPECT_FALSE(a > a); - EXPECT_TRUE (a < b); EXPECT_TRUE (b > a); - EXPECT_TRUE (a < c); EXPECT_TRUE (c > a); - EXPECT_TRUE (a < d); EXPECT_TRUE (d > a); - - EXPECT_FALSE(b < a); EXPECT_FALSE(a > b); - EXPECT_FALSE(b < b); EXPECT_FALSE(b > b); - EXPECT_FALSE(b < c); EXPECT_FALSE(c > b); - EXPECT_TRUE (b < d); EXPECT_TRUE (d > b); - - EXPECT_FALSE(c < a); EXPECT_FALSE(a > c); - EXPECT_FALSE(c < b); EXPECT_FALSE(b > c); - EXPECT_FALSE(c < c); EXPECT_FALSE(c > c); - EXPECT_TRUE (c < d); EXPECT_TRUE (d > c); - - EXPECT_FALSE(d < a); EXPECT_FALSE(a > d); - EXPECT_FALSE(d < b); EXPECT_FALSE(b > d); - EXPECT_FALSE(d < c); EXPECT_FALSE(c > d); - EXPECT_FALSE(d < d); EXPECT_FALSE(d > d); - - EXPECT_TRUE (a <= b); - EXPECT_TRUE (b <= c); - EXPECT_TRUE (c <= d); - - EXPECT_TRUE (a == a); - EXPECT_FALSE(a == b); - EXPECT_TRUE (b == c); - EXPECT_FALSE(c == d); - EXPECT_FALSE(d == a); - - EXPECT_FALSE(a != a); - EXPECT_TRUE (a != b); - EXPECT_FALSE(b != c); - EXPECT_TRUE (c != d); - EXPECT_TRUE (d != a); -} - -TEST(TEnumTest, OrderingWithDomainValues) -{ - EColor color(EColor::Black); - - EXPECT_LT(EColor::Red, color); - EXPECT_LT(color, EColor::White); - - EXPECT_GT(color, EColor::Red); - EXPECT_GT(EColor::White, color); - - EXPECT_LE(EColor::Red, color); - EXPECT_LE(color, EColor::White); - - EXPECT_GE(EColor::White, color); - EXPECT_GE(color, EColor::Red); - - EXPECT_EQ(color, EColor::Black); - EXPECT_EQ(EColor::Black, color); - - EXPECT_NE(color, EColor::Blue); - EXPECT_NE(EColor::Blue, color); -} - -TEST(TEnumTest, DomainSize) -{ - EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize); - EXPECT_EQ(5, TEnumTraits<EColor>::DomainSize); -} - -TEST(TEnumTest, DomainValues) -{ - std::vector<ESimple> simpleValues; - simpleValues.push_back(ESimple::X); - simpleValues.push_back(ESimple::Y); - simpleValues.push_back(ESimple::Z); - EXPECT_EQ(simpleValues, ToVector(TEnumTraits<ESimple>::GetDomainValues())); - - std::vector<EColor> colorValues; - colorValues.push_back(EColor::Red); - colorValues.push_back(EColor::Green); - colorValues.push_back(EColor::Blue); - colorValues.push_back(EColor::Black); - colorValues.push_back(EColor::White); - EXPECT_EQ(colorValues, ToVector(TEnumTraits<EColor>::GetDomainValues())); -} - -TEST(TEnumTest, Decompose1) -{ - auto f = EFlag(0); - std::vector<EFlag> ff { }; - EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); -} - -TEST(TEnumTest, Decompose2) -{ - auto f = EFlag::_1; - std::vector<EFlag> ff {EFlag::_1}; - EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); -} - -TEST(TEnumTest, Decompose3) -{ - auto f = EFlag(EFlag::_1|EFlag::_2); - std::vector<EFlag> ff{EFlag::_1, EFlag::_2}; - EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); -} - -TEST(TEnumTest, Decompose4) -{ - auto f = EFlag(EFlag::_2|EFlag::_4); - std::vector<EFlag> ff{EFlag::_2, EFlag::_4}; - EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); -} - -TEST(TEnumTest, MultipleNames) -{ - EXPECT_EQ(EMultipleNames::A1, TEnumTraits<EMultipleNames>::FromString("A1")); - EXPECT_EQ(EMultipleNames::A1, TEnumTraits<EMultipleNames>::FromString("A2")); - EXPECT_EQ(EMultipleNames::B, TEnumTraits<EMultipleNames>::FromString("B")); - EXPECT_EQ(EMultipleNames::C, TEnumTraits<EMultipleNames>::FromString("C")); - EXPECT_EQ(EMultipleNames::D1, TEnumTraits<EMultipleNames>::FromString("D1")); - EXPECT_EQ(EMultipleNames::D1, TEnumTraits<EMultipleNames>::FromString("D2")); - - EXPECT_EQ("A1", ToString(EMultipleNames::A1)); - EXPECT_EQ("A1", ToString(EMultipleNames::A2)); - EXPECT_EQ("B", ToString(EMultipleNames::B)); - EXPECT_EQ("C", ToString(EMultipleNames::C)); - EXPECT_EQ("D1", ToString(EMultipleNames::D1)); - EXPECT_EQ("D1", ToString(EMultipleNames::D2)); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT - + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +DEFINE_ENUM(ESimple, + (X) + (Y) + (Z) +); + +DEFINE_ENUM(EColor, + ((Red) (10)) + ((Green)(20)) + ((Blue) (30)) + (Black) + (White) +); + +DEFINE_BIT_ENUM(EFlag, + ((_1)(0x0001)) + ((_2)(0x0002)) + ((_3)(0x0004)) + ((_4)(0x0008)) +); + +DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(EMultipleNames, int, + (A1) + ((A2)(0)) + (B) + (C) + ((D1)(100)) + ((D2)(100)) +); + +//////////////////////////////////////////////////////////////////////////////// + +template <class T, size_t N> +std::vector<T> ToVector(std::array<T, N> array) +{ + return std::vector<T>(array.begin(), array.end()); +} + +TEST(TEnumTest, Domain) +{ + EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize); + std::vector<ESimple> v { + ESimple::X, + ESimple::Y, + ESimple::Z + }; + EXPECT_EQ(v, ToVector(TEnumTraits<ESimple>::GetDomainValues())); + EXPECT_EQ(ESimple::X, TEnumTraits<ESimple>::GetMinValue()); + EXPECT_EQ(ESimple::Z, TEnumTraits<ESimple>::GetMaxValue()); +} + +TEST(TEnumTest, Basic) +{ + EXPECT_EQ(0, static_cast<int>(ESimple::X)); + EXPECT_EQ(1, static_cast<int>(ESimple::Y)); + EXPECT_EQ(2, static_cast<int>(ESimple::Z)); + + EXPECT_EQ(0, static_cast<int>(EColor( ))); + EXPECT_EQ(5, static_cast<int>(EColor(5))); + + EXPECT_EQ(10, static_cast<int>(EColor::Red )); + EXPECT_EQ(20, static_cast<int>(EColor::Green)); + EXPECT_EQ(30, static_cast<int>(EColor::Blue )); + EXPECT_EQ(31, static_cast<int>(EColor::Black)); + EXPECT_EQ(32, static_cast<int>(EColor::White)); +} + +TEST(TEnumTest, ToString) +{ + EXPECT_EQ("EColor(0)", ToString(EColor( ))); + EXPECT_EQ("EColor(5)", ToString(EColor(5))); + + EXPECT_EQ("Red", ToString(EColor(EColor::Red ))); + EXPECT_EQ("Green", ToString(EColor::Green)); + EXPECT_EQ("Blue", ToString(EColor(EColor::Blue ))); + EXPECT_EQ("Black", ToString(EColor::Black)); + EXPECT_EQ("White", ToString(EColor::White)); +} + +TEST(TEnumTest, FromString) +{ + EXPECT_EQ(EColor::Red , TEnumTraits<EColor>::FromString("Red" )); + EXPECT_EQ(EColor::Green, TEnumTraits<EColor>::FromString("Green")); + EXPECT_EQ(EColor::Blue , TEnumTraits<EColor>::FromString("Blue" )); + EXPECT_EQ(EColor::Black, TEnumTraits<EColor>::FromString("Black")); + EXPECT_EQ(EColor::White, TEnumTraits<EColor>::FromString("White")); + + EXPECT_THROW(TEnumTraits<EColor>::FromString("Pink"), std::exception); + + EColor color; + bool returnValue; + + returnValue = TEnumTraits<EColor>::FindValueByLiteral("Red", &color); + EXPECT_EQ(EColor::Red, color); + EXPECT_TRUE(returnValue); + + returnValue = TEnumTraits<EColor>::FindValueByLiteral("Pink", &color); + EXPECT_EQ(EColor::Red, color); + EXPECT_FALSE(returnValue); +} + +TEST(TEnumTest, Ordering) +{ + ESimple a(ESimple::X); + ESimple b(ESimple::Y); + ESimple c(ESimple::Y); + ESimple d(ESimple::Z); + + EXPECT_FALSE(a < a); EXPECT_FALSE(a > a); + EXPECT_TRUE (a < b); EXPECT_TRUE (b > a); + EXPECT_TRUE (a < c); EXPECT_TRUE (c > a); + EXPECT_TRUE (a < d); EXPECT_TRUE (d > a); + + EXPECT_FALSE(b < a); EXPECT_FALSE(a > b); + EXPECT_FALSE(b < b); EXPECT_FALSE(b > b); + EXPECT_FALSE(b < c); EXPECT_FALSE(c > b); + EXPECT_TRUE (b < d); EXPECT_TRUE (d > b); + + EXPECT_FALSE(c < a); EXPECT_FALSE(a > c); + EXPECT_FALSE(c < b); EXPECT_FALSE(b > c); + EXPECT_FALSE(c < c); EXPECT_FALSE(c > c); + EXPECT_TRUE (c < d); EXPECT_TRUE (d > c); + + EXPECT_FALSE(d < a); EXPECT_FALSE(a > d); + EXPECT_FALSE(d < b); EXPECT_FALSE(b > d); + EXPECT_FALSE(d < c); EXPECT_FALSE(c > d); + EXPECT_FALSE(d < d); EXPECT_FALSE(d > d); + + EXPECT_TRUE (a <= b); + EXPECT_TRUE (b <= c); + EXPECT_TRUE (c <= d); + + EXPECT_TRUE (a == a); + EXPECT_FALSE(a == b); + EXPECT_TRUE (b == c); + EXPECT_FALSE(c == d); + EXPECT_FALSE(d == a); + + EXPECT_FALSE(a != a); + EXPECT_TRUE (a != b); + EXPECT_FALSE(b != c); + EXPECT_TRUE (c != d); + EXPECT_TRUE (d != a); +} + +TEST(TEnumTest, OrderingWithDomainValues) +{ + EColor color(EColor::Black); + + EXPECT_LT(EColor::Red, color); + EXPECT_LT(color, EColor::White); + + EXPECT_GT(color, EColor::Red); + EXPECT_GT(EColor::White, color); + + EXPECT_LE(EColor::Red, color); + EXPECT_LE(color, EColor::White); + + EXPECT_GE(EColor::White, color); + EXPECT_GE(color, EColor::Red); + + EXPECT_EQ(color, EColor::Black); + EXPECT_EQ(EColor::Black, color); + + EXPECT_NE(color, EColor::Blue); + EXPECT_NE(EColor::Blue, color); +} + +TEST(TEnumTest, DomainSize) +{ + EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize); + EXPECT_EQ(5, TEnumTraits<EColor>::DomainSize); +} + +TEST(TEnumTest, DomainValues) +{ + std::vector<ESimple> simpleValues; + simpleValues.push_back(ESimple::X); + simpleValues.push_back(ESimple::Y); + simpleValues.push_back(ESimple::Z); + EXPECT_EQ(simpleValues, ToVector(TEnumTraits<ESimple>::GetDomainValues())); + + std::vector<EColor> colorValues; + colorValues.push_back(EColor::Red); + colorValues.push_back(EColor::Green); + colorValues.push_back(EColor::Blue); + colorValues.push_back(EColor::Black); + colorValues.push_back(EColor::White); + EXPECT_EQ(colorValues, ToVector(TEnumTraits<EColor>::GetDomainValues())); +} + +TEST(TEnumTest, Decompose1) +{ + auto f = EFlag(0); + std::vector<EFlag> ff { }; + EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); +} + +TEST(TEnumTest, Decompose2) +{ + auto f = EFlag::_1; + std::vector<EFlag> ff {EFlag::_1}; + EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); +} + +TEST(TEnumTest, Decompose3) +{ + auto f = EFlag(EFlag::_1|EFlag::_2); + std::vector<EFlag> ff{EFlag::_1, EFlag::_2}; + EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); +} + +TEST(TEnumTest, Decompose4) +{ + auto f = EFlag(EFlag::_2|EFlag::_4); + std::vector<EFlag> ff{EFlag::_2, EFlag::_4}; + EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff); +} + +TEST(TEnumTest, MultipleNames) +{ + EXPECT_EQ(EMultipleNames::A1, TEnumTraits<EMultipleNames>::FromString("A1")); + EXPECT_EQ(EMultipleNames::A1, TEnumTraits<EMultipleNames>::FromString("A2")); + EXPECT_EQ(EMultipleNames::B, TEnumTraits<EMultipleNames>::FromString("B")); + EXPECT_EQ(EMultipleNames::C, TEnumTraits<EMultipleNames>::FromString("C")); + EXPECT_EQ(EMultipleNames::D1, TEnumTraits<EMultipleNames>::FromString("D1")); + EXPECT_EQ(EMultipleNames::D1, TEnumTraits<EMultipleNames>::FromString("D2")); + + EXPECT_EQ("A1", ToString(EMultipleNames::A1)); + EXPECT_EQ("A1", ToString(EMultipleNames::A2)); + EXPECT_EQ("B", ToString(EMultipleNames::B)); + EXPECT_EQ("C", ToString(EMultipleNames::C)); + EXPECT_EQ("D1", ToString(EMultipleNames::D1)); + EXPECT_EQ("D1", ToString(EMultipleNames::D2)); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT + diff --git a/library/cpp/yt/misc/unittests/guid_ut.cpp b/library/cpp/yt/misc/unittests/guid_ut.cpp index ce9ee52109..bbbd6037aa 100644 --- a/library/cpp/yt/misc/unittests/guid_ut.cpp +++ b/library/cpp/yt/misc/unittests/guid_ut.cpp @@ -1,20 +1,20 @@ #include <library/cpp/testing/gtest/gtest.h> - + #include <library/cpp/yt/misc/guid.h> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TGuidTest, RandomGuids) -{ - auto guid = TGuid::Create(); - auto otherGuid = TGuid::Create(); - EXPECT_FALSE(guid == otherGuid); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TGuidTest, RandomGuids) +{ + auto guid = TGuid::Create(); + auto otherGuid = TGuid::Create(); + EXPECT_FALSE(guid == otherGuid); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/misc/unittests/preprocessor_ut.cpp b/library/cpp/yt/misc/unittests/preprocessor_ut.cpp index 397e2a6a61..b8ec44c00b 100644 --- a/library/cpp/yt/misc/unittests/preprocessor_ut.cpp +++ b/library/cpp/yt/misc/unittests/preprocessor_ut.cpp @@ -1,102 +1,102 @@ -#include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/yt/misc/preprocessor.h> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TPreprocessorTest, Concatenation) -{ - EXPECT_EQ(12, PP_CONCAT(1, 2)); - EXPECT_STREQ("FooBar", PP_STRINGIZE(PP_CONCAT(Foo, Bar))); -} - -TEST(TPreprocessorTest, Stringize) -{ - EXPECT_STREQ(PP_STRINGIZE(123456), "123456"); - EXPECT_STREQ(PP_STRINGIZE(FooBar), "FooBar"); - EXPECT_STREQ(PP_STRINGIZE(T::XYZ), "T::XYZ"); -} - -TEST(TPreprocessorTest, Count) -{ - EXPECT_EQ(0, PP_COUNT()); - EXPECT_EQ(1, PP_COUNT((0))); - EXPECT_EQ(2, PP_COUNT((0)(0))); - EXPECT_EQ(3, PP_COUNT((0)(0)(0))); - EXPECT_EQ(4, PP_COUNT((0)(0)(0)(0))); - EXPECT_EQ(5, PP_COUNT((0)(0)(0)(0)(0))); -} - -TEST(TPreprocessorTest, Kill) -{ - EXPECT_STREQ("PP_NIL (0)", PP_STRINGIZE(PP_NIL PP_KILL((0), 0))); - EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_KILL((0), 1))); - EXPECT_STREQ("PP_NIL (0)(1)(2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 0))); - EXPECT_STREQ("PP_NIL (1)(2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 1))); - EXPECT_STREQ("PP_NIL (2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 2))); - EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 3))); -} - -TEST(TPreprocessorTest, Head) -{ - EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)))); - EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)(1)))); - EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)(1)(2)))); -} - -TEST(TPreprocessorTest, Tail) -{ - EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_TAIL((0)))); - EXPECT_STREQ("PP_NIL (1)", PP_STRINGIZE(PP_NIL PP_TAIL((0)(1)))); - EXPECT_STREQ("PP_NIL (1)(2)", PP_STRINGIZE(PP_NIL PP_TAIL((0)(1)(2)))); -} - -TEST(TPreprocessorTest, ForEach) -{ - EXPECT_STREQ( - "\"Foo\" \"Bar\" \"Spam\" \"Ham\"", - PP_STRINGIZE(PP_FOR_EACH(PP_STRINGIZE, (Foo)(Bar)(Spam)(Ham))) - ); -#define my_functor(x) +x+ - EXPECT_STREQ( - "+1+ +2+ +3+", - PP_STRINGIZE(PP_FOR_EACH(my_functor, (1)(2)(3))) - ); -#undef my_functor -} - -TEST(TPreprocessorTest, MakeSingleton) -{ - EXPECT_EQ(1, PP_ELEMENT((1), 0)); - EXPECT_EQ(1, PP_ELEMENT((1)(2), 0)); - EXPECT_EQ(2, PP_ELEMENT((1)(2), 1)); - EXPECT_EQ(1, PP_ELEMENT((1)(2)(3), 0)); - EXPECT_EQ(2, PP_ELEMENT((1)(2)(3), 1)); - EXPECT_EQ(3, PP_ELEMENT((1)(2)(3), 2)); - EXPECT_EQ(1, PP_ELEMENT((1)(2)(3)(4), 0)); - EXPECT_EQ(2, PP_ELEMENT((1)(2)(3)(4), 1)); - EXPECT_EQ(3, PP_ELEMENT((1)(2)(3)(4), 2)); - EXPECT_EQ(4, PP_ELEMENT((1)(2)(3)(4), 3)); -} - -TEST(TPreprocessorTest, Conditional) -{ - EXPECT_EQ(1, PP_IF(PP_TRUE, 1, 2)); - EXPECT_EQ(2, PP_IF(PP_FALSE, 1, 2)); -} - -TEST(TPreprocessorTest, IsSequence) -{ - EXPECT_STREQ("PP_FALSE", PP_STRINGIZE(PP_IS_SEQUENCE( 0 ))); - EXPECT_STREQ("PP_TRUE", PP_STRINGIZE(PP_IS_SEQUENCE((0) ))); - EXPECT_STREQ("PP_TRUE", PP_STRINGIZE(PP_IS_SEQUENCE((0)(0)))); - EXPECT_STREQ("PP_FALSE", PP_STRINGIZE(PP_IS_SEQUENCE(PP_NIL))); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/yt/misc/preprocessor.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TPreprocessorTest, Concatenation) +{ + EXPECT_EQ(12, PP_CONCAT(1, 2)); + EXPECT_STREQ("FooBar", PP_STRINGIZE(PP_CONCAT(Foo, Bar))); +} + +TEST(TPreprocessorTest, Stringize) +{ + EXPECT_STREQ(PP_STRINGIZE(123456), "123456"); + EXPECT_STREQ(PP_STRINGIZE(FooBar), "FooBar"); + EXPECT_STREQ(PP_STRINGIZE(T::XYZ), "T::XYZ"); +} + +TEST(TPreprocessorTest, Count) +{ + EXPECT_EQ(0, PP_COUNT()); + EXPECT_EQ(1, PP_COUNT((0))); + EXPECT_EQ(2, PP_COUNT((0)(0))); + EXPECT_EQ(3, PP_COUNT((0)(0)(0))); + EXPECT_EQ(4, PP_COUNT((0)(0)(0)(0))); + EXPECT_EQ(5, PP_COUNT((0)(0)(0)(0)(0))); +} + +TEST(TPreprocessorTest, Kill) +{ + EXPECT_STREQ("PP_NIL (0)", PP_STRINGIZE(PP_NIL PP_KILL((0), 0))); + EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_KILL((0), 1))); + EXPECT_STREQ("PP_NIL (0)(1)(2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 0))); + EXPECT_STREQ("PP_NIL (1)(2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 1))); + EXPECT_STREQ("PP_NIL (2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 2))); + EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 3))); +} + +TEST(TPreprocessorTest, Head) +{ + EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)))); + EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)(1)))); + EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)(1)(2)))); +} + +TEST(TPreprocessorTest, Tail) +{ + EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_TAIL((0)))); + EXPECT_STREQ("PP_NIL (1)", PP_STRINGIZE(PP_NIL PP_TAIL((0)(1)))); + EXPECT_STREQ("PP_NIL (1)(2)", PP_STRINGIZE(PP_NIL PP_TAIL((0)(1)(2)))); +} + +TEST(TPreprocessorTest, ForEach) +{ + EXPECT_STREQ( + "\"Foo\" \"Bar\" \"Spam\" \"Ham\"", + PP_STRINGIZE(PP_FOR_EACH(PP_STRINGIZE, (Foo)(Bar)(Spam)(Ham))) + ); +#define my_functor(x) +x+ + EXPECT_STREQ( + "+1+ +2+ +3+", + PP_STRINGIZE(PP_FOR_EACH(my_functor, (1)(2)(3))) + ); +#undef my_functor +} + +TEST(TPreprocessorTest, MakeSingleton) +{ + EXPECT_EQ(1, PP_ELEMENT((1), 0)); + EXPECT_EQ(1, PP_ELEMENT((1)(2), 0)); + EXPECT_EQ(2, PP_ELEMENT((1)(2), 1)); + EXPECT_EQ(1, PP_ELEMENT((1)(2)(3), 0)); + EXPECT_EQ(2, PP_ELEMENT((1)(2)(3), 1)); + EXPECT_EQ(3, PP_ELEMENT((1)(2)(3), 2)); + EXPECT_EQ(1, PP_ELEMENT((1)(2)(3)(4), 0)); + EXPECT_EQ(2, PP_ELEMENT((1)(2)(3)(4), 1)); + EXPECT_EQ(3, PP_ELEMENT((1)(2)(3)(4), 2)); + EXPECT_EQ(4, PP_ELEMENT((1)(2)(3)(4), 3)); +} + +TEST(TPreprocessorTest, Conditional) +{ + EXPECT_EQ(1, PP_IF(PP_TRUE, 1, 2)); + EXPECT_EQ(2, PP_IF(PP_FALSE, 1, 2)); +} + +TEST(TPreprocessorTest, IsSequence) +{ + EXPECT_STREQ("PP_FALSE", PP_STRINGIZE(PP_IS_SEQUENCE( 0 ))); + EXPECT_STREQ("PP_TRUE", PP_STRINGIZE(PP_IS_SEQUENCE((0) ))); + EXPECT_STREQ("PP_TRUE", PP_STRINGIZE(PP_IS_SEQUENCE((0)(0)))); + EXPECT_STREQ("PP_FALSE", PP_STRINGIZE(PP_IS_SEQUENCE(PP_NIL))); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/misc/unittests/ya.make b/library/cpp/yt/misc/unittests/ya.make index 690082ca59..539c7c1a4e 100644 --- a/library/cpp/yt/misc/unittests/ya.make +++ b/library/cpp/yt/misc/unittests/ya.make @@ -1,15 +1,15 @@ -GTEST(unittester-library-misc) - -OWNER(g:yt) - -SRCS( +GTEST(unittester-library-misc) + +OWNER(g:yt) + +SRCS( enum_ut.cpp guid_ut.cpp - preprocessor_ut.cpp -) - -PEERDIR( - library/cpp/yt/misc -) - -END() + preprocessor_ut.cpp +) + +PEERDIR( + library/cpp/yt/misc +) + +END() diff --git a/library/cpp/yt/misc/variant-inl.h b/library/cpp/yt/misc/variant-inl.h index fb7d98d4be..73d302eece 100644 --- a/library/cpp/yt/misc/variant-inl.h +++ b/library/cpp/yt/misc/variant-inl.h @@ -1,70 +1,70 @@ -#ifndef VARIANT_INL_H_ -#error "Direct inclusion of this file is not allowed, include variant.h" +#ifndef VARIANT_INL_H_ +#error "Direct inclusion of this file is not allowed, include variant.h" // For the sake of sane code completion. #include "variant.h" -#endif - -#include <type_traits> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -namespace NDetail { - -template <class T> -struct TIndexOf<T> -{ - static constexpr size_t Value = std::numeric_limits<size_t>::max(); -}; - -template <class T, class T0, class... Ts> -struct TIndexOf<T, T0, Ts...> -{ - static constexpr size_t Value = std::is_same_v<T, T0> - ? 0 - : 1 + TIndexOf<T, Ts...>::Value; -}; - -template <size_t Index, class... Ts> -struct TVariantFormatter; - -template <size_t Index> -struct TVariantFormatter<Index> -{ - template <class TVariant> - static void Do(TStringBuilderBase* /*builder*/, const TVariant& /*variant*/, TStringBuf /*spec*/) - { } -}; - -template <size_t Index, class T, class... Ts> -struct TVariantFormatter<Index, T, Ts...> -{ - template <class TVariant> - static void Do(TStringBuilderBase* builder, const TVariant& variant, TStringBuf spec) - { - if (variant.index() == Index) { - FormatValue(builder, std::get<Index>(variant), spec); - } else { - TVariantFormatter<Index + 1, Ts...>::Do(builder, variant, spec); - } - } -}; - -} // namespace NDetail - -template <class... Ts> -void FormatValue(TStringBuilderBase* builder, const std::variant<Ts...>& variant, TStringBuf spec) -{ - NDetail::TVariantFormatter<0, Ts...>::Do(builder, variant, spec); -} - -template <class... Ts> -TString ToString(const std::variant<Ts...>& variant) -{ - return ToStringViaBuilder(variant); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#endif + +#include <type_traits> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + +template <class T> +struct TIndexOf<T> +{ + static constexpr size_t Value = std::numeric_limits<size_t>::max(); +}; + +template <class T, class T0, class... Ts> +struct TIndexOf<T, T0, Ts...> +{ + static constexpr size_t Value = std::is_same_v<T, T0> + ? 0 + : 1 + TIndexOf<T, Ts...>::Value; +}; + +template <size_t Index, class... Ts> +struct TVariantFormatter; + +template <size_t Index> +struct TVariantFormatter<Index> +{ + template <class TVariant> + static void Do(TStringBuilderBase* /*builder*/, const TVariant& /*variant*/, TStringBuf /*spec*/) + { } +}; + +template <size_t Index, class T, class... Ts> +struct TVariantFormatter<Index, T, Ts...> +{ + template <class TVariant> + static void Do(TStringBuilderBase* builder, const TVariant& variant, TStringBuf spec) + { + if (variant.index() == Index) { + FormatValue(builder, std::get<Index>(variant), spec); + } else { + TVariantFormatter<Index + 1, Ts...>::Do(builder, variant, spec); + } + } +}; + +} // namespace NDetail + +template <class... Ts> +void FormatValue(TStringBuilderBase* builder, const std::variant<Ts...>& variant, TStringBuf spec) +{ + NDetail::TVariantFormatter<0, Ts...>::Do(builder, variant, spec); +} + +template <class... Ts> +TString ToString(const std::variant<Ts...>& variant) +{ + return ToStringViaBuilder(variant); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/variant.h b/library/cpp/yt/misc/variant.h index 27c0a2bc08..a6b6821e1e 100644 --- a/library/cpp/yt/misc/variant.h +++ b/library/cpp/yt/misc/variant.h @@ -1,41 +1,41 @@ -#pragma once - -#include <variant> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -namespace NDetail { - -template <class T, class... Ts> -struct TIndexOf; - -} // namespace NDetail - -template <class T, class V> -struct TVariantIndex; - -template <class T, class... Ts> -struct TVariantIndex<T, std::variant<Ts...>> - : std::integral_constant<size_t, NDetail::TIndexOf<T, Ts...>::Value> -{ }; - -template <class T, class V> -constexpr size_t VariantIndexV = TVariantIndex<T, V>::value; - -//////////////////////////////////////////////////////////////////////////////// - -class TStringBuilderBase; - +#pragma once + +#include <variant> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + +template <class T, class... Ts> +struct TIndexOf; + +} // namespace NDetail + +template <class T, class V> +struct TVariantIndex; + +template <class T, class... Ts> +struct TVariantIndex<T, std::variant<Ts...>> + : std::integral_constant<size_t, NDetail::TIndexOf<T, Ts...>::Value> +{ }; + +template <class T, class V> +constexpr size_t VariantIndexV = TVariantIndex<T, V>::value; + +//////////////////////////////////////////////////////////////////////////////// + +class TStringBuilderBase; + +template <class... Ts> +void FormatValue(TStringBuilderBase* builder, const std::variant<Ts...>& variant, TStringBuf spec); + template <class... Ts> -void FormatValue(TStringBuilderBase* builder, const std::variant<Ts...>& variant, TStringBuf spec); - -template <class... Ts> -TString ToString(const std::variant<Ts...>& variant); - -//////////////////////////////////////////////////////////////////////////////// +TString ToString(const std::variant<Ts...>& variant); +//////////////////////////////////////////////////////////////////////////////// + //! A concise way of creating a functor with an overloaded operator(). /*! * Very useful for std::visit-ing variants. For example: @@ -69,8 +69,8 @@ auto Visit(T&& variant, U&&... visitorOverloads) //////////////////////////////////////////////////////////////////////////////// -} // namespace NYT - -#define VARIANT_INL_H_ -#include "variant-inl.h" -#undef VARIANT_INL_H_ +} // namespace NYT + +#define VARIANT_INL_H_ +#include "variant-inl.h" +#undef VARIANT_INL_H_ diff --git a/library/cpp/yt/misc/ya.make b/library/cpp/yt/misc/ya.make index bb76711ddd..76323eb06a 100644 --- a/library/cpp/yt/misc/ya.make +++ b/library/cpp/yt/misc/ya.make @@ -8,7 +8,7 @@ SRCS( ) PEERDIR( - library/cpp/yt/exception + library/cpp/yt/exception ) CHECK_DEPENDENT_DIRS( @@ -21,7 +21,7 @@ CHECK_DEPENDENT_DIRS( ) END() - -RECURSE_FOR_TESTS( - unittests -) + +RECURSE_FOR_TESTS( + unittests +) diff --git a/library/cpp/yt/small_containers/compact_set.h b/library/cpp/yt/small_containers/compact_set.h index 2ca8713ea7..a02afa833b 100644 --- a/library/cpp/yt/small_containers/compact_set.h +++ b/library/cpp/yt/small_containers/compact_set.h @@ -1,4 +1,4 @@ -//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===// +//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -32,7 +32,7 @@ namespace NYT { /// Note that any modification of the set may invalidate *all* iterators. template <typename T, unsigned N, typename C = std::less<T>> class TCompactSet -{ +{ private: /// Use a CompactVector to hold the elements here (even though it will never /// reach its 'large' stage) to avoid calling the default ctors of elements diff --git a/library/cpp/yt/small_containers/compact_vector-inl.h b/library/cpp/yt/small_containers/compact_vector-inl.h index 52507e4768..32a59bec50 100644 --- a/library/cpp/yt/small_containers/compact_vector-inl.h +++ b/library/cpp/yt/small_containers/compact_vector-inl.h @@ -1,694 +1,694 @@ -#ifndef COMPACT_VECTOR_INL_H_ -#error "Direct inclusion of this file is not allowed, include compact_vector.h" -// For the sake of sane code completion. -#include "compact_vector.h" -#endif -#undef COMPACT_VECTOR_INL_H_ - -#include <library/cpp/yt/assert/assert.h> - -#include <library/cpp/yt/malloc/malloc.h> - -#include <util/system/compiler.h> - -#include <algorithm> -#include <bit> - -#include <string.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -static_assert(sizeof(uintptr_t) == 8); - +#ifndef COMPACT_VECTOR_INL_H_ +#error "Direct inclusion of this file is not allowed, include compact_vector.h" +// For the sake of sane code completion. +#include "compact_vector.h" +#endif +#undef COMPACT_VECTOR_INL_H_ + +#include <library/cpp/yt/assert/assert.h> + +#include <library/cpp/yt/malloc/malloc.h> + +#include <util/system/compiler.h> + +#include <algorithm> +#include <bit> + +#include <string.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +static_assert(sizeof(uintptr_t) == 8); + // TODO(gritukan, babenko): Uncomment check below after DEVTOOLS-7870. // static_assert(std::endian::native == std::endian::little); -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -struct TCompactVectorOnHeapStorage -{ - T* End; - T* Capacity; - T Elements[0]; -}; - -//////////////////////////////////////////////////////////////////////////////// - -template <class TVector, class TPtr> -class TCompactVectorReallocationPtrAdjuster -{ -public: - TCompactVectorReallocationPtrAdjuster(TVector* vector, TPtr& ptr) - : Vector_(vector) - , Ptr_(ptr) +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +struct TCompactVectorOnHeapStorage +{ + T* End; + T* Capacity; + T Elements[0]; +}; + +//////////////////////////////////////////////////////////////////////////////// + +template <class TVector, class TPtr> +class TCompactVectorReallocationPtrAdjuster +{ +public: + TCompactVectorReallocationPtrAdjuster(TVector* vector, TPtr& ptr) + : Vector_(vector) + , Ptr_(ptr) , Index_(ptr >= Vector_->begin() && ptr <= Vector_->end() - ? std::distance(Vector_->begin(), const_cast<typename TVector::iterator>(ptr)) - : -1) - { } - - ~TCompactVectorReallocationPtrAdjuster() - { - if (Index_ >= 0) { - Ptr_ = Vector_->begin() + Index_; - } - } - -private: - TVector* const Vector_; - TPtr& Ptr_; - const ptrdiff_t Index_; -}; - -template <class TVector> -class TCompactVectorReallocationPtrAdjuster<TVector, std::nullptr_t> -{ -public: - TCompactVectorReallocationPtrAdjuster(TVector* /*vector*/, std::nullptr_t /*ptr*/) - { } -}; - -//////////////////////////////////////////////////////////////////////////////// - -template <class T, size_t N> -TCompactVector<T, N>::TCompactVector() noexcept -{ - InlineMeta_.SizePlusOne = 1; -} - -template <class T, size_t N> -TCompactVector<T, N>::TCompactVector(const TCompactVector& other) - : TCompactVector() -{ - assign(other.begin(), other.end()); -} - -template <class T, size_t N> -template <size_t OtherN> -TCompactVector<T, N>::TCompactVector(const TCompactVector<T, OtherN>& other) - : TCompactVector() -{ - assign(other.begin(), other.end()); -} - -template <class T, size_t N> + ? std::distance(Vector_->begin(), const_cast<typename TVector::iterator>(ptr)) + : -1) + { } + + ~TCompactVectorReallocationPtrAdjuster() + { + if (Index_ >= 0) { + Ptr_ = Vector_->begin() + Index_; + } + } + +private: + TVector* const Vector_; + TPtr& Ptr_; + const ptrdiff_t Index_; +}; + +template <class TVector> +class TCompactVectorReallocationPtrAdjuster<TVector, std::nullptr_t> +{ +public: + TCompactVectorReallocationPtrAdjuster(TVector* /*vector*/, std::nullptr_t /*ptr*/) + { } +}; + +//////////////////////////////////////////////////////////////////////////////// + +template <class T, size_t N> +TCompactVector<T, N>::TCompactVector() noexcept +{ + InlineMeta_.SizePlusOne = 1; +} + +template <class T, size_t N> +TCompactVector<T, N>::TCompactVector(const TCompactVector& other) + : TCompactVector() +{ + assign(other.begin(), other.end()); +} + +template <class T, size_t N> +template <size_t OtherN> +TCompactVector<T, N>::TCompactVector(const TCompactVector<T, OtherN>& other) + : TCompactVector() +{ + assign(other.begin(), other.end()); +} + +template <class T, size_t N> TCompactVector<T, N>::TCompactVector(TCompactVector&& other) noexcept(std::is_nothrow_move_constructible_v<T>) - : TCompactVector() -{ - swap(other); -} - -template <class T, size_t N> -template <size_t OtherN> -TCompactVector<T, N>::TCompactVector(TCompactVector<T, OtherN>&& other) - : TCompactVector() -{ - swap(other); -} - -template <class T, size_t N> -TCompactVector<T, N>::TCompactVector(size_type count) - : TCompactVector() -{ - assign(count, T()); -} - -template <class T, size_t N> -TCompactVector<T, N>::TCompactVector(size_type count, const T& value) - : TCompactVector() -{ - assign(count, value); -} - -template <class T, size_t N> -template <class TIterator> -TCompactVector<T, N>::TCompactVector(TIterator first, TIterator last) - : TCompactVector() -{ - assign(first, last); -} - -template <class T, size_t N> -TCompactVector<T, N>::TCompactVector(std::initializer_list<T> list) - : TCompactVector() -{ - assign(list.begin(), list.end()); -} - -template <class T, size_t N> -TCompactVector<T, N>::~TCompactVector() -{ - if (Y_LIKELY(IsInline())) { - Destroy(&InlineElements_[0], &InlineElements_[InlineMeta_.SizePlusOne - 1]); - } else { - auto* storage = OnHeapMeta_.Storage; - Destroy(storage->Elements, storage->End); - ::free(storage); - } -} - -template <class T, size_t N> -bool TCompactVector<T, N>::empty() const -{ - if (Y_LIKELY(IsInline())) { - return InlineMeta_.SizePlusOne == 1; - } else { - const auto* storage = OnHeapMeta_.Storage; - return storage->Elements == storage->End; - } -} - -template <class T, size_t N> -auto TCompactVector<T, N>::begin() -> iterator -{ - return Y_LIKELY(IsInline()) ? &InlineElements_[0] : OnHeapMeta_.Storage->Elements; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::begin() const -> const_iterator -{ - return const_cast<TCompactVector*>(this)->begin(); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::end() -> iterator -{ - return Y_LIKELY(IsInline()) ? &InlineElements_[InlineMeta_.SizePlusOne - 1] : OnHeapMeta_.Storage->End; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::end() const -> const_iterator -{ - return const_cast<TCompactVector*>(this)->end(); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::rbegin() -> reverse_iterator -{ - return static_cast<reverse_iterator>(end()); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::rbegin() const -> const_reverse_iterator -{ - return static_cast<const_reverse_iterator>(end()); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::rend() -> reverse_iterator -{ - return static_cast<reverse_iterator>(begin()); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::rend() const -> const_reverse_iterator -{ - return static_cast<const_reverse_iterator>(begin()); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::size() const -> size_type -{ - if (Y_LIKELY(IsInline())) { - return InlineMeta_.SizePlusOne - 1; - } else { - const auto* storage = OnHeapMeta_.Storage; - return storage->End - storage->Elements; - } -} - -template <class T, size_t N> -auto TCompactVector<T, N>::capacity() const -> size_type -{ - if (Y_LIKELY(IsInline())) { - return N; - } else { - const auto* storage = OnHeapMeta_.Storage; - return storage->Capacity - storage->Elements; - } -} - -template <class T, size_t N> -auto TCompactVector<T, N>::max_size() const -> size_type -{ - return static_cast<size_type>(-1) / sizeof(T); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::data() -> pointer -{ - return static_cast<pointer>(begin()); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::data() const -> const_pointer -{ - return static_cast<const_pointer>(begin()); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::operator[](size_type index) -> reference -{ - YT_ASSERT(index < size()); - return begin()[index]; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::operator[](size_type index) const -> const_reference -{ - return const_cast<TCompactVector*>(this)->operator[](index); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::front() -> reference -{ - YT_ASSERT(!empty()); - return begin()[0]; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::front() const -> const_reference -{ - return const_cast<TCompactVector*>(this)->front(); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::back() -> reference -{ - YT_ASSERT(!empty()); - return end()[-1]; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::back() const -> const_reference -{ - return const_cast<TCompactVector*>(this)->back(); -} - -template <class T, size_t N> -void TCompactVector<T, N>::push_back(const T& value) -{ - PushBackImpl( - &value, - [&] (T* dst, const T* value) { - ::new(dst) T(*value); - }); -} - -template <class T, size_t N> -void TCompactVector<T, N>::push_back(T&& value) -{ - PushBackImpl( - &value, - [&] (T* dst, T* value) { - ::new(dst) T(std::move(*value)); - }); -} - -template <class T, size_t N> -template <class... TArgs> -auto TCompactVector<T, N>::emplace(const_iterator pos, TArgs&&... args) -> iterator -{ - return InsertOneImpl( - pos, - nullptr, - [&] (auto* dst, std::nullptr_t) { - ::new(dst) T(std::forward<TArgs>(args)...); - }, - [&] (auto* dst, std::nullptr_t) { - *dst = T(std::forward<TArgs>(args)...); - }); -} - -template <class T, size_t N> -template <class... TArgs> -auto TCompactVector<T, N>::emplace_back(TArgs&&... args) -> reference -{ - return PushBackImpl( - nullptr, - [&] (T* dst, std::nullptr_t) { - ::new(dst) T(std::forward<TArgs>(args)...); - }); -} - -template <class T, size_t N> -void TCompactVector<T, N>::pop_back() -{ - YT_ASSERT(!empty()); - - if (Y_LIKELY(IsInline())) { - InlineElements_[InlineMeta_.SizePlusOne - 2].T::~T(); - --InlineMeta_.SizePlusOne; - } else { - auto* storage = OnHeapMeta_.Storage; - storage->End[-1].T::~T(); - --storage->End; - } -} - -template <class T, size_t N> -auto TCompactVector<T, N>::erase(const_iterator pos) -> iterator -{ - YT_ASSERT(pos >= begin()); - YT_ASSERT(pos < end()); - - auto* mutablePos = const_cast<iterator>(pos); - Move(mutablePos + 1, end(), mutablePos); - pop_back(); - - return mutablePos; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::erase(const_iterator first, const_iterator last) -> iterator -{ - YT_ASSERT(first >= begin()); - YT_ASSERT(last <= end()); - - auto* mutableFirst = const_cast<iterator>(first); - auto* mutableLast = const_cast<iterator>(last); - auto count = std::distance(mutableFirst, mutableLast); - - if (Y_LIKELY(IsInline())) { - auto* end = &InlineElements_[0] + InlineMeta_.SizePlusOne - 1; - Move(mutableLast, end, mutableFirst); - Destroy(end - count, end); - InlineMeta_.SizePlusOne -= count; - } else { - auto* storage = OnHeapMeta_.Storage; - auto* end = storage->End; - Move(mutableLast, storage->End, mutableFirst); - Destroy(end - count, end); - storage->End -= count; - } - - return mutableFirst; -} - -template <class T, size_t N> -void TCompactVector<T, N>::clear() -{ - if (Y_LIKELY(IsInline())) { - Destroy(&InlineElements_[0], &InlineElements_[InlineMeta_.SizePlusOne - 1]); - InlineMeta_.SizePlusOne = 1; - } else { - auto* storage = OnHeapMeta_.Storage; - Destroy(storage->Elements, storage->End); - storage->End = storage->Elements; - } -} - -template <class T, size_t N> -void TCompactVector<T, N>::resize(size_type newSize) -{ - ResizeImpl( - newSize, - [] (auto* dst) { - ::new(dst) T(); - }); -} - -template <class T, size_t N> -void TCompactVector<T, N>::resize(size_type newSize, const T& value) -{ - ResizeImpl( - newSize, - [&] (auto* dst) { - ::new(dst) T(value); - }); -} - -template <class T, size_t N> -void TCompactVector<T, N>::reserve(size_t newCapacity) -{ - if (Y_UNLIKELY(newCapacity > N)) { - EnsureOnHeapCapacity(newCapacity, /*incremental*/ false); - } -} - -template <class T, size_t N> -void TCompactVector<T, N>::swap(TCompactVector& other) -{ - if (this == &other) { - return; - } - - if (!IsInline() && !other.IsInline()) { - std::swap(OnHeapMeta_.Storage, other.OnHeapMeta_.Storage); - return; - } - - auto* lhs = this; - auto* rhs = &other; - if (lhs->size() < rhs->size()) { - std::swap(lhs, rhs); - } - - size_t rhsSize = rhs->size(); - size_t lhsSize = lhs->size(); - if (lhsSize > rhs->capacity()) { - rhs->EnsureOnHeapCapacity(lhs->size(), /*incremental*/ false); - } - - for (size_t index = 0; index < rhsSize; ++index) { - std::swap((*lhs)[index], (*rhs)[index]); - } - - UninitializedMove(lhs->begin() + rhsSize, lhs->end(), rhs->end()); - Destroy(lhs->begin() + rhsSize, lhs->end()); - - rhs->SetSize(lhsSize); - lhs->SetSize(rhsSize); -} - -template <class T, size_t N> -void TCompactVector<T, N>::assign(size_type count, const T& value) -{ - clear(); - - if (Y_UNLIKELY(count > capacity())) { - EnsureOnHeapCapacity(count, /*incremental*/ false); - } - - auto* dst = begin(); - std::uninitialized_fill(dst, dst + count, value); - - SetSize(count); -} - -template <class T, size_t N> -template <class TIterator> -void TCompactVector<T, N>::assign(TIterator first, TIterator last) -{ - clear(); - - auto count = std::distance(first, last); - if (Y_UNLIKELY(count > static_cast<ptrdiff_t>(capacity()))) { - EnsureOnHeapCapacity(count, /*incremental*/ false); - } - - std::uninitialized_copy(first, last, begin()); - - SetSize(count); -} - -template <class T, size_t N> -void TCompactVector<T, N>::assign(std::initializer_list<T> list) -{ - assign(list.begin(), list.end()); -} - -template <class T, size_t N> -template <size_t OtherN> -void TCompactVector<T, N>::assign(const TCompactVector<T, OtherN>& other) -{ - if constexpr(N == OtherN) { - if (this == &other) { - return; - } - } - - auto otherSize = other.size(); - auto otherBegin = other.begin(); - - if (capacity() >= otherSize) { - const auto* src = other.begin(); - auto* dst = begin(); - - auto thisSize = size(); - auto copySize = std::min(thisSize, otherSize); - Copy(src, src + copySize, dst); - src += copySize; - dst += copySize; - - auto uninitializedCopySize = otherSize - copySize; - UninitializedCopy(src, src + uninitializedCopySize, dst); - // NB: src += uninitializedCopySize is not needed. - dst += uninitializedCopySize; - - if (thisSize > otherSize) { - Destroy(dst, end()); - } - - SetSize(otherSize); - return; - } - - clear(); - - EnsureOnHeapCapacity(otherSize, /*incremental*/ false); - - YT_ASSERT(!IsInline()); - auto* storage = OnHeapMeta_.Storage; - UninitializedCopy(otherBegin, otherBegin + otherSize, storage->Elements); - storage->End = storage->Elements + otherSize; -} - -template <class T, size_t N> -template <size_t OtherN> -void TCompactVector<T, N>::assign(TCompactVector<T, OtherN>&& other) -{ - if constexpr(N == OtherN) { - if (this == &other) { - return; - } - } - - clear(); - - if (!other.IsInline()) { - if (Y_UNLIKELY(!IsInline())) { - ::free(OnHeapMeta_.Storage); - } - OnHeapMeta_.Storage = other.OnHeapMeta_.Storage; - other.InlineMeta_.SizePlusOne = 1; - return; - } - - auto otherSize = other.size(); - if (Y_UNLIKELY(otherSize > capacity())) { - EnsureOnHeapCapacity(otherSize, /*incremental*/ false); - } - - auto* otherBegin = other.begin(); - UninitializedMove(otherBegin, otherBegin + otherSize, begin()); - SetSize(otherSize); - - other.clear(); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::operator=(const TCompactVector& other) -> TCompactVector& -{ - assign(other); - return *this; -} - -template <class T, size_t N> -template <size_t OtherN> -auto TCompactVector<T, N>::operator=(const TCompactVector<T, OtherN>& other) -> TCompactVector& -{ - assign(other); - return *this; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::operator=(TCompactVector&& other) -> TCompactVector& -{ - assign(std::move(other)); - return *this; -} - -template <class T, size_t N> -template <size_t OtherN> -auto TCompactVector<T, N>::operator=(TCompactVector<T, OtherN>&& other) -> TCompactVector& -{ - assign(std::move(other)); - return *this; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::operator=(std::initializer_list<T> list) -> TCompactVector& -{ - assign(list); - return *this; -} - -template <class T, size_t N> -auto TCompactVector<T, N>::insert(const_iterator pos, const T& value) -> iterator -{ - return InsertOneImpl( - pos, - &value, - [&] (auto* dst, const auto* value) { - ::new(dst) T(*value); - }, - [&] (auto* dst, const auto* value) { - *dst = *value; - }); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::insert(const_iterator pos, T&& value) -> iterator -{ - return InsertOneImpl( - pos, - &value, - [&] (auto* dst, auto* value) { - ::new(dst) T(std::move(*value)); - }, - [&] (auto* dst, auto* value) { - *dst = std::move(*value); - }); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::insert(const_iterator pos, size_type count, const T& value) -> iterator -{ - return InsertManyImpl( - pos, - count, - [&] (auto* dstFirst, auto* dstLast) { - for (auto* dst = dstFirst; dst != dstLast; ++dst) { - ::new(dst) T(value); - } - }, - [&] (auto* dstFirst, auto* dstLast) { - for (auto* dst = dstFirst; dst != dstLast; ++dst) { - *dst = value; - } - }); -} - -template <class T, size_t N> -template <class TIterator> -auto TCompactVector<T, N>::insert(const_iterator pos, TIterator first, TIterator last) -> iterator -{ - auto current = first; - return InsertManyImpl( - pos, - std::distance(first, last), - [&] (auto* dstFirst, auto* dstLast) { - for (auto* dst = dstFirst; dst != dstLast; ++dst) { - ::new(dst) T(*current++); - } - }, - [&] (auto* dstFirst, auto* dstLast) { - for (auto* dst = dstFirst; dst != dstLast; ++dst) { - *dst = *current++; - } - }); -} - -template <class T, size_t N> -auto TCompactVector<T, N>::insert(const_iterator pos, std::initializer_list<T> list) -> iterator -{ - return insert(pos, list.begin(), list.end()); -} - -template <class T, size_t N> + : TCompactVector() +{ + swap(other); +} + +template <class T, size_t N> +template <size_t OtherN> +TCompactVector<T, N>::TCompactVector(TCompactVector<T, OtherN>&& other) + : TCompactVector() +{ + swap(other); +} + +template <class T, size_t N> +TCompactVector<T, N>::TCompactVector(size_type count) + : TCompactVector() +{ + assign(count, T()); +} + +template <class T, size_t N> +TCompactVector<T, N>::TCompactVector(size_type count, const T& value) + : TCompactVector() +{ + assign(count, value); +} + +template <class T, size_t N> +template <class TIterator> +TCompactVector<T, N>::TCompactVector(TIterator first, TIterator last) + : TCompactVector() +{ + assign(first, last); +} + +template <class T, size_t N> +TCompactVector<T, N>::TCompactVector(std::initializer_list<T> list) + : TCompactVector() +{ + assign(list.begin(), list.end()); +} + +template <class T, size_t N> +TCompactVector<T, N>::~TCompactVector() +{ + if (Y_LIKELY(IsInline())) { + Destroy(&InlineElements_[0], &InlineElements_[InlineMeta_.SizePlusOne - 1]); + } else { + auto* storage = OnHeapMeta_.Storage; + Destroy(storage->Elements, storage->End); + ::free(storage); + } +} + +template <class T, size_t N> +bool TCompactVector<T, N>::empty() const +{ + if (Y_LIKELY(IsInline())) { + return InlineMeta_.SizePlusOne == 1; + } else { + const auto* storage = OnHeapMeta_.Storage; + return storage->Elements == storage->End; + } +} + +template <class T, size_t N> +auto TCompactVector<T, N>::begin() -> iterator +{ + return Y_LIKELY(IsInline()) ? &InlineElements_[0] : OnHeapMeta_.Storage->Elements; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::begin() const -> const_iterator +{ + return const_cast<TCompactVector*>(this)->begin(); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::end() -> iterator +{ + return Y_LIKELY(IsInline()) ? &InlineElements_[InlineMeta_.SizePlusOne - 1] : OnHeapMeta_.Storage->End; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::end() const -> const_iterator +{ + return const_cast<TCompactVector*>(this)->end(); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::rbegin() -> reverse_iterator +{ + return static_cast<reverse_iterator>(end()); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::rbegin() const -> const_reverse_iterator +{ + return static_cast<const_reverse_iterator>(end()); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::rend() -> reverse_iterator +{ + return static_cast<reverse_iterator>(begin()); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::rend() const -> const_reverse_iterator +{ + return static_cast<const_reverse_iterator>(begin()); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::size() const -> size_type +{ + if (Y_LIKELY(IsInline())) { + return InlineMeta_.SizePlusOne - 1; + } else { + const auto* storage = OnHeapMeta_.Storage; + return storage->End - storage->Elements; + } +} + +template <class T, size_t N> +auto TCompactVector<T, N>::capacity() const -> size_type +{ + if (Y_LIKELY(IsInline())) { + return N; + } else { + const auto* storage = OnHeapMeta_.Storage; + return storage->Capacity - storage->Elements; + } +} + +template <class T, size_t N> +auto TCompactVector<T, N>::max_size() const -> size_type +{ + return static_cast<size_type>(-1) / sizeof(T); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::data() -> pointer +{ + return static_cast<pointer>(begin()); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::data() const -> const_pointer +{ + return static_cast<const_pointer>(begin()); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::operator[](size_type index) -> reference +{ + YT_ASSERT(index < size()); + return begin()[index]; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::operator[](size_type index) const -> const_reference +{ + return const_cast<TCompactVector*>(this)->operator[](index); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::front() -> reference +{ + YT_ASSERT(!empty()); + return begin()[0]; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::front() const -> const_reference +{ + return const_cast<TCompactVector*>(this)->front(); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::back() -> reference +{ + YT_ASSERT(!empty()); + return end()[-1]; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::back() const -> const_reference +{ + return const_cast<TCompactVector*>(this)->back(); +} + +template <class T, size_t N> +void TCompactVector<T, N>::push_back(const T& value) +{ + PushBackImpl( + &value, + [&] (T* dst, const T* value) { + ::new(dst) T(*value); + }); +} + +template <class T, size_t N> +void TCompactVector<T, N>::push_back(T&& value) +{ + PushBackImpl( + &value, + [&] (T* dst, T* value) { + ::new(dst) T(std::move(*value)); + }); +} + +template <class T, size_t N> +template <class... TArgs> +auto TCompactVector<T, N>::emplace(const_iterator pos, TArgs&&... args) -> iterator +{ + return InsertOneImpl( + pos, + nullptr, + [&] (auto* dst, std::nullptr_t) { + ::new(dst) T(std::forward<TArgs>(args)...); + }, + [&] (auto* dst, std::nullptr_t) { + *dst = T(std::forward<TArgs>(args)...); + }); +} + +template <class T, size_t N> +template <class... TArgs> +auto TCompactVector<T, N>::emplace_back(TArgs&&... args) -> reference +{ + return PushBackImpl( + nullptr, + [&] (T* dst, std::nullptr_t) { + ::new(dst) T(std::forward<TArgs>(args)...); + }); +} + +template <class T, size_t N> +void TCompactVector<T, N>::pop_back() +{ + YT_ASSERT(!empty()); + + if (Y_LIKELY(IsInline())) { + InlineElements_[InlineMeta_.SizePlusOne - 2].T::~T(); + --InlineMeta_.SizePlusOne; + } else { + auto* storage = OnHeapMeta_.Storage; + storage->End[-1].T::~T(); + --storage->End; + } +} + +template <class T, size_t N> +auto TCompactVector<T, N>::erase(const_iterator pos) -> iterator +{ + YT_ASSERT(pos >= begin()); + YT_ASSERT(pos < end()); + + auto* mutablePos = const_cast<iterator>(pos); + Move(mutablePos + 1, end(), mutablePos); + pop_back(); + + return mutablePos; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::erase(const_iterator first, const_iterator last) -> iterator +{ + YT_ASSERT(first >= begin()); + YT_ASSERT(last <= end()); + + auto* mutableFirst = const_cast<iterator>(first); + auto* mutableLast = const_cast<iterator>(last); + auto count = std::distance(mutableFirst, mutableLast); + + if (Y_LIKELY(IsInline())) { + auto* end = &InlineElements_[0] + InlineMeta_.SizePlusOne - 1; + Move(mutableLast, end, mutableFirst); + Destroy(end - count, end); + InlineMeta_.SizePlusOne -= count; + } else { + auto* storage = OnHeapMeta_.Storage; + auto* end = storage->End; + Move(mutableLast, storage->End, mutableFirst); + Destroy(end - count, end); + storage->End -= count; + } + + return mutableFirst; +} + +template <class T, size_t N> +void TCompactVector<T, N>::clear() +{ + if (Y_LIKELY(IsInline())) { + Destroy(&InlineElements_[0], &InlineElements_[InlineMeta_.SizePlusOne - 1]); + InlineMeta_.SizePlusOne = 1; + } else { + auto* storage = OnHeapMeta_.Storage; + Destroy(storage->Elements, storage->End); + storage->End = storage->Elements; + } +} + +template <class T, size_t N> +void TCompactVector<T, N>::resize(size_type newSize) +{ + ResizeImpl( + newSize, + [] (auto* dst) { + ::new(dst) T(); + }); +} + +template <class T, size_t N> +void TCompactVector<T, N>::resize(size_type newSize, const T& value) +{ + ResizeImpl( + newSize, + [&] (auto* dst) { + ::new(dst) T(value); + }); +} + +template <class T, size_t N> +void TCompactVector<T, N>::reserve(size_t newCapacity) +{ + if (Y_UNLIKELY(newCapacity > N)) { + EnsureOnHeapCapacity(newCapacity, /*incremental*/ false); + } +} + +template <class T, size_t N> +void TCompactVector<T, N>::swap(TCompactVector& other) +{ + if (this == &other) { + return; + } + + if (!IsInline() && !other.IsInline()) { + std::swap(OnHeapMeta_.Storage, other.OnHeapMeta_.Storage); + return; + } + + auto* lhs = this; + auto* rhs = &other; + if (lhs->size() < rhs->size()) { + std::swap(lhs, rhs); + } + + size_t rhsSize = rhs->size(); + size_t lhsSize = lhs->size(); + if (lhsSize > rhs->capacity()) { + rhs->EnsureOnHeapCapacity(lhs->size(), /*incremental*/ false); + } + + for (size_t index = 0; index < rhsSize; ++index) { + std::swap((*lhs)[index], (*rhs)[index]); + } + + UninitializedMove(lhs->begin() + rhsSize, lhs->end(), rhs->end()); + Destroy(lhs->begin() + rhsSize, lhs->end()); + + rhs->SetSize(lhsSize); + lhs->SetSize(rhsSize); +} + +template <class T, size_t N> +void TCompactVector<T, N>::assign(size_type count, const T& value) +{ + clear(); + + if (Y_UNLIKELY(count > capacity())) { + EnsureOnHeapCapacity(count, /*incremental*/ false); + } + + auto* dst = begin(); + std::uninitialized_fill(dst, dst + count, value); + + SetSize(count); +} + +template <class T, size_t N> +template <class TIterator> +void TCompactVector<T, N>::assign(TIterator first, TIterator last) +{ + clear(); + + auto count = std::distance(first, last); + if (Y_UNLIKELY(count > static_cast<ptrdiff_t>(capacity()))) { + EnsureOnHeapCapacity(count, /*incremental*/ false); + } + + std::uninitialized_copy(first, last, begin()); + + SetSize(count); +} + +template <class T, size_t N> +void TCompactVector<T, N>::assign(std::initializer_list<T> list) +{ + assign(list.begin(), list.end()); +} + +template <class T, size_t N> +template <size_t OtherN> +void TCompactVector<T, N>::assign(const TCompactVector<T, OtherN>& other) +{ + if constexpr(N == OtherN) { + if (this == &other) { + return; + } + } + + auto otherSize = other.size(); + auto otherBegin = other.begin(); + + if (capacity() >= otherSize) { + const auto* src = other.begin(); + auto* dst = begin(); + + auto thisSize = size(); + auto copySize = std::min(thisSize, otherSize); + Copy(src, src + copySize, dst); + src += copySize; + dst += copySize; + + auto uninitializedCopySize = otherSize - copySize; + UninitializedCopy(src, src + uninitializedCopySize, dst); + // NB: src += uninitializedCopySize is not needed. + dst += uninitializedCopySize; + + if (thisSize > otherSize) { + Destroy(dst, end()); + } + + SetSize(otherSize); + return; + } + + clear(); + + EnsureOnHeapCapacity(otherSize, /*incremental*/ false); + + YT_ASSERT(!IsInline()); + auto* storage = OnHeapMeta_.Storage; + UninitializedCopy(otherBegin, otherBegin + otherSize, storage->Elements); + storage->End = storage->Elements + otherSize; +} + +template <class T, size_t N> +template <size_t OtherN> +void TCompactVector<T, N>::assign(TCompactVector<T, OtherN>&& other) +{ + if constexpr(N == OtherN) { + if (this == &other) { + return; + } + } + + clear(); + + if (!other.IsInline()) { + if (Y_UNLIKELY(!IsInline())) { + ::free(OnHeapMeta_.Storage); + } + OnHeapMeta_.Storage = other.OnHeapMeta_.Storage; + other.InlineMeta_.SizePlusOne = 1; + return; + } + + auto otherSize = other.size(); + if (Y_UNLIKELY(otherSize > capacity())) { + EnsureOnHeapCapacity(otherSize, /*incremental*/ false); + } + + auto* otherBegin = other.begin(); + UninitializedMove(otherBegin, otherBegin + otherSize, begin()); + SetSize(otherSize); + + other.clear(); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::operator=(const TCompactVector& other) -> TCompactVector& +{ + assign(other); + return *this; +} + +template <class T, size_t N> +template <size_t OtherN> +auto TCompactVector<T, N>::operator=(const TCompactVector<T, OtherN>& other) -> TCompactVector& +{ + assign(other); + return *this; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::operator=(TCompactVector&& other) -> TCompactVector& +{ + assign(std::move(other)); + return *this; +} + +template <class T, size_t N> +template <size_t OtherN> +auto TCompactVector<T, N>::operator=(TCompactVector<T, OtherN>&& other) -> TCompactVector& +{ + assign(std::move(other)); + return *this; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::operator=(std::initializer_list<T> list) -> TCompactVector& +{ + assign(list); + return *this; +} + +template <class T, size_t N> +auto TCompactVector<T, N>::insert(const_iterator pos, const T& value) -> iterator +{ + return InsertOneImpl( + pos, + &value, + [&] (auto* dst, const auto* value) { + ::new(dst) T(*value); + }, + [&] (auto* dst, const auto* value) { + *dst = *value; + }); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::insert(const_iterator pos, T&& value) -> iterator +{ + return InsertOneImpl( + pos, + &value, + [&] (auto* dst, auto* value) { + ::new(dst) T(std::move(*value)); + }, + [&] (auto* dst, auto* value) { + *dst = std::move(*value); + }); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::insert(const_iterator pos, size_type count, const T& value) -> iterator +{ + return InsertManyImpl( + pos, + count, + [&] (auto* dstFirst, auto* dstLast) { + for (auto* dst = dstFirst; dst != dstLast; ++dst) { + ::new(dst) T(value); + } + }, + [&] (auto* dstFirst, auto* dstLast) { + for (auto* dst = dstFirst; dst != dstLast; ++dst) { + *dst = value; + } + }); +} + +template <class T, size_t N> +template <class TIterator> +auto TCompactVector<T, N>::insert(const_iterator pos, TIterator first, TIterator last) -> iterator +{ + auto current = first; + return InsertManyImpl( + pos, + std::distance(first, last), + [&] (auto* dstFirst, auto* dstLast) { + for (auto* dst = dstFirst; dst != dstLast; ++dst) { + ::new(dst) T(*current++); + } + }, + [&] (auto* dstFirst, auto* dstLast) { + for (auto* dst = dstFirst; dst != dstLast; ++dst) { + *dst = *current++; + } + }); +} + +template <class T, size_t N> +auto TCompactVector<T, N>::insert(const_iterator pos, std::initializer_list<T> list) -> iterator +{ + return insert(pos, list.begin(), list.end()); +} + +template <class T, size_t N> void TCompactVector<T, N>::shrink_to_small() { if (Y_LIKELY(IsInline())) { @@ -709,303 +709,303 @@ void TCompactVector<T, N>::shrink_to_small() } template <class T, size_t N> -bool TCompactVector<T, N>::IsInline() const -{ - return InlineMeta_.SizePlusOne != 0; -} - -template <class T, size_t N> -void TCompactVector<T, N>::SetSize(size_t newSize) -{ - if (Y_LIKELY(IsInline())) { - InlineMeta_.SizePlusOne = newSize + 1; - } else { - auto* storage = OnHeapMeta_.Storage; - storage->End = storage->Elements + newSize; - } -} - -template <class T, size_t N> -void TCompactVector<T, N>::EnsureOnHeapCapacity(size_t newCapacity, bool incremental) -{ - newCapacity = std::max(newCapacity, N + 1); - if (incremental) { - newCapacity = std::max(newCapacity, capacity() * 2); - } - - auto byteSize = sizeof(TOnHeapStorage) + newCapacity * sizeof(T); +bool TCompactVector<T, N>::IsInline() const +{ + return InlineMeta_.SizePlusOne != 0; +} + +template <class T, size_t N> +void TCompactVector<T, N>::SetSize(size_t newSize) +{ + if (Y_LIKELY(IsInline())) { + InlineMeta_.SizePlusOne = newSize + 1; + } else { + auto* storage = OnHeapMeta_.Storage; + storage->End = storage->Elements + newSize; + } +} + +template <class T, size_t N> +void TCompactVector<T, N>::EnsureOnHeapCapacity(size_t newCapacity, bool incremental) +{ + newCapacity = std::max(newCapacity, N + 1); + if (incremental) { + newCapacity = std::max(newCapacity, capacity() * 2); + } + + auto byteSize = sizeof(TOnHeapStorage) + newCapacity * sizeof(T); byteSize = nallocx(byteSize, 0); - - newCapacity = (byteSize - sizeof(TOnHeapStorage)) / sizeof(T); - - auto* newStorage = static_cast<TOnHeapStorage*>(::malloc(byteSize)); - YT_VERIFY((reinterpret_cast<uintptr_t>(newStorage) >> 56) == 0); - - newStorage->Capacity = newStorage->Elements + newCapacity; - - size_t size; - if (IsInline()) { - size = InlineMeta_.SizePlusOne - 1; - UninitializedMove(&InlineElements_[0], &InlineElements_[0] + size, newStorage->Elements); - Destroy(&InlineElements_[0], &InlineElements_[0] + size); - } else { - auto* storage = OnHeapMeta_.Storage; - size = storage->End - storage->Elements; - UninitializedMove(storage->Elements, storage->End, newStorage->Elements); - Destroy(storage->Elements, storage->End); - ::free(storage); - } - - newStorage->End = newStorage->Elements + size; - OnHeapMeta_.Storage = newStorage; -} - -template <class T, size_t N> -template <class TPtr, class F> -auto TCompactVector<T, N>::PushBackImpl(TPtr valuePtr, F&& func) -> reference -{ - auto sizePlusOne = InlineMeta_.SizePlusOne; - if (Y_LIKELY(sizePlusOne != 0 && sizePlusOne != N + 1)) { - auto* dst = &InlineElements_[sizePlusOne - 1]; - func(dst, valuePtr); - ++InlineMeta_.SizePlusOne; - return *dst; - } - - auto hasSpareOnHeapCapacity = [&] { - if (sizePlusOne != 0) { - return false; - } - auto* storage = OnHeapMeta_.Storage; - return storage->End < storage->Capacity; - }; - - if (Y_UNLIKELY(!hasSpareOnHeapCapacity())) { - TCompactVectorReallocationPtrAdjuster<TCompactVector, TPtr> valuePtrAdjuster(this, valuePtr); - EnsureOnHeapCapacity(0, /*incremental*/ true); - } - - YT_ASSERT(!IsInline()); - auto* storage = OnHeapMeta_.Storage; - auto* dst = storage->End++; - func(dst, valuePtr); - - return *dst; -} - -template <class T, size_t N> -template <class F> -void TCompactVector<T, N>::ResizeImpl(size_type newSize, F&& func) -{ - auto size = this->size(); - if (newSize > size) { - if (Y_UNLIKELY(newSize > capacity())) { - EnsureOnHeapCapacity(newSize, /*incremental*/ false); - } - - auto* first = end(); - auto* last = first + newSize - size; - for (auto* current = first; current != last; ++current) { - func(current); - } - } else if (newSize < size) { - Destroy(begin() + newSize, end()); - } - - SetSize(newSize); -} - -template <class T, size_t N> -template <class TPtr, class UninitializedF, class InitializedF> -auto TCompactVector<T, N>::InsertOneImpl(const_iterator pos, TPtr valuePtr, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc) -> iterator -{ - YT_ASSERT(pos >= begin()); - YT_ASSERT(pos <= end()); - - auto* mutablePos = const_cast<iterator>(pos); - - auto newSize = size() + 1; - if (Y_UNLIKELY(newSize > capacity())) { - TCompactVectorReallocationPtrAdjuster<TCompactVector, iterator> mutablePosAdjuster(this, mutablePos); - TCompactVectorReallocationPtrAdjuster<TCompactVector, TPtr> valuePtrAdjuster(this, valuePtr); - EnsureOnHeapCapacity(newSize, /*incremental*/ true); - } - - auto* end = this->end(); - - if constexpr(!std::is_same_v<TPtr, std::nullptr_t>) { - if (valuePtr >= mutablePos && valuePtr < end) { - ++valuePtr; - } - } - - auto moveCount = std::distance(mutablePos, end); - if (moveCount == 0) { - uninitializedFunc(end, valuePtr); - } else { - if constexpr(std::is_trivially_copyable_v<T>) { - ::memmove(mutablePos + 1, mutablePos, moveCount * sizeof(T)); - } else { - ::new(end) T(std::move(end[-1])); - MoveBackward(mutablePos, end - 1, mutablePos + 1); - } - initializedFunc(mutablePos, valuePtr); - } - - SetSize(newSize); - - return mutablePos; -} - -template <class T, size_t N> -template <class UninitializedF, class InitializedF> -auto TCompactVector<T, N>::InsertManyImpl(const_iterator pos, size_t insertCount, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc) -> iterator -{ - YT_ASSERT(pos >= begin()); - YT_ASSERT(pos <= end()); - - auto* mutablePos = const_cast<iterator>(pos); - if (insertCount == 0) { - return mutablePos; - } - - auto size = this->size(); - auto newSize = size + insertCount; - if (Y_UNLIKELY(newSize > capacity())) { - auto index = std::distance(begin(), mutablePos); - EnsureOnHeapCapacity(newSize, /*incremental*/ true); - mutablePos = begin() + index; - } - - auto* end = this->end(); - auto moveCount = std::distance(mutablePos, end); - if constexpr(std::is_trivially_copyable_v<T>) { - ::memmove(mutablePos + insertCount, mutablePos, moveCount * sizeof(T)); - initializedFunc(mutablePos, mutablePos + insertCount); - } else { - if (static_cast<ptrdiff_t>(insertCount) >= moveCount) { - UninitializedMove(mutablePos, end, mutablePos + insertCount); - initializedFunc(mutablePos, end); - uninitializedFunc(end, end + insertCount - moveCount); - } else { - auto overlapCount = moveCount - insertCount; - UninitializedMove(mutablePos + overlapCount, end, mutablePos + overlapCount + insertCount); - MoveBackward(mutablePos, mutablePos + overlapCount, mutablePos + insertCount); - initializedFunc(mutablePos, mutablePos + insertCount); - } - } - - SetSize(newSize); - - return mutablePos; -} - -template <class T, size_t N> -void TCompactVector<T, N>::Destroy(T* first, T* last) -{ - if constexpr(!std::is_trivially_destructible_v<T>) { - for (auto* current = first; current != last; ++current) { - current->T::~T(); - } - } -} - -template <class T, size_t N> -template <class T1, class T2> -void TCompactVector<T, N>::Copy(const T1* srcFirst, const T1* srcLast, T2* dst) -{ - if constexpr(std::is_trivially_copyable_v<T1> && std::is_same_v<T1, T2>) { - ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T)); - } else { - std::copy(srcFirst, srcLast, dst); - } -} - -template <class T, size_t N> -template <class T1, class T2> -void TCompactVector<T, N>::UninitializedCopy(const T1* srcFirst, const T1* srcLast, T2* dst) -{ - if constexpr(std::is_trivially_copyable_v<T1> && std::is_same_v<T1, T2>) { - ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T)); - } else { - std::uninitialized_copy(srcFirst, srcLast, dst); - } -} - -template <class T, size_t N> -void TCompactVector<T, N>::Move(T* srcFirst, T* srcLast, T* dst) -{ - if constexpr(std::is_trivially_copyable_v<T>) { + + newCapacity = (byteSize - sizeof(TOnHeapStorage)) / sizeof(T); + + auto* newStorage = static_cast<TOnHeapStorage*>(::malloc(byteSize)); + YT_VERIFY((reinterpret_cast<uintptr_t>(newStorage) >> 56) == 0); + + newStorage->Capacity = newStorage->Elements + newCapacity; + + size_t size; + if (IsInline()) { + size = InlineMeta_.SizePlusOne - 1; + UninitializedMove(&InlineElements_[0], &InlineElements_[0] + size, newStorage->Elements); + Destroy(&InlineElements_[0], &InlineElements_[0] + size); + } else { + auto* storage = OnHeapMeta_.Storage; + size = storage->End - storage->Elements; + UninitializedMove(storage->Elements, storage->End, newStorage->Elements); + Destroy(storage->Elements, storage->End); + ::free(storage); + } + + newStorage->End = newStorage->Elements + size; + OnHeapMeta_.Storage = newStorage; +} + +template <class T, size_t N> +template <class TPtr, class F> +auto TCompactVector<T, N>::PushBackImpl(TPtr valuePtr, F&& func) -> reference +{ + auto sizePlusOne = InlineMeta_.SizePlusOne; + if (Y_LIKELY(sizePlusOne != 0 && sizePlusOne != N + 1)) { + auto* dst = &InlineElements_[sizePlusOne - 1]; + func(dst, valuePtr); + ++InlineMeta_.SizePlusOne; + return *dst; + } + + auto hasSpareOnHeapCapacity = [&] { + if (sizePlusOne != 0) { + return false; + } + auto* storage = OnHeapMeta_.Storage; + return storage->End < storage->Capacity; + }; + + if (Y_UNLIKELY(!hasSpareOnHeapCapacity())) { + TCompactVectorReallocationPtrAdjuster<TCompactVector, TPtr> valuePtrAdjuster(this, valuePtr); + EnsureOnHeapCapacity(0, /*incremental*/ true); + } + + YT_ASSERT(!IsInline()); + auto* storage = OnHeapMeta_.Storage; + auto* dst = storage->End++; + func(dst, valuePtr); + + return *dst; +} + +template <class T, size_t N> +template <class F> +void TCompactVector<T, N>::ResizeImpl(size_type newSize, F&& func) +{ + auto size = this->size(); + if (newSize > size) { + if (Y_UNLIKELY(newSize > capacity())) { + EnsureOnHeapCapacity(newSize, /*incremental*/ false); + } + + auto* first = end(); + auto* last = first + newSize - size; + for (auto* current = first; current != last; ++current) { + func(current); + } + } else if (newSize < size) { + Destroy(begin() + newSize, end()); + } + + SetSize(newSize); +} + +template <class T, size_t N> +template <class TPtr, class UninitializedF, class InitializedF> +auto TCompactVector<T, N>::InsertOneImpl(const_iterator pos, TPtr valuePtr, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc) -> iterator +{ + YT_ASSERT(pos >= begin()); + YT_ASSERT(pos <= end()); + + auto* mutablePos = const_cast<iterator>(pos); + + auto newSize = size() + 1; + if (Y_UNLIKELY(newSize > capacity())) { + TCompactVectorReallocationPtrAdjuster<TCompactVector, iterator> mutablePosAdjuster(this, mutablePos); + TCompactVectorReallocationPtrAdjuster<TCompactVector, TPtr> valuePtrAdjuster(this, valuePtr); + EnsureOnHeapCapacity(newSize, /*incremental*/ true); + } + + auto* end = this->end(); + + if constexpr(!std::is_same_v<TPtr, std::nullptr_t>) { + if (valuePtr >= mutablePos && valuePtr < end) { + ++valuePtr; + } + } + + auto moveCount = std::distance(mutablePos, end); + if (moveCount == 0) { + uninitializedFunc(end, valuePtr); + } else { + if constexpr(std::is_trivially_copyable_v<T>) { + ::memmove(mutablePos + 1, mutablePos, moveCount * sizeof(T)); + } else { + ::new(end) T(std::move(end[-1])); + MoveBackward(mutablePos, end - 1, mutablePos + 1); + } + initializedFunc(mutablePos, valuePtr); + } + + SetSize(newSize); + + return mutablePos; +} + +template <class T, size_t N> +template <class UninitializedF, class InitializedF> +auto TCompactVector<T, N>::InsertManyImpl(const_iterator pos, size_t insertCount, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc) -> iterator +{ + YT_ASSERT(pos >= begin()); + YT_ASSERT(pos <= end()); + + auto* mutablePos = const_cast<iterator>(pos); + if (insertCount == 0) { + return mutablePos; + } + + auto size = this->size(); + auto newSize = size + insertCount; + if (Y_UNLIKELY(newSize > capacity())) { + auto index = std::distance(begin(), mutablePos); + EnsureOnHeapCapacity(newSize, /*incremental*/ true); + mutablePos = begin() + index; + } + + auto* end = this->end(); + auto moveCount = std::distance(mutablePos, end); + if constexpr(std::is_trivially_copyable_v<T>) { + ::memmove(mutablePos + insertCount, mutablePos, moveCount * sizeof(T)); + initializedFunc(mutablePos, mutablePos + insertCount); + } else { + if (static_cast<ptrdiff_t>(insertCount) >= moveCount) { + UninitializedMove(mutablePos, end, mutablePos + insertCount); + initializedFunc(mutablePos, end); + uninitializedFunc(end, end + insertCount - moveCount); + } else { + auto overlapCount = moveCount - insertCount; + UninitializedMove(mutablePos + overlapCount, end, mutablePos + overlapCount + insertCount); + MoveBackward(mutablePos, mutablePos + overlapCount, mutablePos + insertCount); + initializedFunc(mutablePos, mutablePos + insertCount); + } + } + + SetSize(newSize); + + return mutablePos; +} + +template <class T, size_t N> +void TCompactVector<T, N>::Destroy(T* first, T* last) +{ + if constexpr(!std::is_trivially_destructible_v<T>) { + for (auto* current = first; current != last; ++current) { + current->T::~T(); + } + } +} + +template <class T, size_t N> +template <class T1, class T2> +void TCompactVector<T, N>::Copy(const T1* srcFirst, const T1* srcLast, T2* dst) +{ + if constexpr(std::is_trivially_copyable_v<T1> && std::is_same_v<T1, T2>) { + ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T)); + } else { + std::copy(srcFirst, srcLast, dst); + } +} + +template <class T, size_t N> +template <class T1, class T2> +void TCompactVector<T, N>::UninitializedCopy(const T1* srcFirst, const T1* srcLast, T2* dst) +{ + if constexpr(std::is_trivially_copyable_v<T1> && std::is_same_v<T1, T2>) { + ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T)); + } else { + std::uninitialized_copy(srcFirst, srcLast, dst); + } +} + +template <class T, size_t N> +void TCompactVector<T, N>::Move(T* srcFirst, T* srcLast, T* dst) +{ + if constexpr(std::is_trivially_copyable_v<T>) { ::memmove(dst, srcFirst, (srcLast - srcFirst) * sizeof(T)); - } else { - std::move(srcFirst, srcLast, dst); - } -} - -template <class T, size_t N> -void TCompactVector<T, N>::UninitializedMove(T* srcFirst, T* srcLast, T* dst) -{ - if constexpr(std::is_trivially_copyable_v<T>) { - ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T)); - } else { - std::uninitialized_move(srcFirst, srcLast, dst); - } -} - -template <class T, size_t N> -void TCompactVector<T, N>::MoveBackward(T* srcFirst, T* srcLast, T* dst) -{ - auto* src = srcLast; - dst += std::distance(srcFirst, srcLast); - while (src > srcFirst) { - *--dst = std::move(*--src); - } -} - -///////////////////////////////////////////////////////////////////////////// - -template <class T, size_t LhsN, size_t RhsN> -bool operator==(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs) -{ - if constexpr(LhsN == RhsN) { - if (&lhs == &rhs) { - return true; - } - } - - if (lhs.size() != rhs.size()) { - return false; - } - - return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} - -template <class T, size_t LhsN, size_t RhsN> -bool operator!=(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs) -{ - return !(lhs == rhs); -} - -template <class T, size_t LhsN, size_t RhsN> -bool operator<(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs) -{ - return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} - -///////////////////////////////////////////////////////////////////////////// - -} // namespace NYT - -namespace std { - -//////////////////////////////////////////////////////////////////////////////// - -template <class T, size_t N> -void swap(NYT::TCompactVector<T, N>& lhs, NYT::TCompactVector<T, N>& rhs) -{ - lhs.swap(rhs); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace std + } else { + std::move(srcFirst, srcLast, dst); + } +} + +template <class T, size_t N> +void TCompactVector<T, N>::UninitializedMove(T* srcFirst, T* srcLast, T* dst) +{ + if constexpr(std::is_trivially_copyable_v<T>) { + ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T)); + } else { + std::uninitialized_move(srcFirst, srcLast, dst); + } +} + +template <class T, size_t N> +void TCompactVector<T, N>::MoveBackward(T* srcFirst, T* srcLast, T* dst) +{ + auto* src = srcLast; + dst += std::distance(srcFirst, srcLast); + while (src > srcFirst) { + *--dst = std::move(*--src); + } +} + +///////////////////////////////////////////////////////////////////////////// + +template <class T, size_t LhsN, size_t RhsN> +bool operator==(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs) +{ + if constexpr(LhsN == RhsN) { + if (&lhs == &rhs) { + return true; + } + } + + if (lhs.size() != rhs.size()) { + return false; + } + + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template <class T, size_t LhsN, size_t RhsN> +bool operator!=(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs) +{ + return !(lhs == rhs); +} + +template <class T, size_t LhsN, size_t RhsN> +bool operator<(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +///////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +namespace std { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T, size_t N> +void swap(NYT::TCompactVector<T, N>& lhs, NYT::TCompactVector<T, N>& rhs) +{ + lhs.swap(rhs); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace std diff --git a/library/cpp/yt/small_containers/compact_vector.h b/library/cpp/yt/small_containers/compact_vector.h index 6c4a0b0e39..a2054ef9e7 100644 --- a/library/cpp/yt/small_containers/compact_vector.h +++ b/library/cpp/yt/small_containers/compact_vector.h @@ -1,219 +1,219 @@ -#pragma once - +#pragma once + #include <util/system/defaults.h> -#include <cstdint> -#include <iterator> -#include <limits> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -struct TCompactVectorOnHeapStorage; - -//! A vector-like structure optimized for storing elements inline -//! and with little memory overhead. -/*! - * Stores up to #N (<= 254) elements inline. - * - * When capacity starts exceeding #N, moves all elements to heap; - * \see #TCompactVectorOnHeapStorage. - * - * When linked with YTAlloc, employs its API to adjust the on-heap capacity in accordance - * to the actual size of the allocated region. - * - * Assuming the entropy and the alignment constraints, yields a seemingly optimal memory overhead. - * E.g. TCompactVector<uint8_t, 7> takes 8 bytes and TCompactVector<uint32_t, 3> takes 16 bytes. - * \see #ByteSize. - * - * Assumes (and asserts) the following: - * 1) the platform is 64 bit; - * 2) the highest 8 bits of pointers returned by |malloc| are zeroes; - * 3) the platform is little-endian. - */ -template <class T, size_t N> -class TCompactVector -{ -public: - static_assert(N < std::numeric_limits<uint8_t>::max()); - - using size_type = size_t; - using difference_type = ptrdiff_t; - - using value_type = T; - - using iterator = T*; - using const_iterator = const T*; - - using const_reverse_iterator = std::reverse_iterator<const_iterator>; - using reverse_iterator = std::reverse_iterator<iterator>; - - using reference = T&; - using const_reference = const T&; - - using pointer = T*; - using const_pointer = const T*; - - TCompactVector() noexcept; - TCompactVector(const TCompactVector& other); - template <size_t OtherN> - TCompactVector(const TCompactVector<T, OtherN>& other); +#include <cstdint> +#include <iterator> +#include <limits> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +struct TCompactVectorOnHeapStorage; + +//! A vector-like structure optimized for storing elements inline +//! and with little memory overhead. +/*! + * Stores up to #N (<= 254) elements inline. + * + * When capacity starts exceeding #N, moves all elements to heap; + * \see #TCompactVectorOnHeapStorage. + * + * When linked with YTAlloc, employs its API to adjust the on-heap capacity in accordance + * to the actual size of the allocated region. + * + * Assuming the entropy and the alignment constraints, yields a seemingly optimal memory overhead. + * E.g. TCompactVector<uint8_t, 7> takes 8 bytes and TCompactVector<uint32_t, 3> takes 16 bytes. + * \see #ByteSize. + * + * Assumes (and asserts) the following: + * 1) the platform is 64 bit; + * 2) the highest 8 bits of pointers returned by |malloc| are zeroes; + * 3) the platform is little-endian. + */ +template <class T, size_t N> +class TCompactVector +{ +public: + static_assert(N < std::numeric_limits<uint8_t>::max()); + + using size_type = size_t; + using difference_type = ptrdiff_t; + + using value_type = T; + + using iterator = T*; + using const_iterator = const T*; + + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using reverse_iterator = std::reverse_iterator<iterator>; + + using reference = T&; + using const_reference = const T&; + + using pointer = T*; + using const_pointer = const T*; + + TCompactVector() noexcept; + TCompactVector(const TCompactVector& other); + template <size_t OtherN> + TCompactVector(const TCompactVector<T, OtherN>& other); TCompactVector(TCompactVector&& other) noexcept(std::is_nothrow_move_constructible_v<T>); - template <size_t OtherN> - TCompactVector(TCompactVector<T, OtherN>&& other); - explicit TCompactVector(size_type count); - TCompactVector(size_type count, const T& value); - template <class TIterator> - TCompactVector(TIterator first, TIterator last); - TCompactVector(std::initializer_list<T> list); - - ~TCompactVector(); - - [[nodiscard]] bool empty() const; - - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - - reverse_iterator rbegin(); - const_reverse_iterator rbegin() const; - reverse_iterator rend(); - const_reverse_iterator rend() const; - - size_type size() const; - size_type capacity() const; - size_type max_size() const; - - pointer data(); - const_pointer data() const; - - reference operator[](size_type index); - const_reference operator[](size_type index) const; - - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - void push_back(const T& value); - void push_back(T&& value); - - template <class... TArgs> - iterator emplace(const_iterator pos, TArgs&&... args); - template <class... TArgs> - reference emplace_back(TArgs&&... args); - - void pop_back(); - - iterator erase(const_iterator pos); - iterator erase(const_iterator first, const_iterator last); - - void clear(); - - void resize(size_type newSize); - void resize(size_type newSize, const T& value); - - void reserve(size_type newCapacity); - - void swap(TCompactVector& other); - - void assign(size_type count, const T& value); - template <class TIterator> - void assign(TIterator first, TIterator last); - void assign(std::initializer_list<T> list); - template <size_t OtherN> - void assign(const TCompactVector<T, OtherN>& other); - template <size_t OtherN> - void assign(TCompactVector<T, OtherN>&& other); - - TCompactVector& operator=(const TCompactVector& other); - template <size_t OtherN> - TCompactVector& operator=(const TCompactVector<T, OtherN>& other); - TCompactVector& operator=(TCompactVector&& other); - template <size_t OtherN> - TCompactVector& operator=(TCompactVector<T, OtherN>&& other); - TCompactVector& operator=(std::initializer_list<T> list); - - iterator insert(const_iterator pos, const T& value); - iterator insert(const_iterator pos, T&& value); - iterator insert(const_iterator pos, size_type count, const T& value); - template <class TIterator> - iterator insert(const_iterator pos, TIterator first, TIterator last); - iterator insert(const_iterator pos, std::initializer_list<T> list); - + template <size_t OtherN> + TCompactVector(TCompactVector<T, OtherN>&& other); + explicit TCompactVector(size_type count); + TCompactVector(size_type count, const T& value); + template <class TIterator> + TCompactVector(TIterator first, TIterator last); + TCompactVector(std::initializer_list<T> list); + + ~TCompactVector(); + + [[nodiscard]] bool empty() const; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + reverse_iterator rend(); + const_reverse_iterator rend() const; + + size_type size() const; + size_type capacity() const; + size_type max_size() const; + + pointer data(); + const_pointer data() const; + + reference operator[](size_type index); + const_reference operator[](size_type index) const; + + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + void push_back(const T& value); + void push_back(T&& value); + + template <class... TArgs> + iterator emplace(const_iterator pos, TArgs&&... args); + template <class... TArgs> + reference emplace_back(TArgs&&... args); + + void pop_back(); + + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + + void clear(); + + void resize(size_type newSize); + void resize(size_type newSize, const T& value); + + void reserve(size_type newCapacity); + + void swap(TCompactVector& other); + + void assign(size_type count, const T& value); + template <class TIterator> + void assign(TIterator first, TIterator last); + void assign(std::initializer_list<T> list); + template <size_t OtherN> + void assign(const TCompactVector<T, OtherN>& other); + template <size_t OtherN> + void assign(TCompactVector<T, OtherN>&& other); + + TCompactVector& operator=(const TCompactVector& other); + template <size_t OtherN> + TCompactVector& operator=(const TCompactVector<T, OtherN>& other); + TCompactVector& operator=(TCompactVector&& other); + template <size_t OtherN> + TCompactVector& operator=(TCompactVector<T, OtherN>&& other); + TCompactVector& operator=(std::initializer_list<T> list); + + iterator insert(const_iterator pos, const T& value); + iterator insert(const_iterator pos, T&& value); + iterator insert(const_iterator pos, size_type count, const T& value); + template <class TIterator> + iterator insert(const_iterator pos, TIterator first, TIterator last); + iterator insert(const_iterator pos, std::initializer_list<T> list); + void shrink_to_small(); -private: - template <class OtherT, size_t OtherN> - friend class TCompactVector; - - using TOnHeapStorage = TCompactVectorOnHeapStorage<T>; - - static constexpr size_t ByteSize = - (sizeof(T) * N + alignof(T) + sizeof(uintptr_t) - 1) & - ~(sizeof(uintptr_t) - 1); - - struct TInlineMeta - { - char Padding[ByteSize - sizeof(uint8_t)]; - // > 0 indicates inline storage - // == 0 indicates on-heap storage - uint8_t SizePlusOne; +private: + template <class OtherT, size_t OtherN> + friend class TCompactVector; + + using TOnHeapStorage = TCompactVectorOnHeapStorage<T>; + + static constexpr size_t ByteSize = + (sizeof(T) * N + alignof(T) + sizeof(uintptr_t) - 1) & + ~(sizeof(uintptr_t) - 1); + + struct TInlineMeta + { + char Padding[ByteSize - sizeof(uint8_t)]; + // > 0 indicates inline storage + // == 0 indicates on-heap storage + uint8_t SizePlusOne; } alias_hack; - - struct TOnHeapMeta - { - char Padding[ByteSize - sizeof(uintptr_t)]; - TOnHeapStorage* Storage; + + struct TOnHeapMeta + { + char Padding[ByteSize - sizeof(uintptr_t)]; + TOnHeapStorage* Storage; } alias_hack; - - union - { - T InlineElements_[N]; - TInlineMeta InlineMeta_; - TOnHeapMeta OnHeapMeta_; - }; - - bool IsInline() const; - void SetSize(size_t newSize); - void EnsureOnHeapCapacity(size_t newCapacity, bool incremental); - template <class TPtr, class F> - reference PushBackImpl(TPtr valuePtr, F&& func); - template <class F> - void ResizeImpl(size_t newSize, F&& func); - template <class TPtr, class UninitializedF, class InitializedF> - iterator InsertOneImpl(const_iterator pos, TPtr valuePtr, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc); - template <class UninitializedF, class InitializedF> - iterator InsertManyImpl(const_iterator pos, size_t insertCount, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc); - - static void Destroy(T* first, T* last); - template <class T1, class T2> - static void Copy(const T1* srcFirst, const T1* srcLast, T2* dst); - template <class T1, class T2> - static void UninitializedCopy(const T1* srcFirst, const T1* srcLast, T2* dst); - static void Move(T* srcFirst, T* srcLast, T* dst); - static void MoveBackward(T* srcFirst, T* srcLast, T* dst); - static void UninitializedMove(T* srcFirst, T* srcLast, T* dst); -}; - -//////////////////////////////////////////////////////////////////////////////// - -template <class T, size_t LhsN, size_t RhsN> -bool operator==(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs); - -template <class T, size_t LhsN, size_t RhsN> -bool operator!=(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs); - -template <class T, size_t LhsN, size_t RhsN> -bool operator<(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs); - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT - -#define COMPACT_VECTOR_INL_H_ -#include "compact_vector-inl.h" -#undef COMPACT_VECTOR_INL_H_ + + union + { + T InlineElements_[N]; + TInlineMeta InlineMeta_; + TOnHeapMeta OnHeapMeta_; + }; + + bool IsInline() const; + void SetSize(size_t newSize); + void EnsureOnHeapCapacity(size_t newCapacity, bool incremental); + template <class TPtr, class F> + reference PushBackImpl(TPtr valuePtr, F&& func); + template <class F> + void ResizeImpl(size_t newSize, F&& func); + template <class TPtr, class UninitializedF, class InitializedF> + iterator InsertOneImpl(const_iterator pos, TPtr valuePtr, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc); + template <class UninitializedF, class InitializedF> + iterator InsertManyImpl(const_iterator pos, size_t insertCount, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc); + + static void Destroy(T* first, T* last); + template <class T1, class T2> + static void Copy(const T1* srcFirst, const T1* srcLast, T2* dst); + template <class T1, class T2> + static void UninitializedCopy(const T1* srcFirst, const T1* srcLast, T2* dst); + static void Move(T* srcFirst, T* srcLast, T* dst); + static void MoveBackward(T* srcFirst, T* srcLast, T* dst); + static void UninitializedMove(T* srcFirst, T* srcLast, T* dst); +}; + +//////////////////////////////////////////////////////////////////////////////// + +template <class T, size_t LhsN, size_t RhsN> +bool operator==(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs); + +template <class T, size_t LhsN, size_t RhsN> +bool operator!=(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs); + +template <class T, size_t LhsN, size_t RhsN> +bool operator<(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define COMPACT_VECTOR_INL_H_ +#include "compact_vector-inl.h" +#undef COMPACT_VECTOR_INL_H_ diff --git a/library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp b/library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp index 0b2f290692..5fed31d6c1 100644 --- a/library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp +++ b/library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp @@ -1,134 +1,134 @@ #include <yt/yt/core/test_framework/framework.h> - + #include <yt/yt/core/misc/compact_flat_map.h> -#include <string> -#include <vector> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - +#include <string> +#include <vector> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + using TMap = TCompactFlatMap<std::string, std::string, 2>; - -TMap CreateMap() -{ - std::vector<std::pair<std::string, std::string>> data = {{"I", "met"}, {"a", "traveller"}, {"from", "an"}, {"antique", "land"}}; - return {data.begin(), data.end()}; -} - + +TMap CreateMap() +{ + std::vector<std::pair<std::string, std::string>> data = {{"I", "met"}, {"a", "traveller"}, {"from", "an"}, {"antique", "land"}}; + return {data.begin(), data.end()}; +} + TEST(CompactFlatMapTest, DefaultEmpty) { - TMap m; - EXPECT_TRUE(m.empty()); - EXPECT_EQ(m.begin(), m.end()); -} - + TMap m; + EXPECT_TRUE(m.empty()); + EXPECT_EQ(m.begin(), m.end()); +} + TEST(CompactFlatMapTest, Reserve) { - // No real way to test reserve - just use it and wiggle about. - auto m1 = CreateMap(); - TMap m2; - m2.reserve(m1.size()); - m2.insert(m1.begin(), m1.end()); - EXPECT_EQ(m1.size(), m2.size()); -} - + // No real way to test reserve - just use it and wiggle about. + auto m1 = CreateMap(); + TMap m2; + m2.reserve(m1.size()); + m2.insert(m1.begin(), m1.end()); + EXPECT_EQ(m1.size(), m2.size()); +} + TEST(CompactFlatMapTest, Size) { - auto m = CreateMap(); - + auto m = CreateMap(); + EXPECT_EQ(m.size(), 4u); - EXPECT_EQ(m.ssize(), 4); - - m.insert({"Who", "said"}); - + EXPECT_EQ(m.ssize(), 4); + + m.insert({"Who", "said"}); + EXPECT_EQ(m.size(), 5u); - EXPECT_EQ(m.ssize(), 5); - - m.erase("antique"); - + EXPECT_EQ(m.ssize(), 5); + + m.erase("antique"); + EXPECT_EQ(m.size(), 4u); - EXPECT_EQ(m.ssize(), 4); -} - + EXPECT_EQ(m.ssize(), 4); +} + TEST(CompactFlatMapTest, ClearAndEmpty) { - auto m = CreateMap(); - - EXPECT_FALSE(m.empty()); - EXPECT_NE(m.begin(), m.end()); - - m.clear(); - - EXPECT_TRUE(m.empty()); - EXPECT_EQ(m.begin(), m.end()); - - m.insert({"Who", "said"}); - - EXPECT_FALSE(m.empty()); - EXPECT_NE(m.begin(), m.end()); -} - + auto m = CreateMap(); + + EXPECT_FALSE(m.empty()); + EXPECT_NE(m.begin(), m.end()); + + m.clear(); + + EXPECT_TRUE(m.empty()); + EXPECT_EQ(m.begin(), m.end()); + + m.insert({"Who", "said"}); + + EXPECT_FALSE(m.empty()); + EXPECT_NE(m.begin(), m.end()); +} + TEST(CompactFlatMapTest, FindMutable) { - auto m = CreateMap(); - { - auto it = m.find("from"); - EXPECT_NE(it, m.end()); - EXPECT_EQ(it->second, "an"); - it->second = "the"; - } - { - auto it = m.find("from"); - EXPECT_NE(it, m.end()); - EXPECT_EQ(it->second, "the"); - } - { - auto it = m.find("Who"); - EXPECT_EQ(it, m.end()); - } -} - + auto m = CreateMap(); + { + auto it = m.find("from"); + EXPECT_NE(it, m.end()); + EXPECT_EQ(it->second, "an"); + it->second = "the"; + } + { + auto it = m.find("from"); + EXPECT_NE(it, m.end()); + EXPECT_EQ(it->second, "the"); + } + { + auto it = m.find("Who"); + EXPECT_EQ(it, m.end()); + } +} + TEST(CompactFlatMapTest, FindConst) { - const auto& m = CreateMap(); - { - auto it = m.find("from"); - EXPECT_NE(it, m.end()); - EXPECT_EQ(it->second, "an"); - } - { - auto it = m.find("Who"); - EXPECT_EQ(it, m.end()); - } -} - + const auto& m = CreateMap(); + { + auto it = m.find("from"); + EXPECT_NE(it, m.end()); + EXPECT_EQ(it->second, "an"); + } + { + auto it = m.find("Who"); + EXPECT_EQ(it, m.end()); + } +} + TEST(CompactFlatMapTest, Insert) { - auto m = CreateMap(); - - auto [it, inserted] = m.insert({"Who", "said"}); - EXPECT_TRUE(inserted); + auto m = CreateMap(); + + auto [it, inserted] = m.insert({"Who", "said"}); + EXPECT_TRUE(inserted); EXPECT_EQ(m.ssize(), 5); - EXPECT_NE(it, m.end()); - EXPECT_EQ(it, m.find("Who")); - EXPECT_EQ(it->second, "said"); - - auto [it2, inserted2] = m.insert({"Who", "told"}); - EXPECT_FALSE(inserted2); + EXPECT_NE(it, m.end()); + EXPECT_EQ(it, m.find("Who")); + EXPECT_EQ(it->second, "said"); + + auto [it2, inserted2] = m.insert({"Who", "told"}); + EXPECT_FALSE(inserted2); EXPECT_EQ(m.ssize(), 5); - EXPECT_EQ(it2, it); - EXPECT_EQ(it->second, "said"); - - std::vector<std::pair<std::string, std::string>> data = {{"Two", "vast"}, {"and", "trunkless"}, {"legs", "of"}, {"stone", "Stand"}, {"in", "the"}, {"desert", "..."}}; - m.insert(data.begin(), data.end()); + EXPECT_EQ(it2, it); + EXPECT_EQ(it->second, "said"); + + std::vector<std::pair<std::string, std::string>> data = {{"Two", "vast"}, {"and", "trunkless"}, {"legs", "of"}, {"stone", "Stand"}, {"in", "the"}, {"desert", "..."}}; + m.insert(data.begin(), data.end()); EXPECT_EQ(m.ssize(), 11); - EXPECT_NE(m.find("and"), m.end()); - EXPECT_EQ(m.find("and")->second, "trunkless"); -} - + EXPECT_NE(m.find("and"), m.end()); + EXPECT_EQ(m.find("and")->second, "trunkless"); +} + TEST(CompactFlatMapTest, Emplace) { auto m = CreateMap(); @@ -149,77 +149,77 @@ TEST(CompactFlatMapTest, Emplace) TEST(CompactFlatMapTest, Subscript) { - auto m = CreateMap(); - - EXPECT_EQ(m["antique"], "land"); + auto m = CreateMap(); + + EXPECT_EQ(m["antique"], "land"); EXPECT_EQ(m.ssize(), 4); - - EXPECT_EQ(m["Who"], ""); + + EXPECT_EQ(m["Who"], ""); EXPECT_EQ(m.ssize(), 5); -} - +} + TEST(CompactFlatMapTest, Erase) { - auto m = CreateMap(); - - m.erase("antique"); + auto m = CreateMap(); + + m.erase("antique"); EXPECT_EQ(m.ssize(), 3); - - m.erase("Who"); + + m.erase("Who"); EXPECT_EQ(m.ssize(), 3); - - m.erase(m.begin(), m.end()); - EXPECT_TRUE(m.empty()); -} - + + m.erase(m.begin(), m.end()); + EXPECT_TRUE(m.empty()); +} + TEST(CompactFlatMapTest, GrowShrink) { - TMap m; - m.insert({"Two", "vast"}); - m.insert({"and", "trunkless"}); - m.insert({"legs", "of"}); - m.insert({"stone", "Stand"}); - m.insert({"in", "the"}); - m.insert({"desert", "..."}); - - m.erase("legs"); - m.erase("stone"); - m.erase("in"); - m.erase("desert"); - + TMap m; + m.insert({"Two", "vast"}); + m.insert({"and", "trunkless"}); + m.insert({"legs", "of"}); + m.insert({"stone", "Stand"}); + m.insert({"in", "the"}); + m.insert({"desert", "..."}); + + m.erase("legs"); + m.erase("stone"); + m.erase("in"); + m.erase("desert"); + EXPECT_EQ(m.ssize(), 2); - - // Must not crash or trigger asan. -} - + + // Must not crash or trigger asan. +} + TEST(CompactFlatMapTest, GrowShrinkGrow) { - TMap m; - m.insert({"Two", "vast"}); - m.insert({"and", "trunkless"}); - m.insert({"legs", "of"}); - m.insert({"stone", "Stand"}); - m.insert({"in", "the"}); - m.insert({"desert", "..."}); - - m.erase("legs"); - m.erase("stone"); - m.erase("in"); - m.erase("desert"); - + TMap m; + m.insert({"Two", "vast"}); + m.insert({"and", "trunkless"}); + m.insert({"legs", "of"}); + m.insert({"stone", "Stand"}); + m.insert({"in", "the"}); + m.insert({"desert", "..."}); + + m.erase("legs"); + m.erase("stone"); + m.erase("in"); + m.erase("desert"); + EXPECT_EQ(m.ssize(), 2); - - m.insert({"I", "met"}); - m.insert({"a", "traveller"}); - m.insert({"from", "an"}); - m.insert({"antique", "land"}); - + + m.insert({"I", "met"}); + m.insert({"a", "traveller"}); + m.insert({"from", "an"}); + m.insert({"antique", "land"}); + EXPECT_EQ(m.ssize(), 6); - - // Must not crash or trigger asan. -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT + + // Must not crash or trigger asan. +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/small_containers/unittests/compact_set_ut.cpp b/library/cpp/yt/small_containers/unittests/compact_set_ut.cpp index ebab5846e1..bbb2f5927b 100644 --- a/library/cpp/yt/small_containers/unittests/compact_set_ut.cpp +++ b/library/cpp/yt/small_containers/unittests/compact_set_ut.cpp @@ -1,204 +1,204 @@ //===- llvm/unittest/ADT/SmallSetTest.cpp ---------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// // CompactSet unit tests. -// -//===----------------------------------------------------------------------===// - +// +//===----------------------------------------------------------------------===// + #include <library/cpp/yt/small_containers/compact_set.h> - + #include <library/cpp/testing/gtest/gtest.h> -#include <string> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - +#include <string> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + TEST(CompactSetTest, Insert) { - + TCompactSet<int, 4> s1; - - for (int i = 0; i < 4; i++) - s1.insert(i); - - for (int i = 0; i < 4; i++) - s1.insert(i); - - EXPECT_EQ(4u, s1.size()); - - for (int i = 0; i < 4; i++) - EXPECT_EQ(1u, s1.count(i)); - - EXPECT_EQ(0u, s1.count(4)); -} - + + for (int i = 0; i < 4; i++) + s1.insert(i); + + for (int i = 0; i < 4; i++) + s1.insert(i); + + EXPECT_EQ(4u, s1.size()); + + for (int i = 0; i < 4; i++) + EXPECT_EQ(1u, s1.count(i)); + + EXPECT_EQ(0u, s1.count(4)); +} + TEST(CompactSetTest, Grow) { TCompactSet<int, 4> s1; - - for (int i = 0; i < 8; i++) - s1.insert(i); - - EXPECT_EQ(8u, s1.size()); - - for (int i = 0; i < 8; i++) - EXPECT_EQ(1u, s1.count(i)); - - EXPECT_EQ(0u, s1.count(8)); -} - + + for (int i = 0; i < 8; i++) + s1.insert(i); + + EXPECT_EQ(8u, s1.size()); + + for (int i = 0; i < 8; i++) + EXPECT_EQ(1u, s1.count(i)); + + EXPECT_EQ(0u, s1.count(8)); +} + TEST(CompactSetTest, Erase) { TCompactSet<int, 4> s1; - - for (int i = 0; i < 8; i++) - s1.insert(i); - - EXPECT_EQ(8u, s1.size()); - - // Remove elements one by one and check if all other elements are still there. - for (int i = 0; i < 8; i++) { - EXPECT_EQ(1u, s1.count(i)); - EXPECT_TRUE(s1.erase(i)); - EXPECT_EQ(0u, s1.count(i)); - EXPECT_EQ(8u - i - 1, s1.size()); - for (int j = i + 1; j < 8; j++) - EXPECT_EQ(1u, s1.count(j)); - } - - EXPECT_EQ(0u, s1.count(8)); -} - + + for (int i = 0; i < 8; i++) + s1.insert(i); + + EXPECT_EQ(8u, s1.size()); + + // Remove elements one by one and check if all other elements are still there. + for (int i = 0; i < 8; i++) { + EXPECT_EQ(1u, s1.count(i)); + EXPECT_TRUE(s1.erase(i)); + EXPECT_EQ(0u, s1.count(i)); + EXPECT_EQ(8u - i - 1, s1.size()); + for (int j = i + 1; j < 8; j++) + EXPECT_EQ(1u, s1.count(j)); + } + + EXPECT_EQ(0u, s1.count(8)); +} + TEST(CompactSetTest, IteratorInt) { TCompactSet<int, 4> s1; - - // Test the 'small' case. - for (int i = 0; i < 3; i++) - s1.insert(i); - - std::vector<int> V(s1.begin(), s1.end()); - // Make sure the elements are in the expected order. - std::sort(V.begin(), V.end()); - for (int i = 0; i < 3; i++) - EXPECT_EQ(i, V[i]); - - // Test the 'big' case by adding a few more elements to switch to std::set - // internally. - for (int i = 3; i < 6; i++) - s1.insert(i); - - V.assign(s1.begin(), s1.end()); - // Make sure the elements are in the expected order. - std::sort(V.begin(), V.end()); - for (int i = 0; i < 6; i++) - EXPECT_EQ(i, V[i]); -} - + + // Test the 'small' case. + for (int i = 0; i < 3; i++) + s1.insert(i); + + std::vector<int> V(s1.begin(), s1.end()); + // Make sure the elements are in the expected order. + std::sort(V.begin(), V.end()); + for (int i = 0; i < 3; i++) + EXPECT_EQ(i, V[i]); + + // Test the 'big' case by adding a few more elements to switch to std::set + // internally. + for (int i = 3; i < 6; i++) + s1.insert(i); + + V.assign(s1.begin(), s1.end()); + // Make sure the elements are in the expected order. + std::sort(V.begin(), V.end()); + for (int i = 0; i < 6; i++) + EXPECT_EQ(i, V[i]); +} + TEST(CompactSetTest, IteratorString) { // Test CompactSetIterator for TCompactSet with a type with non-trivial - // ctors/dtors. + // ctors/dtors. TCompactSet<std::string, 2> s1; - - s1.insert("str 1"); - s1.insert("str 2"); - s1.insert("str 1"); - - std::vector<std::string> V(s1.begin(), s1.end()); - std::sort(V.begin(), V.end()); - EXPECT_EQ(2u, s1.size()); - EXPECT_EQ("str 1", V[0]); - EXPECT_EQ("str 2", V[1]); - - s1.insert("str 4"); - s1.insert("str 0"); - s1.insert("str 4"); - - V.assign(s1.begin(), s1.end()); - // Make sure the elements are in the expected order. - std::sort(V.begin(), V.end()); - EXPECT_EQ(4u, s1.size()); - EXPECT_EQ("str 0", V[0]); - EXPECT_EQ("str 1", V[1]); - EXPECT_EQ("str 2", V[2]); - EXPECT_EQ("str 4", V[3]); -} - + + s1.insert("str 1"); + s1.insert("str 2"); + s1.insert("str 1"); + + std::vector<std::string> V(s1.begin(), s1.end()); + std::sort(V.begin(), V.end()); + EXPECT_EQ(2u, s1.size()); + EXPECT_EQ("str 1", V[0]); + EXPECT_EQ("str 2", V[1]); + + s1.insert("str 4"); + s1.insert("str 0"); + s1.insert("str 4"); + + V.assign(s1.begin(), s1.end()); + // Make sure the elements are in the expected order. + std::sort(V.begin(), V.end()); + EXPECT_EQ(4u, s1.size()); + EXPECT_EQ("str 0", V[0]); + EXPECT_EQ("str 1", V[1]); + EXPECT_EQ("str 2", V[2]); + EXPECT_EQ("str 4", V[3]); +} + TEST(CompactSetTest, IteratorIncMoveCopy) { // Test CompactSetIterator for TCompactSet with a type with non-trivial - // ctors/dtors. + // ctors/dtors. TCompactSet<std::string, 2> s1; - - s1.insert("str 1"); - s1.insert("str 2"); - - auto Iter = s1.begin(); - EXPECT_EQ("str 1", *Iter); - ++Iter; - EXPECT_EQ("str 2", *Iter); - - s1.insert("str 4"); - s1.insert("str 0"); - auto Iter2 = s1.begin(); - Iter = std::move(Iter2); - EXPECT_EQ("str 0", *Iter); -} - -// These test weren't taken from llvm. - + + s1.insert("str 1"); + s1.insert("str 2"); + + auto Iter = s1.begin(); + EXPECT_EQ("str 1", *Iter); + ++Iter; + EXPECT_EQ("str 2", *Iter); + + s1.insert("str 4"); + s1.insert("str 0"); + auto Iter2 = s1.begin(); + Iter = std::move(Iter2); + EXPECT_EQ("str 0", *Iter); +} + +// These test weren't taken from llvm. + TEST(CompactSetTest, Empty) { TCompactSet<int, 10> v; - EXPECT_TRUE(v.empty()); - - auto data = {1, 2, 3, 4, 5}; - - v.insert(data.begin(), data.end()); // not crossing size threshold - v.erase(4); - v.erase(2); - v.erase(3); - v.erase(5); - v.erase(1); - EXPECT_TRUE(v.empty()); - - auto data2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - v.insert(data2.begin(), data2.end()); // crossing size threshold - v.erase(7); - v.erase(3); - v.erase(1); - v.erase(10); - v.erase(9); - v.erase(0); - v.erase(2); - v.erase(6); - v.erase(4); - v.erase(5); - v.erase(8); - EXPECT_TRUE(v.empty()); -} - + EXPECT_TRUE(v.empty()); + + auto data = {1, 2, 3, 4, 5}; + + v.insert(data.begin(), data.end()); // not crossing size threshold + v.erase(4); + v.erase(2); + v.erase(3); + v.erase(5); + v.erase(1); + EXPECT_TRUE(v.empty()); + + auto data2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + v.insert(data2.begin(), data2.end()); // crossing size threshold + v.erase(7); + v.erase(3); + v.erase(1); + v.erase(10); + v.erase(9); + v.erase(0); + v.erase(2); + v.erase(6); + v.erase(4); + v.erase(5); + v.erase(8); + EXPECT_TRUE(v.empty()); +} + TEST(CompactSetTest, ForEach) { TCompactSet<int, 10> v; - - auto data = {10, 9, 3, 4, 1, 5, 6, 8}; - - v.insert(data.begin(), data.end()); - - std::vector<int> buf(v.begin(), v.end()); - std::vector<int> expected{1, 3, 4, 5, 6, 8, 9, 10}; - EXPECT_EQ(expected, buf); - - auto data2 = {7, 1, 2, 0}; - v.insert(data2.begin(), data2.end()); - buf.assign(v.begin(), v.end()); - expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - EXPECT_EQ(expected, buf); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT + + auto data = {10, 9, 3, 4, 1, 5, 6, 8}; + + v.insert(data.begin(), data.end()); + + std::vector<int> buf(v.begin(), v.end()); + std::vector<int> expected{1, 3, 4, 5, 6, 8, 9, 10}; + EXPECT_EQ(expected, buf); + + auto data2 = {7, 1, 2, 0}; + v.insert(data2.begin(), data2.end()); + buf.assign(v.begin(), v.end()); + expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + EXPECT_EQ(expected, buf); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp b/library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp index 770d62b9fd..508a29d103 100644 --- a/library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp +++ b/library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp @@ -1,272 +1,272 @@ -// Adapted from the following: -//===- llvm/unittest/ADT/CompactVectorTest.cpp ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// +// Adapted from the following: +//===- llvm/unittest/ADT/CompactVectorTest.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// // TCompactVector unit tests. -// -//===----------------------------------------------------------------------===// - -#include <yt/yt/core/test_framework/framework.h> - -#include <yt/yt/core/misc/compact_vector.h> - -#include <algorithm> -#include <list> - -#include <stdarg.h> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -/// A helper class that counts the total number of constructor and -/// destructor calls. -class Constructable { -private: - static int numConstructorCalls; - static int numMoveConstructorCalls; - static int numCopyConstructorCalls; - static int numDestructorCalls; - static int numAssignmentCalls; - static int numMoveAssignmentCalls; - static int numCopyAssignmentCalls; - - bool constructed; - int value; - -public: - Constructable() : constructed(true), value(0) { - ++numConstructorCalls; - } - - Constructable(int val) : constructed(true), value(val) { - ++numConstructorCalls; - } - - Constructable(const Constructable & src) : constructed(true) { - value = src.value; - ++numConstructorCalls; - ++numCopyConstructorCalls; - } - - Constructable(Constructable && src) : constructed(true) { - value = src.value; - ++numConstructorCalls; - ++numMoveConstructorCalls; - } - - ~Constructable() { - EXPECT_TRUE(constructed); - ++numDestructorCalls; - constructed = false; - } - - Constructable & operator=(const Constructable & src) { - EXPECT_TRUE(constructed); - value = src.value; - ++numAssignmentCalls; - ++numCopyAssignmentCalls; - return *this; - } - - Constructable & operator=(Constructable && src) { - EXPECT_TRUE(constructed); - value = src.value; - ++numAssignmentCalls; - ++numMoveAssignmentCalls; - return *this; - } - - int getValue() const { - return abs(value); - } - - static void reset() { - numConstructorCalls = 0; - numMoveConstructorCalls = 0; - numCopyConstructorCalls = 0; - numDestructorCalls = 0; - numAssignmentCalls = 0; - numMoveAssignmentCalls = 0; - numCopyAssignmentCalls = 0; - } - - static int getNumConstructorCalls() { - return numConstructorCalls; - } - - static int getNumMoveConstructorCalls() { - return numMoveConstructorCalls; - } - - static int getNumCopyConstructorCalls() { - return numCopyConstructorCalls; - } - - static int getNumDestructorCalls() { - return numDestructorCalls; - } - - static int getNumAssignmentCalls() { - return numAssignmentCalls; - } - - static int getNumMoveAssignmentCalls() { - return numMoveAssignmentCalls; - } - - static int getNumCopyAssignmentCalls() { - return numCopyAssignmentCalls; - } - - friend bool operator==(const Constructable & c0, const Constructable & c1) { - return c0.getValue() == c1.getValue(); - } -}; - -int Constructable::numConstructorCalls; -int Constructable::numCopyConstructorCalls; -int Constructable::numMoveConstructorCalls; -int Constructable::numDestructorCalls; -int Constructable::numAssignmentCalls; -int Constructable::numCopyAssignmentCalls; -int Constructable::numMoveAssignmentCalls; - -struct NonCopyable { - NonCopyable() {} - NonCopyable(NonCopyable &&) {} - NonCopyable &operator=(NonCopyable &&) { return *this; } -private: - NonCopyable(const NonCopyable &) = delete; - NonCopyable &operator=(const NonCopyable &) = delete; -}; - -[[maybe_unused]] void CompileTest() { - TCompactVector<NonCopyable, 0> V; - V.resize(42); -} - -class CompactVectorTestBase : public testing::Test { -protected: - +// +//===----------------------------------------------------------------------===// + +#include <yt/yt/core/test_framework/framework.h> + +#include <yt/yt/core/misc/compact_vector.h> + +#include <algorithm> +#include <list> + +#include <stdarg.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +/// A helper class that counts the total number of constructor and +/// destructor calls. +class Constructable { +private: + static int numConstructorCalls; + static int numMoveConstructorCalls; + static int numCopyConstructorCalls; + static int numDestructorCalls; + static int numAssignmentCalls; + static int numMoveAssignmentCalls; + static int numCopyAssignmentCalls; + + bool constructed; + int value; + +public: + Constructable() : constructed(true), value(0) { + ++numConstructorCalls; + } + + Constructable(int val) : constructed(true), value(val) { + ++numConstructorCalls; + } + + Constructable(const Constructable & src) : constructed(true) { + value = src.value; + ++numConstructorCalls; + ++numCopyConstructorCalls; + } + + Constructable(Constructable && src) : constructed(true) { + value = src.value; + ++numConstructorCalls; + ++numMoveConstructorCalls; + } + + ~Constructable() { + EXPECT_TRUE(constructed); + ++numDestructorCalls; + constructed = false; + } + + Constructable & operator=(const Constructable & src) { + EXPECT_TRUE(constructed); + value = src.value; + ++numAssignmentCalls; + ++numCopyAssignmentCalls; + return *this; + } + + Constructable & operator=(Constructable && src) { + EXPECT_TRUE(constructed); + value = src.value; + ++numAssignmentCalls; + ++numMoveAssignmentCalls; + return *this; + } + + int getValue() const { + return abs(value); + } + + static void reset() { + numConstructorCalls = 0; + numMoveConstructorCalls = 0; + numCopyConstructorCalls = 0; + numDestructorCalls = 0; + numAssignmentCalls = 0; + numMoveAssignmentCalls = 0; + numCopyAssignmentCalls = 0; + } + + static int getNumConstructorCalls() { + return numConstructorCalls; + } + + static int getNumMoveConstructorCalls() { + return numMoveConstructorCalls; + } + + static int getNumCopyConstructorCalls() { + return numCopyConstructorCalls; + } + + static int getNumDestructorCalls() { + return numDestructorCalls; + } + + static int getNumAssignmentCalls() { + return numAssignmentCalls; + } + + static int getNumMoveAssignmentCalls() { + return numMoveAssignmentCalls; + } + + static int getNumCopyAssignmentCalls() { + return numCopyAssignmentCalls; + } + + friend bool operator==(const Constructable & c0, const Constructable & c1) { + return c0.getValue() == c1.getValue(); + } +}; + +int Constructable::numConstructorCalls; +int Constructable::numCopyConstructorCalls; +int Constructable::numMoveConstructorCalls; +int Constructable::numDestructorCalls; +int Constructable::numAssignmentCalls; +int Constructable::numCopyAssignmentCalls; +int Constructable::numMoveAssignmentCalls; + +struct NonCopyable { + NonCopyable() {} + NonCopyable(NonCopyable &&) {} + NonCopyable &operator=(NonCopyable &&) { return *this; } +private: + NonCopyable(const NonCopyable &) = delete; + NonCopyable &operator=(const NonCopyable &) = delete; +}; + +[[maybe_unused]] void CompileTest() { + TCompactVector<NonCopyable, 0> V; + V.resize(42); +} + +class CompactVectorTestBase : public testing::Test { +protected: + void SetUp() override { - Constructable::reset(); - } - - template <typename VectorT> - void assertEmpty(VectorT & v) { - // Size tests - EXPECT_EQ(0u, v.size()); - EXPECT_TRUE(v.empty()); - - // Iterator tests - EXPECT_TRUE(v.begin() == v.end()); - } - - // Assert that v contains the specified values, in order. - template <typename VectorT> - void assertValuesInOrder(VectorT & v, size_t size, ...) { - EXPECT_EQ(size, v.size()); - - va_list ap; - va_start(ap, size); - for (size_t i = 0; i < size; ++i) { - int value = va_arg(ap, int); - EXPECT_EQ(value, v[i].getValue()); - } - - va_end(ap); - } - - // Generate a sequence of values to initialize the vector. - template <typename VectorT> - void makeSequence(VectorT & v, int start, int end) { - for (int i = start; i <= end; ++i) { - v.push_back(Constructable(i)); - } - } -}; - -// Test fixture class -template <typename VectorT> -class CompactVectorTest : public CompactVectorTestBase { -protected: - VectorT theVector; - VectorT otherVector; -}; - - -typedef ::testing::Types<TCompactVector<Constructable, 0>, - TCompactVector<Constructable, 1>, - TCompactVector<Constructable, 2>, - TCompactVector<Constructable, 4>, - TCompactVector<Constructable, 5> - > CompactVectorTestTypes; -TYPED_TEST_SUITE(CompactVectorTest, CompactVectorTestTypes); - -// New vector test. -TYPED_TEST(CompactVectorTest, EmptyVectorTest) { - SCOPED_TRACE("EmptyVectorTest"); - this->assertEmpty(this->theVector); - EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend()); - EXPECT_EQ(0, Constructable::getNumConstructorCalls()); - EXPECT_EQ(0, Constructable::getNumDestructorCalls()); -} - -// Simple insertions and deletions. -TYPED_TEST(CompactVectorTest, PushPopTest) { - SCOPED_TRACE("PushPopTest"); - - // Track whether the vector will potentially have to grow. - bool RequiresGrowth = this->theVector.capacity() < 3; - - // Push an element - this->theVector.push_back(Constructable(1)); - - // Size tests - this->assertValuesInOrder(this->theVector, 1u, 1); - EXPECT_FALSE(this->theVector.begin() == this->theVector.end()); - EXPECT_FALSE(this->theVector.empty()); - - // Push another element - this->theVector.push_back(Constructable(2)); - this->assertValuesInOrder(this->theVector, 2u, 1, 2); - - // Insert at beginning - this->theVector.insert(this->theVector.begin(), this->theVector[1]); - this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2); - - // Pop one element - this->theVector.pop_back(); - this->assertValuesInOrder(this->theVector, 2u, 2, 1); - - // Pop remaining elements - this->theVector.pop_back(); - this->theVector.pop_back(); - this->assertEmpty(this->theVector); - - // Check number of constructor calls. Should be 2 for each list element, - // one for the argument to push_back, one for the argument to insert, - // and one for the list element itself. - if (!RequiresGrowth) { - EXPECT_EQ(5, Constructable::getNumConstructorCalls()); - EXPECT_EQ(5, Constructable::getNumDestructorCalls()); - } else { - // If we had to grow the vector, these only have a lower bound, but should - // always be equal. - EXPECT_LE(5, Constructable::getNumConstructorCalls()); - EXPECT_EQ(Constructable::getNumConstructorCalls(), - Constructable::getNumDestructorCalls()); - } -} - + Constructable::reset(); + } + + template <typename VectorT> + void assertEmpty(VectorT & v) { + // Size tests + EXPECT_EQ(0u, v.size()); + EXPECT_TRUE(v.empty()); + + // Iterator tests + EXPECT_TRUE(v.begin() == v.end()); + } + + // Assert that v contains the specified values, in order. + template <typename VectorT> + void assertValuesInOrder(VectorT & v, size_t size, ...) { + EXPECT_EQ(size, v.size()); + + va_list ap; + va_start(ap, size); + for (size_t i = 0; i < size; ++i) { + int value = va_arg(ap, int); + EXPECT_EQ(value, v[i].getValue()); + } + + va_end(ap); + } + + // Generate a sequence of values to initialize the vector. + template <typename VectorT> + void makeSequence(VectorT & v, int start, int end) { + for (int i = start; i <= end; ++i) { + v.push_back(Constructable(i)); + } + } +}; + +// Test fixture class +template <typename VectorT> +class CompactVectorTest : public CompactVectorTestBase { +protected: + VectorT theVector; + VectorT otherVector; +}; + + +typedef ::testing::Types<TCompactVector<Constructable, 0>, + TCompactVector<Constructable, 1>, + TCompactVector<Constructable, 2>, + TCompactVector<Constructable, 4>, + TCompactVector<Constructable, 5> + > CompactVectorTestTypes; +TYPED_TEST_SUITE(CompactVectorTest, CompactVectorTestTypes); + +// New vector test. +TYPED_TEST(CompactVectorTest, EmptyVectorTest) { + SCOPED_TRACE("EmptyVectorTest"); + this->assertEmpty(this->theVector); + EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend()); + EXPECT_EQ(0, Constructable::getNumConstructorCalls()); + EXPECT_EQ(0, Constructable::getNumDestructorCalls()); +} + +// Simple insertions and deletions. +TYPED_TEST(CompactVectorTest, PushPopTest) { + SCOPED_TRACE("PushPopTest"); + + // Track whether the vector will potentially have to grow. + bool RequiresGrowth = this->theVector.capacity() < 3; + + // Push an element + this->theVector.push_back(Constructable(1)); + + // Size tests + this->assertValuesInOrder(this->theVector, 1u, 1); + EXPECT_FALSE(this->theVector.begin() == this->theVector.end()); + EXPECT_FALSE(this->theVector.empty()); + + // Push another element + this->theVector.push_back(Constructable(2)); + this->assertValuesInOrder(this->theVector, 2u, 1, 2); + + // Insert at beginning + this->theVector.insert(this->theVector.begin(), this->theVector[1]); + this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2); + + // Pop one element + this->theVector.pop_back(); + this->assertValuesInOrder(this->theVector, 2u, 2, 1); + + // Pop remaining elements + this->theVector.pop_back(); + this->theVector.pop_back(); + this->assertEmpty(this->theVector); + + // Check number of constructor calls. Should be 2 for each list element, + // one for the argument to push_back, one for the argument to insert, + // and one for the list element itself. + if (!RequiresGrowth) { + EXPECT_EQ(5, Constructable::getNumConstructorCalls()); + EXPECT_EQ(5, Constructable::getNumDestructorCalls()); + } else { + // If we had to grow the vector, these only have a lower bound, but should + // always be equal. + EXPECT_LE(5, Constructable::getNumConstructorCalls()); + EXPECT_EQ(Constructable::getNumConstructorCalls(), + Constructable::getNumDestructorCalls()); + } +} + TYPED_TEST(CompactVectorTest, InsertEnd) { SCOPED_TRACE("InsertEnd"); @@ -304,781 +304,781 @@ TYPED_TEST(CompactVectorTest, ShrinkToSmall) } } -// Clear test. -TYPED_TEST(CompactVectorTest, ClearTest) { - SCOPED_TRACE("ClearTest"); - - this->theVector.reserve(2); - this->makeSequence(this->theVector, 1, 2); - this->theVector.clear(); - - this->assertEmpty(this->theVector); - EXPECT_EQ(4, Constructable::getNumConstructorCalls()); - EXPECT_EQ(4, Constructable::getNumDestructorCalls()); -} - -// Resize smaller test. -TYPED_TEST(CompactVectorTest, ResizeShrinkTest) { - SCOPED_TRACE("ResizeShrinkTest"); - - this->theVector.reserve(3); - this->makeSequence(this->theVector, 1, 3); - this->theVector.resize(1); - - this->assertValuesInOrder(this->theVector, 1u, 1); - EXPECT_EQ(6, Constructable::getNumConstructorCalls()); - EXPECT_EQ(5, Constructable::getNumDestructorCalls()); -} - -// Resize bigger test. -TYPED_TEST(CompactVectorTest, ResizeGrowTest) { - SCOPED_TRACE("ResizeGrowTest"); - - this->theVector.resize(2); - - EXPECT_EQ(2, Constructable::getNumConstructorCalls()); - EXPECT_EQ(0, Constructable::getNumDestructorCalls()); - EXPECT_EQ(2u, this->theVector.size()); -} - -TYPED_TEST(CompactVectorTest, ResizeWithElementsTest) { - this->theVector.resize(2); - - Constructable::reset(); - - this->theVector.resize(4); - - size_t Ctors = Constructable::getNumConstructorCalls(); - EXPECT_TRUE(Ctors == 2 || Ctors == 4); - size_t MoveCtors = Constructable::getNumMoveConstructorCalls(); - EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2); - size_t Dtors = Constructable::getNumDestructorCalls(); - EXPECT_TRUE(Dtors == 0 || Dtors == 2); -} - -// Resize with fill value. -TYPED_TEST(CompactVectorTest, ResizeFillTest) { - SCOPED_TRACE("ResizeFillTest"); - - this->theVector.resize(3, Constructable(77)); - this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77); -} - -// Overflow past fixed size. -TYPED_TEST(CompactVectorTest, OverflowTest) { - SCOPED_TRACE("OverflowTest"); - - // Push more elements than the fixed size. - this->makeSequence(this->theVector, 1, 10); - - // Test size and values. - EXPECT_EQ(10u, this->theVector.size()); - for (int i = 0; i < 10; ++i) { - EXPECT_EQ(i+1, this->theVector[i].getValue()); - } - - // Now resize back to fixed size. - this->theVector.resize(1); - - this->assertValuesInOrder(this->theVector, 1u, 1); -} - -// Iteration tests. -TYPED_TEST(CompactVectorTest, IterationTest) { - this->makeSequence(this->theVector, 1, 2); - - // Forward Iteration - typename TypeParam::iterator it = this->theVector.begin(); - EXPECT_TRUE(*it == this->theVector.front()); - EXPECT_TRUE(*it == this->theVector[0]); - EXPECT_EQ(1, it->getValue()); - ++it; - EXPECT_TRUE(*it == this->theVector[1]); - EXPECT_TRUE(*it == this->theVector.back()); - EXPECT_EQ(2, it->getValue()); - ++it; - EXPECT_TRUE(it == this->theVector.end()); - --it; - EXPECT_TRUE(*it == this->theVector[1]); - EXPECT_EQ(2, it->getValue()); - --it; - EXPECT_TRUE(*it == this->theVector[0]); - EXPECT_EQ(1, it->getValue()); - - // Reverse Iteration - typename TypeParam::reverse_iterator rit = this->theVector.rbegin(); - EXPECT_TRUE(*rit == this->theVector[1]); - EXPECT_EQ(2, rit->getValue()); - ++rit; - EXPECT_TRUE(*rit == this->theVector[0]); - EXPECT_EQ(1, rit->getValue()); - ++rit; - EXPECT_TRUE(rit == this->theVector.rend()); - --rit; - EXPECT_TRUE(*rit == this->theVector[0]); - EXPECT_EQ(1, rit->getValue()); - --rit; - EXPECT_TRUE(*rit == this->theVector[1]); - EXPECT_EQ(2, rit->getValue()); -} - -// Swap test. -TYPED_TEST(CompactVectorTest, SwapTest) { - SCOPED_TRACE("SwapTest"); - - this->makeSequence(this->theVector, 1, 2); - std::swap(this->theVector, this->otherVector); - - this->assertEmpty(this->theVector); - this->assertValuesInOrder(this->otherVector, 2u, 1, 2); -} - -// Append test -TYPED_TEST(CompactVectorTest, AppendTest) { - SCOPED_TRACE("AppendTest"); - - this->makeSequence(this->otherVector, 2, 3); - - this->theVector.push_back(Constructable(1)); - this->theVector.insert(this->theVector.end(), this->otherVector.begin(), this->otherVector.end()); - - this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); -} - -// Append repeated test -TYPED_TEST(CompactVectorTest, AppendRepeatedTest) { - SCOPED_TRACE("AppendRepeatedTest"); - - this->theVector.push_back(Constructable(1)); - this->theVector.insert(this->theVector.end(), 2, Constructable(77)); - this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77); -} - -// Assign test -TYPED_TEST(CompactVectorTest, AssignTest) { - SCOPED_TRACE("AssignTest"); - - this->theVector.push_back(Constructable(1)); - this->theVector.assign(2, Constructable(77)); - this->assertValuesInOrder(this->theVector, 2u, 77, 77); -} - -// Move-assign test -TYPED_TEST(CompactVectorTest, MoveAssignTest) { - SCOPED_TRACE("MoveAssignTest"); - - // Set up our vector with a single element, but enough capacity for 4. - this->theVector.reserve(4); - this->theVector.push_back(Constructable(1)); - - // Set up the other vector with 2 elements. - this->otherVector.push_back(Constructable(2)); - this->otherVector.push_back(Constructable(3)); - - // Move-assign from the other vector. - this->theVector = std::move(this->otherVector); - - // Make sure we have the right result. - this->assertValuesInOrder(this->theVector, 2u, 2, 3); - - // Make sure the # of constructor/destructor calls line up. There - // are two live objects after clearing the other vector. - this->otherVector.clear(); - EXPECT_EQ(Constructable::getNumConstructorCalls()-2, - Constructable::getNumDestructorCalls()); - - // There shouldn't be any live objects any more. - this->theVector.clear(); - EXPECT_EQ(Constructable::getNumConstructorCalls(), - Constructable::getNumDestructorCalls()); -} - -// Erase a single element -TYPED_TEST(CompactVectorTest, EraseTest) { - SCOPED_TRACE("EraseTest"); - - this->makeSequence(this->theVector, 1, 3); - this->theVector.erase(this->theVector.begin()); - this->assertValuesInOrder(this->theVector, 2u, 2, 3); -} - -// Erase a range of elements -TYPED_TEST(CompactVectorTest, EraseRangeTest) { - SCOPED_TRACE("EraseRangeTest"); - - this->makeSequence(this->theVector, 1, 3); - this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2); - this->assertValuesInOrder(this->theVector, 1u, 3); -} - -// Insert a single element. -TYPED_TEST(CompactVectorTest, InsertTest) { - SCOPED_TRACE("InsertTest"); - - this->makeSequence(this->theVector, 1, 3); - typename TypeParam::iterator I = - this->theVector.insert(this->theVector.begin() + 1, Constructable(77)); - EXPECT_EQ(this->theVector.begin() + 1, I); - this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); -} - -// Insert a copy of a single element. -TYPED_TEST(CompactVectorTest, InsertCopy) { - SCOPED_TRACE("InsertTest"); - - this->makeSequence(this->theVector, 1, 3); - Constructable C(77); - typename TypeParam::iterator I = - this->theVector.insert(this->theVector.begin() + 1, C); - EXPECT_EQ(this->theVector.begin() + 1, I); - this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); -} - -// Insert repeated elements. -TYPED_TEST(CompactVectorTest, InsertRepeatedTest) { - SCOPED_TRACE("InsertRepeatedTest"); - - this->makeSequence(this->theVector, 1, 4); - Constructable::reset(); - auto I = - this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16)); - // Move construct the top element into newly allocated space, and optionally - // reallocate the whole buffer, move constructing into it. - // FIXME: This is inefficient, we shouldn't move things into newly allocated - // space, then move them up/around, there should only be 2 or 4 move - // constructions here. - EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || - Constructable::getNumMoveConstructorCalls() == 6); - // Move assign the next two to shift them up and make a gap. - EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls()); - // Copy construct the two new elements from the parameter. - EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); - // All without any copy construction. - EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls()); - EXPECT_EQ(this->theVector.begin() + 1, I); - this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4); -} - - -TYPED_TEST(CompactVectorTest, InsertRepeatedAtEndTest) { - SCOPED_TRACE("InsertRepeatedTest"); - - this->makeSequence(this->theVector, 1, 4); - Constructable::reset(); - auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16)); - // Just copy construct them into newly allocated space - EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls()); - // Move everything across if reallocation is needed. - EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || - Constructable::getNumMoveConstructorCalls() == 4); - // Without ever moving or copying anything else. - EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); - EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); - - EXPECT_EQ(this->theVector.begin() + 4, I); - this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16); -} - -TYPED_TEST(CompactVectorTest, InsertRepeatedEmptyTest) { - SCOPED_TRACE("InsertRepeatedTest"); - - this->makeSequence(this->theVector, 10, 15); - - // Empty insert. - EXPECT_EQ(this->theVector.end(), - this->theVector.insert(this->theVector.end(), - 0, Constructable(42))); - EXPECT_EQ(this->theVector.begin() + 1, - this->theVector.insert(this->theVector.begin() + 1, - 0, Constructable(42))); -} - -// Insert range. -TYPED_TEST(CompactVectorTest, InsertRangeTest) { - SCOPED_TRACE("InsertRangeTest"); - - Constructable Arr[3] = - { Constructable(77), Constructable(77), Constructable(77) }; - - this->makeSequence(this->theVector, 1, 3); - Constructable::reset(); - auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3); - // Move construct the top 3 elements into newly allocated space. - // Possibly move the whole sequence into new space first. - // FIXME: This is inefficient, we shouldn't move things into newly allocated - // space, then move them up/around, there should only be 2 or 3 move - // constructions here. - EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || - Constructable::getNumMoveConstructorCalls() == 5); - // Copy assign the lower 2 new elements into existing space. - EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); - // Copy construct the third element into newly allocated space. - EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls()); - EXPECT_EQ(this->theVector.begin() + 1, I); - this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3); -} - - -TYPED_TEST(CompactVectorTest, InsertRangeAtEndTest) { - SCOPED_TRACE("InsertRangeTest"); - - Constructable Arr[3] = - { Constructable(77), Constructable(77), Constructable(77) }; - - this->makeSequence(this->theVector, 1, 3); - - // Insert at end. - Constructable::reset(); - auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3); - // Copy construct the 3 elements into new space at the top. - EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls()); - // Don't copy/move anything else. - EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); - // Reallocation might occur, causing all elements to be moved into the new - // buffer. - EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || - Constructable::getNumMoveConstructorCalls() == 3); - EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); - EXPECT_EQ(this->theVector.begin() + 3, I); - this->assertValuesInOrder(this->theVector, 6u, - 1, 2, 3, 77, 77, 77); -} - -TYPED_TEST(CompactVectorTest, InsertEmptyRangeTest) { - SCOPED_TRACE("InsertRangeTest"); - - this->makeSequence(this->theVector, 1, 3); - - // Empty insert. - EXPECT_EQ(this->theVector.end(), - this->theVector.insert(this->theVector.end(), - this->theVector.begin(), - this->theVector.begin())); - EXPECT_EQ(this->theVector.begin() + 1, - this->theVector.insert(this->theVector.begin() + 1, - this->theVector.begin(), - this->theVector.begin())); -} - -// Comparison tests. -TYPED_TEST(CompactVectorTest, ComparisonTest) { - SCOPED_TRACE("ComparisonTest"); - - this->makeSequence(this->theVector, 1, 3); - this->makeSequence(this->otherVector, 1, 3); - - EXPECT_TRUE(this->theVector == this->otherVector); - EXPECT_FALSE(this->theVector != this->otherVector); - - this->otherVector.clear(); - this->makeSequence(this->otherVector, 2, 4); - - EXPECT_FALSE(this->theVector == this->otherVector); - EXPECT_TRUE(this->theVector != this->otherVector); -} - -// Constant vector tests. -TYPED_TEST(CompactVectorTest, ConstVectorTest) { - const TypeParam constVector; - - EXPECT_EQ(0u, constVector.size()); - EXPECT_TRUE(constVector.empty()); - EXPECT_TRUE(constVector.begin() == constVector.end()); -} - -// Direct array access. -TYPED_TEST(CompactVectorTest, DirectVectorTest) { - EXPECT_EQ(0u, this->theVector.size()); - this->theVector.reserve(4); - EXPECT_LE(4u, this->theVector.capacity()); - EXPECT_EQ(0, Constructable::getNumConstructorCalls()); - this->theVector.push_back(1); - this->theVector.push_back(2); - this->theVector.push_back(3); - this->theVector.push_back(4); - EXPECT_EQ(4u, this->theVector.size()); - EXPECT_EQ(8, Constructable::getNumConstructorCalls()); - EXPECT_EQ(1, this->theVector[0].getValue()); - EXPECT_EQ(2, this->theVector[1].getValue()); - EXPECT_EQ(3, this->theVector[2].getValue()); - EXPECT_EQ(4, this->theVector[3].getValue()); -} - -TYPED_TEST(CompactVectorTest, IteratorTest) { - std::list<int> L; - this->theVector.insert(this->theVector.end(), L.begin(), L.end()); -} - -template <typename InvalidType> class DualCompactVectorsTest; - -template <typename VectorT1, typename VectorT2> -class DualCompactVectorsTest<std::pair<VectorT1, VectorT2>> : public CompactVectorTestBase { -protected: - VectorT1 theVector; - VectorT2 otherVector; - - template <typename T, size_t N> - static size_t NumBuiltinElts(const TCompactVector<T, N>&) { return N; } -}; - -typedef ::testing::Types< - // Small mode -> Small mode. - std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 4>>, - // Small mode -> Big mode. - std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 2>>, - // Big mode -> Small mode. - std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 4>>, - // Big mode -> Big mode. - std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 2>> - > DualCompactVectorTestTypes; - -TYPED_TEST_SUITE(DualCompactVectorsTest, DualCompactVectorTestTypes); - -TYPED_TEST(DualCompactVectorsTest, MoveAssignment) { - SCOPED_TRACE("MoveAssignTest-DualVectorTypes"); - - // Set up our vector with four elements. - for (unsigned I = 0; I < 4; ++I) - this->otherVector.push_back(Constructable(I)); - - const Constructable *OrigDataPtr = this->otherVector.data(); - - // Move-assign from the other vector. - this->theVector = - std::move(this->otherVector); - - // Make sure we have the right result. - this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3); - - // Make sure the # of constructor/destructor calls line up. There - // are two live objects after clearing the other vector. - this->otherVector.clear(); - EXPECT_EQ(Constructable::getNumConstructorCalls()-4, - Constructable::getNumDestructorCalls()); - - // If the source vector (otherVector) was in small-mode, assert that we just - // moved the data pointer over. - EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 || - this->theVector.data() == OrigDataPtr); - - // There shouldn't be any live objects any more. - this->theVector.clear(); - EXPECT_EQ(Constructable::getNumConstructorCalls(), - Constructable::getNumDestructorCalls()); - - // We shouldn't have copied anything in this whole process. - EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0); -} - -struct notassignable { - int &x; - notassignable(int &x) : x(x) {} -}; - -TEST(CompactVectorCustomTest, NoAssignTest) { - int x = 0; - TCompactVector<notassignable, 2> vec; - vec.push_back(notassignable(x)); - x = 42; - EXPECT_EQ(42, vec.back().x); -} - -struct MovedFrom { - bool hasValue; - MovedFrom() : hasValue(true) { - } - MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) { - m.hasValue = false; - } - MovedFrom &operator=(MovedFrom&& m) { - hasValue = m.hasValue; - m.hasValue = false; - return *this; - } -}; - -TEST(CompactVectorTest, MidInsert) { - TCompactVector<MovedFrom, 3> v; - v.push_back(MovedFrom()); - v.insert(v.begin(), MovedFrom()); - for (MovedFrom &m : v) - EXPECT_TRUE(m.hasValue); -} - -enum EmplaceableArgState { - EAS_Defaulted, - EAS_Arg, - EAS_LValue, - EAS_RValue, - EAS_Failure -}; -template <int I> struct EmplaceableArg { - EmplaceableArgState State; - EmplaceableArg() : State(EAS_Defaulted) {} - EmplaceableArg(EmplaceableArg &&X) - : State(X.State == EAS_Arg ? EAS_RValue : EAS_Failure) {} - EmplaceableArg(EmplaceableArg &X) - : State(X.State == EAS_Arg ? EAS_LValue : EAS_Failure) {} - - explicit EmplaceableArg(bool) : State(EAS_Arg) {} - -private: - EmplaceableArg &operator=(EmplaceableArg &&) = delete; - EmplaceableArg &operator=(const EmplaceableArg &) = delete; -}; - -enum EmplaceableState { ES_Emplaced, ES_Moved }; -struct Emplaceable { - EmplaceableArg<0> A0; - EmplaceableArg<1> A1; - EmplaceableArg<2> A2; - EmplaceableArg<3> A3; - EmplaceableState State; - - Emplaceable() : State(ES_Emplaced) {} - - template <class A0Ty> - explicit Emplaceable(A0Ty &&A0) - : A0(std::forward<A0Ty>(A0)), State(ES_Emplaced) {} - - template <class A0Ty, class A1Ty> - Emplaceable(A0Ty &&A0, A1Ty &&A1) - : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), - State(ES_Emplaced) {} - - template <class A0Ty, class A1Ty, class A2Ty> - Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2) - : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), - A2(std::forward<A2Ty>(A2)), State(ES_Emplaced) {} - - template <class A0Ty, class A1Ty, class A2Ty, class A3Ty> - Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2, A3Ty &&A3) - : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), - A2(std::forward<A2Ty>(A2)), A3(std::forward<A3Ty>(A3)), - State(ES_Emplaced) {} - - Emplaceable(Emplaceable &&) : State(ES_Moved) {} - Emplaceable &operator=(Emplaceable &&) { - State = ES_Moved; - return *this; - } - -private: - Emplaceable(const Emplaceable &) = delete; - Emplaceable &operator=(const Emplaceable &) = delete; -}; - -TEST(CompactVectorTest, EmplaceBack) { - EmplaceableArg<0> A0(true); - EmplaceableArg<1> A1(true); - EmplaceableArg<2> A2(true); - EmplaceableArg<3> A3(true); - { - TCompactVector<Emplaceable, 3> V; - V.emplace_back(); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace_back(std::move(A0)); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_RValue); - EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace_back(A0); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_LValue); - EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace_back(A0, A1); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_LValue); - EXPECT_TRUE(V.back().A1.State == EAS_LValue); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace_back(std::move(A0), std::move(A1)); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_RValue); - EXPECT_TRUE(V.back().A1.State == EAS_RValue); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace_back(std::move(A0), A1, std::move(A2), A3); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_RValue); - EXPECT_TRUE(V.back().A1.State == EAS_LValue); - EXPECT_TRUE(V.back().A2.State == EAS_RValue); - EXPECT_TRUE(V.back().A3.State == EAS_LValue); - } - { - TCompactVector<int, 1> V; - V.emplace_back(); - V.emplace_back(42); - EXPECT_EQ(2U, V.size()); - EXPECT_EQ(0, V[0]); - EXPECT_EQ(42, V[1]); - } -} - -TEST(CompactVectorTest, Emplace) { - EmplaceableArg<0> A0(true); - EmplaceableArg<1> A1(true); - EmplaceableArg<2> A2(true); - EmplaceableArg<3> A3(true); - { - TCompactVector<Emplaceable, 3> V; - V.emplace(V.end()); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace(V.end(), std::move(A0)); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_RValue); - EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace(V.end(), A0); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_LValue); - EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace(V.end(), A0, A1); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_LValue); - EXPECT_TRUE(V.back().A1.State == EAS_LValue); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace(V.end(), std::move(A0), std::move(A1)); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_RValue); - EXPECT_TRUE(V.back().A1.State == EAS_RValue); - EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); - EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); - } - { - TCompactVector<Emplaceable, 3> V; - V.emplace(V.end(), std::move(A0), A1, std::move(A2), A3); - EXPECT_TRUE(V.size() == 1); - EXPECT_TRUE(V.back().State == ES_Emplaced); - EXPECT_TRUE(V.back().A0.State == EAS_RValue); - EXPECT_TRUE(V.back().A1.State == EAS_LValue); - EXPECT_TRUE(V.back().A2.State == EAS_RValue); - EXPECT_TRUE(V.back().A3.State == EAS_LValue); - } - { - TCompactVector<int, 1> V; - V.emplace_back(42); - V.emplace(V.begin(), 0); - EXPECT_EQ(2U, V.size()); - EXPECT_EQ(0, V[0]); - EXPECT_EQ(42, V[1]); - } -} - -template <class T, size_t N> -class TStubArray -{ -public: - TStubArray(const TCompactVector<T, N>& vector) - : Vector_(vector) - { } - - bool equals(std::initializer_list<T> list) - { - return std::equal(Vector_.begin(), Vector_.end(), list.begin()); - } - - TCompactVector<T, N> Vector_; -}; - -template <typename T, size_t N> -TStubArray<T, N> makeArrayRef(const TCompactVector<T, N>& vector) -{ - return TStubArray<T, N>(vector); -} - -TEST(CompactVectorTest, InitializerList) { - TCompactVector<int, 2> V1 = {}; - EXPECT_TRUE(V1.empty()); - V1 = {0, 0}; - EXPECT_TRUE(makeArrayRef(V1).equals({0, 0})); - V1 = {-1, -1}; - EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1})); - - TCompactVector<int, 2> V2 = {1, 2, 3, 4}; - EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4})); - V2.assign({4}); - EXPECT_TRUE(makeArrayRef(V2).equals({4})); - V2.insert(V2.end(), {3, 2}); - EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2})); - V2.insert(V2.begin() + 1, 5); - EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2})); -} - -TEST(CompactVectorTest, AssignToShorter) { - TCompactVector<TString, 4> lhs; - TCompactVector<TString, 4> rhs; - rhs.emplace_back("foo"); - lhs = rhs; - EXPECT_EQ(1U, lhs.size()); - EXPECT_EQ("foo", lhs[0]); -} - -TEST(CompactVectorTest, AssignToLonger) { - TCompactVector<TString, 4> lhs; - lhs.emplace_back("bar"); - lhs.emplace_back("baz"); - TCompactVector<TString, 4> rhs; - rhs.emplace_back("foo"); - lhs = rhs; - EXPECT_EQ(1U, lhs.size()); - EXPECT_EQ("foo", lhs[0]); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT +// Clear test. +TYPED_TEST(CompactVectorTest, ClearTest) { + SCOPED_TRACE("ClearTest"); + + this->theVector.reserve(2); + this->makeSequence(this->theVector, 1, 2); + this->theVector.clear(); + + this->assertEmpty(this->theVector); + EXPECT_EQ(4, Constructable::getNumConstructorCalls()); + EXPECT_EQ(4, Constructable::getNumDestructorCalls()); +} + +// Resize smaller test. +TYPED_TEST(CompactVectorTest, ResizeShrinkTest) { + SCOPED_TRACE("ResizeShrinkTest"); + + this->theVector.reserve(3); + this->makeSequence(this->theVector, 1, 3); + this->theVector.resize(1); + + this->assertValuesInOrder(this->theVector, 1u, 1); + EXPECT_EQ(6, Constructable::getNumConstructorCalls()); + EXPECT_EQ(5, Constructable::getNumDestructorCalls()); +} + +// Resize bigger test. +TYPED_TEST(CompactVectorTest, ResizeGrowTest) { + SCOPED_TRACE("ResizeGrowTest"); + + this->theVector.resize(2); + + EXPECT_EQ(2, Constructable::getNumConstructorCalls()); + EXPECT_EQ(0, Constructable::getNumDestructorCalls()); + EXPECT_EQ(2u, this->theVector.size()); +} + +TYPED_TEST(CompactVectorTest, ResizeWithElementsTest) { + this->theVector.resize(2); + + Constructable::reset(); + + this->theVector.resize(4); + + size_t Ctors = Constructable::getNumConstructorCalls(); + EXPECT_TRUE(Ctors == 2 || Ctors == 4); + size_t MoveCtors = Constructable::getNumMoveConstructorCalls(); + EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2); + size_t Dtors = Constructable::getNumDestructorCalls(); + EXPECT_TRUE(Dtors == 0 || Dtors == 2); +} + +// Resize with fill value. +TYPED_TEST(CompactVectorTest, ResizeFillTest) { + SCOPED_TRACE("ResizeFillTest"); + + this->theVector.resize(3, Constructable(77)); + this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77); +} + +// Overflow past fixed size. +TYPED_TEST(CompactVectorTest, OverflowTest) { + SCOPED_TRACE("OverflowTest"); + + // Push more elements than the fixed size. + this->makeSequence(this->theVector, 1, 10); + + // Test size and values. + EXPECT_EQ(10u, this->theVector.size()); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(i+1, this->theVector[i].getValue()); + } + + // Now resize back to fixed size. + this->theVector.resize(1); + + this->assertValuesInOrder(this->theVector, 1u, 1); +} + +// Iteration tests. +TYPED_TEST(CompactVectorTest, IterationTest) { + this->makeSequence(this->theVector, 1, 2); + + // Forward Iteration + typename TypeParam::iterator it = this->theVector.begin(); + EXPECT_TRUE(*it == this->theVector.front()); + EXPECT_TRUE(*it == this->theVector[0]); + EXPECT_EQ(1, it->getValue()); + ++it; + EXPECT_TRUE(*it == this->theVector[1]); + EXPECT_TRUE(*it == this->theVector.back()); + EXPECT_EQ(2, it->getValue()); + ++it; + EXPECT_TRUE(it == this->theVector.end()); + --it; + EXPECT_TRUE(*it == this->theVector[1]); + EXPECT_EQ(2, it->getValue()); + --it; + EXPECT_TRUE(*it == this->theVector[0]); + EXPECT_EQ(1, it->getValue()); + + // Reverse Iteration + typename TypeParam::reverse_iterator rit = this->theVector.rbegin(); + EXPECT_TRUE(*rit == this->theVector[1]); + EXPECT_EQ(2, rit->getValue()); + ++rit; + EXPECT_TRUE(*rit == this->theVector[0]); + EXPECT_EQ(1, rit->getValue()); + ++rit; + EXPECT_TRUE(rit == this->theVector.rend()); + --rit; + EXPECT_TRUE(*rit == this->theVector[0]); + EXPECT_EQ(1, rit->getValue()); + --rit; + EXPECT_TRUE(*rit == this->theVector[1]); + EXPECT_EQ(2, rit->getValue()); +} + +// Swap test. +TYPED_TEST(CompactVectorTest, SwapTest) { + SCOPED_TRACE("SwapTest"); + + this->makeSequence(this->theVector, 1, 2); + std::swap(this->theVector, this->otherVector); + + this->assertEmpty(this->theVector); + this->assertValuesInOrder(this->otherVector, 2u, 1, 2); +} + +// Append test +TYPED_TEST(CompactVectorTest, AppendTest) { + SCOPED_TRACE("AppendTest"); + + this->makeSequence(this->otherVector, 2, 3); + + this->theVector.push_back(Constructable(1)); + this->theVector.insert(this->theVector.end(), this->otherVector.begin(), this->otherVector.end()); + + this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); +} + +// Append repeated test +TYPED_TEST(CompactVectorTest, AppendRepeatedTest) { + SCOPED_TRACE("AppendRepeatedTest"); + + this->theVector.push_back(Constructable(1)); + this->theVector.insert(this->theVector.end(), 2, Constructable(77)); + this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77); +} + +// Assign test +TYPED_TEST(CompactVectorTest, AssignTest) { + SCOPED_TRACE("AssignTest"); + + this->theVector.push_back(Constructable(1)); + this->theVector.assign(2, Constructable(77)); + this->assertValuesInOrder(this->theVector, 2u, 77, 77); +} + +// Move-assign test +TYPED_TEST(CompactVectorTest, MoveAssignTest) { + SCOPED_TRACE("MoveAssignTest"); + + // Set up our vector with a single element, but enough capacity for 4. + this->theVector.reserve(4); + this->theVector.push_back(Constructable(1)); + + // Set up the other vector with 2 elements. + this->otherVector.push_back(Constructable(2)); + this->otherVector.push_back(Constructable(3)); + + // Move-assign from the other vector. + this->theVector = std::move(this->otherVector); + + // Make sure we have the right result. + this->assertValuesInOrder(this->theVector, 2u, 2, 3); + + // Make sure the # of constructor/destructor calls line up. There + // are two live objects after clearing the other vector. + this->otherVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls()-2, + Constructable::getNumDestructorCalls()); + + // There shouldn't be any live objects any more. + this->theVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls(), + Constructable::getNumDestructorCalls()); +} + +// Erase a single element +TYPED_TEST(CompactVectorTest, EraseTest) { + SCOPED_TRACE("EraseTest"); + + this->makeSequence(this->theVector, 1, 3); + this->theVector.erase(this->theVector.begin()); + this->assertValuesInOrder(this->theVector, 2u, 2, 3); +} + +// Erase a range of elements +TYPED_TEST(CompactVectorTest, EraseRangeTest) { + SCOPED_TRACE("EraseRangeTest"); + + this->makeSequence(this->theVector, 1, 3); + this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2); + this->assertValuesInOrder(this->theVector, 1u, 3); +} + +// Insert a single element. +TYPED_TEST(CompactVectorTest, InsertTest) { + SCOPED_TRACE("InsertTest"); + + this->makeSequence(this->theVector, 1, 3); + typename TypeParam::iterator I = + this->theVector.insert(this->theVector.begin() + 1, Constructable(77)); + EXPECT_EQ(this->theVector.begin() + 1, I); + this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); +} + +// Insert a copy of a single element. +TYPED_TEST(CompactVectorTest, InsertCopy) { + SCOPED_TRACE("InsertTest"); + + this->makeSequence(this->theVector, 1, 3); + Constructable C(77); + typename TypeParam::iterator I = + this->theVector.insert(this->theVector.begin() + 1, C); + EXPECT_EQ(this->theVector.begin() + 1, I); + this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); +} + +// Insert repeated elements. +TYPED_TEST(CompactVectorTest, InsertRepeatedTest) { + SCOPED_TRACE("InsertRepeatedTest"); + + this->makeSequence(this->theVector, 1, 4); + Constructable::reset(); + auto I = + this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16)); + // Move construct the top element into newly allocated space, and optionally + // reallocate the whole buffer, move constructing into it. + // FIXME: This is inefficient, we shouldn't move things into newly allocated + // space, then move them up/around, there should only be 2 or 4 move + // constructions here. + EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || + Constructable::getNumMoveConstructorCalls() == 6); + // Move assign the next two to shift them up and make a gap. + EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls()); + // Copy construct the two new elements from the parameter. + EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); + // All without any copy construction. + EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls()); + EXPECT_EQ(this->theVector.begin() + 1, I); + this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4); +} + + +TYPED_TEST(CompactVectorTest, InsertRepeatedAtEndTest) { + SCOPED_TRACE("InsertRepeatedTest"); + + this->makeSequence(this->theVector, 1, 4); + Constructable::reset(); + auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16)); + // Just copy construct them into newly allocated space + EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls()); + // Move everything across if reallocation is needed. + EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || + Constructable::getNumMoveConstructorCalls() == 4); + // Without ever moving or copying anything else. + EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); + EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); + + EXPECT_EQ(this->theVector.begin() + 4, I); + this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16); +} + +TYPED_TEST(CompactVectorTest, InsertRepeatedEmptyTest) { + SCOPED_TRACE("InsertRepeatedTest"); + + this->makeSequence(this->theVector, 10, 15); + + // Empty insert. + EXPECT_EQ(this->theVector.end(), + this->theVector.insert(this->theVector.end(), + 0, Constructable(42))); + EXPECT_EQ(this->theVector.begin() + 1, + this->theVector.insert(this->theVector.begin() + 1, + 0, Constructable(42))); +} + +// Insert range. +TYPED_TEST(CompactVectorTest, InsertRangeTest) { + SCOPED_TRACE("InsertRangeTest"); + + Constructable Arr[3] = + { Constructable(77), Constructable(77), Constructable(77) }; + + this->makeSequence(this->theVector, 1, 3); + Constructable::reset(); + auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3); + // Move construct the top 3 elements into newly allocated space. + // Possibly move the whole sequence into new space first. + // FIXME: This is inefficient, we shouldn't move things into newly allocated + // space, then move them up/around, there should only be 2 or 3 move + // constructions here. + EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || + Constructable::getNumMoveConstructorCalls() == 5); + // Copy assign the lower 2 new elements into existing space. + EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); + // Copy construct the third element into newly allocated space. + EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls()); + EXPECT_EQ(this->theVector.begin() + 1, I); + this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3); +} + + +TYPED_TEST(CompactVectorTest, InsertRangeAtEndTest) { + SCOPED_TRACE("InsertRangeTest"); + + Constructable Arr[3] = + { Constructable(77), Constructable(77), Constructable(77) }; + + this->makeSequence(this->theVector, 1, 3); + + // Insert at end. + Constructable::reset(); + auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3); + // Copy construct the 3 elements into new space at the top. + EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls()); + // Don't copy/move anything else. + EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); + // Reallocation might occur, causing all elements to be moved into the new + // buffer. + EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || + Constructable::getNumMoveConstructorCalls() == 3); + EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); + EXPECT_EQ(this->theVector.begin() + 3, I); + this->assertValuesInOrder(this->theVector, 6u, + 1, 2, 3, 77, 77, 77); +} + +TYPED_TEST(CompactVectorTest, InsertEmptyRangeTest) { + SCOPED_TRACE("InsertRangeTest"); + + this->makeSequence(this->theVector, 1, 3); + + // Empty insert. + EXPECT_EQ(this->theVector.end(), + this->theVector.insert(this->theVector.end(), + this->theVector.begin(), + this->theVector.begin())); + EXPECT_EQ(this->theVector.begin() + 1, + this->theVector.insert(this->theVector.begin() + 1, + this->theVector.begin(), + this->theVector.begin())); +} + +// Comparison tests. +TYPED_TEST(CompactVectorTest, ComparisonTest) { + SCOPED_TRACE("ComparisonTest"); + + this->makeSequence(this->theVector, 1, 3); + this->makeSequence(this->otherVector, 1, 3); + + EXPECT_TRUE(this->theVector == this->otherVector); + EXPECT_FALSE(this->theVector != this->otherVector); + + this->otherVector.clear(); + this->makeSequence(this->otherVector, 2, 4); + + EXPECT_FALSE(this->theVector == this->otherVector); + EXPECT_TRUE(this->theVector != this->otherVector); +} + +// Constant vector tests. +TYPED_TEST(CompactVectorTest, ConstVectorTest) { + const TypeParam constVector; + + EXPECT_EQ(0u, constVector.size()); + EXPECT_TRUE(constVector.empty()); + EXPECT_TRUE(constVector.begin() == constVector.end()); +} + +// Direct array access. +TYPED_TEST(CompactVectorTest, DirectVectorTest) { + EXPECT_EQ(0u, this->theVector.size()); + this->theVector.reserve(4); + EXPECT_LE(4u, this->theVector.capacity()); + EXPECT_EQ(0, Constructable::getNumConstructorCalls()); + this->theVector.push_back(1); + this->theVector.push_back(2); + this->theVector.push_back(3); + this->theVector.push_back(4); + EXPECT_EQ(4u, this->theVector.size()); + EXPECT_EQ(8, Constructable::getNumConstructorCalls()); + EXPECT_EQ(1, this->theVector[0].getValue()); + EXPECT_EQ(2, this->theVector[1].getValue()); + EXPECT_EQ(3, this->theVector[2].getValue()); + EXPECT_EQ(4, this->theVector[3].getValue()); +} + +TYPED_TEST(CompactVectorTest, IteratorTest) { + std::list<int> L; + this->theVector.insert(this->theVector.end(), L.begin(), L.end()); +} + +template <typename InvalidType> class DualCompactVectorsTest; + +template <typename VectorT1, typename VectorT2> +class DualCompactVectorsTest<std::pair<VectorT1, VectorT2>> : public CompactVectorTestBase { +protected: + VectorT1 theVector; + VectorT2 otherVector; + + template <typename T, size_t N> + static size_t NumBuiltinElts(const TCompactVector<T, N>&) { return N; } +}; + +typedef ::testing::Types< + // Small mode -> Small mode. + std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 4>>, + // Small mode -> Big mode. + std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 2>>, + // Big mode -> Small mode. + std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 4>>, + // Big mode -> Big mode. + std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 2>> + > DualCompactVectorTestTypes; + +TYPED_TEST_SUITE(DualCompactVectorsTest, DualCompactVectorTestTypes); + +TYPED_TEST(DualCompactVectorsTest, MoveAssignment) { + SCOPED_TRACE("MoveAssignTest-DualVectorTypes"); + + // Set up our vector with four elements. + for (unsigned I = 0; I < 4; ++I) + this->otherVector.push_back(Constructable(I)); + + const Constructable *OrigDataPtr = this->otherVector.data(); + + // Move-assign from the other vector. + this->theVector = + std::move(this->otherVector); + + // Make sure we have the right result. + this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3); + + // Make sure the # of constructor/destructor calls line up. There + // are two live objects after clearing the other vector. + this->otherVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls()-4, + Constructable::getNumDestructorCalls()); + + // If the source vector (otherVector) was in small-mode, assert that we just + // moved the data pointer over. + EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 || + this->theVector.data() == OrigDataPtr); + + // There shouldn't be any live objects any more. + this->theVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls(), + Constructable::getNumDestructorCalls()); + + // We shouldn't have copied anything in this whole process. + EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0); +} + +struct notassignable { + int &x; + notassignable(int &x) : x(x) {} +}; + +TEST(CompactVectorCustomTest, NoAssignTest) { + int x = 0; + TCompactVector<notassignable, 2> vec; + vec.push_back(notassignable(x)); + x = 42; + EXPECT_EQ(42, vec.back().x); +} + +struct MovedFrom { + bool hasValue; + MovedFrom() : hasValue(true) { + } + MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) { + m.hasValue = false; + } + MovedFrom &operator=(MovedFrom&& m) { + hasValue = m.hasValue; + m.hasValue = false; + return *this; + } +}; + +TEST(CompactVectorTest, MidInsert) { + TCompactVector<MovedFrom, 3> v; + v.push_back(MovedFrom()); + v.insert(v.begin(), MovedFrom()); + for (MovedFrom &m : v) + EXPECT_TRUE(m.hasValue); +} + +enum EmplaceableArgState { + EAS_Defaulted, + EAS_Arg, + EAS_LValue, + EAS_RValue, + EAS_Failure +}; +template <int I> struct EmplaceableArg { + EmplaceableArgState State; + EmplaceableArg() : State(EAS_Defaulted) {} + EmplaceableArg(EmplaceableArg &&X) + : State(X.State == EAS_Arg ? EAS_RValue : EAS_Failure) {} + EmplaceableArg(EmplaceableArg &X) + : State(X.State == EAS_Arg ? EAS_LValue : EAS_Failure) {} + + explicit EmplaceableArg(bool) : State(EAS_Arg) {} + +private: + EmplaceableArg &operator=(EmplaceableArg &&) = delete; + EmplaceableArg &operator=(const EmplaceableArg &) = delete; +}; + +enum EmplaceableState { ES_Emplaced, ES_Moved }; +struct Emplaceable { + EmplaceableArg<0> A0; + EmplaceableArg<1> A1; + EmplaceableArg<2> A2; + EmplaceableArg<3> A3; + EmplaceableState State; + + Emplaceable() : State(ES_Emplaced) {} + + template <class A0Ty> + explicit Emplaceable(A0Ty &&A0) + : A0(std::forward<A0Ty>(A0)), State(ES_Emplaced) {} + + template <class A0Ty, class A1Ty> + Emplaceable(A0Ty &&A0, A1Ty &&A1) + : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), + State(ES_Emplaced) {} + + template <class A0Ty, class A1Ty, class A2Ty> + Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2) + : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), + A2(std::forward<A2Ty>(A2)), State(ES_Emplaced) {} + + template <class A0Ty, class A1Ty, class A2Ty, class A3Ty> + Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2, A3Ty &&A3) + : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), + A2(std::forward<A2Ty>(A2)), A3(std::forward<A3Ty>(A3)), + State(ES_Emplaced) {} + + Emplaceable(Emplaceable &&) : State(ES_Moved) {} + Emplaceable &operator=(Emplaceable &&) { + State = ES_Moved; + return *this; + } + +private: + Emplaceable(const Emplaceable &) = delete; + Emplaceable &operator=(const Emplaceable &) = delete; +}; + +TEST(CompactVectorTest, EmplaceBack) { + EmplaceableArg<0> A0(true); + EmplaceableArg<1> A1(true); + EmplaceableArg<2> A2(true); + EmplaceableArg<3> A3(true); + { + TCompactVector<Emplaceable, 3> V; + V.emplace_back(); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace_back(std::move(A0)); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_RValue); + EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace_back(A0); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_LValue); + EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace_back(A0, A1); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_LValue); + EXPECT_TRUE(V.back().A1.State == EAS_LValue); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace_back(std::move(A0), std::move(A1)); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_RValue); + EXPECT_TRUE(V.back().A1.State == EAS_RValue); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace_back(std::move(A0), A1, std::move(A2), A3); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_RValue); + EXPECT_TRUE(V.back().A1.State == EAS_LValue); + EXPECT_TRUE(V.back().A2.State == EAS_RValue); + EXPECT_TRUE(V.back().A3.State == EAS_LValue); + } + { + TCompactVector<int, 1> V; + V.emplace_back(); + V.emplace_back(42); + EXPECT_EQ(2U, V.size()); + EXPECT_EQ(0, V[0]); + EXPECT_EQ(42, V[1]); + } +} + +TEST(CompactVectorTest, Emplace) { + EmplaceableArg<0> A0(true); + EmplaceableArg<1> A1(true); + EmplaceableArg<2> A2(true); + EmplaceableArg<3> A3(true); + { + TCompactVector<Emplaceable, 3> V; + V.emplace(V.end()); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace(V.end(), std::move(A0)); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_RValue); + EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace(V.end(), A0); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_LValue); + EXPECT_TRUE(V.back().A1.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace(V.end(), A0, A1); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_LValue); + EXPECT_TRUE(V.back().A1.State == EAS_LValue); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace(V.end(), std::move(A0), std::move(A1)); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_RValue); + EXPECT_TRUE(V.back().A1.State == EAS_RValue); + EXPECT_TRUE(V.back().A2.State == EAS_Defaulted); + EXPECT_TRUE(V.back().A3.State == EAS_Defaulted); + } + { + TCompactVector<Emplaceable, 3> V; + V.emplace(V.end(), std::move(A0), A1, std::move(A2), A3); + EXPECT_TRUE(V.size() == 1); + EXPECT_TRUE(V.back().State == ES_Emplaced); + EXPECT_TRUE(V.back().A0.State == EAS_RValue); + EXPECT_TRUE(V.back().A1.State == EAS_LValue); + EXPECT_TRUE(V.back().A2.State == EAS_RValue); + EXPECT_TRUE(V.back().A3.State == EAS_LValue); + } + { + TCompactVector<int, 1> V; + V.emplace_back(42); + V.emplace(V.begin(), 0); + EXPECT_EQ(2U, V.size()); + EXPECT_EQ(0, V[0]); + EXPECT_EQ(42, V[1]); + } +} + +template <class T, size_t N> +class TStubArray +{ +public: + TStubArray(const TCompactVector<T, N>& vector) + : Vector_(vector) + { } + + bool equals(std::initializer_list<T> list) + { + return std::equal(Vector_.begin(), Vector_.end(), list.begin()); + } + + TCompactVector<T, N> Vector_; +}; + +template <typename T, size_t N> +TStubArray<T, N> makeArrayRef(const TCompactVector<T, N>& vector) +{ + return TStubArray<T, N>(vector); +} + +TEST(CompactVectorTest, InitializerList) { + TCompactVector<int, 2> V1 = {}; + EXPECT_TRUE(V1.empty()); + V1 = {0, 0}; + EXPECT_TRUE(makeArrayRef(V1).equals({0, 0})); + V1 = {-1, -1}; + EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1})); + + TCompactVector<int, 2> V2 = {1, 2, 3, 4}; + EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4})); + V2.assign({4}); + EXPECT_TRUE(makeArrayRef(V2).equals({4})); + V2.insert(V2.end(), {3, 2}); + EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2})); + V2.insert(V2.begin() + 1, 5); + EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2})); +} + +TEST(CompactVectorTest, AssignToShorter) { + TCompactVector<TString, 4> lhs; + TCompactVector<TString, 4> rhs; + rhs.emplace_back("foo"); + lhs = rhs; + EXPECT_EQ(1U, lhs.size()); + EXPECT_EQ("foo", lhs[0]); +} + +TEST(CompactVectorTest, AssignToLonger) { + TCompactVector<TString, 4> lhs; + lhs.emplace_back("bar"); + lhs.emplace_back("baz"); + TCompactVector<TString, 4> rhs; + rhs.emplace_back("foo"); + lhs = rhs; + EXPECT_EQ(1U, lhs.size()); + EXPECT_EQ("foo", lhs[0]); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/small_containers/unittests/ya.make b/library/cpp/yt/small_containers/unittests/ya.make index 6bd8e1d0ec..d4cb7b71e2 100644 --- a/library/cpp/yt/small_containers/unittests/ya.make +++ b/library/cpp/yt/small_containers/unittests/ya.make @@ -3,14 +3,14 @@ GTEST(unittester-small-containers) OWNER(g:yt) SRCS( - compact_flat_map_ut.cpp + compact_flat_map_ut.cpp compact_heap_ut.cpp compact_set_ut.cpp - compact_vector_ut.cpp + compact_vector_ut.cpp ) PEERDIR( - library/cpp/yt/small_containers + library/cpp/yt/small_containers library/cpp/testing/gtest ) diff --git a/library/cpp/yt/small_containers/ya.make b/library/cpp/yt/small_containers/ya.make index d886b2ddac..b73e27ba90 100644 --- a/library/cpp/yt/small_containers/ya.make +++ b/library/cpp/yt/small_containers/ya.make @@ -1,8 +1,8 @@ LIBRARY() PEERDIR( - library/cpp/yt/assert - library/cpp/yt/malloc + library/cpp/yt/assert + library/cpp/yt/malloc ) CHECK_DEPENDENT_DIRS( diff --git a/library/cpp/yt/string/enum-inl.h b/library/cpp/yt/string/enum-inl.h index ab8acff71b..0095979824 100644 --- a/library/cpp/yt/string/enum-inl.h +++ b/library/cpp/yt/string/enum-inl.h @@ -1,118 +1,118 @@ -#ifndef ENUM_INL_H_ -#error "Direct inclusion of this file is not allowed, include enum.h" -// For the sake of sane code completion. -#include "enum.h" -#endif - -#include <util/string/printf.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -namespace NDetail { - -[[noreturn]] -void ThrowMalformedEnumValueException( - TStringBuf typeName, - TStringBuf value); - -void FormatUnknownEnumValue( - TStringBuilderBase* builder, - TStringBuf name, - i64 value); - -} // namespace NDetail - -template <class T> -std::optional<T> TryParseEnum(TStringBuf value) -{ - static_assert(TEnumTraits<T>::IsEnum); - - auto tryFromString = [] (TStringBuf value) -> std::optional<T> { - T result; - if (auto ok = TEnumTraits<T>::FindValueByLiteral(DecodeEnumValue(value), &result)) { - return result; - } - return {}; - }; - - if constexpr (TEnumTraits<T>::IsBitEnum) { - T result{}; - TStringBuf token; - while (value.NextTok('|', token)) { - if (auto scalar = tryFromString(StripString(token))) { - result |= *scalar; - } else { - return {}; - } - } - return result; - } else { - return tryFromString(value); - } -} - -template <class T> -T ParseEnum(TStringBuf value) -{ - if (auto optionalResult = TryParseEnum<T>(value)) { - return *optionalResult; - } - NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), value); -} - -template <class T> -void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase) -{ - static_assert(TEnumTraits<T>::IsEnum); - - auto formatScalarValue = [builder, lowerCase] (T value) { - auto* literal = TEnumTraits<T>::FindLiteralByValue(value); - if (!literal) { - YT_VERIFY(!TEnumTraits<T>::IsBitEnum); - NDetail::FormatUnknownEnumValue( - builder, - TEnumTraits<T>::GetTypeName(), - static_cast<typename TEnumTraits<T>::TUnderlying>(value)); - return; - } - - if (lowerCase) { - CamelCaseToUnderscoreCase(builder, *literal); - } else { - builder->AppendString(*literal); - } - }; - - if constexpr (TEnumTraits<T>::IsBitEnum) { - if (auto* literal = TEnumTraits<T>::FindLiteralByValue(value)) { - formatScalarValue(value); - return; - } - auto first = true; - for (auto scalarValue : TEnumTraits<T>::GetDomainValues()) { - if (Any(value & scalarValue)) { - if (!first) { - builder->AppendString(TStringBuf(" | ")); - } - first = false; - formatScalarValue(scalarValue); - } - } - } else { - formatScalarValue(value); - } -} - -template <class T> -TString FormatEnum(T value, typename TEnumTraits<T>::TType*) -{ - TStringBuilder builder; - FormatEnum(&builder, value, /*lowerCase*/ true); - return builder.Flush(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +#ifndef ENUM_INL_H_ +#error "Direct inclusion of this file is not allowed, include enum.h" +// For the sake of sane code completion. +#include "enum.h" +#endif + +#include <util/string/printf.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + +[[noreturn]] +void ThrowMalformedEnumValueException( + TStringBuf typeName, + TStringBuf value); + +void FormatUnknownEnumValue( + TStringBuilderBase* builder, + TStringBuf name, + i64 value); + +} // namespace NDetail + +template <class T> +std::optional<T> TryParseEnum(TStringBuf value) +{ + static_assert(TEnumTraits<T>::IsEnum); + + auto tryFromString = [] (TStringBuf value) -> std::optional<T> { + T result; + if (auto ok = TEnumTraits<T>::FindValueByLiteral(DecodeEnumValue(value), &result)) { + return result; + } + return {}; + }; + + if constexpr (TEnumTraits<T>::IsBitEnum) { + T result{}; + TStringBuf token; + while (value.NextTok('|', token)) { + if (auto scalar = tryFromString(StripString(token))) { + result |= *scalar; + } else { + return {}; + } + } + return result; + } else { + return tryFromString(value); + } +} + +template <class T> +T ParseEnum(TStringBuf value) +{ + if (auto optionalResult = TryParseEnum<T>(value)) { + return *optionalResult; + } + NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), value); +} + +template <class T> +void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase) +{ + static_assert(TEnumTraits<T>::IsEnum); + + auto formatScalarValue = [builder, lowerCase] (T value) { + auto* literal = TEnumTraits<T>::FindLiteralByValue(value); + if (!literal) { + YT_VERIFY(!TEnumTraits<T>::IsBitEnum); + NDetail::FormatUnknownEnumValue( + builder, + TEnumTraits<T>::GetTypeName(), + static_cast<typename TEnumTraits<T>::TUnderlying>(value)); + return; + } + + if (lowerCase) { + CamelCaseToUnderscoreCase(builder, *literal); + } else { + builder->AppendString(*literal); + } + }; + + if constexpr (TEnumTraits<T>::IsBitEnum) { + if (auto* literal = TEnumTraits<T>::FindLiteralByValue(value)) { + formatScalarValue(value); + return; + } + auto first = true; + for (auto scalarValue : TEnumTraits<T>::GetDomainValues()) { + if (Any(value & scalarValue)) { + if (!first) { + builder->AppendString(TStringBuf(" | ")); + } + first = false; + formatScalarValue(scalarValue); + } + } + } else { + formatScalarValue(value); + } +} + +template <class T> +TString FormatEnum(T value, typename TEnumTraits<T>::TType*) +{ + TStringBuilder builder; + FormatEnum(&builder, value, /*lowerCase*/ true); + return builder.Flush(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/string/enum.cpp b/library/cpp/yt/string/enum.cpp index 7cb8e5c6b6..5f8c032edf 100644 --- a/library/cpp/yt/string/enum.cpp +++ b/library/cpp/yt/string/enum.cpp @@ -1,44 +1,44 @@ #include "enum.h" - + #include "format.h" - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + TString DecodeEnumValue(TStringBuf value) -{ - auto camelValue = UnderscoreCaseToCamelCase(value); +{ + auto camelValue = UnderscoreCaseToCamelCase(value); auto underscoreValue = CamelCaseToUnderscoreCase(camelValue); if (value != underscoreValue) { - throw TSimpleException(Format("Enum value %Qv is not in a proper underscore case; did you mean %Qv?", + throw TSimpleException(Format("Enum value %Qv is not in a proper underscore case; did you mean %Qv?", value, - underscoreValue)); + underscoreValue)); } - return camelValue; -} - + return camelValue; +} + TString EncodeEnumValue(TStringBuf value) +{ + return CamelCaseToUnderscoreCase(value); +} + +namespace NDetail { + +void ThrowMalformedEnumValueException(TStringBuf typeName, TStringBuf value) { - return CamelCaseToUnderscoreCase(value); + throw TSimpleException(Format("Error parsing %v value %Qv", + typeName, + value)); } -namespace NDetail { - -void ThrowMalformedEnumValueException(TStringBuf typeName, TStringBuf value) -{ - throw TSimpleException(Format("Error parsing %v value %Qv", - typeName, - value)); -} - -void FormatUnknownEnumValue(TStringBuilderBase* builder, TStringBuf name, i64 value) +void FormatUnknownEnumValue(TStringBuilderBase* builder, TStringBuf name, i64 value) { builder->AppendFormat("%v(%v)", name, value); } -} // namespace NDetail - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT +} // namespace NDetail + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/string/enum.h b/library/cpp/yt/string/enum.h index 10dc02610f..774ad5eb02 100644 --- a/library/cpp/yt/string/enum.h +++ b/library/cpp/yt/string/enum.h @@ -1,31 +1,31 @@ -#pragma once - +#pragma once + #include "string.h" - + #include <library/cpp/yt/misc/enum.h> - + #include <optional> -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + TString DecodeEnumValue(TStringBuf value); TString EncodeEnumValue(TStringBuf value); - + template <class T> -T ParseEnum(TStringBuf value); +T ParseEnum(TStringBuf value); template <class T> -void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase); +void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase); template <class T> -TString FormatEnum(T value, typename TEnumTraits<T>::TType* = nullptr); +TString FormatEnum(T value, typename TEnumTraits<T>::TType* = nullptr); //////////////////////////////////////////////////////////////////////////////// -} // namespace NYT - -#define ENUM_INL_H_ -#include "enum-inl.h" -#undef ENUM_INL_H_ +} // namespace NYT + +#define ENUM_INL_H_ +#include "enum-inl.h" +#undef ENUM_INL_H_ diff --git a/library/cpp/yt/string/format-inl.h b/library/cpp/yt/string/format-inl.h index 5484d4a216..550869846e 100644 --- a/library/cpp/yt/string/format-inl.h +++ b/library/cpp/yt/string/format-inl.h @@ -1,72 +1,72 @@ -#ifndef FORMAT_INL_H_ -#error "Direct inclusion of this file is not allowed, include format.h" +#ifndef FORMAT_INL_H_ +#error "Direct inclusion of this file is not allowed, include format.h" // For the sake of sane code completion. #include "format.h" -#endif - +#endif + #include "enum.h" -#include "string.h" - -#include <library/cpp/yt/assert/assert.h> +#include "string.h" + +#include <library/cpp/yt/assert/assert.h> #include <library/cpp/yt/small_containers/compact_vector.h> -#include <library/cpp/yt/misc/enum.h> +#include <library/cpp/yt/misc/enum.h> #include <cctype> #include <optional> -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + static const char GenericSpecSymbol = 'v'; - + inline bool IsQuotationSpecSymbol(char symbol) { return symbol == 'Q' || symbol == 'q'; } -// TStringBuf -inline void FormatValue(TStringBuilderBase* builder, TStringBuf value, TStringBuf format) -{ - if (!format) { - builder->AppendString(value); - return; - } - - // Parse alignment. - bool alignLeft = false; - const char* current = format.begin(); - if (*current == '-') { - alignLeft = true; - ++current; - } - - bool hasAlign = false; - int alignSize = 0; - while (*current >= '0' && *current <= '9') { - hasAlign = true; - alignSize = 10 * alignSize + (*current - '0'); - if (alignSize > 1000000) { +// TStringBuf +inline void FormatValue(TStringBuilderBase* builder, TStringBuf value, TStringBuf format) +{ + if (!format) { + builder->AppendString(value); + return; + } + + // Parse alignment. + bool alignLeft = false; + const char* current = format.begin(); + if (*current == '-') { + alignLeft = true; + ++current; + } + + bool hasAlign = false; + int alignSize = 0; + while (*current >= '0' && *current <= '9') { + hasAlign = true; + alignSize = 10 * alignSize + (*current - '0'); + if (alignSize > 1000000) { builder->AppendString(TStringBuf("<alignment overflow>")); - return; - } - ++current; - } - - int padding = 0; - bool padLeft = false; - bool padRight = false; - if (hasAlign) { - padding = alignSize - value.size(); - if (padding < 0) { - padding = 0; - } - padLeft = !alignLeft; - padRight = alignLeft; - } - + return; + } + ++current; + } + + int padding = 0; + bool padLeft = false; + bool padRight = false; + if (hasAlign) { + padding = alignSize - value.size(); + if (padding < 0) { + padding = 0; + } + padLeft = !alignLeft; + padRight = alignLeft; + } + bool singleQuotes = false; bool doubleQuotes = false; while (current < format.end()) { @@ -78,9 +78,9 @@ inline void FormatValue(TStringBuilderBase* builder, TStringBuf value, TStringBu ++current; } - if (padLeft) { - builder->AppendChar(' ', padding); - } + if (padLeft) { + builder->AppendChar(' ', padding); + } if (singleQuotes || doubleQuotes) { for (const char* valueCurrent = value.begin(); valueCurrent < value.end(); ++valueCurrent) { @@ -104,92 +104,92 @@ inline void FormatValue(TStringBuilderBase* builder, TStringBuf value, TStringBu builder->AppendString(value); } - if (padRight) { - builder->AppendChar(' ', padding); - } -} - + if (padRight) { + builder->AppendChar(' ', padding); + } +} + // TString -inline void FormatValue(TStringBuilderBase* builder, const TString& value, TStringBuf format) -{ - FormatValue(builder, TStringBuf(value), format); -} - -// const char* -inline void FormatValue(TStringBuilderBase* builder, const char* value, TStringBuf format) -{ - FormatValue(builder, TStringBuf(value), format); -} - +inline void FormatValue(TStringBuilderBase* builder, const TString& value, TStringBuf format) +{ + FormatValue(builder, TStringBuf(value), format); +} + +// const char* +inline void FormatValue(TStringBuilderBase* builder, const char* value, TStringBuf format) +{ + FormatValue(builder, TStringBuf(value), format); +} + // char -inline void FormatValue(TStringBuilderBase* builder, char value, TStringBuf format) +inline void FormatValue(TStringBuilderBase* builder, char value, TStringBuf format) { FormatValue(builder, TStringBuf(&value, 1), format); } -// bool -inline void FormatValue(TStringBuilderBase* builder, bool value, TStringBuf format) -{ - // Parse custom flags. - bool lowercase = false; - const char* current = format.begin(); - while (current != format.end()) { - if (*current == 'l') { - ++current; - lowercase = true; +// bool +inline void FormatValue(TStringBuilderBase* builder, bool value, TStringBuf format) +{ + // Parse custom flags. + bool lowercase = false; + const char* current = format.begin(); + while (current != format.end()) { + if (*current == 'l') { + ++current; + lowercase = true; } else if (IsQuotationSpecSymbol(*current)) { ++current; - } else - break; - } - - auto str = lowercase + } else + break; + } + + auto str = lowercase ? (value ? TStringBuf("true") : TStringBuf("false")) : (value ? TStringBuf("True") : TStringBuf("False")); - - builder->AppendString(str); -} - -// Fallback to ToString -struct TToStringFallbackValueFormatterTag -{ }; - -template <class TValue, class = void> -struct TValueFormatter -{ - static TToStringFallbackValueFormatterTag Do(TStringBuilderBase* builder, const TValue& value, TStringBuf format) - { - using ::ToString; - FormatValue(builder, ToString(value), format); - return {}; - } -}; - -// Enum -template <class TEnum> -struct TValueFormatter<TEnum, typename std::enable_if<TEnumTraits<TEnum>::IsEnum>::type> -{ - static void Do(TStringBuilderBase* builder, TEnum value, TStringBuf format) - { - // Parse custom flags. - bool lowercase = false; - const char* current = format.begin(); - while (current != format.end()) { - if (*current == 'l') { - ++current; - lowercase = true; + + builder->AppendString(str); +} + +// Fallback to ToString +struct TToStringFallbackValueFormatterTag +{ }; + +template <class TValue, class = void> +struct TValueFormatter +{ + static TToStringFallbackValueFormatterTag Do(TStringBuilderBase* builder, const TValue& value, TStringBuf format) + { + using ::ToString; + FormatValue(builder, ToString(value), format); + return {}; + } +}; + +// Enum +template <class TEnum> +struct TValueFormatter<TEnum, typename std::enable_if<TEnumTraits<TEnum>::IsEnum>::type> +{ + static void Do(TStringBuilderBase* builder, TEnum value, TStringBuf format) + { + // Parse custom flags. + bool lowercase = false; + const char* current = format.begin(); + while (current != format.end()) { + if (*current == 'l') { + ++current; + lowercase = true; } else if (IsQuotationSpecSymbol(*current)) { ++current; } else { - break; + break; } - } - + } + FormatEnum(builder, value, lowercase); - } -}; - -template <class TRange, class TFormatter> + } +}; + +template <class TRange, class TFormatter> typename TFormattableView<TRange, TFormatter>::TBegin TFormattableView<TRange, TFormatter>::begin() const { return RangeBegin; @@ -203,42 +203,42 @@ typename TFormattableView<TRange, TFormatter>::TEnd TFormattableView<TRange, TFo template <class TRange, class TFormatter> TFormattableView<TRange, TFormatter> MakeFormattableView( - const TRange& range, + const TRange& range, TFormatter&& formatter) -{ +{ return TFormattableView<TRange, std::decay_t<TFormatter>>{range.begin(), range.end(), std::forward<TFormatter>(formatter)}; -} - -template <class TRange, class TFormatter> +} + +template <class TRange, class TFormatter> TFormattableView<TRange, TFormatter> MakeShrunkFormattableView( const TRange& range, TFormatter&& formatter, size_t limit) -{ +{ return TFormattableView<TRange, std::decay_t<TFormatter>>{range.begin(), range.end(), std::forward<TFormatter>(formatter), limit}; } template <class TRange, class TFormatter> -void FormatRange(TStringBuilderBase* builder, const TRange& range, const TFormatter& formatter, size_t limit = std::numeric_limits<size_t>::max()) +void FormatRange(TStringBuilderBase* builder, const TRange& range, const TFormatter& formatter, size_t limit = std::numeric_limits<size_t>::max()) { - builder->AppendChar('['); + builder->AppendChar('['); size_t index = 0; - for (const auto& item : range) { + for (const auto& item : range) { if (index > 0) { - builder->AppendString(DefaultJoinToStringDelimiter); - } + builder->AppendString(DefaultJoinToStringDelimiter); + } if (index == limit) { builder->AppendString(DefaultRangeEllipsisFormat); break; } - formatter(builder, item); + formatter(builder, item); ++index; - } - builder->AppendChar(']'); -} - + } + builder->AppendChar(']'); +} + template <class TRange, class TFormatter> -void FormatKeyValueRange(TStringBuilderBase* builder, const TRange& range, const TFormatter& formatter, size_t limit = std::numeric_limits<size_t>::max()) +void FormatKeyValueRange(TStringBuilderBase* builder, const TRange& range, const TFormatter& formatter, size_t limit = std::numeric_limits<size_t>::max()) { builder->AppendChar('{'); size_t index = 0; @@ -259,44 +259,44 @@ void FormatKeyValueRange(TStringBuilderBase* builder, const TRange& range, const } // TFormattableView -template <class TRange, class TFormatter> +template <class TRange, class TFormatter> struct TValueFormatter<TFormattableView<TRange, TFormatter>> -{ - static void Do(TStringBuilderBase* builder, const TFormattableView<TRange, TFormatter>& range, TStringBuf /*format*/) - { +{ + static void Do(TStringBuilderBase* builder, const TFormattableView<TRange, TFormatter>& range, TStringBuf /*format*/) + { FormatRange(builder, range, range.Formatter, range.Limit); - } -}; - -template <class TFormatter> -TFormatterWrapper<TFormatter> MakeFormatterWrapper( - TFormatter&& formatter) -{ - return TFormatterWrapper<TFormatter>{ - .Formatter = std::move(formatter) - }; -} - -// TFormatterWrapper -template <class TFormatter> -struct TValueFormatter<TFormatterWrapper<TFormatter>> -{ - static void Do(TStringBuilderBase* builder, const TFormatterWrapper<TFormatter>& wrapper, TStringBuf /*format*/) - { - wrapper.Formatter(builder); - } -}; - -// std::vector + } +}; + +template <class TFormatter> +TFormatterWrapper<TFormatter> MakeFormatterWrapper( + TFormatter&& formatter) +{ + return TFormatterWrapper<TFormatter>{ + .Formatter = std::move(formatter) + }; +} + +// TFormatterWrapper +template <class TFormatter> +struct TValueFormatter<TFormatterWrapper<TFormatter>> +{ + static void Do(TStringBuilderBase* builder, const TFormatterWrapper<TFormatter>& wrapper, TStringBuf /*format*/) + { + wrapper.Formatter(builder); + } +}; + +// std::vector template <class T, class TAllocator> struct TValueFormatter<std::vector<T, TAllocator>> -{ +{ static void Do(TStringBuilderBase* builder, const std::vector<T, TAllocator>& collection, TStringBuf /*format*/) - { - FormatRange(builder, collection, TDefaultFormatter()); - } -}; - + { + FormatRange(builder, collection, TDefaultFormatter()); + } +}; + // TCompactVector template <class T, unsigned N> struct TValueFormatter<TCompactVector<T, N>> @@ -307,21 +307,21 @@ struct TValueFormatter<TCompactVector<T, N>> } }; -// std::set -template <class T> -struct TValueFormatter<std::set<T>> -{ - static void Do(TStringBuilderBase* builder, const std::set<T>& collection, TStringBuf /*format*/) - { - FormatRange(builder, collection, TDefaultFormatter()); - } -}; - +// std::set +template <class T> +struct TValueFormatter<std::set<T>> +{ + static void Do(TStringBuilderBase* builder, const std::set<T>& collection, TStringBuf /*format*/) + { + FormatRange(builder, collection, TDefaultFormatter()); + } +}; + // std::map template <class K, class V> struct TValueFormatter<std::map<K, V>> { - static void Do(TStringBuilderBase* builder, const std::map<K, V>& collection, TStringBuf /*format*/) + static void Do(TStringBuilderBase* builder, const std::map<K, V>& collection, TStringBuf /*format*/) { FormatKeyValueRange(builder, collection, TDefaultFormatter()); } @@ -331,37 +331,37 @@ struct TValueFormatter<std::map<K, V>> template <class K, class V> struct TValueFormatter<std::multimap<K, V>> { - static void Do(TStringBuilderBase* builder, const std::multimap<K, V>& collection, TStringBuf /*format*/) + static void Do(TStringBuilderBase* builder, const std::multimap<K, V>& collection, TStringBuf /*format*/) { FormatKeyValueRange(builder, collection, TDefaultFormatter()); } }; // THashSet -template <class T> +template <class T> struct TValueFormatter<THashSet<T>> -{ - static void Do(TStringBuilderBase* builder, const THashSet<T>& collection, TStringBuf /*format*/) - { - FormatRange(builder, collection, TDefaultFormatter()); - } -}; - -// THashMultiSet -template <class T> -struct TValueFormatter<THashMultiSet<T>> -{ - static void Do(TStringBuilderBase* builder, const THashMultiSet<T>& collection, TStringBuf /*format*/) - { - FormatRange(builder, collection, TDefaultFormatter()); - } -}; - +{ + static void Do(TStringBuilderBase* builder, const THashSet<T>& collection, TStringBuf /*format*/) + { + FormatRange(builder, collection, TDefaultFormatter()); + } +}; + +// THashMultiSet +template <class T> +struct TValueFormatter<THashMultiSet<T>> +{ + static void Do(TStringBuilderBase* builder, const THashMultiSet<T>& collection, TStringBuf /*format*/) + { + FormatRange(builder, collection, TDefaultFormatter()); + } +}; + // THashMap template <class K, class V> struct TValueFormatter<THashMap<K, V>> { - static void Do(TStringBuilderBase* builder, const THashMap<K, V>& collection, TStringBuf /*format*/) + static void Do(TStringBuilderBase* builder, const THashMap<K, V>& collection, TStringBuf /*format*/) { FormatKeyValueRange(builder, collection, TDefaultFormatter()); } @@ -371,7 +371,7 @@ struct TValueFormatter<THashMap<K, V>> template <class K, class V> struct TValueFormatter<THashMultiMap<K, V>> { - static void Do(TStringBuilderBase* builder, const THashMultiMap<K, V>& collection, TStringBuf /*format*/) + static void Do(TStringBuilderBase* builder, const THashMultiMap<K, V>& collection, TStringBuf /*format*/) { FormatKeyValueRange(builder, collection, TDefaultFormatter()); } @@ -412,42 +412,42 @@ struct TValueFormatter<std::pair<T1, T2>> } }; -// std::optional -inline void FormatValue(TStringBuilderBase* builder, std::nullopt_t, TStringBuf /*format*/) -{ +// std::optional +inline void FormatValue(TStringBuilderBase* builder, std::nullopt_t, TStringBuf /*format*/) +{ builder->AppendString(TStringBuf("<null>")); -} - -template <class T> -struct TValueFormatter<std::optional<T>> -{ - static void Do(TStringBuilderBase* builder, const std::optional<T>& value, TStringBuf format) - { - if (value) { - FormatValue(builder, *value, format); - } else { - FormatValue(builder, std::nullopt, format); - } - } -}; - -template <class TValue> -auto FormatValue(TStringBuilderBase* builder, const TValue& value, TStringBuf format) -> - decltype(TValueFormatter<TValue>::Do(builder, value, format)) -{ - return TValueFormatter<TValue>::Do(builder, value, format); -} - -template <class TValue> +} + +template <class T> +struct TValueFormatter<std::optional<T>> +{ + static void Do(TStringBuilderBase* builder, const std::optional<T>& value, TStringBuf format) + { + if (value) { + FormatValue(builder, *value, format); + } else { + FormatValue(builder, std::nullopt, format); + } + } +}; + +template <class TValue> +auto FormatValue(TStringBuilderBase* builder, const TValue& value, TStringBuf format) -> + decltype(TValueFormatter<TValue>::Do(builder, value, format)) +{ + return TValueFormatter<TValue>::Do(builder, value, format); +} + +template <class TValue> void FormatValueViaSprintf( - TStringBuilderBase* builder, + TStringBuilderBase* builder, TValue value, - TStringBuf format, - TStringBuf genericSpec) -{ - constexpr int MaxFormatSize = 64; - constexpr int SmallResultSize = 64; - + TStringBuf format, + TStringBuf genericSpec) +{ + constexpr int MaxFormatSize = 64; + constexpr int SmallResultSize = 64; + auto copyFormat = [] (char* destination, const char* source, int length) { int position = 0; for (int index = 0; index < length; ++index) { @@ -460,32 +460,32 @@ void FormatValueViaSprintf( return destination + position; }; - char formatBuf[MaxFormatSize]; - YT_VERIFY(format.length() >= 1 && format.length() <= MaxFormatSize - 2); // one for %, one for \0 - formatBuf[0] = '%'; - if (format[format.length() - 1] == GenericSpecSymbol) { + char formatBuf[MaxFormatSize]; + YT_VERIFY(format.length() >= 1 && format.length() <= MaxFormatSize - 2); // one for %, one for \0 + formatBuf[0] = '%'; + if (format[format.length() - 1] == GenericSpecSymbol) { char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length() - 1); - ::memcpy(formatEnd, genericSpec.begin(), genericSpec.length()); + ::memcpy(formatEnd, genericSpec.begin(), genericSpec.length()); formatEnd[genericSpec.length()] = '\0'; - } else { + } else { char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length()); *formatEnd = '\0'; - } - + } + char* result = builder->Preallocate(SmallResultSize); - size_t resultSize = ::snprintf(result, SmallResultSize, formatBuf, value); + size_t resultSize = ::snprintf(result, SmallResultSize, formatBuf, value); if (resultSize >= SmallResultSize) { result = builder->Preallocate(resultSize + 1); - YT_VERIFY(::snprintf(result, resultSize + 1, formatBuf, value) == static_cast<int>(resultSize)); + YT_VERIFY(::snprintf(result, resultSize + 1, formatBuf, value) == static_cast<int>(resultSize)); } - builder->Advance(resultSize); -} - + builder->Advance(resultSize); +} + template <class TValue> char* WriteIntToBufferBackwards(char* buffer, TValue value); template <class TValue> -void FormatValueViaHelper(TStringBuilderBase* builder, TValue value, TStringBuf format, TStringBuf genericSpec) +void FormatValueViaHelper(TStringBuilderBase* builder, TValue value, TStringBuf format, TStringBuf genericSpec) { if (format == TStringBuf("v")) { const int MaxResultSize = 64; @@ -499,11 +499,11 @@ void FormatValueViaHelper(TStringBuilderBase* builder, TValue value, TStringBuf } #define XX(valueType, castType, genericSpec) \ - inline void FormatValue(TStringBuilderBase* builder, valueType value, TStringBuf format) \ - { \ + inline void FormatValue(TStringBuilderBase* builder, valueType value, TStringBuf format) \ + { \ FormatValueViaHelper(builder, static_cast<castType>(value), format, genericSpec); \ - } - + } + XX(i8, int, TStringBuf("d")) XX(ui8, unsigned int, TStringBuf("u")) XX(i16, int, TStringBuf("d")) @@ -512,11 +512,11 @@ XX(i32, int, TStringBuf("d")) XX(ui32, unsigned int, TStringBuf("u")) XX(long, long, TStringBuf("ld")) XX(unsigned long, unsigned long, TStringBuf("lu")) - + #undef XX - + #define XX(valueType, castType, genericSpec) \ - inline void FormatValue(TStringBuilderBase* builder, valueType value, TStringBuf format) \ + inline void FormatValue(TStringBuilderBase* builder, valueType value, TStringBuf format) \ { \ FormatValueViaSprintf(builder, static_cast<castType>(value), format, genericSpec); \ } @@ -526,219 +526,219 @@ XX(float, float, TStringBuf("f")) #undef XX -// Pointer +// Pointer template <class T> -void FormatValue(TStringBuilderBase* builder, T* value, TStringBuf format) +void FormatValue(TStringBuilderBase* builder, T* value, TStringBuf format) { FormatValueViaSprintf(builder, value, format, TStringBuf("p")); } // TDuration (specialize for performance reasons) -inline void FormatValue(TStringBuilderBase* builder, TDuration value, TStringBuf /*format*/) -{ - builder->AppendFormat("%vus", value.MicroSeconds()); -} - -// TInstant (specialize for TFormatTraits) -inline void FormatValue(TStringBuilderBase* builder, TInstant value, TStringBuf format) +inline void FormatValue(TStringBuilderBase* builder, TDuration value, TStringBuf /*format*/) { - // TODO(babenko): optimize - builder->AppendFormat("%v", ToString(value), format); + builder->AppendFormat("%vus", value.MicroSeconds()); } -//////////////////////////////////////////////////////////////////////////////// - -template <class TArgFormatter> -void FormatImpl( - TStringBuilderBase* builder, - TStringBuf format, - const TArgFormatter& argFormatter) -{ - size_t argIndex = 0; - auto current = format.begin(); - while (true) { - // Scan verbatim part until stop symbol. - auto verbatimBegin = current; - auto verbatimEnd = verbatimBegin; - while (verbatimEnd != format.end() && *verbatimEnd != '%') { - ++verbatimEnd; - } - - // Copy verbatim part, if any. - size_t verbatimSize = verbatimEnd - verbatimBegin; - if (verbatimSize > 0) { - builder->AppendString(TStringBuf(verbatimBegin, verbatimSize)); - } - - // Handle stop symbol. - current = verbatimEnd; - if (current == format.end()) { - break; - } - - YT_ASSERT(*current == '%'); - ++current; - - if (*current == '%') { - // Verbatim %. - builder->AppendChar('%'); - ++current; - } else { - // Scan format part until stop symbol. - auto argFormatBegin = current; - auto argFormatEnd = argFormatBegin; +// TInstant (specialize for TFormatTraits) +inline void FormatValue(TStringBuilderBase* builder, TInstant value, TStringBuf format) +{ + // TODO(babenko): optimize + builder->AppendFormat("%v", ToString(value), format); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class TArgFormatter> +void FormatImpl( + TStringBuilderBase* builder, + TStringBuf format, + const TArgFormatter& argFormatter) +{ + size_t argIndex = 0; + auto current = format.begin(); + while (true) { + // Scan verbatim part until stop symbol. + auto verbatimBegin = current; + auto verbatimEnd = verbatimBegin; + while (verbatimEnd != format.end() && *verbatimEnd != '%') { + ++verbatimEnd; + } + + // Copy verbatim part, if any. + size_t verbatimSize = verbatimEnd - verbatimBegin; + if (verbatimSize > 0) { + builder->AppendString(TStringBuf(verbatimBegin, verbatimSize)); + } + + // Handle stop symbol. + current = verbatimEnd; + if (current == format.end()) { + break; + } + + YT_ASSERT(*current == '%'); + ++current; + + if (*current == '%') { + // Verbatim %. + builder->AppendChar('%'); + ++current; + } else { + // Scan format part until stop symbol. + auto argFormatBegin = current; + auto argFormatEnd = argFormatBegin; bool singleQuotes = false; bool doubleQuotes = false; - while ( - argFormatEnd != format.end() && - *argFormatEnd != GenericSpecSymbol && // value in generic format - *argFormatEnd != 'd' && // others are standard specifiers supported by printf - *argFormatEnd != 'i' && - *argFormatEnd != 'u' && - *argFormatEnd != 'o' && - *argFormatEnd != 'x' && - *argFormatEnd != 'X' && - *argFormatEnd != 'f' && - *argFormatEnd != 'F' && - *argFormatEnd != 'e' && - *argFormatEnd != 'E' && - *argFormatEnd != 'g' && - *argFormatEnd != 'G' && - *argFormatEnd != 'a' && - *argFormatEnd != 'A' && - *argFormatEnd != 'c' && - *argFormatEnd != 's' && - *argFormatEnd != 'p' && - *argFormatEnd != 'n') - { + while ( + argFormatEnd != format.end() && + *argFormatEnd != GenericSpecSymbol && // value in generic format + *argFormatEnd != 'd' && // others are standard specifiers supported by printf + *argFormatEnd != 'i' && + *argFormatEnd != 'u' && + *argFormatEnd != 'o' && + *argFormatEnd != 'x' && + *argFormatEnd != 'X' && + *argFormatEnd != 'f' && + *argFormatEnd != 'F' && + *argFormatEnd != 'e' && + *argFormatEnd != 'E' && + *argFormatEnd != 'g' && + *argFormatEnd != 'G' && + *argFormatEnd != 'a' && + *argFormatEnd != 'A' && + *argFormatEnd != 'c' && + *argFormatEnd != 's' && + *argFormatEnd != 'p' && + *argFormatEnd != 'n') + { if (*argFormatEnd == 'q') { singleQuotes = true; } else if (*argFormatEnd == 'Q') { doubleQuotes = true; } - ++argFormatEnd; - } - - // Handle end of format string. - if (argFormatEnd != format.end()) { - ++argFormatEnd; - } - - // 'n' means 'nothing'; skip the argument. - if (*argFormatBegin != 'n') { - // Format argument. - TStringBuf argFormat(argFormatBegin, argFormatEnd); - if (singleQuotes) { - builder->AppendChar('\''); - } - if (doubleQuotes) { - builder->AppendChar('"'); - } - argFormatter(argIndex++, builder, argFormat); - if (singleQuotes) { - builder->AppendChar('\''); - } - if (doubleQuotes) { - builder->AppendChar('"'); - } - } - - current = argFormatEnd; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -struct TFormatTraits -{ - static constexpr bool HasCustomFormatValue = !std::is_same_v< - decltype(FormatValue( - static_cast<TStringBuilderBase*>(nullptr), - *static_cast<const T*>(nullptr), - TStringBuf())), - TToStringFallbackValueFormatterTag>; -}; - -//////////////////////////////////////////////////////////////////////////////// - -template <size_t IndexBase, class... TArgs> -struct TArgFormatterImpl; - -template <size_t IndexBase> -struct TArgFormatterImpl<IndexBase> -{ - void operator() (size_t /*index*/, TStringBuilderBase* builder, TStringBuf /*format*/) const - { + ++argFormatEnd; + } + + // Handle end of format string. + if (argFormatEnd != format.end()) { + ++argFormatEnd; + } + + // 'n' means 'nothing'; skip the argument. + if (*argFormatBegin != 'n') { + // Format argument. + TStringBuf argFormat(argFormatBegin, argFormatEnd); + if (singleQuotes) { + builder->AppendChar('\''); + } + if (doubleQuotes) { + builder->AppendChar('"'); + } + argFormatter(argIndex++, builder, argFormat); + if (singleQuotes) { + builder->AppendChar('\''); + } + if (doubleQuotes) { + builder->AppendChar('"'); + } + } + + current = argFormatEnd; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +struct TFormatTraits +{ + static constexpr bool HasCustomFormatValue = !std::is_same_v< + decltype(FormatValue( + static_cast<TStringBuilderBase*>(nullptr), + *static_cast<const T*>(nullptr), + TStringBuf())), + TToStringFallbackValueFormatterTag>; +}; + +//////////////////////////////////////////////////////////////////////////////// + +template <size_t IndexBase, class... TArgs> +struct TArgFormatterImpl; + +template <size_t IndexBase> +struct TArgFormatterImpl<IndexBase> +{ + void operator() (size_t /*index*/, TStringBuilderBase* builder, TStringBuf /*format*/) const + { builder->AppendString(TStringBuf("<missing argument>")); - } -}; - -template <size_t IndexBase, class THeadArg, class... TTailArgs> -struct TArgFormatterImpl<IndexBase, THeadArg, TTailArgs...> -{ - explicit TArgFormatterImpl(const THeadArg& headArg, const TTailArgs&... tailArgs) - : HeadArg(headArg) - , TailFormatter(tailArgs...) - { } - - const THeadArg& HeadArg; - TArgFormatterImpl<IndexBase + 1, TTailArgs...> TailFormatter; - - void operator() (size_t index, TStringBuilderBase* builder, TStringBuf format) const - { - YT_ASSERT(index >= IndexBase); - if (index == IndexBase) { - FormatValue(builder, HeadArg, format); - } else { - TailFormatter(index, builder, format); - } - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -template <size_t Length, class... TArgs> -void Format( - TStringBuilderBase* builder, - const char (&format)[Length], - TArgs&&... args) -{ - Format(builder, TStringBuf(format, Length - 1), std::forward<TArgs>(args)...); -} - -template <class... TArgs> -void Format( - TStringBuilderBase* builder, - TStringBuf format, - TArgs&&... args) -{ - TArgFormatterImpl<0, TArgs...> argFormatter(args...); - FormatImpl(builder, format, argFormatter); -} - -template <size_t Length, class... TArgs> -TString Format( - const char (&format)[Length], - TArgs&&... args) -{ - TStringBuilder builder; - Format(&builder, format, std::forward<TArgs>(args)...); - return builder.Flush(); -} - -template <class... TArgs> + } +}; + +template <size_t IndexBase, class THeadArg, class... TTailArgs> +struct TArgFormatterImpl<IndexBase, THeadArg, TTailArgs...> +{ + explicit TArgFormatterImpl(const THeadArg& headArg, const TTailArgs&... tailArgs) + : HeadArg(headArg) + , TailFormatter(tailArgs...) + { } + + const THeadArg& HeadArg; + TArgFormatterImpl<IndexBase + 1, TTailArgs...> TailFormatter; + + void operator() (size_t index, TStringBuilderBase* builder, TStringBuf format) const + { + YT_ASSERT(index >= IndexBase); + if (index == IndexBase) { + FormatValue(builder, HeadArg, format); + } else { + TailFormatter(index, builder, format); + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// + +template <size_t Length, class... TArgs> +void Format( + TStringBuilderBase* builder, + const char (&format)[Length], + TArgs&&... args) +{ + Format(builder, TStringBuf(format, Length - 1), std::forward<TArgs>(args)...); +} + +template <class... TArgs> +void Format( + TStringBuilderBase* builder, + TStringBuf format, + TArgs&&... args) +{ + TArgFormatterImpl<0, TArgs...> argFormatter(args...); + FormatImpl(builder, format, argFormatter); +} + +template <size_t Length, class... TArgs> +TString Format( + const char (&format)[Length], + TArgs&&... args) +{ + TStringBuilder builder; + Format(&builder, format, std::forward<TArgs>(args)...); + return builder.Flush(); +} + +template <class... TArgs> TString Format( - TStringBuf format, - TArgs&&... args) -{ - TStringBuilder builder; - Format(&builder, format, std::forward<TArgs>(args)...); - return builder.Flush(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT + TStringBuf format, + TArgs&&... args) +{ + TStringBuilder builder; + Format(&builder, format, std::forward<TArgs>(args)...); + return builder.Flush(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/string/format.h b/library/cpp/yt/string/format.h index 9708fe5906..956682b3d7 100644 --- a/library/cpp/yt/string/format.h +++ b/library/cpp/yt/string/format.h @@ -1,92 +1,92 @@ -#pragma once - -#include "string_builder.h" - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -/* - * Format: a type-safe and fast formatting utility. - * - * Basically works as a type-safe analogue of |sprintf| and is expected to - * be backwards-compatible with the latter. +#pragma once + +#include "string_builder.h" + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +/* + * Format: a type-safe and fast formatting utility. + * + * Basically works as a type-safe analogue of |sprintf| and is expected to + * be backwards-compatible with the latter. * - * Like Go's |Sprintf|, supports the ultimate format specifier |v| - * causing arguments to be emitted in default format. - * This is the default and preferred way of formatting things, - * which should be used in newer code. + * Like Go's |Sprintf|, supports the ultimate format specifier |v| + * causing arguments to be emitted in default format. + * This is the default and preferred way of formatting things, + * which should be used in newer code. * - * |Format| may currently invoke |sprintf| internally for emitting numeric and some other - * types. You can always write your own optimized implementation, if you wish :) + * |Format| may currently invoke |sprintf| internally for emitting numeric and some other + * types. You can always write your own optimized implementation, if you wish :) * - * In additional to the usual |sprintf|, supports a number of non-standard flags: + * In additional to the usual |sprintf|, supports a number of non-standard flags: * - * |q| Causes the argument to be surrounded with single quotes (|'|). - * Applies to all types. + * |q| Causes the argument to be surrounded with single quotes (|'|). + * Applies to all types. * - * |Q| Causes the argument to be surrounded with double quotes (|"|). - * Applies to all types. + * |Q| Causes the argument to be surrounded with double quotes (|"|). + * Applies to all types. * - * |l| The argument is emitted in "lowercase" style. - * Only applies to enums and bools. + * |l| The argument is emitted in "lowercase" style. + * Only applies to enums and bools. * - * The following argument types are supported: + * The following argument types are supported: * * Strings (including |const char*|, |TStringBuf|, and |TString|) and chars: - * Emitted as is. Fast. + * Emitted as is. Fast. * - * Numerics and pointers: - * Emitted using |sprintf|. Maybe not that fast. + * Numerics and pointers: + * Emitted using |sprintf|. Maybe not that fast. * - * |bool|: - * Emitted either as |True| and |False| or |true| and |false| (if lowercase mode is ON). + * |bool|: + * Emitted either as |True| and |False| or |true| and |false| (if lowercase mode is ON). * - * Enums: - * Emitted in either camel (|SomeName|) or in lowercase-with-underscores style - * (|some_name|, if lowercase mode is ON). + * Enums: + * Emitted in either camel (|SomeName|) or in lowercase-with-underscores style + * (|some_name|, if lowercase mode is ON). * - * Nullables: - * |std::nullopt| is emitted as |<null>|. + * Nullables: + * |std::nullopt| is emitted as |<null>|. * - * All others: - * Emitted as strings by calling |ToString|. - * - */ - -template <size_t Length, class... TArgs> -void Format(TStringBuilderBase* builder, const char (&format)[Length], TArgs&&... args); -template <class... TArgs> -void Format(TStringBuilderBase* builder, TStringBuf format, TArgs&&... args); - -template <size_t Length, class... TArgs> -TString Format(const char (&format)[Length], TArgs&&... args); -template <class... TArgs> -TString Format(TStringBuf format, TArgs&&... args); - -//////////////////////////////////////////////////////////////////////////////// - -template <class TRange, class TFormatter> + * All others: + * Emitted as strings by calling |ToString|. + * + */ + +template <size_t Length, class... TArgs> +void Format(TStringBuilderBase* builder, const char (&format)[Length], TArgs&&... args); +template <class... TArgs> +void Format(TStringBuilderBase* builder, TStringBuf format, TArgs&&... args); + +template <size_t Length, class... TArgs> +TString Format(const char (&format)[Length], TArgs&&... args); +template <class... TArgs> +TString Format(TStringBuf format, TArgs&&... args); + +//////////////////////////////////////////////////////////////////////////////// + +template <class TRange, class TFormatter> struct TFormattableView -{ +{ using TBegin = std::decay_t<decltype(std::declval<const TRange>().begin())>; using TEnd = std::decay_t<decltype(std::declval<const TRange>().end())>; TBegin RangeBegin; TEnd RangeEnd; - TFormatter Formatter; + TFormatter Formatter; size_t Limit = std::numeric_limits<size_t>::max(); TBegin begin() const; TEnd end() const; -}; - -//! Annotates a given #range with #formatter to be applied to each item. -template <class TRange, class TFormatter> +}; + +//! Annotates a given #range with #formatter to be applied to each item. +template <class TRange, class TFormatter> TFormattableView<TRange, TFormatter> MakeFormattableView( - const TRange& range, + const TRange& range, TFormatter&& formatter); - + template <class TRange, class TFormatter> TFormattableView<TRange, TFormatter> MakeShrunkFormattableView( const TRange& range, @@ -95,20 +95,20 @@ TFormattableView<TRange, TFormatter> MakeShrunkFormattableView( //////////////////////////////////////////////////////////////////////////////// -template <class TFormatter> -struct TFormatterWrapper -{ - TFormatter Formatter; -}; - -template <class TFormatter> -TFormatterWrapper<TFormatter> MakeFormatterWrapper( - TFormatter&& formatter); - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT - -#define FORMAT_INL_H_ -#include "format-inl.h" -#undef FORMAT_INL_H_ +template <class TFormatter> +struct TFormatterWrapper +{ + TFormatter Formatter; +}; + +template <class TFormatter> +TFormatterWrapper<TFormatter> MakeFormatterWrapper( + TFormatter&& formatter); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define FORMAT_INL_H_ +#include "format-inl.h" +#undef FORMAT_INL_H_ diff --git a/library/cpp/yt/string/guid.cpp b/library/cpp/yt/string/guid.cpp index 6c133a9778..1d87478c7b 100644 --- a/library/cpp/yt/string/guid.cpp +++ b/library/cpp/yt/string/guid.cpp @@ -6,7 +6,7 @@ namespace NYT { void FormatValue(TStringBuilderBase* builder, TGuid value, TStringBuf /*format*/) { - char* begin = builder->Preallocate(MaxGuidStringSize); + char* begin = builder->Preallocate(MaxGuidStringSize); char* end = WriteGuidToBuffer(begin, value); builder->Advance(end - begin); } diff --git a/library/cpp/yt/string/string.cpp b/library/cpp/yt/string/string.cpp index 7440ac3fdd..683c46ab2f 100644 --- a/library/cpp/yt/string/string.cpp +++ b/library/cpp/yt/string/string.cpp @@ -1,78 +1,78 @@ -#include "string.h" +#include "string.h" #include "format.h" - -#include <library/cpp/yt/assert/assert.h> + +#include <library/cpp/yt/assert/assert.h> #include <util/generic/hash.h> -#include <util/string/ascii.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -void UnderscoreCaseToCamelCase(TStringBuilderBase* builder, TStringBuf str) -{ +#include <util/string/ascii.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +void UnderscoreCaseToCamelCase(TStringBuilderBase* builder, TStringBuf str) +{ bool first = true; - bool upper = true; - for (char c : str) { - if (c == '_') { - upper = true; - } else { - if (upper) { + bool upper = true; + for (char c : str) { + if (c == '_') { + upper = true; + } else { + if (upper) { if (!std::isalpha(c) && !first) { - builder->AppendChar('_'); + builder->AppendChar('_'); } - c = std::toupper(c); - } - builder->AppendChar(c); - upper = false; - } + c = std::toupper(c); + } + builder->AppendChar(c); + upper = false; + } first = false; - } -} - -TString UnderscoreCaseToCamelCase(TStringBuf str) -{ - TStringBuilder builder; - UnderscoreCaseToCamelCase(&builder, str); - return builder.Flush(); -} - -void CamelCaseToUnderscoreCase(TStringBuilderBase* builder, TStringBuf str) -{ - bool first = true; - for (char c : str) { + } +} + +TString UnderscoreCaseToCamelCase(TStringBuf str) +{ + TStringBuilder builder; + UnderscoreCaseToCamelCase(&builder, str); + return builder.Flush(); +} + +void CamelCaseToUnderscoreCase(TStringBuilderBase* builder, TStringBuf str) +{ + bool first = true; + for (char c : str) { if (std::isupper(c) && std::isalpha(c)) { - if (!first) { - builder->AppendChar('_'); - } + if (!first) { + builder->AppendChar('_'); + } c = std::tolower(c); - } - builder->AppendChar(c); - first = false; - } -} - -TString CamelCaseToUnderscoreCase(TStringBuf str) -{ - TStringBuilder builder; - CamelCaseToUnderscoreCase(&builder, str); - return builder.Flush(); -} - -//////////////////////////////////////////////////////////////////////////////// - + } + builder->AppendChar(c); + first = false; + } +} + +TString CamelCaseToUnderscoreCase(TStringBuf str) +{ + TStringBuilder builder; + CamelCaseToUnderscoreCase(&builder, str); + return builder.Flush(); +} + +//////////////////////////////////////////////////////////////////////////////// + TString TrimLeadingWhitespaces(const TString& str) -{ +{ for (int i = 0; i < static_cast<int>(str.size()); ++i) { - if (str[i] != ' ') { - return str.substr(i); - } - } - return ""; -} - + if (str[i] != ' ') { + return str.substr(i); + } + } + return ""; +} + TString Trim(const TString& str, const TString& whitespaces) { size_t end = str.size(); @@ -96,13 +96,13 @@ TString Trim(const TString& str, const TString& whitespaces) } size_t begin = str.find_first_not_of(whitespaces); - YT_VERIFY(begin != TString::npos); - YT_VERIFY(begin < end); + YT_VERIFY(begin != TString::npos); + YT_VERIFY(begin < end); return str.substr(begin, end - begin); } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + namespace { ui16 DecimalDigits2[100] = { @@ -119,7 +119,7 @@ ui16 DecimalDigits2[100] = { }; template <class T> -char* WriteSignedIntToBufferBackwardsImpl(char* ptr, T value, TStringBuf min) +char* WriteSignedIntToBufferBackwardsImpl(char* ptr, T value, TStringBuf min) { if (value == 0) { --ptr; @@ -214,50 +214,50 @@ char* WriteIntToBufferBackwards(char* ptr, ui64 value) //////////////////////////////////////////////////////////////////////////////// -size_t TCaseInsensitiveStringHasher::operator()(TStringBuf arg) const -{ - auto compute = [&] (char* buffer) { - for (size_t index = 0; index < arg.length(); ++index) { - buffer[index] = AsciiToLower(arg[index]); - } +size_t TCaseInsensitiveStringHasher::operator()(TStringBuf arg) const +{ + auto compute = [&] (char* buffer) { + for (size_t index = 0; index < arg.length(); ++index) { + buffer[index] = AsciiToLower(arg[index]); + } return ComputeHash(TStringBuf(buffer, arg.length())); - }; - const size_t SmallSize = 256; - if (arg.length() <= SmallSize) { - std::array<char, SmallSize> stackBuffer; - return compute(stackBuffer.data()); - } else { - std::unique_ptr<char[]> heapBuffer(new char[arg.length()]); - return compute(heapBuffer.get()); - } -} - -bool TCaseInsensitiveStringEqualityComparer::operator()(TStringBuf lhs, TStringBuf rhs) const -{ - return AsciiEqualsIgnoreCase(lhs, rhs); -} - -//////////////////////////////////////////////////////////////////////////////// - -bool TryParseBool(TStringBuf value, bool* result) + }; + const size_t SmallSize = 256; + if (arg.length() <= SmallSize) { + std::array<char, SmallSize> stackBuffer; + return compute(stackBuffer.data()); + } else { + std::unique_ptr<char[]> heapBuffer(new char[arg.length()]); + return compute(heapBuffer.get()); + } +} + +bool TCaseInsensitiveStringEqualityComparer::operator()(TStringBuf lhs, TStringBuf rhs) const +{ + return AsciiEqualsIgnoreCase(lhs, rhs); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool TryParseBool(TStringBuf value, bool* result) { if (value == "true" || value == "1") { - *result = true; + *result = true; return true; } else if (value == "false" || value == "0") { - *result = false; + *result = false; return true; } else { return false; } } -bool ParseBool(TStringBuf value) +bool ParseBool(TStringBuf value) { bool result; - if (!TryParseBool(value, &result)) { - throw TSimpleException(Format("Error parsing boolean value %Qv", - value)); + if (!TryParseBool(value, &result)) { + throw TSimpleException(Format("Error parsing boolean value %Qv", + value)); } return result; } @@ -269,4 +269,4 @@ TStringBuf FormatBool(bool value) //////////////////////////////////////////////////////////////////////////////// -} // namespace NYT +} // namespace NYT diff --git a/library/cpp/yt/string/string.h b/library/cpp/yt/string/string.h index ae6c99caab..92c7a2f472 100644 --- a/library/cpp/yt/string/string.h +++ b/library/cpp/yt/string/string.h @@ -1,9 +1,9 @@ -#pragma once - -#include "string_builder.h" - -#include <library/cpp/yt/exception/exception.h> - +#pragma once + +#include "string_builder.h" + +#include <library/cpp/yt/exception/exception.h> + #include <util/datetime/base.h> #include <util/generic/string.h> @@ -14,184 +14,184 @@ #include <set> #include <map> -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -//! Formatters enable customizable way to turn an object into a string. -//! This default implementation uses |FormatValue|. -struct TDefaultFormatter -{ - template <class T> - void operator()(TStringBuilderBase* builder, const T& obj) const - { +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +//! Formatters enable customizable way to turn an object into a string. +//! This default implementation uses |FormatValue|. +struct TDefaultFormatter +{ + template <class T> + void operator()(TStringBuilderBase* builder, const T& obj) const + { FormatValue(builder, obj, TStringBuf("v")); - } -}; - + } +}; + static constexpr TStringBuf DefaultJoinToStringDelimiter = ", "; static constexpr TStringBuf DefaultKeyValueDelimiter = ": "; static constexpr TStringBuf DefaultRangeEllipsisFormat = "..."; - + // ASCII characters from 0x20 = ' ' to 0x7e = '~' are printable. static constexpr char PrintableASCIILow = 0x20; static constexpr char PrintableASCIIHigh = 0x7e; static constexpr TStringBuf Int2Hex = "0123456789abcdef"; -//! Joins a range of items into a string intermixing them with the delimiter. -/*! - * \param builder String builder where the output goes. - * \param begin Iterator pointing to the first item (inclusive). - * \param end Iterator pointing to the last item (not inclusive). - * \param formatter Formatter to apply to the items. - * \param delimiter A delimiter to be inserted between items: ", " by default. - * \return The resulting combined string. - */ -template <class TIterator, class TFormatter> -void JoinToString( - TStringBuilderBase* builder, - const TIterator& begin, - const TIterator& end, - const TFormatter& formatter, - TStringBuf delimiter = DefaultJoinToStringDelimiter) -{ - for (auto current = begin; current != end; ++current) { - if (current != begin) { - builder->AppendString(delimiter); - } - formatter(builder, *current); - } -} - -template <class TIterator, class TFormatter> +//! Joins a range of items into a string intermixing them with the delimiter. +/*! + * \param builder String builder where the output goes. + * \param begin Iterator pointing to the first item (inclusive). + * \param end Iterator pointing to the last item (not inclusive). + * \param formatter Formatter to apply to the items. + * \param delimiter A delimiter to be inserted between items: ", " by default. + * \return The resulting combined string. + */ +template <class TIterator, class TFormatter> +void JoinToString( + TStringBuilderBase* builder, + const TIterator& begin, + const TIterator& end, + const TFormatter& formatter, + TStringBuf delimiter = DefaultJoinToStringDelimiter) +{ + for (auto current = begin; current != end; ++current) { + if (current != begin) { + builder->AppendString(delimiter); + } + formatter(builder, *current); + } +} + +template <class TIterator, class TFormatter> TString JoinToString( - const TIterator& begin, - const TIterator& end, - const TFormatter& formatter, - TStringBuf delimiter = DefaultJoinToStringDelimiter) -{ - TStringBuilder builder; - JoinToString(&builder, begin, end, formatter, delimiter); - return builder.Flush(); -} - -//! A handy shortcut with default formatter. -template <class TIterator> + const TIterator& begin, + const TIterator& end, + const TFormatter& formatter, + TStringBuf delimiter = DefaultJoinToStringDelimiter) +{ + TStringBuilder builder; + JoinToString(&builder, begin, end, formatter, delimiter); + return builder.Flush(); +} + +//! A handy shortcut with default formatter. +template <class TIterator> TString JoinToString( - const TIterator& begin, - const TIterator& end, - TStringBuf delimiter = DefaultJoinToStringDelimiter) -{ - return JoinToString(begin, end, TDefaultFormatter(), delimiter); -} - -//! Joins a collection of given items into a string intermixing them with the delimiter. -/*! - * \param collection A collection containing the items to be joined. - * \param formatter Formatter to apply to the items. - * \param delimiter A delimiter to be inserted between items; ", " by default. - */ -template <class TCollection, class TFormatter> + const TIterator& begin, + const TIterator& end, + TStringBuf delimiter = DefaultJoinToStringDelimiter) +{ + return JoinToString(begin, end, TDefaultFormatter(), delimiter); +} + +//! Joins a collection of given items into a string intermixing them with the delimiter. +/*! + * \param collection A collection containing the items to be joined. + * \param formatter Formatter to apply to the items. + * \param delimiter A delimiter to be inserted between items; ", " by default. + */ +template <class TCollection, class TFormatter> TString JoinToString( - const TCollection& collection, - const TFormatter& formatter, - TStringBuf delimiter = DefaultJoinToStringDelimiter) -{ + const TCollection& collection, + const TFormatter& formatter, + TStringBuf delimiter = DefaultJoinToStringDelimiter) +{ using std::begin; using std::end; - return JoinToString(begin(collection), end(collection), formatter, delimiter); -} - -//! A handy shortcut with the default formatter. -template <class TCollection> + return JoinToString(begin(collection), end(collection), formatter, delimiter); +} + +//! A handy shortcut with the default formatter. +template <class TCollection> TString JoinToString( - const TCollection& collection, - TStringBuf delimiter = DefaultJoinToStringDelimiter) -{ - return JoinToString(collection, TDefaultFormatter(), delimiter); -} - -//! Concatenates a bunch of TStringBuf-like instances into TString. -template <class... Ts> -TString ConcatToString(Ts... args) -{ - size_t length = 0; - ((length += args.length()), ...); - - TString result; - result.reserve(length); - (result.append(args), ...); - - return result; -} - -//! Converts a range of items into strings. -template <class TIter, class TFormatter> + const TCollection& collection, + TStringBuf delimiter = DefaultJoinToStringDelimiter) +{ + return JoinToString(collection, TDefaultFormatter(), delimiter); +} + +//! Concatenates a bunch of TStringBuf-like instances into TString. +template <class... Ts> +TString ConcatToString(Ts... args) +{ + size_t length = 0; + ((length += args.length()), ...); + + TString result; + result.reserve(length); + (result.append(args), ...); + + return result; +} + +//! Converts a range of items into strings. +template <class TIter, class TFormatter> std::vector<TString> ConvertToStrings( - const TIter& begin, - const TIter& end, - const TFormatter& formatter, - size_t maxSize = std::numeric_limits<size_t>::max()) -{ + const TIter& begin, + const TIter& end, + const TFormatter& formatter, + size_t maxSize = std::numeric_limits<size_t>::max()) +{ std::vector<TString> result; - for (auto it = begin; it != end; ++it) { - TStringBuilder builder; - formatter(&builder, *it); - result.push_back(builder.Flush()); - if (result.size() == maxSize) { - break; - } - } - return result; -} - -//! A handy shortcut with the default formatter. -template <class TIter> + for (auto it = begin; it != end; ++it) { + TStringBuilder builder; + formatter(&builder, *it); + result.push_back(builder.Flush()); + if (result.size() == maxSize) { + break; + } + } + return result; +} + +//! A handy shortcut with the default formatter. +template <class TIter> std::vector<TString> ConvertToStrings( - const TIter& begin, - const TIter& end, - size_t maxSize = std::numeric_limits<size_t>::max()) -{ - return ConvertToStrings(begin, end, TDefaultFormatter(), maxSize); -} - -//! Converts a given collection of items into strings. -/*! - * \param collection A collection containing the items to be converted. - * \param formatter Formatter to apply to the items. - * \param maxSize Size limit for the resulting vector. - */ -template <class TCollection, class TFormatter> + const TIter& begin, + const TIter& end, + size_t maxSize = std::numeric_limits<size_t>::max()) +{ + return ConvertToStrings(begin, end, TDefaultFormatter(), maxSize); +} + +//! Converts a given collection of items into strings. +/*! + * \param collection A collection containing the items to be converted. + * \param formatter Formatter to apply to the items. + * \param maxSize Size limit for the resulting vector. + */ +template <class TCollection, class TFormatter> std::vector<TString> ConvertToStrings( - const TCollection& collection, - const TFormatter& formatter, - size_t maxSize = std::numeric_limits<size_t>::max()) -{ + const TCollection& collection, + const TFormatter& formatter, + size_t maxSize = std::numeric_limits<size_t>::max()) +{ using std::begin; using std::end; return ConvertToStrings(begin(collection), end(collection), formatter, maxSize); -} - -//! A handy shortcut with default formatter. -template <class TCollection> +} + +//! A handy shortcut with default formatter. +template <class TCollection> std::vector<TString> ConvertToStrings( - const TCollection& collection, - size_t maxSize = std::numeric_limits<size_t>::max()) -{ - return ConvertToStrings(collection, TDefaultFormatter(), maxSize); -} - -//////////////////////////////////////////////////////////////////////////////// - -void UnderscoreCaseToCamelCase(TStringBuilderBase* builder, TStringBuf str); -TString UnderscoreCaseToCamelCase(TStringBuf str); - -void CamelCaseToUnderscoreCase(TStringBuilderBase* builder, TStringBuf str); -TString CamelCaseToUnderscoreCase(TStringBuf str); + const TCollection& collection, + size_t maxSize = std::numeric_limits<size_t>::max()) +{ + return ConvertToStrings(collection, TDefaultFormatter(), maxSize); +} + +//////////////////////////////////////////////////////////////////////////////// + +void UnderscoreCaseToCamelCase(TStringBuilderBase* builder, TStringBuf str); +TString UnderscoreCaseToCamelCase(TStringBuf str); + +void CamelCaseToUnderscoreCase(TStringBuilderBase* builder, TStringBuf str); +TString CamelCaseToUnderscoreCase(TStringBuf str); TString TrimLeadingWhitespaces(const TString& str); TString Trim(const TString& str, const TString& whitespaces); - + //////////////////////////////////////////////////////////////////////////////// //! Implemented for |[u]i(32|64)|. @@ -200,22 +200,22 @@ char* WriteIntToBufferBackwards(char* ptr, T value); //////////////////////////////////////////////////////////////////////////////// -struct TCaseInsensitiveStringHasher -{ - size_t operator()(TStringBuf arg) const; -}; - -struct TCaseInsensitiveStringEqualityComparer -{ - bool operator()(TStringBuf lhs, TStringBuf rhs) const; -}; - -//////////////////////////////////////////////////////////////////////////////// - -bool TryParseBool(TStringBuf value, bool* result); -bool ParseBool(TStringBuf value); +struct TCaseInsensitiveStringHasher +{ + size_t operator()(TStringBuf arg) const; +}; + +struct TCaseInsensitiveStringEqualityComparer +{ + bool operator()(TStringBuf lhs, TStringBuf rhs) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +bool TryParseBool(TStringBuf value, bool* result); +bool ParseBool(TStringBuf value); TStringBuf FormatBool(bool value); //////////////////////////////////////////////////////////////////////////////// -} // namespace NYT +} // namespace NYT diff --git a/library/cpp/yt/string/string_builder-inl.h b/library/cpp/yt/string/string_builder-inl.h index 151fcabf7f..b207452568 100644 --- a/library/cpp/yt/string/string_builder-inl.h +++ b/library/cpp/yt/string/string_builder-inl.h @@ -1,129 +1,129 @@ -#ifndef STRING_BUILDER_INL_H_ -#error "Direct inclusion of this file is not allowed, include string.h" -// For the sake of sane code completion. -#include "string_builder.h" -#endif - -#include <library/cpp/yt/assert/assert.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -inline char* TStringBuilderBase::Preallocate(size_t size) -{ +#ifndef STRING_BUILDER_INL_H_ +#error "Direct inclusion of this file is not allowed, include string.h" +// For the sake of sane code completion. +#include "string_builder.h" +#endif + +#include <library/cpp/yt/assert/assert.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +inline char* TStringBuilderBase::Preallocate(size_t size) +{ if (Y_UNLIKELY(End_ - Current_ < static_cast<ssize_t>(size))) { - size_t length = GetLength(); - auto newLength = std::max(length + size, MinBufferLength); - DoPreallocate(newLength); - Current_ = Begin_ + length; - } - return Current_; -} - -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); + size_t length = GetLength(); + auto newLength = std::max(length + size, MinBufferLength); + DoPreallocate(newLength); + Current_ = Begin_ + length; + } + return Current_; +} + +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() -{ +} + +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, format, std::forward<TArgs>(args)...); -} - -template <size_t Length, class... TArgs> -void TStringBuilderBase::AppendFormat(const char (&format)[Length], TArgs&& ... args) -{ - Format(this, 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::DoPreallocate(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 /*format*/) -{ - builder->AppendString(value.GetBuffer()); -} - -template <class T> -TString ToStringViaBuilder(const T& value, TStringBuf spec) -{ - TStringBuilder builder; - FormatValue(&builder, value, spec); - return builder.Flush(); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT + DoReset(); +} + +template <class... TArgs> +void TStringBuilderBase::AppendFormat(TStringBuf format, TArgs&& ... args) +{ + Format(this, format, std::forward<TArgs>(args)...); +} + +template <size_t Length, class... TArgs> +void TStringBuilderBase::AppendFormat(const char (&format)[Length], TArgs&& ... args) +{ + Format(this, 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::DoPreallocate(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 /*format*/) +{ + builder->AppendString(value.GetBuffer()); +} + +template <class T> +TString ToStringViaBuilder(const T& value, TStringBuf spec) +{ + TStringBuilder builder; + FormatValue(&builder, value, spec); + return builder.Flush(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/string/string_builder.h b/library/cpp/yt/string/string_builder.h index 0e13e70904..6dac4a3eea 100644 --- a/library/cpp/yt/string/string_builder.h +++ b/library/cpp/yt/string/string_builder.h @@ -1,116 +1,116 @@ -#pragma once - -#include <util/generic/string.h> - -namespace NYT { - -//////////////////////////////////////////////////////////////////////////////// - -// Forward declarations. -class TStringBuilderBase; -class TStringBuilder; -class TDelimitedStringBuilderWrapper; - -template <size_t Length, class... TArgs> -void Format(TStringBuilderBase* builder, const char (&format)[Length], TArgs&&... args); -template <class... TArgs> -void Format(TStringBuilderBase* builder, TStringBuf format, TArgs&&... args); - -//////////////////////////////////////////////////////////////////////////////// - -//! A simple helper for constructing strings by a sequence of appends. -class TStringBuilderBase -{ -public: +#pragma once + +#include <util/generic/string.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +// Forward declarations. +class TStringBuilderBase; +class TStringBuilder; +class TDelimitedStringBuilderWrapper; + +template <size_t Length, class... TArgs> +void Format(TStringBuilderBase* builder, const char (&format)[Length], TArgs&&... args); +template <class... TArgs> +void Format(TStringBuilderBase* builder, TStringBuf format, TArgs&&... args); + +//////////////////////////////////////////////////////////////////////////////// + +//! A simple helper for constructing strings by a sequence of appends. +class TStringBuilderBase +{ +public: virtual ~TStringBuilderBase() = default; - char* Preallocate(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* Preallocate(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 DoPreallocate(size_t newLength) = 0; - - // -64 must account for any reasonable overhead in dynamic string allocation. - static constexpr size_t MinBufferLength = 1024 - 64; -}; - -//////////////////////////////////////////////////////////////////////////////// - -class TStringBuilder - : public TStringBuilderBase -{ -public: - TString Flush(); - -protected: - TString Buffer_; - + + virtual void DoReset() = 0; + virtual void DoPreallocate(size_t newLength) = 0; + + // -64 must account for any reasonable overhead in dynamic string allocation. + static constexpr size_t MinBufferLength = 1024 - 64; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class TStringBuilder + : public TStringBuilderBase +{ +public: + TString Flush(); + +protected: + TString Buffer_; + void DoReset() override; void DoPreallocate(size_t size) override; -}; - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> +}; + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> TString ToStringViaBuilder(const T& value, TStringBuf spec = TStringBuf("v")); - -//////////////////////////////////////////////////////////////////////////////// - -//! Appends a certain delimiter starting from the second call. -class TDelimitedStringBuilderWrapper - : private TNonCopyable -{ -public: - TDelimitedStringBuilderWrapper( - TStringBuilderBase* builder, + +//////////////////////////////////////////////////////////////////////////////// + +//! Appends a certain delimiter starting from the second call. +class TDelimitedStringBuilderWrapper + : private TNonCopyable +{ +public: + TDelimitedStringBuilderWrapper( + TStringBuilderBase* builder, TStringBuf delimiter = TStringBuf(", ")) - : Builder_(builder) - , Delimiter_(delimiter) - { } - - TStringBuilderBase* operator->() - { - if (!FirstCall_) { - Builder_->AppendString(Delimiter_); - } - FirstCall_ = false; - return Builder_; - } - -private: - TStringBuilderBase* const Builder_; - const TStringBuf Delimiter_; - - bool FirstCall_ = true; -}; - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT - -#define STRING_BUILDER_INL_H_ -#include "string_builder-inl.h" -#undef STRING_BUILDER_INL_H_ + : Builder_(builder) + , Delimiter_(delimiter) + { } + + TStringBuilderBase* operator->() + { + if (!FirstCall_) { + Builder_->AppendString(Delimiter_); + } + FirstCall_ = false; + return Builder_; + } + +private: + TStringBuilderBase* const Builder_; + const TStringBuf Delimiter_; + + bool FirstCall_ = true; +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define STRING_BUILDER_INL_H_ +#include "string_builder-inl.h" +#undef STRING_BUILDER_INL_H_ diff --git a/library/cpp/yt/string/unittests/enum_ut.cpp b/library/cpp/yt/string/unittests/enum_ut.cpp index b8076fd8ee..948a0dd000 100644 --- a/library/cpp/yt/string/unittests/enum_ut.cpp +++ b/library/cpp/yt/string/unittests/enum_ut.cpp @@ -1,61 +1,61 @@ #include <library/cpp/testing/gtest/gtest.h> - + #include <library/cpp/yt/string/enum.h> #include <library/cpp/yt/string/format.h> - -#include <limits> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -// Some compile-time sanity checks. -DEFINE_ENUM(ESample, (One)(Two)); -static_assert(TFormatTraits<ESample>::HasCustomFormatValue); -static_assert(TFormatTraits<TEnumIndexedVector<ESample, int>>::HasCustomFormatValue); - -DEFINE_ENUM(EColor, - (Red) - (BlackAndWhite) -); - -DEFINE_BIT_ENUM(ELangs, - ((None) (0x00)) - ((Cpp) (0x01)) - ((Go) (0x02)) - ((Rust) (0x04)) - ((Python) (0x08)) - ((JavaScript) (0x10)) -) - -TEST(TFormatTest, Enum) -{ - EXPECT_EQ("Red", Format("%v", EColor::Red)); - EXPECT_EQ("red", Format("%lv", EColor::Red)); - - EXPECT_EQ("BlackAndWhite", Format("%v", EColor::BlackAndWhite)); - EXPECT_EQ("black_and_white", Format("%lv", EColor::BlackAndWhite)); - - EXPECT_EQ("EColor(100)", Format("%v", EColor(100))); - - EXPECT_EQ("JavaScript", Format("%v", ELangs::JavaScript)); - EXPECT_EQ("java_script", Format("%lv", ELangs::JavaScript)); - - EXPECT_EQ("None", Format("%v", ELangs::None)); - EXPECT_EQ("none", Format("%lv", ELangs::None)); - - EXPECT_EQ("Cpp | Go", Format("%v", ELangs::Cpp | ELangs::Go)); - EXPECT_EQ("cpp | go", Format("%lv", ELangs::Cpp | ELangs::Go)); - - auto four = ELangs::Cpp | ELangs::Go | ELangs::Python | ELangs::JavaScript; - EXPECT_EQ("Cpp | Go | Python | JavaScript", Format("%v", four)); - EXPECT_EQ("cpp | go | python | java_script", Format("%lv", four)); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT - + +#include <limits> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +// Some compile-time sanity checks. +DEFINE_ENUM(ESample, (One)(Two)); +static_assert(TFormatTraits<ESample>::HasCustomFormatValue); +static_assert(TFormatTraits<TEnumIndexedVector<ESample, int>>::HasCustomFormatValue); + +DEFINE_ENUM(EColor, + (Red) + (BlackAndWhite) +); + +DEFINE_BIT_ENUM(ELangs, + ((None) (0x00)) + ((Cpp) (0x01)) + ((Go) (0x02)) + ((Rust) (0x04)) + ((Python) (0x08)) + ((JavaScript) (0x10)) +) + +TEST(TFormatTest, Enum) +{ + EXPECT_EQ("Red", Format("%v", EColor::Red)); + EXPECT_EQ("red", Format("%lv", EColor::Red)); + + EXPECT_EQ("BlackAndWhite", Format("%v", EColor::BlackAndWhite)); + EXPECT_EQ("black_and_white", Format("%lv", EColor::BlackAndWhite)); + + EXPECT_EQ("EColor(100)", Format("%v", EColor(100))); + + EXPECT_EQ("JavaScript", Format("%v", ELangs::JavaScript)); + EXPECT_EQ("java_script", Format("%lv", ELangs::JavaScript)); + + EXPECT_EQ("None", Format("%v", ELangs::None)); + EXPECT_EQ("none", Format("%lv", ELangs::None)); + + EXPECT_EQ("Cpp | Go", Format("%v", ELangs::Cpp | ELangs::Go)); + EXPECT_EQ("cpp | go", Format("%lv", ELangs::Cpp | ELangs::Go)); + + auto four = ELangs::Cpp | ELangs::Go | ELangs::Python | ELangs::JavaScript; + EXPECT_EQ("Cpp | Go | Python | JavaScript", Format("%v", four)); + EXPECT_EQ("cpp | go | python | java_script", Format("%lv", four)); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT + diff --git a/library/cpp/yt/string/unittests/format_ut.cpp b/library/cpp/yt/string/unittests/format_ut.cpp index ee069bb2c0..58c757be0d 100644 --- a/library/cpp/yt/string/unittests/format_ut.cpp +++ b/library/cpp/yt/string/unittests/format_ut.cpp @@ -1,149 +1,149 @@ #include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/yt/string/format.h> - + +#include <library/cpp/yt/string/format.h> + #include <library/cpp/yt/small_containers/compact_vector.h> -#include <limits> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -// Some compile-time sanity checks. -static_assert(TFormatTraits<int>::HasCustomFormatValue); -static_assert(TFormatTraits<double>::HasCustomFormatValue); -static_assert(TFormatTraits<void*>::HasCustomFormatValue); -static_assert(TFormatTraits<const char*>::HasCustomFormatValue); -static_assert(TFormatTraits<TStringBuf>::HasCustomFormatValue); -static_assert(TFormatTraits<TString>::HasCustomFormatValue); -static_assert(TFormatTraits<std::vector<int>>::HasCustomFormatValue); +#include <limits> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +// Some compile-time sanity checks. +static_assert(TFormatTraits<int>::HasCustomFormatValue); +static_assert(TFormatTraits<double>::HasCustomFormatValue); +static_assert(TFormatTraits<void*>::HasCustomFormatValue); +static_assert(TFormatTraits<const char*>::HasCustomFormatValue); +static_assert(TFormatTraits<TStringBuf>::HasCustomFormatValue); +static_assert(TFormatTraits<TString>::HasCustomFormatValue); +static_assert(TFormatTraits<std::vector<int>>::HasCustomFormatValue); // N.B. TCompactVector<int, 1> is not buildable on Windows static_assert(TFormatTraits<TCompactVector<int, 2>>::HasCustomFormatValue); -static_assert(TFormatTraits<std::set<int>>::HasCustomFormatValue); -static_assert(TFormatTraits<std::map<int, int>>::HasCustomFormatValue); -static_assert(TFormatTraits<std::multimap<int, int>>::HasCustomFormatValue); -static_assert(TFormatTraits<THashSet<int>>::HasCustomFormatValue); -static_assert(TFormatTraits<THashMap<int, int>>::HasCustomFormatValue); -static_assert(TFormatTraits<THashMultiSet<int>>::HasCustomFormatValue); -static_assert(TFormatTraits<std::pair<int, int>>::HasCustomFormatValue); -static_assert(TFormatTraits<std::optional<int>>::HasCustomFormatValue); -static_assert(TFormatTraits<TDuration>::HasCustomFormatValue); -static_assert(TFormatTraits<TInstant>::HasCustomFormatValue); - -struct TUnformattable -{ }; -static_assert(!TFormatTraits<TUnformattable>::HasCustomFormatValue); - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TFormatTest, Nothing) -{ - EXPECT_EQ("abc", Format("a%nb%nc", 1, 2)); -} - -TEST(TFormatTest, Verbatim) -{ - EXPECT_EQ("", Format("")); - EXPECT_EQ("test", Format("test")); - EXPECT_EQ("%", Format("%%")); - EXPECT_EQ("%hello%world%", Format("%%hello%%world%%")); -} - -TEST(TFormatTest, MultipleArgs) -{ - EXPECT_EQ("2+2=4", Format("%v+%v=%v", 2, 2, 4)); -} - -TEST(TFormatTest, Strings) -{ - EXPECT_EQ("test", Format("%s", "test")); - EXPECT_EQ("test", Format("%s", TStringBuf("test"))); - EXPECT_EQ("test", Format("%s", TString("test"))); - - EXPECT_EQ(" abc", Format("%6s", TString("abc"))); - EXPECT_EQ("abc ", Format("%-6s", TString("abc"))); - EXPECT_EQ(" abc", Format("%10v", TString("abc"))); - EXPECT_EQ("abc ", Format("%-10v", TString("abc"))); - EXPECT_EQ("abc", Format("%2s", TString("abc"))); - EXPECT_EQ("abc", Format("%-2s", TString("abc"))); - EXPECT_EQ("abc", Format("%0s", TString("abc"))); - EXPECT_EQ("abc", Format("%-0s", TString("abc"))); +static_assert(TFormatTraits<std::set<int>>::HasCustomFormatValue); +static_assert(TFormatTraits<std::map<int, int>>::HasCustomFormatValue); +static_assert(TFormatTraits<std::multimap<int, int>>::HasCustomFormatValue); +static_assert(TFormatTraits<THashSet<int>>::HasCustomFormatValue); +static_assert(TFormatTraits<THashMap<int, int>>::HasCustomFormatValue); +static_assert(TFormatTraits<THashMultiSet<int>>::HasCustomFormatValue); +static_assert(TFormatTraits<std::pair<int, int>>::HasCustomFormatValue); +static_assert(TFormatTraits<std::optional<int>>::HasCustomFormatValue); +static_assert(TFormatTraits<TDuration>::HasCustomFormatValue); +static_assert(TFormatTraits<TInstant>::HasCustomFormatValue); + +struct TUnformattable +{ }; +static_assert(!TFormatTraits<TUnformattable>::HasCustomFormatValue); + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TFormatTest, Nothing) +{ + EXPECT_EQ("abc", Format("a%nb%nc", 1, 2)); +} + +TEST(TFormatTest, Verbatim) +{ + EXPECT_EQ("", Format("")); + EXPECT_EQ("test", Format("test")); + EXPECT_EQ("%", Format("%%")); + EXPECT_EQ("%hello%world%", Format("%%hello%%world%%")); +} + +TEST(TFormatTest, MultipleArgs) +{ + EXPECT_EQ("2+2=4", Format("%v+%v=%v", 2, 2, 4)); +} + +TEST(TFormatTest, Strings) +{ + EXPECT_EQ("test", Format("%s", "test")); + EXPECT_EQ("test", Format("%s", TStringBuf("test"))); + EXPECT_EQ("test", Format("%s", TString("test"))); + + EXPECT_EQ(" abc", Format("%6s", TString("abc"))); + EXPECT_EQ("abc ", Format("%-6s", TString("abc"))); + EXPECT_EQ(" abc", Format("%10v", TString("abc"))); + EXPECT_EQ("abc ", Format("%-10v", TString("abc"))); + EXPECT_EQ("abc", Format("%2s", TString("abc"))); + EXPECT_EQ("abc", Format("%-2s", TString("abc"))); + EXPECT_EQ("abc", Format("%0s", TString("abc"))); + EXPECT_EQ("abc", Format("%-0s", TString("abc"))); EXPECT_EQ(100, std::ssize(Format("%100v", "abc"))); -} - -TEST(TFormatTest, Integers) -{ - EXPECT_EQ("123", Format("%d", 123)); - EXPECT_EQ("123", Format("%v", 123)); - +} + +TEST(TFormatTest, Integers) +{ + EXPECT_EQ("123", Format("%d", 123)); + EXPECT_EQ("123", Format("%v", 123)); + EXPECT_EQ("042", Format("%03d", 42)); EXPECT_EQ("42", Format("%01d", 42)); - EXPECT_EQ("2147483647", Format("%d", std::numeric_limits<i32>::max())); - EXPECT_EQ("-2147483648", Format("%d", std::numeric_limits<i32>::min())); - - EXPECT_EQ("0", Format("%u", 0U)); - EXPECT_EQ("0", Format("%v", 0U)); - EXPECT_EQ("4294967295", Format("%u", std::numeric_limits<ui32>::max())); - EXPECT_EQ("4294967295", Format("%v", std::numeric_limits<ui32>::max())); - - EXPECT_EQ("9223372036854775807", Format("%" PRId64, std::numeric_limits<i64>::max())); - EXPECT_EQ("9223372036854775807", Format("%v", std::numeric_limits<i64>::max())); - EXPECT_EQ("-9223372036854775808", Format("%" PRId64, std::numeric_limits<i64>::min())); - EXPECT_EQ("-9223372036854775808", Format("%v", std::numeric_limits<i64>::min())); - - EXPECT_EQ("0", Format("%" PRIu64, 0ULL)); - EXPECT_EQ("0", Format("%v", 0ULL)); - EXPECT_EQ("18446744073709551615", Format("%" PRIu64, std::numeric_limits<ui64>::max())); - EXPECT_EQ("18446744073709551615", Format("%v", std::numeric_limits<ui64>::max())); -} - -TEST(TFormatTest, Floats) -{ - EXPECT_EQ("3.14", Format("%.2f", 3.1415F)); - EXPECT_EQ("3.14", Format("%.2v", 3.1415F)); - EXPECT_EQ("3.14", Format("%.2lf", 3.1415)); - EXPECT_EQ("3.14", Format("%.2v", 3.1415)); - EXPECT_EQ(TString(std::to_string(std::numeric_limits<double>::max())), - Format("%lF", std::numeric_limits<double>::max())); -} - -TEST(TFormatTest, Bool) -{ - EXPECT_EQ("True", Format("%v", true)); - EXPECT_EQ("False", Format("%v", false)); - EXPECT_EQ("true", Format("%lv", true)); - EXPECT_EQ("false", Format("%lv", false)); -} - -TEST(TFormatTest, Quotes) -{ - EXPECT_EQ("\"True\"", Format("%Qv", true)); - EXPECT_EQ("'False'", Format("%qv", false)); - EXPECT_EQ("'\\\'\"'", Format("%qv", "\'\"")); - EXPECT_EQ("\"\\x01\"", Format("%Qv", "\x1")); - EXPECT_EQ("'\\x1b'", Format("%qv", '\x1b')); -} - -TEST(TFormatTest, Nullable) -{ - EXPECT_EQ("1", Format("%v", std::make_optional<int>(1))); - EXPECT_EQ("<null>", Format("%v", std::nullopt)); - EXPECT_EQ("<null>", Format("%v", std::optional<int>())); - EXPECT_EQ("3.14", Format("%.2f", std::optional<double>(3.1415))); -} - -TEST(TFormatTest, Pointers) -{ - // No idea if pointer format is standardized, check against Sprintf. - auto p = reinterpret_cast<void*>(123); - EXPECT_EQ(Sprintf("%p", reinterpret_cast<void*>(123)), Format("%p", p)); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT + EXPECT_EQ("2147483647", Format("%d", std::numeric_limits<i32>::max())); + EXPECT_EQ("-2147483648", Format("%d", std::numeric_limits<i32>::min())); + + EXPECT_EQ("0", Format("%u", 0U)); + EXPECT_EQ("0", Format("%v", 0U)); + EXPECT_EQ("4294967295", Format("%u", std::numeric_limits<ui32>::max())); + EXPECT_EQ("4294967295", Format("%v", std::numeric_limits<ui32>::max())); + + EXPECT_EQ("9223372036854775807", Format("%" PRId64, std::numeric_limits<i64>::max())); + EXPECT_EQ("9223372036854775807", Format("%v", std::numeric_limits<i64>::max())); + EXPECT_EQ("-9223372036854775808", Format("%" PRId64, std::numeric_limits<i64>::min())); + EXPECT_EQ("-9223372036854775808", Format("%v", std::numeric_limits<i64>::min())); + + EXPECT_EQ("0", Format("%" PRIu64, 0ULL)); + EXPECT_EQ("0", Format("%v", 0ULL)); + EXPECT_EQ("18446744073709551615", Format("%" PRIu64, std::numeric_limits<ui64>::max())); + EXPECT_EQ("18446744073709551615", Format("%v", std::numeric_limits<ui64>::max())); +} + +TEST(TFormatTest, Floats) +{ + EXPECT_EQ("3.14", Format("%.2f", 3.1415F)); + EXPECT_EQ("3.14", Format("%.2v", 3.1415F)); + EXPECT_EQ("3.14", Format("%.2lf", 3.1415)); + EXPECT_EQ("3.14", Format("%.2v", 3.1415)); + EXPECT_EQ(TString(std::to_string(std::numeric_limits<double>::max())), + Format("%lF", std::numeric_limits<double>::max())); +} + +TEST(TFormatTest, Bool) +{ + EXPECT_EQ("True", Format("%v", true)); + EXPECT_EQ("False", Format("%v", false)); + EXPECT_EQ("true", Format("%lv", true)); + EXPECT_EQ("false", Format("%lv", false)); +} + +TEST(TFormatTest, Quotes) +{ + EXPECT_EQ("\"True\"", Format("%Qv", true)); + EXPECT_EQ("'False'", Format("%qv", false)); + EXPECT_EQ("'\\\'\"'", Format("%qv", "\'\"")); + EXPECT_EQ("\"\\x01\"", Format("%Qv", "\x1")); + EXPECT_EQ("'\\x1b'", Format("%qv", '\x1b')); +} + +TEST(TFormatTest, Nullable) +{ + EXPECT_EQ("1", Format("%v", std::make_optional<int>(1))); + EXPECT_EQ("<null>", Format("%v", std::nullopt)); + EXPECT_EQ("<null>", Format("%v", std::optional<int>())); + EXPECT_EQ("3.14", Format("%.2f", std::optional<double>(3.1415))); +} + +TEST(TFormatTest, Pointers) +{ + // No idea if pointer format is standardized, check against Sprintf. + auto p = reinterpret_cast<void*>(123); + EXPECT_EQ(Sprintf("%p", reinterpret_cast<void*>(123)), Format("%p", p)); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/string/unittests/guid_ut.cpp b/library/cpp/yt/string/unittests/guid_ut.cpp index 4b5eebea16..b63c45d322 100644 --- a/library/cpp/yt/string/unittests/guid_ut.cpp +++ b/library/cpp/yt/string/unittests/guid_ut.cpp @@ -1,49 +1,49 @@ #include <library/cpp/testing/gtest/gtest.h> - + #include <library/cpp/yt/string/guid.h> #include <library/cpp/yt/string/format.h> - + #include <util/string/hex.h> -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + static_assert(TFormatTraits<TGuid>::HasCustomFormatValue); - -TString CanonicalToString(TGuid value) -{ - return Sprintf("%x-%x-%x-%x", - value.Parts32[3], - value.Parts32[2], - value.Parts32[1], - value.Parts32[0]); -} - + +TString CanonicalToString(TGuid value) +{ + return Sprintf("%x-%x-%x-%x", + value.Parts32[3], + value.Parts32[2], + value.Parts32[1], + value.Parts32[0]); +} + const ui32 TrickyValues[] = { 0, 0x1, 0x12, 0x123, 0x1234, 0x12345, 0x123456, 0x1234567, 0x12345678 }; -TEST(TGuidTest, FormatAllTricky) -{ - for (ui32 a : TrickyValues) { - for (ui32 b : TrickyValues) { - for (ui32 c : TrickyValues) { - for (ui32 d : TrickyValues) { - auto value = TGuid(a, b, c, d); - EXPECT_EQ(CanonicalToString(value), ToString(value)); - } - } - } - } -} - -TEST(TGuidTest, FormatAllSymbols) -{ - const auto Value = TGuid::FromString("12345678-abcdef01-12345678-abcdef01"); - EXPECT_EQ(CanonicalToString(Value), ToString(Value)); -} +TEST(TGuidTest, FormatAllTricky) +{ + for (ui32 a : TrickyValues) { + for (ui32 b : TrickyValues) { + for (ui32 c : TrickyValues) { + for (ui32 d : TrickyValues) { + auto value = TGuid(a, b, c, d); + EXPECT_EQ(CanonicalToString(value), ToString(value)); + } + } + } + } +} + +TEST(TGuidTest, FormatAllSymbols) +{ + const auto Value = TGuid::FromString("12345678-abcdef01-12345678-abcdef01"); + EXPECT_EQ(CanonicalToString(Value), ToString(Value)); +} TEST(TGuidTest, ByteOrder) { @@ -52,7 +52,7 @@ TEST(TGuidTest, ByteOrder) EXPECT_EQ(HexEncode(bytes), "01EFCDAB7856341201EFCDAB78563412"); } -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/string/unittests/string_ut.cpp b/library/cpp/yt/string/unittests/string_ut.cpp index 3e12312af0..758c804b8a 100644 --- a/library/cpp/yt/string/unittests/string_ut.cpp +++ b/library/cpp/yt/string/unittests/string_ut.cpp @@ -1,52 +1,52 @@ #include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/yt/string/string.h> - -namespace NYT { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -struct TTestCase -{ - const char* UnderCase; - const char* CamelCase; -}; - -static std::vector<TTestCase> TestCases { - { "kenny", "Kenny" }, - { "south_park", "SouthPark" }, - { "a", "A" }, - { "a_b_c", "ABC" }, - { "reed_solomon_6_3", "ReedSolomon_6_3" }, - { "lrc_12_2_2", "Lrc_12_2_2" }, - { "0", "0" }, - { "0_1_2", "0_1_2" }, - { "int64", "Int64" } -}; - -//////////////////////////////////////////////////////////////////////////////// - -TEST(TStringTest, UnderscoreCaseToCamelCase) -{ - for (const auto& testCase : TestCases) { - auto result = UnderscoreCaseToCamelCase(testCase.UnderCase); - EXPECT_STREQ(testCase.CamelCase, result.c_str()) - << "Original: \"" << testCase.UnderCase << '"'; - } -} - -TEST(TStringTest, CamelCaseToUnderscoreCase) -{ - for (const auto& testCase : TestCases) { - auto result = CamelCaseToUnderscoreCase(testCase.CamelCase); - EXPECT_STREQ(testCase.UnderCase, result.c_str()) - << "Original: \"" << testCase.CamelCase << '"'; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT - + +#include <library/cpp/yt/string/string.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +struct TTestCase +{ + const char* UnderCase; + const char* CamelCase; +}; + +static std::vector<TTestCase> TestCases { + { "kenny", "Kenny" }, + { "south_park", "SouthPark" }, + { "a", "A" }, + { "a_b_c", "ABC" }, + { "reed_solomon_6_3", "ReedSolomon_6_3" }, + { "lrc_12_2_2", "Lrc_12_2_2" }, + { "0", "0" }, + { "0_1_2", "0_1_2" }, + { "int64", "Int64" } +}; + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TStringTest, UnderscoreCaseToCamelCase) +{ + for (const auto& testCase : TestCases) { + auto result = UnderscoreCaseToCamelCase(testCase.UnderCase); + EXPECT_STREQ(testCase.CamelCase, result.c_str()) + << "Original: \"" << testCase.UnderCase << '"'; + } +} + +TEST(TStringTest, CamelCaseToUnderscoreCase) +{ + for (const auto& testCase : TestCases) { + auto result = CamelCaseToUnderscoreCase(testCase.CamelCase); + EXPECT_STREQ(testCase.UnderCase, result.c_str()) + << "Original: \"" << testCase.CamelCase << '"'; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT + diff --git a/library/cpp/yt/string/unittests/ya.make b/library/cpp/yt/string/unittests/ya.make index 9d539758d1..51c85eea4c 100644 --- a/library/cpp/yt/string/unittests/ya.make +++ b/library/cpp/yt/string/unittests/ya.make @@ -10,7 +10,7 @@ SRCS( ) PEERDIR( - library/cpp/yt/string + library/cpp/yt/string library/cpp/testing/gtest ) diff --git a/library/cpp/yt/string/ya.make b/library/cpp/yt/string/ya.make index 83efd5eb2f..b1fc93929e 100644 --- a/library/cpp/yt/string/ya.make +++ b/library/cpp/yt/string/ya.make @@ -7,8 +7,8 @@ SRCS( ) PEERDIR( - library/cpp/yt/assert - library/cpp/yt/exception + library/cpp/yt/assert + library/cpp/yt/exception library/cpp/yt/misc ) @@ -18,9 +18,9 @@ CHECK_DEPENDENT_DIRS( contrib library util - library/cpp/yt/assert + library/cpp/yt/assert library/cpp/yt/misc - library/cpp/yt/small_containers + library/cpp/yt/small_containers ) END() diff --git a/library/cpp/yt/ya.make b/library/cpp/yt/ya.make index f4d43806f4..64083ccd17 100644 --- a/library/cpp/yt/ya.make +++ b/library/cpp/yt/ya.make @@ -1,24 +1,24 @@ RECURSE( assert - coding - exception + coding + exception misc string - system + system yson yson_string ) -IF (NOT OS_WINDOWS) - RECURSE( - containers - cpu_clock - logging - malloc - memory - mlock - phdr_cache - small_containers - threading - ) +IF (NOT OS_WINDOWS) + RECURSE( + containers + cpu_clock + logging + malloc + memory + mlock + phdr_cache + small_containers + threading + ) ENDIF() diff --git a/library/cpp/yt/yson/consumer.cpp b/library/cpp/yt/yson/consumer.cpp index 9b68ee8a22..90438e541e 100644 --- a/library/cpp/yt/yson/consumer.cpp +++ b/library/cpp/yt/yson/consumer.cpp @@ -6,8 +6,8 @@ namespace NYT::NYson { //////////////////////////////////////////////////////////////////////////////// -void IYsonConsumer::OnRaw(const TYsonStringBuf& yson) -{ +void IYsonConsumer::OnRaw(const TYsonStringBuf& yson) +{ OnRaw(yson.AsStringBuf(), yson.GetType()); } diff --git a/library/cpp/yt/yson/consumer.h b/library/cpp/yt/yson/consumer.h index ea5f586b91..7c3b7b0663 100644 --- a/library/cpp/yt/yson/consumer.h +++ b/library/cpp/yt/yson/consumer.h @@ -1,19 +1,19 @@ #pragma once #include <util/generic/strbuf.h> - + #include <util/system/defaults.h> #include <library/cpp/yt/yson_string/public.h> namespace NYT::NYson { - + //////////////////////////////////////////////////////////////////////////////// //! A SAX-like interface for parsing a YSON stream. -struct IYsonConsumer -{ - virtual ~IYsonConsumer() = default; +struct IYsonConsumer +{ + virtual ~IYsonConsumer() = default; //! The current item is a string scalar (IStringNode). /*! diff --git a/library/cpp/yt/yson_string/convert.cpp b/library/cpp/yt/yson_string/convert.cpp index 27f5c30d01..d49d5d07bc 100644 --- a/library/cpp/yt/yson_string/convert.cpp +++ b/library/cpp/yt/yson_string/convert.cpp @@ -1,381 +1,381 @@ -#include "convert.h" -#include "format.h" - -#include <library/cpp/yt/assert/assert.h> - -#include <library/cpp/yt/string/format.h> - -#include <library/cpp/yt/coding/varint.h> - -#include <library/cpp/yt/misc/cast.h> - -#include <array> - -#include <util/stream/mem.h> - -namespace NYT::NYson { - -//////////////////////////////////////////////////////////////////////////////// - -template <> -TYsonString ConvertToYsonString<i8>(const i8& value) -{ - return ConvertToYsonString(static_cast<i64>(value)); -} - -template <> -TYsonString ConvertToYsonString<i32>(const i32& value) -{ - return ConvertToYsonString(static_cast<i64>(value)); -} - -template <> -TYsonString ConvertToYsonString<i64>(const i64& value) -{ - std::array<char, 1 + MaxVarInt64Size> buffer; - auto* ptr = buffer.data(); - *ptr++ = NDetail::Int64Marker; - ptr += WriteVarInt64(ptr, value); - return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); -} - -template <> -TYsonString ConvertToYsonString<ui8>(const ui8& value) -{ - return ConvertToYsonString(static_cast<ui64>(value)); -} - -template <> -TYsonString ConvertToYsonString<ui32>(const ui32& value) -{ - return ConvertToYsonString(static_cast<ui64>(value)); -} - -template <> -TYsonString ConvertToYsonString<ui64>(const ui64& value) -{ - std::array<char, 1 + MaxVarInt64Size> buffer; - auto* ptr = buffer.data(); - *ptr++ = NDetail::Uint64Marker; - ptr += WriteVarUint64(ptr, value); - return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); -} - -template <> -TYsonString ConvertToYsonString<TString>(const TString& value) -{ - return ConvertToYsonString(static_cast<TStringBuf>(value)); -} - -struct TConvertStringToYsonStringTag -{ }; - -template <> -TYsonString ConvertToYsonString<TStringBuf>(const TStringBuf& value) -{ - auto buffer = TSharedMutableRef::Allocate<TConvertStringToYsonStringTag>( - 1 + MaxVarInt64Size + value.length(), - /*initializeStorage*/ false); - auto* ptr = buffer.Begin(); - *ptr++ = NDetail::StringMarker; - ptr += WriteVarInt64(ptr, static_cast<i64>(value.length())); - ::memcpy(ptr, value.data(), value.length()); - ptr += value.length(); - return TYsonString(buffer.Slice(buffer.Begin(), ptr)); -} - -TYsonString ConvertToYsonString(const char* value) -{ - return ConvertToYsonString(TStringBuf(value)); -} - -template <> -TYsonString ConvertToYsonString<float>(const float& value) -{ - return ConvertToYsonString(static_cast<double>(value)); -} - -template <> -TYsonString ConvertToYsonString<double>(const double& value) -{ - std::array<char, 1 + sizeof(double)> buffer; - auto* ptr = buffer.data(); - *ptr++ = NDetail::DoubleMarker; - ::memcpy(ptr, &value, sizeof(value)); - ptr += sizeof(value); - return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); -} - -template <> -TYsonString ConvertToYsonString<bool>(const bool& value) -{ - char ch = value ? NDetail::TrueMarker : NDetail::FalseMarker; - return TYsonString(TStringBuf(&ch, 1)); -} - -template <> -TYsonString ConvertToYsonString<TInstant>(const TInstant& value) -{ - return ConvertToYsonString(value.ToString()); -} - -template <> -TYsonString ConvertToYsonString<TDuration>(const TDuration& value) -{ - return ConvertToYsonString(value.MilliSeconds()); -} - -template <> -TYsonString ConvertToYsonString<TGuid>(const TGuid& value) -{ - std::array<char, MaxGuidStringSize> guidBuffer; - auto guidLength = WriteGuidToBuffer(guidBuffer.data(), value) - guidBuffer.data(); - std::array<char, 1 + MaxVarInt64Size + MaxGuidStringSize> ysonBuffer; - auto* ptr = ysonBuffer.data(); - *ptr++ = NDetail::StringMarker; - ptr += WriteVarInt64(ptr, static_cast<i64>(guidLength)); - ::memcpy(ptr, guidBuffer.data(), guidLength); - ptr += guidLength; - return TYsonString(TStringBuf(ysonBuffer.data(), ptr - ysonBuffer.data())); -} - -//////////////////////////////////////////////////////////////////////////////// - -namespace { - -TString FormatUnexpectedMarker(char ch) -{ - switch (ch) { - case NDetail::BeginListSymbol: - return "list"; - case NDetail::BeginMapSymbol: - return "map"; - case NDetail::BeginAttributesSymbol: - return "attributes"; - case NDetail::EntitySymbol: - return "\"entity\" literal"; - case NDetail::StringMarker: - return "\"string\" literal"; - case NDetail::Int64Marker: - return "\"int64\" literal"; - case NDetail::DoubleMarker: - return "\"double\" literal"; - case NDetail::FalseMarker: - case NDetail::TrueMarker: - return "\"boolean\" literal"; - case NDetail::Uint64Marker: - return "\"uint64\" literal"; - default: - return Format("unexpected symbol %qv", ch); - } -} - -i64 ParseInt64FromYsonString(const TYsonStringBuf& str) -{ - YT_ASSERT(str.GetType() == EYsonType::Node); - auto strBuf = str.AsStringBuf(); - TMemoryInput input(strBuf.data(), strBuf.length()); - char ch; - if (!input.ReadChar(ch)) { - throw TYsonLiteralParseException("Missing type marker"); - } - if (ch != NDetail::Int64Marker) { - throw TYsonLiteralParseException(Format("Unexpected %v", - FormatUnexpectedMarker(ch))); - } - i64 result; - try { - ReadVarInt64(&input, &result); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Failed to decode \"int64\" value"); - } - return result; -} - -ui64 ParseUint64FromYsonString(const TYsonStringBuf& str) -{ - YT_ASSERT(str.GetType() == EYsonType::Node); - auto strBuf = str.AsStringBuf(); - TMemoryInput input(strBuf.data(), strBuf.length()); - char ch; - if (!input.ReadChar(ch)) { - throw TYsonLiteralParseException("Missing type marker"); - } - if (ch != NDetail::Uint64Marker) { - throw TYsonLiteralParseException(Format("Unexpected %v", - FormatUnexpectedMarker(ch))); - } - ui64 result; - try { - ReadVarUint64(&input, &result); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Failed to decode \"uint64\" value"); - } - return result; -} - -TString ParseStringFromYsonString(const TYsonStringBuf& str) -{ - YT_ASSERT(str.GetType() == EYsonType::Node); - auto strBuf = str.AsStringBuf(); - TMemoryInput input(strBuf.data(), strBuf.length()); - char ch; - if (!input.ReadChar(ch)) { - throw TYsonLiteralParseException("Missing type marker"); - } - if (ch != NDetail::StringMarker) { - throw TYsonLiteralParseException(Format("Unexpected %v", - FormatUnexpectedMarker(ch))); - } - i64 length; - try { - ReadVarInt64(&input, &length); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Failed to decode string length"); - } - if (length < 0) { - throw TYsonLiteralParseException(Format("Negative string length ", - length)); - } - if (static_cast<i64>(input.Avail()) != length) { - throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v", - length, - input.Avail())); - } - TString result; - result.ReserveAndResize(length); - YT_VERIFY(static_cast<i64>(input.Read(result.Detach(), length)) == length); - return result; -} - -double ParseDoubleFromYsonString(const TYsonStringBuf& str) -{ - YT_ASSERT(str.GetType() == EYsonType::Node); - auto strBuf = str.AsStringBuf(); - TMemoryInput input(strBuf.data(), strBuf.length()); - char ch; - if (!input.ReadChar(ch)) { - throw TYsonLiteralParseException("Missing type marker"); - } - if (ch != NDetail::DoubleMarker) { - throw TYsonLiteralParseException(Format("Unexpected %v", - FormatUnexpectedMarker(ch))); - } - if (input.Avail() != sizeof(double)) { - throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v", - sizeof(double), - input.Avail())); - } - double result; - YT_VERIFY(input.Read(&result, sizeof(result))); - return result; -} - -} // namespace - -#define PARSE(type, underlyingType) \ - template <> \ - type ConvertFromYsonString<type>(const TYsonStringBuf& str) \ - { \ - try { \ - return CheckedIntegralCast<type>(Parse ## underlyingType ## FromYsonString(str)); \ - } catch (const std::exception& ex) { \ - throw TYsonLiteralParseException(ex, "Error parsing \"" #type "\" value from YSON"); \ - } \ - } - -PARSE(i8, Int64 ) -PARSE(i16, Int64 ) -PARSE(i32, Int64 ) -PARSE(i64, Int64 ) -PARSE(ui8, Uint64) -PARSE(ui16, Uint64) -PARSE(ui32, Uint64) -PARSE(ui64, Uint64) - -#undef PARSE - -template <> -TString ConvertFromYsonString<TString>(const TYsonStringBuf& str) -{ - try { - return ParseStringFromYsonString(str); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Error parsing \"string\" value from YSON"); - } -} - -template <> -float ConvertFromYsonString<float>(const TYsonStringBuf& str) -{ - try { - return static_cast<float>(ParseDoubleFromYsonString(str)); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Error parsing \"float\" value from YSON"); - } -} - -template <> -double ConvertFromYsonString<double>(const TYsonStringBuf& str) -{ - try { - return ParseDoubleFromYsonString(str); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Error parsing \"double\" value from YSON"); - } -} - -template <> -bool ConvertFromYsonString<bool>(const TYsonStringBuf& str) -{ - try { - YT_ASSERT(str.GetType() == EYsonType::Node); - auto strBuf = str.AsStringBuf(); - TMemoryInput input(strBuf.data(), strBuf.length()); - char ch; - if (!input.ReadChar(ch)) { - throw TYsonLiteralParseException("Missing type marker"); - } - if (ch != NDetail::TrueMarker && ch != NDetail::FalseMarker) { - throw TYsonLiteralParseException(Format("Unexpected %v", - FormatUnexpectedMarker(ch))); - } - return ch == NDetail::TrueMarker; - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Error parsing \"boolean\" value from YSON"); - } -} - -template <> -TInstant ConvertFromYsonString<TInstant>(const TYsonStringBuf& str) -{ - try { - return TInstant::ParseIso8601(ParseStringFromYsonString(str)); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Error parsing \"instant\" value from YSON"); - } -} - -template <> -TDuration ConvertFromYsonString<TDuration>(const TYsonStringBuf& str) -{ - try { - return TDuration::MilliSeconds(ParseUint64FromYsonString(str)); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Error parsing \"duration\" value from YSON"); - } -} - -template <> -TGuid ConvertFromYsonString<TGuid>(const TYsonStringBuf& str) -{ - try { - return TGuid::FromString(ParseStringFromYsonString(str)); - } catch (const std::exception& ex) { - throw TYsonLiteralParseException(ex, "Error parsing \"guid\" value from YSON"); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYson +#include "convert.h" +#include "format.h" + +#include <library/cpp/yt/assert/assert.h> + +#include <library/cpp/yt/string/format.h> + +#include <library/cpp/yt/coding/varint.h> + +#include <library/cpp/yt/misc/cast.h> + +#include <array> + +#include <util/stream/mem.h> + +namespace NYT::NYson { + +//////////////////////////////////////////////////////////////////////////////// + +template <> +TYsonString ConvertToYsonString<i8>(const i8& value) +{ + return ConvertToYsonString(static_cast<i64>(value)); +} + +template <> +TYsonString ConvertToYsonString<i32>(const i32& value) +{ + return ConvertToYsonString(static_cast<i64>(value)); +} + +template <> +TYsonString ConvertToYsonString<i64>(const i64& value) +{ + std::array<char, 1 + MaxVarInt64Size> buffer; + auto* ptr = buffer.data(); + *ptr++ = NDetail::Int64Marker; + ptr += WriteVarInt64(ptr, value); + return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); +} + +template <> +TYsonString ConvertToYsonString<ui8>(const ui8& value) +{ + return ConvertToYsonString(static_cast<ui64>(value)); +} + +template <> +TYsonString ConvertToYsonString<ui32>(const ui32& value) +{ + return ConvertToYsonString(static_cast<ui64>(value)); +} + +template <> +TYsonString ConvertToYsonString<ui64>(const ui64& value) +{ + std::array<char, 1 + MaxVarInt64Size> buffer; + auto* ptr = buffer.data(); + *ptr++ = NDetail::Uint64Marker; + ptr += WriteVarUint64(ptr, value); + return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); +} + +template <> +TYsonString ConvertToYsonString<TString>(const TString& value) +{ + return ConvertToYsonString(static_cast<TStringBuf>(value)); +} + +struct TConvertStringToYsonStringTag +{ }; + +template <> +TYsonString ConvertToYsonString<TStringBuf>(const TStringBuf& value) +{ + auto buffer = TSharedMutableRef::Allocate<TConvertStringToYsonStringTag>( + 1 + MaxVarInt64Size + value.length(), + /*initializeStorage*/ false); + auto* ptr = buffer.Begin(); + *ptr++ = NDetail::StringMarker; + ptr += WriteVarInt64(ptr, static_cast<i64>(value.length())); + ::memcpy(ptr, value.data(), value.length()); + ptr += value.length(); + return TYsonString(buffer.Slice(buffer.Begin(), ptr)); +} + +TYsonString ConvertToYsonString(const char* value) +{ + return ConvertToYsonString(TStringBuf(value)); +} + +template <> +TYsonString ConvertToYsonString<float>(const float& value) +{ + return ConvertToYsonString(static_cast<double>(value)); +} + +template <> +TYsonString ConvertToYsonString<double>(const double& value) +{ + std::array<char, 1 + sizeof(double)> buffer; + auto* ptr = buffer.data(); + *ptr++ = NDetail::DoubleMarker; + ::memcpy(ptr, &value, sizeof(value)); + ptr += sizeof(value); + return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); +} + +template <> +TYsonString ConvertToYsonString<bool>(const bool& value) +{ + char ch = value ? NDetail::TrueMarker : NDetail::FalseMarker; + return TYsonString(TStringBuf(&ch, 1)); +} + +template <> +TYsonString ConvertToYsonString<TInstant>(const TInstant& value) +{ + return ConvertToYsonString(value.ToString()); +} + +template <> +TYsonString ConvertToYsonString<TDuration>(const TDuration& value) +{ + return ConvertToYsonString(value.MilliSeconds()); +} + +template <> +TYsonString ConvertToYsonString<TGuid>(const TGuid& value) +{ + std::array<char, MaxGuidStringSize> guidBuffer; + auto guidLength = WriteGuidToBuffer(guidBuffer.data(), value) - guidBuffer.data(); + std::array<char, 1 + MaxVarInt64Size + MaxGuidStringSize> ysonBuffer; + auto* ptr = ysonBuffer.data(); + *ptr++ = NDetail::StringMarker; + ptr += WriteVarInt64(ptr, static_cast<i64>(guidLength)); + ::memcpy(ptr, guidBuffer.data(), guidLength); + ptr += guidLength; + return TYsonString(TStringBuf(ysonBuffer.data(), ptr - ysonBuffer.data())); +} + +//////////////////////////////////////////////////////////////////////////////// + +namespace { + +TString FormatUnexpectedMarker(char ch) +{ + switch (ch) { + case NDetail::BeginListSymbol: + return "list"; + case NDetail::BeginMapSymbol: + return "map"; + case NDetail::BeginAttributesSymbol: + return "attributes"; + case NDetail::EntitySymbol: + return "\"entity\" literal"; + case NDetail::StringMarker: + return "\"string\" literal"; + case NDetail::Int64Marker: + return "\"int64\" literal"; + case NDetail::DoubleMarker: + return "\"double\" literal"; + case NDetail::FalseMarker: + case NDetail::TrueMarker: + return "\"boolean\" literal"; + case NDetail::Uint64Marker: + return "\"uint64\" literal"; + default: + return Format("unexpected symbol %qv", ch); + } +} + +i64 ParseInt64FromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::Int64Marker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + i64 result; + try { + ReadVarInt64(&input, &result); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Failed to decode \"int64\" value"); + } + return result; +} + +ui64 ParseUint64FromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::Uint64Marker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + ui64 result; + try { + ReadVarUint64(&input, &result); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Failed to decode \"uint64\" value"); + } + return result; +} + +TString ParseStringFromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::StringMarker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + i64 length; + try { + ReadVarInt64(&input, &length); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Failed to decode string length"); + } + if (length < 0) { + throw TYsonLiteralParseException(Format("Negative string length ", + length)); + } + if (static_cast<i64>(input.Avail()) != length) { + throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v", + length, + input.Avail())); + } + TString result; + result.ReserveAndResize(length); + YT_VERIFY(static_cast<i64>(input.Read(result.Detach(), length)) == length); + return result; +} + +double ParseDoubleFromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::DoubleMarker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + if (input.Avail() != sizeof(double)) { + throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v", + sizeof(double), + input.Avail())); + } + double result; + YT_VERIFY(input.Read(&result, sizeof(result))); + return result; +} + +} // namespace + +#define PARSE(type, underlyingType) \ + template <> \ + type ConvertFromYsonString<type>(const TYsonStringBuf& str) \ + { \ + try { \ + return CheckedIntegralCast<type>(Parse ## underlyingType ## FromYsonString(str)); \ + } catch (const std::exception& ex) { \ + throw TYsonLiteralParseException(ex, "Error parsing \"" #type "\" value from YSON"); \ + } \ + } + +PARSE(i8, Int64 ) +PARSE(i16, Int64 ) +PARSE(i32, Int64 ) +PARSE(i64, Int64 ) +PARSE(ui8, Uint64) +PARSE(ui16, Uint64) +PARSE(ui32, Uint64) +PARSE(ui64, Uint64) + +#undef PARSE + +template <> +TString ConvertFromYsonString<TString>(const TYsonStringBuf& str) +{ + try { + return ParseStringFromYsonString(str); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"string\" value from YSON"); + } +} + +template <> +float ConvertFromYsonString<float>(const TYsonStringBuf& str) +{ + try { + return static_cast<float>(ParseDoubleFromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"float\" value from YSON"); + } +} + +template <> +double ConvertFromYsonString<double>(const TYsonStringBuf& str) +{ + try { + return ParseDoubleFromYsonString(str); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"double\" value from YSON"); + } +} + +template <> +bool ConvertFromYsonString<bool>(const TYsonStringBuf& str) +{ + try { + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::TrueMarker && ch != NDetail::FalseMarker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + return ch == NDetail::TrueMarker; + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"boolean\" value from YSON"); + } +} + +template <> +TInstant ConvertFromYsonString<TInstant>(const TYsonStringBuf& str) +{ + try { + return TInstant::ParseIso8601(ParseStringFromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"instant\" value from YSON"); + } +} + +template <> +TDuration ConvertFromYsonString<TDuration>(const TYsonStringBuf& str) +{ + try { + return TDuration::MilliSeconds(ParseUint64FromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"duration\" value from YSON"); + } +} + +template <> +TGuid ConvertFromYsonString<TGuid>(const TYsonStringBuf& str) +{ + try { + return TGuid::FromString(ParseStringFromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"guid\" value from YSON"); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson diff --git a/library/cpp/yt/yson_string/convert.h b/library/cpp/yt/yson_string/convert.h index 3c2cc7d284..4bd636b2c6 100644 --- a/library/cpp/yt/yson_string/convert.h +++ b/library/cpp/yt/yson_string/convert.h @@ -1,114 +1,114 @@ -#pragma once - -#include "string.h" - -#include <library/cpp/yt/misc/guid.h> - -#include <library/cpp/yt/exception/exception.h> - -#include <util/generic/string.h> - -#include <util/datetime/base.h> - -namespace NYT::NYson { - -//////////////////////////////////////////////////////////////////////////////// -// Generic forward declarations. - -template <class T> -TYsonString ConvertToYsonString(const T& value); - -template <class T> -TYsonString ConvertToYsonString(const T& value, EYsonFormat format); - -template <class T> -T ConvertFromYsonString(const TYsonStringBuf& str); - -//////////////////////////////////////////////////////////////////////////////// -// Basic specializations for ConvertToYsonString. - -template <> -TYsonString ConvertToYsonString<i8>(const i8& value); -template <> -TYsonString ConvertToYsonString<i32>(const i32& value); -template <> -TYsonString ConvertToYsonString<i64>(const i64& value); - -template <> -TYsonString ConvertToYsonString<ui8>(const ui8& value); -template <> -TYsonString ConvertToYsonString<ui32>(const ui32& value); -template <> -TYsonString ConvertToYsonString<ui64>(const ui64& value); - -template <> -TYsonString ConvertToYsonString<TString>(const TString& value); -template <> -TYsonString ConvertToYsonString<TStringBuf>(const TStringBuf& value); -TYsonString ConvertToYsonString(const char* value); - -template <> -TYsonString ConvertToYsonString<float>(const float& value); -template <> -TYsonString ConvertToYsonString<double>(const double& value); - -template <> -TYsonString ConvertToYsonString<bool>(const bool& value); - -template <> -TYsonString ConvertToYsonString<TInstant>(const TInstant& value); - -template <> -TYsonString ConvertToYsonString<TDuration>(const TDuration& value); - -template <> -TYsonString ConvertToYsonString<TGuid>(const TGuid& value); - -//////////////////////////////////////////////////////////////////////////////// -// Basic specializations for ConvertFromYsonString. -// Note: these currently support a subset of NYT::NYTree::Convert features. - -class TYsonLiteralParseException - : public TCompositeException -{ -public: - using TCompositeException::TCompositeException; -}; - -template <> -i8 ConvertFromYsonString<i8>(const TYsonStringBuf& str); -template <> -i32 ConvertFromYsonString<i32>(const TYsonStringBuf& str); -template <> -i64 ConvertFromYsonString<i64>(const TYsonStringBuf& str); - -template <> -ui8 ConvertFromYsonString<ui8>(const TYsonStringBuf& str); -template <> -ui32 ConvertFromYsonString<ui32>(const TYsonStringBuf& str); -template <> -ui64 ConvertFromYsonString<ui64>(const TYsonStringBuf& str); - -template <> -TString ConvertFromYsonString<TString>(const TYsonStringBuf& str); - -template <> -float ConvertFromYsonString<float>(const TYsonStringBuf& str); -template <> -double ConvertFromYsonString<double>(const TYsonStringBuf& str); - -template <> -bool ConvertFromYsonString<bool>(const TYsonStringBuf& str); - -template <> -TInstant ConvertFromYsonString<TInstant>(const TYsonStringBuf& str); - -template <> -TDuration ConvertFromYsonString<TDuration>(const TYsonStringBuf& str); - -template <> -TGuid ConvertFromYsonString<TGuid>(const TYsonStringBuf& str); - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYson +#pragma once + +#include "string.h" + +#include <library/cpp/yt/misc/guid.h> + +#include <library/cpp/yt/exception/exception.h> + +#include <util/generic/string.h> + +#include <util/datetime/base.h> + +namespace NYT::NYson { + +//////////////////////////////////////////////////////////////////////////////// +// Generic forward declarations. + +template <class T> +TYsonString ConvertToYsonString(const T& value); + +template <class T> +TYsonString ConvertToYsonString(const T& value, EYsonFormat format); + +template <class T> +T ConvertFromYsonString(const TYsonStringBuf& str); + +//////////////////////////////////////////////////////////////////////////////// +// Basic specializations for ConvertToYsonString. + +template <> +TYsonString ConvertToYsonString<i8>(const i8& value); +template <> +TYsonString ConvertToYsonString<i32>(const i32& value); +template <> +TYsonString ConvertToYsonString<i64>(const i64& value); + +template <> +TYsonString ConvertToYsonString<ui8>(const ui8& value); +template <> +TYsonString ConvertToYsonString<ui32>(const ui32& value); +template <> +TYsonString ConvertToYsonString<ui64>(const ui64& value); + +template <> +TYsonString ConvertToYsonString<TString>(const TString& value); +template <> +TYsonString ConvertToYsonString<TStringBuf>(const TStringBuf& value); +TYsonString ConvertToYsonString(const char* value); + +template <> +TYsonString ConvertToYsonString<float>(const float& value); +template <> +TYsonString ConvertToYsonString<double>(const double& value); + +template <> +TYsonString ConvertToYsonString<bool>(const bool& value); + +template <> +TYsonString ConvertToYsonString<TInstant>(const TInstant& value); + +template <> +TYsonString ConvertToYsonString<TDuration>(const TDuration& value); + +template <> +TYsonString ConvertToYsonString<TGuid>(const TGuid& value); + +//////////////////////////////////////////////////////////////////////////////// +// Basic specializations for ConvertFromYsonString. +// Note: these currently support a subset of NYT::NYTree::Convert features. + +class TYsonLiteralParseException + : public TCompositeException +{ +public: + using TCompositeException::TCompositeException; +}; + +template <> +i8 ConvertFromYsonString<i8>(const TYsonStringBuf& str); +template <> +i32 ConvertFromYsonString<i32>(const TYsonStringBuf& str); +template <> +i64 ConvertFromYsonString<i64>(const TYsonStringBuf& str); + +template <> +ui8 ConvertFromYsonString<ui8>(const TYsonStringBuf& str); +template <> +ui32 ConvertFromYsonString<ui32>(const TYsonStringBuf& str); +template <> +ui64 ConvertFromYsonString<ui64>(const TYsonStringBuf& str); + +template <> +TString ConvertFromYsonString<TString>(const TYsonStringBuf& str); + +template <> +float ConvertFromYsonString<float>(const TYsonStringBuf& str); +template <> +double ConvertFromYsonString<double>(const TYsonStringBuf& str); + +template <> +bool ConvertFromYsonString<bool>(const TYsonStringBuf& str); + +template <> +TInstant ConvertFromYsonString<TInstant>(const TYsonStringBuf& str); + +template <> +TDuration ConvertFromYsonString<TDuration>(const TYsonStringBuf& str); + +template <> +TGuid ConvertFromYsonString<TGuid>(const TYsonStringBuf& str); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson diff --git a/library/cpp/yt/yson_string/format.h b/library/cpp/yt/yson_string/format.h index 2efd4fa39a..23f14213d5 100644 --- a/library/cpp/yt/yson_string/format.h +++ b/library/cpp/yt/yson_string/format.h @@ -1,44 +1,44 @@ -#pragma once - -namespace NYT::NYson::NDetail { - -//////////////////////////////////////////////////////////////////////////////// - -//! Indicates the beginning of a list. -constexpr char BeginListSymbol = '['; -//! Indicates the end of a list. -constexpr char EndListSymbol = ']'; - -//! Indicates the beginning of a map. -constexpr char BeginMapSymbol = '{'; -//! Indicates the end of a map. -constexpr char EndMapSymbol = '}'; - -//! Indicates the beginning of an attribute map. -constexpr char BeginAttributesSymbol = '<'; -//! Indicates the end of an attribute map. -constexpr char EndAttributesSymbol = '>'; - -//! Separates items in lists, maps, attributes. -constexpr char ItemSeparatorSymbol = ';'; -//! Separates keys from values in maps. -constexpr char KeyValueSeparatorSymbol = '='; - -//! Indicates an entity. -constexpr char EntitySymbol = '#'; -//! Marks the beginning of a binary string literal. -constexpr char StringMarker = '\x01'; -//! Marks the beginning of a binary i64 literal. -constexpr char Int64Marker = '\x02'; -//! Marks the beginning of a binary double literal. -constexpr char DoubleMarker = '\x03'; -//! Marks |false| boolean value. -constexpr char FalseMarker = '\x04'; -//! Marks |true| boolean value. -constexpr char TrueMarker = '\x05'; -//! Marks the beginning of a binary ui64 literal. -constexpr char Uint64Marker = '\x06'; - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYson::NDetail +#pragma once + +namespace NYT::NYson::NDetail { + +//////////////////////////////////////////////////////////////////////////////// + +//! Indicates the beginning of a list. +constexpr char BeginListSymbol = '['; +//! Indicates the end of a list. +constexpr char EndListSymbol = ']'; + +//! Indicates the beginning of a map. +constexpr char BeginMapSymbol = '{'; +//! Indicates the end of a map. +constexpr char EndMapSymbol = '}'; + +//! Indicates the beginning of an attribute map. +constexpr char BeginAttributesSymbol = '<'; +//! Indicates the end of an attribute map. +constexpr char EndAttributesSymbol = '>'; + +//! Separates items in lists, maps, attributes. +constexpr char ItemSeparatorSymbol = ';'; +//! Separates keys from values in maps. +constexpr char KeyValueSeparatorSymbol = '='; + +//! Indicates an entity. +constexpr char EntitySymbol = '#'; +//! Marks the beginning of a binary string literal. +constexpr char StringMarker = '\x01'; +//! Marks the beginning of a binary i64 literal. +constexpr char Int64Marker = '\x02'; +//! Marks the beginning of a binary double literal. +constexpr char DoubleMarker = '\x03'; +//! Marks |false| boolean value. +constexpr char FalseMarker = '\x04'; +//! Marks |true| boolean value. +constexpr char TrueMarker = '\x05'; +//! Marks the beginning of a binary ui64 literal. +constexpr char Uint64Marker = '\x06'; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson::NDetail diff --git a/library/cpp/yt/yson_string/public.h b/library/cpp/yt/yson_string/public.h index 42c1ce80bb..6e89f54ab2 100644 --- a/library/cpp/yt/yson_string/public.h +++ b/library/cpp/yt/yson_string/public.h @@ -1,39 +1,39 @@ -#pragma once - -#include <library/cpp/yt/misc/enum.h> - -namespace NYT::NYson { - -//////////////////////////////////////////////////////////////////////////////// - -//! The data format. -DEFINE_ENUM(EYsonFormat, - // Binary. - // Most compact but not human-readable. - (Binary) - - // Text. - // Not so compact but human-readable. - // Does not use indentation. - // Uses escaping for non-text characters. - (Text) - - // Text with indentation. - // Extremely verbose but human-readable. - // Uses escaping for non-text characters. - (Pretty) -); - -// NB: -1 is used for serializing null TYsonString. -DEFINE_ENUM_WITH_UNDERLYING_TYPE(EYsonType, i8, - ((Node) (0)) - ((ListFragment) (1)) - ((MapFragment) (2)) -); - -class TYsonString; -class TYsonStringBuf; - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYson +#pragma once + +#include <library/cpp/yt/misc/enum.h> + +namespace NYT::NYson { + +//////////////////////////////////////////////////////////////////////////////// + +//! The data format. +DEFINE_ENUM(EYsonFormat, + // Binary. + // Most compact but not human-readable. + (Binary) + + // Text. + // Not so compact but human-readable. + // Does not use indentation. + // Uses escaping for non-text characters. + (Text) + + // Text with indentation. + // Extremely verbose but human-readable. + // Uses escaping for non-text characters. + (Pretty) +); + +// NB: -1 is used for serializing null TYsonString. +DEFINE_ENUM_WITH_UNDERLYING_TYPE(EYsonType, i8, + ((Node) (0)) + ((ListFragment) (1)) + ((MapFragment) (2)) +); + +class TYsonString; +class TYsonStringBuf; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson diff --git a/library/cpp/yt/yson_string/string-inl.h b/library/cpp/yt/yson_string/string-inl.h index 5c41629cc0..11e8af65a2 100644 --- a/library/cpp/yt/yson_string/string-inl.h +++ b/library/cpp/yt/yson_string/string-inl.h @@ -1,93 +1,93 @@ -#ifndef STRING_INL_H_ -#error "Direct inclusion of this file is not allowed, include string.h" -// For the sake of sane code completion. -#include "string.h" -#endif - -namespace NYT::NYson { - -//////////////////////////////////////////////////////////////////////////////// - -namespace NDetail { - -template <typename TLeft, typename TRight> -bool Equals(const TLeft& lhs, const TRight& rhs) -{ - auto lhsNull = !lhs.operator bool(); - auto rhsNull = !rhs.operator bool(); - if (lhsNull != rhsNull) { - return false; - } - if (lhsNull && rhsNull) { - return true; - } - return - lhs.AsStringBuf() == rhs.AsStringBuf() && - lhs.GetType() == rhs.GetType(); -} - -} // namespace NDetail - -inline bool operator == (const TYsonString& lhs, const TYsonString& rhs) -{ - return NDetail::Equals(lhs, rhs); -} - -inline bool operator == (const TYsonString& lhs, const TYsonStringBuf& rhs) -{ - return NDetail::Equals(lhs, rhs); -} - -inline bool operator == (const TYsonStringBuf& lhs, const TYsonString& rhs) -{ - return NDetail::Equals(lhs, rhs); -} - -inline bool operator == (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs) -{ - return NDetail::Equals(lhs, rhs); -} - -inline bool operator != (const TYsonString& lhs, const TYsonString& rhs) -{ - return !(lhs == rhs); -} - -inline bool operator != (const TYsonString& lhs, const TYsonStringBuf& rhs) -{ - return !(lhs == rhs); -} - -inline bool operator != (const TYsonStringBuf& lhs, const TYsonString& rhs) -{ - return !(lhs == rhs); -} - -inline bool operator != (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs) -{ - return !(lhs == rhs); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYson - -//! A hasher for TYsonString -template <> -struct THash<NYT::NYson::TYsonString> -{ - size_t operator () (const NYT::NYson::TYsonString& str) const - { - return str.ComputeHash(); - } -}; - -//! A hasher for TYsonStringBuf -template <> -struct THash<NYT::NYson::TYsonStringBuf> -{ - size_t operator () (const NYT::NYson::TYsonStringBuf& str) const - { - return THash<TStringBuf>()(str.AsStringBuf()); - } -}; +#ifndef STRING_INL_H_ +#error "Direct inclusion of this file is not allowed, include string.h" +// For the sake of sane code completion. +#include "string.h" +#endif + +namespace NYT::NYson { + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + +template <typename TLeft, typename TRight> +bool Equals(const TLeft& lhs, const TRight& rhs) +{ + auto lhsNull = !lhs.operator bool(); + auto rhsNull = !rhs.operator bool(); + if (lhsNull != rhsNull) { + return false; + } + if (lhsNull && rhsNull) { + return true; + } + return + lhs.AsStringBuf() == rhs.AsStringBuf() && + lhs.GetType() == rhs.GetType(); +} + +} // namespace NDetail + +inline bool operator == (const TYsonString& lhs, const TYsonString& rhs) +{ + return NDetail::Equals(lhs, rhs); +} + +inline bool operator == (const TYsonString& lhs, const TYsonStringBuf& rhs) +{ + return NDetail::Equals(lhs, rhs); +} + +inline bool operator == (const TYsonStringBuf& lhs, const TYsonString& rhs) +{ + return NDetail::Equals(lhs, rhs); +} + +inline bool operator == (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs) +{ + return NDetail::Equals(lhs, rhs); +} + +inline bool operator != (const TYsonString& lhs, const TYsonString& rhs) +{ + return !(lhs == rhs); +} + +inline bool operator != (const TYsonString& lhs, const TYsonStringBuf& rhs) +{ + return !(lhs == rhs); +} + +inline bool operator != (const TYsonStringBuf& lhs, const TYsonString& rhs) +{ + return !(lhs == rhs); +} + +inline bool operator != (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs) +{ + return !(lhs == rhs); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson + +//! A hasher for TYsonString +template <> +struct THash<NYT::NYson::TYsonString> +{ + size_t operator () (const NYT::NYson::TYsonString& str) const + { + return str.ComputeHash(); + } +}; + +//! A hasher for TYsonStringBuf +template <> +struct THash<NYT::NYson::TYsonStringBuf> +{ + size_t operator () (const NYT::NYson::TYsonStringBuf& str) const + { + return THash<TStringBuf>()(str.AsStringBuf()); + } +}; diff --git a/library/cpp/yt/yson_string/string.cpp b/library/cpp/yt/yson_string/string.cpp index 99d45e8616..3643a7107d 100644 --- a/library/cpp/yt/yson_string/string.cpp +++ b/library/cpp/yt/yson_string/string.cpp @@ -1,185 +1,185 @@ #include "string.h" - -#include <library/cpp/yt/assert/assert.h> - -#include <library/cpp/yt/misc/variant.h> - -#include <library/cpp/yt/memory/new.h> - -namespace NYT::NYson { - -//////////////////////////////////////////////////////////////////////////////// - -TYsonStringBuf::TYsonStringBuf() -{ - Type_ = EYsonType::Node; // fake - Null_ = true; -} - -TYsonStringBuf::TYsonStringBuf(const TYsonString& ysonString) -{ - if (ysonString) { - Data_ = ysonString.AsStringBuf(); - Type_ = ysonString.GetType(); - Null_ = false; - } else { - Type_ = EYsonType::Node; // fake - Null_ = true; - } -} - -TYsonStringBuf::TYsonStringBuf(const TString& data, EYsonType type) - : TYsonStringBuf(TStringBuf(data), type) -{ } - -TYsonStringBuf::TYsonStringBuf(TStringBuf data, EYsonType type) - : Data_(data) + +#include <library/cpp/yt/assert/assert.h> + +#include <library/cpp/yt/misc/variant.h> + +#include <library/cpp/yt/memory/new.h> + +namespace NYT::NYson { + +//////////////////////////////////////////////////////////////////////////////// + +TYsonStringBuf::TYsonStringBuf() +{ + Type_ = EYsonType::Node; // fake + Null_ = true; +} + +TYsonStringBuf::TYsonStringBuf(const TYsonString& ysonString) +{ + if (ysonString) { + Data_ = ysonString.AsStringBuf(); + Type_ = ysonString.GetType(); + Null_ = false; + } else { + Type_ = EYsonType::Node; // fake + Null_ = true; + } +} + +TYsonStringBuf::TYsonStringBuf(const TString& data, EYsonType type) + : TYsonStringBuf(TStringBuf(data), type) +{ } + +TYsonStringBuf::TYsonStringBuf(TStringBuf data, EYsonType type) + : Data_(data) , Type_(type) - , Null_(false) + , Null_(false) { } TYsonStringBuf::TYsonStringBuf(const char* data, EYsonType type) : TYsonStringBuf(TStringBuf(data), type) { } -TYsonStringBuf::operator bool() const -{ - return !Null_; -} - -TStringBuf TYsonStringBuf::AsStringBuf() const -{ - YT_VERIFY(*this); - return Data_; -} - -EYsonType TYsonStringBuf::GetType() const -{ - YT_VERIFY(*this); - return Type_; -} - -//////////////////////////////////////////////////////////////////////////////// - -TYsonString::TYsonString() -{ - Begin_ = nullptr; - Size_ = 0; - Type_ = EYsonType::Node; // fake -} - -TYsonString::TYsonString(const TYsonStringBuf& ysonStringBuf) -{ - if (ysonStringBuf) { - struct TCapturedYsonStringPayload - : public TRefCounted - , public TWithExtraSpace<TCapturedYsonStringPayload> - { - char* GetData() - { - return static_cast<char*>(GetExtraSpacePtr()); - } - }; - - auto data = ysonStringBuf.AsStringBuf(); - auto payload = NewWithExtraSpace<TCapturedYsonStringPayload>(data.length()); - ::memcpy(payload->GetData(), data.data(), data.length()); - Payload_ = payload; - Begin_ = payload->GetData(); - Size_ = data.Size(); - Type_ = ysonStringBuf.GetType(); +TYsonStringBuf::operator bool() const +{ + return !Null_; +} + +TStringBuf TYsonStringBuf::AsStringBuf() const +{ + YT_VERIFY(*this); + return Data_; +} + +EYsonType TYsonStringBuf::GetType() const +{ + YT_VERIFY(*this); + return Type_; +} + +//////////////////////////////////////////////////////////////////////////////// + +TYsonString::TYsonString() +{ + Begin_ = nullptr; + Size_ = 0; + Type_ = EYsonType::Node; // fake +} + +TYsonString::TYsonString(const TYsonStringBuf& ysonStringBuf) +{ + if (ysonStringBuf) { + struct TCapturedYsonStringPayload + : public TRefCounted + , public TWithExtraSpace<TCapturedYsonStringPayload> + { + char* GetData() + { + return static_cast<char*>(GetExtraSpacePtr()); + } + }; + + auto data = ysonStringBuf.AsStringBuf(); + auto payload = NewWithExtraSpace<TCapturedYsonStringPayload>(data.length()); + ::memcpy(payload->GetData(), data.data(), data.length()); + Payload_ = payload; + Begin_ = payload->GetData(); + Size_ = data.Size(); + Type_ = ysonStringBuf.GetType(); } else { - Begin_ = nullptr; - Size_ = 0; - Type_ = EYsonType::Node; // fake - } -} - -TYsonString::TYsonString( - TStringBuf data, - EYsonType type) - : TYsonString(TYsonStringBuf(data, type)) + Begin_ = nullptr; + Size_ = 0; + Type_ = EYsonType::Node; // fake + } +} + +TYsonString::TYsonString( + TStringBuf data, + EYsonType type) + : TYsonString(TYsonStringBuf(data, type)) { } #ifdef TSTRING_IS_STD_STRING -TYsonString::TYsonString( +TYsonString::TYsonString( const TString& data, - EYsonType type) + EYsonType type) : TYsonString(TYsonStringBuf(data, type)) { } #else TYsonString::TYsonString( const TString& data, EYsonType type) -{ +{ // NOTE: CoW TString implementation is assumed // Moving the payload MUST NOT invalidate its internal pointers - Payload_ = data; - Begin_ = data.data(); - Size_ = data.length(); - Type_ = type; -} + Payload_ = data; + Begin_ = data.data(); + Size_ = data.length(); + Type_ = type; +} #endif -TYsonString::TYsonString( - const TSharedRef& data, - EYsonType type) -{ - Payload_ = data.GetHolder(); - Begin_ = data.Begin(); - Size_ = data.Size(); - Type_ = type; +TYsonString::TYsonString( + const TSharedRef& data, + EYsonType type) +{ + Payload_ = data.GetHolder(); + Begin_ = data.Begin(); + Size_ = data.Size(); + Type_ = type; +} + +TYsonString::operator bool() const +{ + return !std::holds_alternative<TNullPayload>(Payload_); } -TYsonString::operator bool() const +EYsonType TYsonString::GetType() const { - return !std::holds_alternative<TNullPayload>(Payload_); -} - -EYsonType TYsonString::GetType() const + YT_VERIFY(*this); + return Type_; +} + +TStringBuf TYsonString::AsStringBuf() const { - YT_VERIFY(*this); - return Type_; + YT_VERIFY(*this); + return TStringBuf(Begin_, Begin_ + Size_); } -TStringBuf TYsonString::AsStringBuf() const +TString TYsonString::ToString() const { - YT_VERIFY(*this); - return TStringBuf(Begin_, Begin_ + Size_); -} - -TString TYsonString::ToString() const -{ - return Visit( - Payload_, - [] (const TNullPayload&) -> TString { - YT_ABORT(); - }, + return Visit( + Payload_, + [] (const TNullPayload&) -> TString { + YT_ABORT(); + }, [&] (const TRefCountedPtr&) { - return TString(AsStringBuf()); - }, - [] (const TString& payload) { - return payload; - }); + return TString(AsStringBuf()); + }, + [] (const TString& payload) { + return payload; + }); } -size_t TYsonString::ComputeHash() const +size_t TYsonString::ComputeHash() const { - return THash<TStringBuf>()(TStringBuf(Begin_, Begin_ + Size_)); + return THash<TStringBuf>()(TStringBuf(Begin_, Begin_ + Size_)); } -//////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + TString ToString(const TYsonString& yson) -{ - return yson.ToString(); -} - +{ + return yson.ToString(); +} + TString ToString(const TYsonStringBuf& yson) { - return TString(yson.AsStringBuf()); + return TString(yson.AsStringBuf()); } -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYson +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson diff --git a/library/cpp/yt/yson_string/string.h b/library/cpp/yt/yson_string/string.h index e13af37a6d..cbe6810252 100644 --- a/library/cpp/yt/yson_string/string.h +++ b/library/cpp/yt/yson_string/string.h @@ -1,34 +1,34 @@ -#pragma once - -#include "public.h" - -#include <library/cpp/yt/memory/ref.h> - -#include <variant> - -namespace NYT::NYson { - -//////////////////////////////////////////////////////////////////////////////// - -//! Contains a sequence of bytes in YSON encoding annotated with EYsonType describing -//! the content. Could be null. Non-owning. -class TYsonStringBuf -{ -public: - //! Constructs a null instance. - TYsonStringBuf(); - - //! Constructs an instance from TYsonString. - TYsonStringBuf(const TYsonString& ysonString); - +#pragma once + +#include "public.h" + +#include <library/cpp/yt/memory/ref.h> + +#include <variant> + +namespace NYT::NYson { + +//////////////////////////////////////////////////////////////////////////////// + +//! Contains a sequence of bytes in YSON encoding annotated with EYsonType describing +//! the content. Could be null. Non-owning. +class TYsonStringBuf +{ +public: + //! Constructs a null instance. + TYsonStringBuf(); + + //! Constructs an instance from TYsonString. + TYsonStringBuf(const TYsonString& ysonString); + //! Constructs a non-null instance with given type and content. - explicit TYsonStringBuf( - const TString& data, + explicit TYsonStringBuf( + const TString& data, EYsonType type = EYsonType::Node); - + //! Constructs a non-null instance with given type and content. - explicit TYsonStringBuf( - TStringBuf data, + explicit TYsonStringBuf( + TStringBuf data, EYsonType type = EYsonType::Node); //! Constructs a non-null instance with given type and content @@ -38,103 +38,103 @@ public: const char* data, EYsonType type = EYsonType::Node); - //! Returns |true| if the instance is not null. - explicit operator bool() const; - - //! Returns the underlying YSON bytes. The instance must be non-null. - TStringBuf AsStringBuf() const; - - //! Returns type of YSON contained here. The instance must be non-null. - EYsonType GetType() const; - + //! Returns |true| if the instance is not null. + explicit operator bool() const; + + //! Returns the underlying YSON bytes. The instance must be non-null. + TStringBuf AsStringBuf() const; + + //! Returns type of YSON contained here. The instance must be non-null. + EYsonType GetType() const; + protected: - TStringBuf Data_; - EYsonType Type_; + TStringBuf Data_; + EYsonType Type_; bool Null_; }; -//////////////////////////////////////////////////////////////////////////////// - -//! An owning version of TYsonStringBuf. -/*! - * Internally captures the data either via TString or a polymorphic ref-counted holder. - */ +//////////////////////////////////////////////////////////////////////////////// + +//! An owning version of TYsonStringBuf. +/*! + * Internally captures the data either via TString or a polymorphic ref-counted holder. + */ class TYsonString { public: - //! Constructs a null instance. - TYsonString(); + //! Constructs a null instance. + TYsonString(); - //! Constructs an instance from TYsonStringBuf. - //! Copies the data into a ref-counted payload. + //! Constructs an instance from TYsonStringBuf. + //! Copies the data into a ref-counted payload. explicit TYsonString(const TYsonStringBuf& ysonStringBuf); - //! Constructs an instance from TStringBuf. - //! Copies the data into a ref-counted payload. - explicit TYsonString( - TStringBuf data, - EYsonType type = EYsonType::Node); - - //! Constructs an instance from TString. + //! Constructs an instance from TStringBuf. + //! Copies the data into a ref-counted payload. + explicit TYsonString( + TStringBuf data, + EYsonType type = EYsonType::Node); + + //! Constructs an instance from TString. //! Zero-copy for CoW TString: retains the reference to TString in payload. - explicit TYsonString( + explicit TYsonString( const TString& data, - EYsonType type = EYsonType::Node); - - //! Constructs an instance from TSharedRef. - //! Zero-copy; retains the reference to TSharedRef holder in payload. - explicit TYsonString( - const TSharedRef& ref, - EYsonType type = EYsonType::Node); - - //! Returns |true| if the instance is not null. - explicit operator bool() const; - - //! Returns type of YSON contained here. The instance must be non-null. - EYsonType GetType() const; - - //! Returns the non-owning data. The instance must be non-null. - TStringBuf AsStringBuf() const; - - //! Returns the data represented by TString. The instance must be non-null. - //! Copies the data in case the payload is not TString. - TString ToString() const; - - //! Computes the hash code. - size_t ComputeHash() const; - -private: - struct TNullPayload - { }; - + EYsonType type = EYsonType::Node); + + //! Constructs an instance from TSharedRef. + //! Zero-copy; retains the reference to TSharedRef holder in payload. + explicit TYsonString( + const TSharedRef& ref, + EYsonType type = EYsonType::Node); + + //! Returns |true| if the instance is not null. + explicit operator bool() const; + + //! Returns type of YSON contained here. The instance must be non-null. + EYsonType GetType() const; + + //! Returns the non-owning data. The instance must be non-null. + TStringBuf AsStringBuf() const; + + //! Returns the data represented by TString. The instance must be non-null. + //! Copies the data in case the payload is not TString. + TString ToString() const; + + //! Computes the hash code. + size_t ComputeHash() const; + +private: + struct TNullPayload + { }; + using THolder = TRefCountedPtr; - std::variant<TNullPayload, THolder, TString> Payload_; - - const char* Begin_; - ui64 Size_ : 56; - EYsonType Type_ : 8; -}; - -//////////////////////////////////////////////////////////////////////////////// - -bool operator == (const TYsonString& lhs, const TYsonString& rhs); + std::variant<TNullPayload, THolder, TString> Payload_; + + const char* Begin_; + ui64 Size_ : 56; + EYsonType Type_ : 8; +}; + +//////////////////////////////////////////////////////////////////////////////// + +bool operator == (const TYsonString& lhs, const TYsonString& rhs); bool operator == (const TYsonString& lhs, const TYsonStringBuf& rhs); bool operator == (const TYsonStringBuf& lhs, const TYsonString& rhs); bool operator == (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs); -bool operator != (const TYsonString& lhs, const TYsonString& rhs); +bool operator != (const TYsonString& lhs, const TYsonString& rhs); bool operator != (const TYsonString& lhs, const TYsonStringBuf& rhs); bool operator != (const TYsonStringBuf& lhs, const TYsonString& rhs); bool operator != (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs); - + TString ToString(const TYsonString& yson); TString ToString(const TYsonStringBuf& yson); - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYson - -#define STRING_INL_H_ -#include "string-inl.h" -#undef STRING_INL_H_ + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson + +#define STRING_INL_H_ +#include "string-inl.h" +#undef STRING_INL_H_ diff --git a/library/cpp/yt/yson_string/unittests/convert_ut.cpp b/library/cpp/yt/yson_string/unittests/convert_ut.cpp index 3a64f63896..4050eb5889 100644 --- a/library/cpp/yt/yson_string/unittests/convert_ut.cpp +++ b/library/cpp/yt/yson_string/unittests/convert_ut.cpp @@ -1,79 +1,79 @@ -#include <library/cpp/testing/gtest/gtest.h> - -#include <library/cpp/testing/gtest_extensions/assertions.h> - -#include <library/cpp/yt/yson_string/convert.h> - -#include <thread> - -namespace NYT::NYson { -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -template <class T, class R = T, class U> -void Check(const U& value) -{ - auto str = ConvertToYsonString(static_cast<T>(value)); - auto anotherValue = ConvertFromYsonString<R>(str); - EXPECT_EQ(static_cast<T>(value), anotherValue); -} - -TEST(TConvertTest, Basic) -{ - Check<i8>(13); - Check<i32>(13); - Check<i64>(13); - Check<i8>(-13); - Check<i32>(-13); - Check<i64>(-13); - Check<ui8>(13); - Check<ui32>(13); - Check<ui64>(13); - Check<TString>(""); - Check<TString>("hello"); - Check<TStringBuf, TString>("hello"); - Check<const char*, TString>("hello"); - Check<float>(3.14); - Check<double>(3.14); - Check<bool>(true); - Check<bool>(false); - Check<TInstant>(TInstant::Now()); - Check<TDuration>(TDuration::Seconds(123)); - Check<TGuid>(TGuid::FromString("12345678-12345678-abcdabcd-fefefefe")); -} - -TEST(TConvertTest, InRange) -{ - EXPECT_EQ(ConvertFromYsonString<i16>(ConvertToYsonString(static_cast<i64>(-123))), -123); - EXPECT_EQ(ConvertFromYsonString<ui16>(ConvertToYsonString(static_cast<ui64>(123))), 123U); -} - -TEST(TConvertTest, OutOfRange) -{ - EXPECT_THROW_MESSAGE_HAS_SUBSTR( - ConvertFromYsonString<i8>(ConvertToYsonString(static_cast<i64>(128))), - TYsonLiteralParseException, - "is out of expected range"); - EXPECT_THROW_MESSAGE_HAS_SUBSTR( - ConvertFromYsonString<ui8>(ConvertToYsonString(static_cast<ui64>(256))), - TYsonLiteralParseException, - "is out of expected range"); -} - -TEST(TConvertTest, MalformedValues) -{ - EXPECT_THROW_MESSAGE_HAS_SUBSTR( - ConvertFromYsonString<TInstant>(ConvertToYsonString(TStringBuf("sometime"))), - TYsonLiteralParseException, - "Error parsing \"instant\" value"); - EXPECT_THROW_MESSAGE_HAS_SUBSTR( - ConvertFromYsonString<TGuid>(ConvertToYsonString(TStringBuf("1-2-3-g"))), - TYsonLiteralParseException, - "Error parsing \"guid\" value"); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace -} // namespace NYT::NYson +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/testing/gtest_extensions/assertions.h> + +#include <library/cpp/yt/yson_string/convert.h> + +#include <thread> + +namespace NYT::NYson { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T, class R = T, class U> +void Check(const U& value) +{ + auto str = ConvertToYsonString(static_cast<T>(value)); + auto anotherValue = ConvertFromYsonString<R>(str); + EXPECT_EQ(static_cast<T>(value), anotherValue); +} + +TEST(TConvertTest, Basic) +{ + Check<i8>(13); + Check<i32>(13); + Check<i64>(13); + Check<i8>(-13); + Check<i32>(-13); + Check<i64>(-13); + Check<ui8>(13); + Check<ui32>(13); + Check<ui64>(13); + Check<TString>(""); + Check<TString>("hello"); + Check<TStringBuf, TString>("hello"); + Check<const char*, TString>("hello"); + Check<float>(3.14); + Check<double>(3.14); + Check<bool>(true); + Check<bool>(false); + Check<TInstant>(TInstant::Now()); + Check<TDuration>(TDuration::Seconds(123)); + Check<TGuid>(TGuid::FromString("12345678-12345678-abcdabcd-fefefefe")); +} + +TEST(TConvertTest, InRange) +{ + EXPECT_EQ(ConvertFromYsonString<i16>(ConvertToYsonString(static_cast<i64>(-123))), -123); + EXPECT_EQ(ConvertFromYsonString<ui16>(ConvertToYsonString(static_cast<ui64>(123))), 123U); +} + +TEST(TConvertTest, OutOfRange) +{ + EXPECT_THROW_MESSAGE_HAS_SUBSTR( + ConvertFromYsonString<i8>(ConvertToYsonString(static_cast<i64>(128))), + TYsonLiteralParseException, + "is out of expected range"); + EXPECT_THROW_MESSAGE_HAS_SUBSTR( + ConvertFromYsonString<ui8>(ConvertToYsonString(static_cast<ui64>(256))), + TYsonLiteralParseException, + "is out of expected range"); +} + +TEST(TConvertTest, MalformedValues) +{ + EXPECT_THROW_MESSAGE_HAS_SUBSTR( + ConvertFromYsonString<TInstant>(ConvertToYsonString(TStringBuf("sometime"))), + TYsonLiteralParseException, + "Error parsing \"instant\" value"); + EXPECT_THROW_MESSAGE_HAS_SUBSTR( + ConvertFromYsonString<TGuid>(ConvertToYsonString(TStringBuf("1-2-3-g"))), + TYsonLiteralParseException, + "Error parsing \"guid\" value"); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT::NYson diff --git a/library/cpp/yt/yson_string/unittests/ya.make b/library/cpp/yt/yson_string/unittests/ya.make index f327d298f1..aee36844f2 100644 --- a/library/cpp/yt/yson_string/unittests/ya.make +++ b/library/cpp/yt/yson_string/unittests/ya.make @@ -1,15 +1,15 @@ -GTEST() - -OWNER(g:yt) - -SRCS( - convert_ut.cpp -) - -PEERDIR( - library/cpp/yt/yson_string - library/cpp/testing/gtest - library/cpp/testing/gtest_extensions -) - -END() +GTEST() + +OWNER(g:yt) + +SRCS( + convert_ut.cpp +) + +PEERDIR( + library/cpp/yt/yson_string + library/cpp/testing/gtest + library/cpp/testing/gtest_extensions +) + +END() diff --git a/library/cpp/yt/yson_string/ya.make b/library/cpp/yt/yson_string/ya.make index b7447d89ff..ea57bc458d 100644 --- a/library/cpp/yt/yson_string/ya.make +++ b/library/cpp/yt/yson_string/ya.make @@ -1,21 +1,21 @@ -LIBRARY() - -SRCS( - convert.cpp - string.cpp -) - -PEERDIR( - library/cpp/yt/assert - library/cpp/yt/coding - library/cpp/yt/exception - library/cpp/yt/string - library/cpp/yt/memory - library/cpp/yt/misc -) - -END() - -RECURSE_FOR_TESTS( - unittests -) +LIBRARY() + +SRCS( + convert.cpp + string.cpp +) + +PEERDIR( + library/cpp/yt/assert + library/cpp/yt/coding + library/cpp/yt/exception + library/cpp/yt/string + library/cpp/yt/memory + library/cpp/yt/misc +) + +END() + +RECURSE_FOR_TESTS( + unittests +) diff --git a/library/cpp/ytalloc/api/README.md b/library/cpp/ytalloc/api/README.md index 1b57e81b5c..08d30a3e66 100644 --- a/library/cpp/ytalloc/api/README.md +++ b/library/cpp/ytalloc/api/README.md @@ -1,6 +1,6 @@ -This lightweight module can be used by anyone interested in YTAlloc -functionality (memory allocation and disposal, memory tagging, etc). - -If YTAlloc happens to be linked in, it provides an efficient implementation. -Otherwise (non-YTAlloc build), weak implementations from fallback.cpp -are used.
\ No newline at end of file +This lightweight module can be used by anyone interested in YTAlloc +functionality (memory allocation and disposal, memory tagging, etc). + +If YTAlloc happens to be linked in, it provides an efficient implementation. +Otherwise (non-YTAlloc build), weak implementations from fallback.cpp +are used.
\ No newline at end of file diff --git a/library/cpp/ytalloc/api/fallback.cpp b/library/cpp/ytalloc/api/fallback.cpp index 5880ede439..6511b62f0f 100644 --- a/library/cpp/ytalloc/api/fallback.cpp +++ b/library/cpp/ytalloc/api/fallback.cpp @@ -1,24 +1,24 @@ -// This file contains the fallback implementations of YTAlloc-specific stuff. -// These implementations are annotated with Y_WEAK to ensure that if the actual YTAlloc -// is available at the link time, the latter is preferred over the fallback. -#include "ytalloc.h" - -#include <util/system/compiler.h> -#include <util/system/yassert.h> - -#include <cstdlib> - -namespace NYT::NYTAlloc { - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void* Allocate(size_t size) -{ - return ::malloc(size); -} - -Y_WEAK void* AllocatePageAligned(size_t size) -{ +// This file contains the fallback implementations of YTAlloc-specific stuff. +// These implementations are annotated with Y_WEAK to ensure that if the actual YTAlloc +// is available at the link time, the latter is preferred over the fallback. +#include "ytalloc.h" + +#include <util/system/compiler.h> +#include <util/system/yassert.h> + +#include <cstdlib> + +namespace NYT::NYTAlloc { + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK void* Allocate(size_t size) +{ + return ::malloc(size); +} + +Y_WEAK void* AllocatePageAligned(size_t size) +{ #if defined(_win_) return ::_aligned_malloc(size, PageSize); #elif defined(_darwin_) || !defined(_musl_) @@ -26,195 +26,195 @@ Y_WEAK void* AllocatePageAligned(size_t size) #else return ::memalign(PageSize, size); #endif -} - -Y_WEAK void* AllocateSmall(size_t rank) -{ - return ::malloc(SmallRankToSize[rank]); -} - -Y_WEAK void Free(void* ptr) -{ - ::free(ptr); -} - -Y_WEAK void FreeNonNull(void* ptr) -{ - Y_ASSERT(ptr); - ::free(ptr); -} - -Y_WEAK size_t GetAllocationSize(const void* /*ptr*/) -{ - return 0; -} - -Y_WEAK size_t GetAllocationSize(size_t size) -{ - return size; -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK TMemoryTag GetCurrentMemoryTag() -{ - return NullMemoryTag; -} - -Y_WEAK void SetCurrentMemoryTag(TMemoryTag /*tag*/) -{ } - -Y_WEAK size_t GetMemoryUsageForTag(TMemoryTag /*tag*/) -{ - return 0; -} - -Y_WEAK void GetMemoryUsageForTags(const TMemoryTag* /*tags*/, size_t /*count*/, size_t* /*results*/) -{ } - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void SetCurrentMemoryZone(EMemoryZone /*zone*/) -{ } - -Y_WEAK EMemoryZone GetCurrentMemoryZone() -{ - return EMemoryZone::Normal; -} - -Y_WEAK EMemoryZone GetAllocationMemoryZone(const void* /*ptr*/) -{ - return EMemoryZone::Normal; -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void SetCurrentFiberId(TFiberId /*id*/) -{ } - -Y_WEAK TFiberId GetCurrentFiberId() -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void EnableLogging(TLogHandler /*logHandler*/) -{ } - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void SetBacktraceProvider(TBacktraceProvider /*provider*/) -{ } - +} + +Y_WEAK void* AllocateSmall(size_t rank) +{ + return ::malloc(SmallRankToSize[rank]); +} + +Y_WEAK void Free(void* ptr) +{ + ::free(ptr); +} + +Y_WEAK void FreeNonNull(void* ptr) +{ + Y_ASSERT(ptr); + ::free(ptr); +} + +Y_WEAK size_t GetAllocationSize(const void* /*ptr*/) +{ + return 0; +} + +Y_WEAK size_t GetAllocationSize(size_t size) +{ + return size; +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK TMemoryTag GetCurrentMemoryTag() +{ + return NullMemoryTag; +} + +Y_WEAK void SetCurrentMemoryTag(TMemoryTag /*tag*/) +{ } + +Y_WEAK size_t GetMemoryUsageForTag(TMemoryTag /*tag*/) +{ + return 0; +} + +Y_WEAK void GetMemoryUsageForTags(const TMemoryTag* /*tags*/, size_t /*count*/, size_t* /*results*/) +{ } + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK void SetCurrentMemoryZone(EMemoryZone /*zone*/) +{ } + +Y_WEAK EMemoryZone GetCurrentMemoryZone() +{ + return EMemoryZone::Normal; +} + +Y_WEAK EMemoryZone GetAllocationMemoryZone(const void* /*ptr*/) +{ + return EMemoryZone::Normal; +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK void SetCurrentFiberId(TFiberId /*id*/) +{ } + +Y_WEAK TFiberId GetCurrentFiberId() +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK void EnableLogging(TLogHandler /*logHandler*/) +{ } + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK void SetBacktraceProvider(TBacktraceProvider /*provider*/) +{ } + Y_WEAK void SetBacktraceFormatter(TBacktraceFormatter /*formatter*/) { } -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK void EnableStockpile() -{ } - -Y_WEAK void SetStockpileInterval(TDuration /*value*/) -{ } - -Y_WEAK void SetStockpileThreadCount(int /*value*/) -{ } - -Y_WEAK void SetStockpileSize(size_t /*value*/) -{ } - -Y_WEAK void SetLargeUnreclaimableCoeff(double /*value*/) -{ } - -Y_WEAK void SetMinLargeUnreclaimableBytes(size_t /*value*/) -{ } - -Y_WEAK void SetMaxLargeUnreclaimableBytes(size_t /*value*/) -{ } - -Y_WEAK void SetTimingEventThreshold(TDuration /*value*/) -{ } - -Y_WEAK void SetAllocationProfilingEnabled(bool /*value*/) -{ } - -Y_WEAK void SetAllocationProfilingSamplingRate(double /*rate*/) -{ } - -Y_WEAK void SetSmallArenaAllocationProfilingEnabled(size_t /*rank*/, bool /*value*/) -{ } - -Y_WEAK void SetLargeArenaAllocationProfilingEnabled(size_t /*rank*/, bool /*value*/) -{ } - -Y_WEAK void SetProfilingBacktraceDepth(int /*depth*/) -{ } - -Y_WEAK void SetMinProfilingBytesUsedToReport(size_t /*size*/) -{ } - -Y_WEAK void SetEnableEagerMemoryRelease(bool /*value*/) -{ } - -Y_WEAK void SetEnableMadvisePopulate(bool /*value*/) -{ } - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK TEnumIndexedVector<ETotalCounter, ssize_t> GetTotalAllocationCounters() -{ - return {}; -} - -Y_WEAK TEnumIndexedVector<ESmallCounter, ssize_t> GetSmallAllocationCounters() -{ - return {}; -} - -Y_WEAK TEnumIndexedVector<ELargeCounter, ssize_t> GetLargeAllocationCounters() -{ - return {}; -} - -Y_WEAK std::array<TEnumIndexedVector<ESmallArenaCounter, ssize_t>, SmallRankCount> GetSmallArenaAllocationCounters() -{ - return {}; -} - -Y_WEAK std::array<TEnumIndexedVector<ELargeArenaCounter, ssize_t>, LargeRankCount> GetLargeArenaAllocationCounters() -{ - return {}; -} - -Y_WEAK TEnumIndexedVector<EHugeCounter, ssize_t> GetHugeAllocationCounters() -{ - return {}; -} - -Y_WEAK TEnumIndexedVector<ESystemCounter, ssize_t> GetSystemAllocationCounters() -{ - return {}; -} - -Y_WEAK TEnumIndexedVector<EUndumpableCounter, ssize_t> GetUndumpableAllocationCounters() -{ - return {}; -} - -Y_WEAK TEnumIndexedVector<ETimingEventType, TTimingEventCounters> GetTimingEventCounters() -{ - return {}; -} - -//////////////////////////////////////////////////////////////////////////////// - -Y_WEAK std::vector<TProfiledAllocation> GetProfiledAllocationStatistics() -{ - return {}; -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYTAlloc - +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK void EnableStockpile() +{ } + +Y_WEAK void SetStockpileInterval(TDuration /*value*/) +{ } + +Y_WEAK void SetStockpileThreadCount(int /*value*/) +{ } + +Y_WEAK void SetStockpileSize(size_t /*value*/) +{ } + +Y_WEAK void SetLargeUnreclaimableCoeff(double /*value*/) +{ } + +Y_WEAK void SetMinLargeUnreclaimableBytes(size_t /*value*/) +{ } + +Y_WEAK void SetMaxLargeUnreclaimableBytes(size_t /*value*/) +{ } + +Y_WEAK void SetTimingEventThreshold(TDuration /*value*/) +{ } + +Y_WEAK void SetAllocationProfilingEnabled(bool /*value*/) +{ } + +Y_WEAK void SetAllocationProfilingSamplingRate(double /*rate*/) +{ } + +Y_WEAK void SetSmallArenaAllocationProfilingEnabled(size_t /*rank*/, bool /*value*/) +{ } + +Y_WEAK void SetLargeArenaAllocationProfilingEnabled(size_t /*rank*/, bool /*value*/) +{ } + +Y_WEAK void SetProfilingBacktraceDepth(int /*depth*/) +{ } + +Y_WEAK void SetMinProfilingBytesUsedToReport(size_t /*size*/) +{ } + +Y_WEAK void SetEnableEagerMemoryRelease(bool /*value*/) +{ } + +Y_WEAK void SetEnableMadvisePopulate(bool /*value*/) +{ } + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK TEnumIndexedVector<ETotalCounter, ssize_t> GetTotalAllocationCounters() +{ + return {}; +} + +Y_WEAK TEnumIndexedVector<ESmallCounter, ssize_t> GetSmallAllocationCounters() +{ + return {}; +} + +Y_WEAK TEnumIndexedVector<ELargeCounter, ssize_t> GetLargeAllocationCounters() +{ + return {}; +} + +Y_WEAK std::array<TEnumIndexedVector<ESmallArenaCounter, ssize_t>, SmallRankCount> GetSmallArenaAllocationCounters() +{ + return {}; +} + +Y_WEAK std::array<TEnumIndexedVector<ELargeArenaCounter, ssize_t>, LargeRankCount> GetLargeArenaAllocationCounters() +{ + return {}; +} + +Y_WEAK TEnumIndexedVector<EHugeCounter, ssize_t> GetHugeAllocationCounters() +{ + return {}; +} + +Y_WEAK TEnumIndexedVector<ESystemCounter, ssize_t> GetSystemAllocationCounters() +{ + return {}; +} + +Y_WEAK TEnumIndexedVector<EUndumpableCounter, ssize_t> GetUndumpableAllocationCounters() +{ + return {}; +} + +Y_WEAK TEnumIndexedVector<ETimingEventType, TTimingEventCounters> GetTimingEventCounters() +{ + return {}; +} + +//////////////////////////////////////////////////////////////////////////////// + +Y_WEAK std::vector<TProfiledAllocation> GetProfiledAllocationStatistics() +{ + return {}; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYTAlloc + diff --git a/library/cpp/ytalloc/api/ya.make b/library/cpp/ytalloc/api/ya.make index 26d0efd381..502d4273fa 100644 --- a/library/cpp/ytalloc/api/ya.make +++ b/library/cpp/ytalloc/api/ya.make @@ -1,13 +1,13 @@ -LIBRARY() - -OWNER(g:yt) - -SRCS( - fallback.cpp -) - -PEERDIR( - library/cpp/yt/misc -) - -END() +LIBRARY() + +OWNER(g:yt) + +SRCS( + fallback.cpp +) + +PEERDIR( + library/cpp/yt/misc +) + +END() diff --git a/library/cpp/ytalloc/api/ytalloc-inl.h b/library/cpp/ytalloc/api/ytalloc-inl.h index 263108423d..8b698a3125 100644 --- a/library/cpp/ytalloc/api/ytalloc-inl.h +++ b/library/cpp/ytalloc/api/ytalloc-inl.h @@ -1,105 +1,105 @@ -#pragma once -#ifndef YT_ALLOC_INL_H_ -#error "Direct inclusion of this file is not allowed, include ytalloc.h" -// For the sake of sane code completion. -#include "ytalloc.h" -#endif - -#include <util/system/types.h> - -namespace NYT::NYTAlloc { - -//////////////////////////////////////////////////////////////////////////////// - -// Maps small chunk ranks to size in bytes. -constexpr ui16 SmallRankToSize[SmallRankCount] = { - 0, - 16, 32, 48, 64, 96, 128, - 192, 256, 384, 512, 768, 1024, 1536, 2048, - 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768 -}; - -// Helper array for mapping size to small chunk rank. -constexpr ui8 SizeToSmallRank1[65] = { - 1, 1, 1, 2, 2, // 16, 32 - 3, 3, 4, 4, // 48, 64 - 5, 5, 5, 5, 6, 6, 6, 6, // 96, 128 - 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, // 192, 256 - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 384 - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 // 512 -}; - -// Helper array for mapping size to small chunk rank. -constexpr unsigned char SizeToSmallRank2[128] = { - 10, 10, 11, 12, // 512, 512, 768, 1022 - 13, 13, 14, 14, // 1536, 2048 - 15, 15, 15, 15, 16, 16, 16, 16, // 3072, 4096 - 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, // 6144, 8192 - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, // 12288 - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 16384 - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, // 22576 - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22 // 32768 -}; - -//////////////////////////////////////////////////////////////////////////////// - -constexpr size_t SizeToSmallRank(size_t size) -{ - if (size <= 512) { - return SizeToSmallRank1[(size + 7) >> 3]; - } else { - if (size <= LargeAllocationSizeThreshold) { - return SizeToSmallRank2[(size - 1) >> 8]; - } else { - return 0; - } - } -} - -void* AllocateSmall(size_t rank); - -template <size_t Size> -void* AllocateConstSize() -{ - constexpr auto rank = SizeToSmallRank(Size); - if constexpr(rank != 0) { - return AllocateSmall(rank); - } else { - return Allocate(Size); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -inline TMemoryTagGuard::TMemoryTagGuard() - : Active_(false) - , PreviousTag_(NullMemoryTag) -{ } - -inline TMemoryTagGuard::TMemoryTagGuard(TMemoryTag tag) - : Active_(true) - , PreviousTag_(GetCurrentMemoryTag()) -{ - SetCurrentMemoryTag(tag); -} - -inline TMemoryTagGuard::TMemoryTagGuard(TMemoryTagGuard&& other) - : Active_(other.Active_) - , PreviousTag_(other.PreviousTag_) -{ - other.Active_ = false; - other.PreviousTag_ = NullMemoryTag; -} - -inline TMemoryTagGuard::~TMemoryTagGuard() -{ - if (Active_) { - SetCurrentMemoryTag(PreviousTag_); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYTAlloc +#pragma once +#ifndef YT_ALLOC_INL_H_ +#error "Direct inclusion of this file is not allowed, include ytalloc.h" +// For the sake of sane code completion. +#include "ytalloc.h" +#endif + +#include <util/system/types.h> + +namespace NYT::NYTAlloc { + +//////////////////////////////////////////////////////////////////////////////// + +// Maps small chunk ranks to size in bytes. +constexpr ui16 SmallRankToSize[SmallRankCount] = { + 0, + 16, 32, 48, 64, 96, 128, + 192, 256, 384, 512, 768, 1024, 1536, 2048, + 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768 +}; + +// Helper array for mapping size to small chunk rank. +constexpr ui8 SizeToSmallRank1[65] = { + 1, 1, 1, 2, 2, // 16, 32 + 3, 3, 4, 4, // 48, 64 + 5, 5, 5, 5, 6, 6, 6, 6, // 96, 128 + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, // 192, 256 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 384 + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 // 512 +}; + +// Helper array for mapping size to small chunk rank. +constexpr unsigned char SizeToSmallRank2[128] = { + 10, 10, 11, 12, // 512, 512, 768, 1022 + 13, 13, 14, 14, // 1536, 2048 + 15, 15, 15, 15, 16, 16, 16, 16, // 3072, 4096 + 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, // 6144, 8192 + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, // 12288 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 16384 + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, // 22576 + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22 // 32768 +}; + +//////////////////////////////////////////////////////////////////////////////// + +constexpr size_t SizeToSmallRank(size_t size) +{ + if (size <= 512) { + return SizeToSmallRank1[(size + 7) >> 3]; + } else { + if (size <= LargeAllocationSizeThreshold) { + return SizeToSmallRank2[(size - 1) >> 8]; + } else { + return 0; + } + } +} + +void* AllocateSmall(size_t rank); + +template <size_t Size> +void* AllocateConstSize() +{ + constexpr auto rank = SizeToSmallRank(Size); + if constexpr(rank != 0) { + return AllocateSmall(rank); + } else { + return Allocate(Size); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +inline TMemoryTagGuard::TMemoryTagGuard() + : Active_(false) + , PreviousTag_(NullMemoryTag) +{ } + +inline TMemoryTagGuard::TMemoryTagGuard(TMemoryTag tag) + : Active_(true) + , PreviousTag_(GetCurrentMemoryTag()) +{ + SetCurrentMemoryTag(tag); +} + +inline TMemoryTagGuard::TMemoryTagGuard(TMemoryTagGuard&& other) + : Active_(other.Active_) + , PreviousTag_(other.PreviousTag_) +{ + other.Active_ = false; + other.PreviousTag_ = NullMemoryTag; +} + +inline TMemoryTagGuard::~TMemoryTagGuard() +{ + if (Active_) { + SetCurrentMemoryTag(PreviousTag_); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYTAlloc diff --git a/library/cpp/ytalloc/api/ytalloc.h b/library/cpp/ytalloc/api/ytalloc.h index d942dde638..ad8e8f948b 100644 --- a/library/cpp/ytalloc/api/ytalloc.h +++ b/library/cpp/ytalloc/api/ytalloc.h @@ -1,416 +1,416 @@ -#pragma once - -#include <stddef.h> - -#include <library/cpp/yt/misc/enum.h> - -#include <util/system/types.h> - -#include <util/generic/size_literals.h> - -#include <util/datetime/base.h> - -namespace NYT::NYTAlloc { - -//////////////////////////////////////////////////////////////////////////////// -// Macros - +#pragma once + +#include <stddef.h> + +#include <library/cpp/yt/misc/enum.h> + +#include <util/system/types.h> + +#include <util/generic/size_literals.h> + +#include <util/datetime/base.h> + +namespace NYT::NYTAlloc { + +//////////////////////////////////////////////////////////////////////////////// +// Macros + #if defined(_linux_) && \ !defined(_asan_enabled_) && \ !defined(_msan_enabled_) && \ - !defined(_tsan_enabled_) - #define YT_ALLOC_ENABLED -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Constants - -constexpr int SmallRankCount = 23; -constexpr int MinLargeRank = 15; -constexpr int LargeRankCount = 30; -constexpr size_t LargeAllocationSizeThreshold = 32_KB; -constexpr size_t HugeAllocationSizeThreshold = 1ULL << (LargeRankCount - 1); -constexpr size_t MaxAllocationSize = 1_TB; -constexpr size_t PageSize = 4_KB; -constexpr size_t RightReadableAreaSize = 16; - -//////////////////////////////////////////////////////////////////////////////// -// Allocation API - -// Allocates a chunk of memory of (at least) #size bytes. -// The returned pointer is guaranteed to be 16-byte aligned. -// Moreover, it is guaranteeed that #RightReadableAreaSize bytes immediately following -// the allocated chunk are readable (but may belong to another allocated chunk). -// This enables eliminating some nasty corner cases in SIMD memory manipulations. -void* Allocate(size_t size); - -// Allocates a chunk of memory of (at least) #size bytes. -// The returned pointer is guaranteed to be 4K-byte aligned. -// #size, however, need not be divisible by page size (but internally it will be rounded up). -void* AllocatePageAligned(size_t size); - -// An optimized version of #Allocate with #Size being known at compile-time. -template <size_t Size> -void* AllocateConstSize(); - -// Frees a chunk of memory previously allocated via Allocate functions. -// Does nothing if #ptr is null. -void Free(void* ptr); - -// Similar to #Free but assumes that #ptr is not null. -void FreeNonNull(void* ptr); - -// Returns the size of the chunk pointed to by #ptr. -// This size is not guaranteed to be exactly equal to #size passed to allocation functions -// due to rounding; the returned size, however, is never less than the latter size. -// If #ptr is null or we are unable to determine the allocation size, then 0 is returned. -size_t GetAllocationSize(const void* ptr); - -// Returns the size of the chunk that will actually be allocated -// when requesting an allocation of given #size. This is never less than #size. -size_t GetAllocationSize(size_t size); - -//////////////////////////////////////////////////////////////////////////////// -// Memory tagging API -// -// Each allocation can be tagged with a number (from 1 to MaxMemoryTag). -// Setting this to NullMemoryTag disables tagging. -// Internally, YTAlloc tracks the number of bytes used by each tag. -// -// Tagged allocations are somewhat slower. Others (large and huge) are not affected -// (but for these performance implications are negligible anyway). -// -// The current memory tag used for allocations is stored in TLS. - -using TMemoryTag = ui32; -constexpr TMemoryTag NullMemoryTag = 0; -constexpr TMemoryTag MaxMemoryTag = (1ULL << 22) - 1; - -// Updates the current tag value in TLS. -void SetCurrentMemoryTag(TMemoryTag tag); - -// Returns the current tag value from TLS. -TMemoryTag GetCurrentMemoryTag(); - -// Returns the memory usage for a given tag. -// The value is somewhat approxiate and racy. -size_t GetMemoryUsageForTag(TMemoryTag tag); - -// A batched version of GetMemoryUsageForTag. -void GetMemoryUsageForTags(const TMemoryTag* tags, size_t count, size_t* results); - -//////////////////////////////////////////////////////////////////////////////// -// Memory zone API -// -// Each allocation is either in the "normal zone" or "undumpable zone". -// The latter indicates that this memory region will be excluded from a coredump -// should it happen. -// -// The current zone used for allocations is stored in TLS. - -// Memory zone is used to pass hint to the allocator. -DEFINE_ENUM(EMemoryZone, - ((Unknown) (-1)) // not a valid zone - ((Normal) ( 0)) // default memory type - ((Undumpable) ( 1)) // memory is omitted from the core dump -); - -// Updates the current zone in TLS. -void SetCurrentMemoryZone(EMemoryZone zone); - -// Returns the current zone from TLS. -EMemoryZone GetCurrentMemoryZone(); - -// Returns the zone where #ptr resides; -// EMemoryZone::Invalid indicates that #ptr is outside of any recognized memory zone. -EMemoryZone GetAllocationMemoryZone(const void* ptr); - -//////////////////////////////////////////////////////////////////////////////// -// When a "timing event" (hiccup) occurs during an allocation, -// YTAlloc records this event and captures the current fiber id. -// The latter is provided externally by calling SetCurrentFiberId. -// -// This may be helpful to correlate various application-level timings -// with internal events in YTAlloc. -// -// The current fiber id is stored in TLS. - -using TFiberId = ui64; - -// Updates the current fiber id in TLS. -void SetCurrentFiberId(TFiberId id); - -// Returns the currently assinged fiber id from TLS. -TFiberId GetCurrentFiberId(); - -//////////////////////////////////////////////////////////////////////////////// -// Logging - -DEFINE_ENUM(ELogEventSeverity, - (Debug) - (Info) - (Warning) - (Error) -); - -struct TLogEvent -{ - ELogEventSeverity Severity; - TStringBuf Message; -}; - -using TLogHandler = void(*)(const TLogEvent& event); - -// Sets the handler to be invoked for each log event produced by YTAlloc. -// Can be called multiple times (but calls to the previous incarnations of the handler -// are racy). -void EnableLogging(TLogHandler logHandler); - -//////////////////////////////////////////////////////////////////////////////// -// Backtraces - -using TBacktraceProvider = int(*)(void** frames, int maxFrames, int skipFrames); - -// Sets the provider used for collecting backtraces when allocation profiling -// is turned ON. Can be called multiple times (but calls to the previous -// incarnations of the provider are racy). -void SetBacktraceProvider(TBacktraceProvider provider); - -using TBacktraceFormatter = TString(*)(const void* const* frames, int frameCount); + !defined(_tsan_enabled_) + #define YT_ALLOC_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Constants + +constexpr int SmallRankCount = 23; +constexpr int MinLargeRank = 15; +constexpr int LargeRankCount = 30; +constexpr size_t LargeAllocationSizeThreshold = 32_KB; +constexpr size_t HugeAllocationSizeThreshold = 1ULL << (LargeRankCount - 1); +constexpr size_t MaxAllocationSize = 1_TB; +constexpr size_t PageSize = 4_KB; +constexpr size_t RightReadableAreaSize = 16; + +//////////////////////////////////////////////////////////////////////////////// +// Allocation API + +// Allocates a chunk of memory of (at least) #size bytes. +// The returned pointer is guaranteed to be 16-byte aligned. +// Moreover, it is guaranteeed that #RightReadableAreaSize bytes immediately following +// the allocated chunk are readable (but may belong to another allocated chunk). +// This enables eliminating some nasty corner cases in SIMD memory manipulations. +void* Allocate(size_t size); + +// Allocates a chunk of memory of (at least) #size bytes. +// The returned pointer is guaranteed to be 4K-byte aligned. +// #size, however, need not be divisible by page size (but internally it will be rounded up). +void* AllocatePageAligned(size_t size); + +// An optimized version of #Allocate with #Size being known at compile-time. +template <size_t Size> +void* AllocateConstSize(); + +// Frees a chunk of memory previously allocated via Allocate functions. +// Does nothing if #ptr is null. +void Free(void* ptr); + +// Similar to #Free but assumes that #ptr is not null. +void FreeNonNull(void* ptr); + +// Returns the size of the chunk pointed to by #ptr. +// This size is not guaranteed to be exactly equal to #size passed to allocation functions +// due to rounding; the returned size, however, is never less than the latter size. +// If #ptr is null or we are unable to determine the allocation size, then 0 is returned. +size_t GetAllocationSize(const void* ptr); + +// Returns the size of the chunk that will actually be allocated +// when requesting an allocation of given #size. This is never less than #size. +size_t GetAllocationSize(size_t size); + +//////////////////////////////////////////////////////////////////////////////// +// Memory tagging API +// +// Each allocation can be tagged with a number (from 1 to MaxMemoryTag). +// Setting this to NullMemoryTag disables tagging. +// Internally, YTAlloc tracks the number of bytes used by each tag. +// +// Tagged allocations are somewhat slower. Others (large and huge) are not affected +// (but for these performance implications are negligible anyway). +// +// The current memory tag used for allocations is stored in TLS. + +using TMemoryTag = ui32; +constexpr TMemoryTag NullMemoryTag = 0; +constexpr TMemoryTag MaxMemoryTag = (1ULL << 22) - 1; + +// Updates the current tag value in TLS. +void SetCurrentMemoryTag(TMemoryTag tag); + +// Returns the current tag value from TLS. +TMemoryTag GetCurrentMemoryTag(); + +// Returns the memory usage for a given tag. +// The value is somewhat approxiate and racy. +size_t GetMemoryUsageForTag(TMemoryTag tag); + +// A batched version of GetMemoryUsageForTag. +void GetMemoryUsageForTags(const TMemoryTag* tags, size_t count, size_t* results); + +//////////////////////////////////////////////////////////////////////////////// +// Memory zone API +// +// Each allocation is either in the "normal zone" or "undumpable zone". +// The latter indicates that this memory region will be excluded from a coredump +// should it happen. +// +// The current zone used for allocations is stored in TLS. + +// Memory zone is used to pass hint to the allocator. +DEFINE_ENUM(EMemoryZone, + ((Unknown) (-1)) // not a valid zone + ((Normal) ( 0)) // default memory type + ((Undumpable) ( 1)) // memory is omitted from the core dump +); + +// Updates the current zone in TLS. +void SetCurrentMemoryZone(EMemoryZone zone); + +// Returns the current zone from TLS. +EMemoryZone GetCurrentMemoryZone(); + +// Returns the zone where #ptr resides; +// EMemoryZone::Invalid indicates that #ptr is outside of any recognized memory zone. +EMemoryZone GetAllocationMemoryZone(const void* ptr); + +//////////////////////////////////////////////////////////////////////////////// +// When a "timing event" (hiccup) occurs during an allocation, +// YTAlloc records this event and captures the current fiber id. +// The latter is provided externally by calling SetCurrentFiberId. +// +// This may be helpful to correlate various application-level timings +// with internal events in YTAlloc. +// +// The current fiber id is stored in TLS. + +using TFiberId = ui64; + +// Updates the current fiber id in TLS. +void SetCurrentFiberId(TFiberId id); + +// Returns the currently assinged fiber id from TLS. +TFiberId GetCurrentFiberId(); + +//////////////////////////////////////////////////////////////////////////////// +// Logging + +DEFINE_ENUM(ELogEventSeverity, + (Debug) + (Info) + (Warning) + (Error) +); + +struct TLogEvent +{ + ELogEventSeverity Severity; + TStringBuf Message; +}; + +using TLogHandler = void(*)(const TLogEvent& event); + +// Sets the handler to be invoked for each log event produced by YTAlloc. +// Can be called multiple times (but calls to the previous incarnations of the handler +// are racy). +void EnableLogging(TLogHandler logHandler); + +//////////////////////////////////////////////////////////////////////////////// +// Backtraces + +using TBacktraceProvider = int(*)(void** frames, int maxFrames, int skipFrames); + +// Sets the provider used for collecting backtraces when allocation profiling +// is turned ON. Can be called multiple times (but calls to the previous +// incarnations of the provider are racy). +void SetBacktraceProvider(TBacktraceProvider provider); + +using TBacktraceFormatter = TString(*)(const void* const* frames, int frameCount); // Sets the callback used for formatting backtraces during large arena mmap calls // to help detect memory leaks. Can be called multiple times (but calls to the // previous incarnations of the provider are racy). void SetBacktraceFormatter(TBacktraceFormatter provider); -//////////////////////////////////////////////////////////////////////////////// -// Misc - -//! Tries to mlock all opened file mappings of the current process. -//! Typically invoked on application startup to lock all binaries in memory -//! and prevent executable code and static data to be paged out -//! causing latency spikes. +//////////////////////////////////////////////////////////////////////////////// +// Misc + +//! Tries to mlock all opened file mappings of the current process. +//! Typically invoked on application startup to lock all binaries in memory +//! and prevent executable code and static data to be paged out +//! causing latency spikes. void MlockFileMappings(bool populate = true); - -//////////////////////////////////////////////////////////////////////////////// -// Configuration API - -// Calling this function enables periodic calls to madvise(ADV_STOCKPILE); -// cf. https://st.yandex-team.ru/KERNEL-186 -void EnableStockpile(); - -// Sets the interval between madvise(ADV_STOCKPILE) calls. -// Only makes sense if stockpile was enabled. -void SetStockpileInterval(TDuration value); - -// Sets the number of threads to be invoking madvise(ADV_STOCKPILE). -// This call should be made before calling #EnableStockpile. -void SetStockpileThreadCount(int value); - -// Sets the size passsed to madvise(ADV_STOCKPILE) calls. -// Only makes sense if stockpile was enabled. -void SetStockpileSize(size_t value); - -// For large blobs, YTAlloc keeps at least -// LargeUnreclaimableCoeff * TotalLargeBytesUsed clamped to range -// [MinLargeUnreclaimableBytes, MaxLargeUnreclaimableBytes] -// bytes of pooled (unreclaimable) memory. -void SetLargeUnreclaimableCoeff(double value); -void SetMinLargeUnreclaimableBytes(size_t value); -void SetMaxLargeUnreclaimableBytes(size_t value); - -// When a syscall (mmap, munmap, or madvise) or an internal lock acquisition -// takes longer then the configured time, a "timing event" is recorded. -void SetTimingEventThreshold(TDuration value); - -// Toggles the global allocation profiling knob (OFF by default). -// For profiled allocations, YTAlloc collects (see #SetBacktraceProvider) and aggregates their -// backtraces. -void SetAllocationProfilingEnabled(bool value); - -// Determines the fraction of allocations to be sampled for profiling. -void SetAllocationProfilingSamplingRate(double rate); - -// Controls if small allocations of a given rank are profiled (OFF by default). -void SetSmallArenaAllocationProfilingEnabled(size_t rank, bool value); - -// Controls if large allocations of a given rank are profiled (OFF by default). -void SetLargeArenaAllocationProfilingEnabled(size_t rank, bool value); - -// Controls the depth of the backtraces to collect. Deeper backtraces -// take more time and affect the program performance. -void SetProfilingBacktraceDepth(int depth); - -// Controls the minimum number of bytes a certain backtrace must -// allocate to appear in profiling reports. -void SetMinProfilingBytesUsedToReport(size_t size); - -// If set to true (default), YTAlloc uses madvise with MADV_DONTNEED to release unused large blob pages -// (slower but leads to more predicable RSS values); -// if false then MADV_FREE is used instead, if available -// (faster but RSS may get stuck arbitrary higher than the actual usage as long -// as no memory pressure is applied). -void SetEnableEagerMemoryRelease(bool value); - -// If set to true, YTAlloc uses madvise with MADV_POPULATE to prefault freshly acclaimed pages. -// Otherwise (this is the default), these pages are prefaulted with linear memory access. -// See https://st.yandex-team.ru/KERNEL-185. -void SetEnableMadvisePopulate(bool value); - -//////////////////////////////////////////////////////////////////////////////// -// Statistics API - -DEFINE_ENUM(EBasicCounter, - (BytesAllocated) - (BytesFreed) - (BytesUsed) -); - -using ESystemCounter = EBasicCounter; -using ESmallCounter = EBasicCounter; -using ELargeCounter = EBasicCounter; -using EUndumpableCounter = EBasicCounter; - -DEFINE_ENUM(ESmallArenaCounter, - (PagesMapped) - (BytesMapped) - (PagesCommitted) - (BytesCommitted) -); - -DEFINE_ENUM(ELargeArenaCounter, - (BytesSpare) - (BytesOverhead) - (BlobsAllocated) - (BlobsFreed) - (BlobsUsed) - (BytesAllocated) - (BytesFreed) - (BytesUsed) - (ExtentsAllocated) - (PagesMapped) - (BytesMapped) - (PagesPopulated) - (BytesPopulated) - (PagesReleased) - (BytesReleased) - (PagesCommitted) - (BytesCommitted) - (OverheadBytesReclaimed) - (SpareBytesReclaimed) -); - -DEFINE_ENUM(EHugeCounter, - (BytesAllocated) - (BytesFreed) - (BytesUsed) - (BlobsAllocated) - (BlobsFreed) - (BlobsUsed) -); - -DEFINE_ENUM(ETotalCounter, - (BytesAllocated) - (BytesFreed) - (BytesUsed) - (BytesCommitted) - (BytesUnaccounted) -); - -// Returns statistics for all user allocations. -TEnumIndexedVector<ETotalCounter, ssize_t> GetTotalAllocationCounters(); - -// Returns statistics for small allocations; these are included into total statistics. -TEnumIndexedVector<ESmallCounter, ssize_t> GetSmallAllocationCounters(); - -// Returns statistics for large allocations; these are included into total statistics. -TEnumIndexedVector<ELargeCounter, ssize_t> GetLargeAllocationCounters(); - -// Returns per-arena statistics for small allocations; these are included into total statistics. -std::array<TEnumIndexedVector<ESmallArenaCounter, ssize_t>, SmallRankCount> GetSmallArenaAllocationCounters(); - -// Returns per-arena statistics for large allocations; these are included into total statistics. -std::array<TEnumIndexedVector<ELargeArenaCounter, ssize_t>, LargeRankCount> GetLargeArenaAllocationCounters(); - -// Returns statistics for huge allocations; these are included into total statistics. -TEnumIndexedVector<EHugeCounter, ssize_t> GetHugeAllocationCounters(); - -// Returns statistics for all system allocations; these are not included into total statistics. -TEnumIndexedVector<ESystemCounter, ssize_t> GetSystemAllocationCounters(); - -// Returns statistics for undumpable allocations. -TEnumIndexedVector<EUndumpableCounter, ssize_t> GetUndumpableAllocationCounters(); - -DEFINE_ENUM(ETimingEventType, - (Mmap) - (Munmap) - (MadvisePopulate) - (MadviseFree) - (MadviseDontNeed) - (Locking) - (Prefault) + +//////////////////////////////////////////////////////////////////////////////// +// Configuration API + +// Calling this function enables periodic calls to madvise(ADV_STOCKPILE); +// cf. https://st.yandex-team.ru/KERNEL-186 +void EnableStockpile(); + +// Sets the interval between madvise(ADV_STOCKPILE) calls. +// Only makes sense if stockpile was enabled. +void SetStockpileInterval(TDuration value); + +// Sets the number of threads to be invoking madvise(ADV_STOCKPILE). +// This call should be made before calling #EnableStockpile. +void SetStockpileThreadCount(int value); + +// Sets the size passsed to madvise(ADV_STOCKPILE) calls. +// Only makes sense if stockpile was enabled. +void SetStockpileSize(size_t value); + +// For large blobs, YTAlloc keeps at least +// LargeUnreclaimableCoeff * TotalLargeBytesUsed clamped to range +// [MinLargeUnreclaimableBytes, MaxLargeUnreclaimableBytes] +// bytes of pooled (unreclaimable) memory. +void SetLargeUnreclaimableCoeff(double value); +void SetMinLargeUnreclaimableBytes(size_t value); +void SetMaxLargeUnreclaimableBytes(size_t value); + +// When a syscall (mmap, munmap, or madvise) or an internal lock acquisition +// takes longer then the configured time, a "timing event" is recorded. +void SetTimingEventThreshold(TDuration value); + +// Toggles the global allocation profiling knob (OFF by default). +// For profiled allocations, YTAlloc collects (see #SetBacktraceProvider) and aggregates their +// backtraces. +void SetAllocationProfilingEnabled(bool value); + +// Determines the fraction of allocations to be sampled for profiling. +void SetAllocationProfilingSamplingRate(double rate); + +// Controls if small allocations of a given rank are profiled (OFF by default). +void SetSmallArenaAllocationProfilingEnabled(size_t rank, bool value); + +// Controls if large allocations of a given rank are profiled (OFF by default). +void SetLargeArenaAllocationProfilingEnabled(size_t rank, bool value); + +// Controls the depth of the backtraces to collect. Deeper backtraces +// take more time and affect the program performance. +void SetProfilingBacktraceDepth(int depth); + +// Controls the minimum number of bytes a certain backtrace must +// allocate to appear in profiling reports. +void SetMinProfilingBytesUsedToReport(size_t size); + +// If set to true (default), YTAlloc uses madvise with MADV_DONTNEED to release unused large blob pages +// (slower but leads to more predicable RSS values); +// if false then MADV_FREE is used instead, if available +// (faster but RSS may get stuck arbitrary higher than the actual usage as long +// as no memory pressure is applied). +void SetEnableEagerMemoryRelease(bool value); + +// If set to true, YTAlloc uses madvise with MADV_POPULATE to prefault freshly acclaimed pages. +// Otherwise (this is the default), these pages are prefaulted with linear memory access. +// See https://st.yandex-team.ru/KERNEL-185. +void SetEnableMadvisePopulate(bool value); + +//////////////////////////////////////////////////////////////////////////////// +// Statistics API + +DEFINE_ENUM(EBasicCounter, + (BytesAllocated) + (BytesFreed) + (BytesUsed) +); + +using ESystemCounter = EBasicCounter; +using ESmallCounter = EBasicCounter; +using ELargeCounter = EBasicCounter; +using EUndumpableCounter = EBasicCounter; + +DEFINE_ENUM(ESmallArenaCounter, + (PagesMapped) + (BytesMapped) + (PagesCommitted) + (BytesCommitted) +); + +DEFINE_ENUM(ELargeArenaCounter, + (BytesSpare) + (BytesOverhead) + (BlobsAllocated) + (BlobsFreed) + (BlobsUsed) + (BytesAllocated) + (BytesFreed) + (BytesUsed) + (ExtentsAllocated) + (PagesMapped) + (BytesMapped) + (PagesPopulated) + (BytesPopulated) + (PagesReleased) + (BytesReleased) + (PagesCommitted) + (BytesCommitted) + (OverheadBytesReclaimed) + (SpareBytesReclaimed) +); + +DEFINE_ENUM(EHugeCounter, + (BytesAllocated) + (BytesFreed) + (BytesUsed) + (BlobsAllocated) + (BlobsFreed) + (BlobsUsed) +); + +DEFINE_ENUM(ETotalCounter, + (BytesAllocated) + (BytesFreed) + (BytesUsed) + (BytesCommitted) + (BytesUnaccounted) +); + +// Returns statistics for all user allocations. +TEnumIndexedVector<ETotalCounter, ssize_t> GetTotalAllocationCounters(); + +// Returns statistics for small allocations; these are included into total statistics. +TEnumIndexedVector<ESmallCounter, ssize_t> GetSmallAllocationCounters(); + +// Returns statistics for large allocations; these are included into total statistics. +TEnumIndexedVector<ELargeCounter, ssize_t> GetLargeAllocationCounters(); + +// Returns per-arena statistics for small allocations; these are included into total statistics. +std::array<TEnumIndexedVector<ESmallArenaCounter, ssize_t>, SmallRankCount> GetSmallArenaAllocationCounters(); + +// Returns per-arena statistics for large allocations; these are included into total statistics. +std::array<TEnumIndexedVector<ELargeArenaCounter, ssize_t>, LargeRankCount> GetLargeArenaAllocationCounters(); + +// Returns statistics for huge allocations; these are included into total statistics. +TEnumIndexedVector<EHugeCounter, ssize_t> GetHugeAllocationCounters(); + +// Returns statistics for all system allocations; these are not included into total statistics. +TEnumIndexedVector<ESystemCounter, ssize_t> GetSystemAllocationCounters(); + +// Returns statistics for undumpable allocations. +TEnumIndexedVector<EUndumpableCounter, ssize_t> GetUndumpableAllocationCounters(); + +DEFINE_ENUM(ETimingEventType, + (Mmap) + (Munmap) + (MadvisePopulate) + (MadviseFree) + (MadviseDontNeed) + (Locking) + (Prefault) (FilePrefault) -); - -struct TTimingEventCounters -{ - // Number of events happened since start. - size_t Count = 0; - // Total size of memory blocks involved in these events (if applicable). - size_t Size = 0; -}; - -// Returns statistics for timing events happened since start. -// See SetTimingEventThreshold. -TEnumIndexedVector<ETimingEventType, TTimingEventCounters> GetTimingEventCounters(); - -//////////////////////////////////////////////////////////////////////////////// - -// We never collect backtraces deeper than this limit. -constexpr int MaxAllocationProfilingBacktraceDepth = 16; - -struct TBacktrace -{ - int FrameCount; - std::array<void*, MaxAllocationProfilingBacktraceDepth> Frames; -}; - -struct TProfiledAllocation -{ - TBacktrace Backtrace; - TEnumIndexedVector<EBasicCounter, ssize_t> Counters; -}; - -// Returns statistics for profiled allocations (available when allocation -// profiling is ON). Allocations are grouped by backtrace; for each backtrace -// we provide the counters indicating the number of allocated, freed, and used bytes. -// To appear here, used bytes counter must be at least the value configured -// via SetMinProfilingBytesUsedToReport. -std::vector<TProfiledAllocation> GetProfiledAllocationStatistics(); - -//////////////////////////////////////////////////////////////////////////////// - -//! An RAII guard for setting the current memory tag in a scope. -class TMemoryTagGuard -{ -public: - TMemoryTagGuard(); - explicit TMemoryTagGuard(TMemoryTag tag); - - TMemoryTagGuard(const TMemoryTagGuard& other) = delete; - TMemoryTagGuard(TMemoryTagGuard&& other); - - ~TMemoryTagGuard(); - -private: - bool Active_; - TMemoryTag PreviousTag_; -}; - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NYTAlloc - -#define YT_ALLOC_INL_H_ -#include "ytalloc-inl.h" -#undef YT_ALLOC_INL_H_ +); + +struct TTimingEventCounters +{ + // Number of events happened since start. + size_t Count = 0; + // Total size of memory blocks involved in these events (if applicable). + size_t Size = 0; +}; + +// Returns statistics for timing events happened since start. +// See SetTimingEventThreshold. +TEnumIndexedVector<ETimingEventType, TTimingEventCounters> GetTimingEventCounters(); + +//////////////////////////////////////////////////////////////////////////////// + +// We never collect backtraces deeper than this limit. +constexpr int MaxAllocationProfilingBacktraceDepth = 16; + +struct TBacktrace +{ + int FrameCount; + std::array<void*, MaxAllocationProfilingBacktraceDepth> Frames; +}; + +struct TProfiledAllocation +{ + TBacktrace Backtrace; + TEnumIndexedVector<EBasicCounter, ssize_t> Counters; +}; + +// Returns statistics for profiled allocations (available when allocation +// profiling is ON). Allocations are grouped by backtrace; for each backtrace +// we provide the counters indicating the number of allocated, freed, and used bytes. +// To appear here, used bytes counter must be at least the value configured +// via SetMinProfilingBytesUsedToReport. +std::vector<TProfiledAllocation> GetProfiledAllocationStatistics(); + +//////////////////////////////////////////////////////////////////////////////// + +//! An RAII guard for setting the current memory tag in a scope. +class TMemoryTagGuard +{ +public: + TMemoryTagGuard(); + explicit TMemoryTagGuard(TMemoryTag tag); + + TMemoryTagGuard(const TMemoryTagGuard& other) = delete; + TMemoryTagGuard(TMemoryTagGuard&& other); + + ~TMemoryTagGuard(); + +private: + bool Active_; + TMemoryTag PreviousTag_; +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYTAlloc + +#define YT_ALLOC_INL_H_ +#include "ytalloc-inl.h" +#undef YT_ALLOC_INL_H_ diff --git a/library/cpp/ytalloc/ya.make b/library/cpp/ytalloc/ya.make index 97aa73c135..f3495efb13 100644 --- a/library/cpp/ytalloc/ya.make +++ b/library/cpp/ytalloc/ya.make @@ -1,17 +1,17 @@ -OWNER(g:yt) - -IF (NOT OS_DARWIN AND NOT SANITIZER_TYPE) - SET(YT_ALLOC_ENABLED yes) -ENDIF() - -RECURSE( - api - impl -) - -IF (YT_ALLOC_ENABLED) - RECURSE( - ut +OWNER(g:yt) + +IF (NOT OS_DARWIN AND NOT SANITIZER_TYPE) + SET(YT_ALLOC_ENABLED yes) +ENDIF() + +RECURSE( + api + impl +) + +IF (YT_ALLOC_ENABLED) + RECURSE( + ut benchmarks - ) -ENDIF() + ) +ENDIF() diff --git a/util/digest/numeric.h b/util/digest/numeric.h index e20bd908e4..70abda0c9f 100644 --- a/util/digest/numeric.h +++ b/util/digest/numeric.h @@ -73,9 +73,9 @@ static constexpr size_t NumericHash(T t) noexcept { using TCvt = TFixedWidthUnsignedInt<T>; union Y_HIDDEN { - T t; + T t; TCvt cvt; - } u{t}; + } u{t}; return (size_t)IntHash(u.cvt); } diff --git a/util/generic/hash_set.h b/util/generic/hash_set.h index e8088cf23b..050d291c43 100644 --- a/util/generic/hash_set.h +++ b/util/generic/hash_set.h @@ -399,10 +399,10 @@ public: iterator insert(const value_type& obj) { return rep.insert_equal(obj); } - template <typename... Args> - iterator emplace(Args&&... args) { - return rep.emplace_equal(std::forward<Args>(args)...); - } + template <typename... Args> + iterator emplace(Args&&... args) { + return rep.emplace_equal(std::forward<Args>(args)...); + } template <class InputIterator> void insert(InputIterator f, InputIterator l) { rep.insert_equal(f, l); diff --git a/util/generic/hash_ut.cpp b/util/generic/hash_ut.cpp index 0551d58770..ddb2e8f825 100644 --- a/util/generic/hash_ut.cpp +++ b/util/generic/hash_ut.cpp @@ -2,7 +2,7 @@ #include "vector.h" #include "hash_set.h" -#include <library/cpp/testing/common/probe.h> +#include <library/cpp/testing/common/probe.h> #include <library/cpp/testing/unittest/registar.h> #include <utility> @@ -28,7 +28,7 @@ class THashTest: public TTestBase { UNIT_TEST(TestHMSetSize); UNIT_TEST(TestHMSet1); UNIT_TEST(TestHMSetEqualityOperator); - UNIT_TEST(TestHMSetEmplace); + UNIT_TEST(TestHMSetEmplace); UNIT_TEST(TestInsertErase); UNIT_TEST(TestResizeOnInsertSmartPtrBug) UNIT_TEST(TestEmpty); @@ -79,7 +79,7 @@ protected: void TestHMSetSize(); void TestHMSet1(); void TestHMSetEqualityOperator(); - void TestHMSetEmplace(); + void TestHMSetEmplace(); void TestInsertErase(); void TestResizeOnInsertSmartPtrBug(); void TestEmpty(); @@ -554,56 +554,56 @@ void THashTest::TestHMSetEqualityOperator() { UNIT_ASSERT(!(c3 == base)); } -void THashTest::TestHMSetEmplace() { - class TKey: public NTesting::TProbe { - public: - TKey(NTesting::TProbeState* state, int key) - : TProbe(state) +void THashTest::TestHMSetEmplace() { + class TKey: public NTesting::TProbe { + public: + TKey(NTesting::TProbeState* state, int key) + : TProbe(state) , Key_(key) { } - - operator size_t() const { + + operator size_t() const { return THash<int>()(Key_); - } - - bool operator==(const TKey& other) const { + } + + bool operator==(const TKey& other) const { return Key_ == other.Key_; - } - - private: + } + + private: int Key_; - }; - - NTesting::TProbeState state; - - { - THashMultiSet<TKey> c; - c.emplace(&state, 1); - c.emplace(&state, 1); - c.emplace(&state, 2); - - UNIT_ASSERT_EQUAL(state.CopyAssignments, 0); - UNIT_ASSERT_EQUAL(state.MoveAssignments, 0); - UNIT_ASSERT_EQUAL(state.Constructors, 3); - UNIT_ASSERT_EQUAL(state.MoveConstructors, 0); - - UNIT_ASSERT_EQUAL(c.count(TKey(&state, 1)), 2); - UNIT_ASSERT_EQUAL(c.count(TKey(&state, 2)), 1); - UNIT_ASSERT_EQUAL(c.count(TKey(&state, 3)), 0); - - UNIT_ASSERT_EQUAL(state.Constructors, 6); - UNIT_ASSERT_EQUAL(state.Destructors, 3); - } - - UNIT_ASSERT_EQUAL(state.CopyAssignments, 0); - UNIT_ASSERT_EQUAL(state.MoveAssignments, 0); - UNIT_ASSERT_EQUAL(state.CopyConstructors, 0); - UNIT_ASSERT_EQUAL(state.MoveConstructors, 0); - UNIT_ASSERT_EQUAL(state.Constructors, 6); - UNIT_ASSERT_EQUAL(state.Destructors, 6); -} - + }; + + NTesting::TProbeState state; + + { + THashMultiSet<TKey> c; + c.emplace(&state, 1); + c.emplace(&state, 1); + c.emplace(&state, 2); + + UNIT_ASSERT_EQUAL(state.CopyAssignments, 0); + UNIT_ASSERT_EQUAL(state.MoveAssignments, 0); + UNIT_ASSERT_EQUAL(state.Constructors, 3); + UNIT_ASSERT_EQUAL(state.MoveConstructors, 0); + + UNIT_ASSERT_EQUAL(c.count(TKey(&state, 1)), 2); + UNIT_ASSERT_EQUAL(c.count(TKey(&state, 2)), 1); + UNIT_ASSERT_EQUAL(c.count(TKey(&state, 3)), 0); + + UNIT_ASSERT_EQUAL(state.Constructors, 6); + UNIT_ASSERT_EQUAL(state.Destructors, 3); + } + + UNIT_ASSERT_EQUAL(state.CopyAssignments, 0); + UNIT_ASSERT_EQUAL(state.MoveAssignments, 0); + UNIT_ASSERT_EQUAL(state.CopyConstructors, 0); + UNIT_ASSERT_EQUAL(state.MoveConstructors, 0); + UNIT_ASSERT_EQUAL(state.Constructors, 6); + UNIT_ASSERT_EQUAL(state.Destructors, 6); +} + void THashTest::TestInsertErase() { using hmap = THashMap<TString, size_t, THash<TString>, TEqualTo<TString>>; using val_type = hmap::value_type; diff --git a/util/system/spinlock.h b/util/system/spinlock.h index af2630890a..f2319d9a66 100644 --- a/util/system/spinlock.h +++ b/util/system/spinlock.h @@ -10,7 +10,7 @@ protected: } public: - inline bool IsLocked() const noexcept { + inline bool IsLocked() const noexcept { return AtomicGet(Val_); } diff --git a/ydb/core/mon_alloc/monitor.cpp b/ydb/core/mon_alloc/monitor.cpp index 8afc7852c9..5f7c9fd7c5 100644 --- a/ydb/core/mon_alloc/monitor.cpp +++ b/ydb/core/mon_alloc/monitor.cpp @@ -13,7 +13,7 @@ #include <library/cpp/malloc/api/malloc.h> #include <library/cpp/monlib/dynamic_counters/counters.h> #include <library/cpp/monlib/service/pages/templates.h> -#include <library/cpp/ytalloc/api/ytalloc.h> +#include <library/cpp/ytalloc/api/ytalloc.h> #include <util/datetime/base.h> #include <util/generic/hash.h> diff --git a/ydb/core/mon_alloc/profiler.cpp b/ydb/core/mon_alloc/profiler.cpp index bfff45c180..f9297d9c1c 100644 --- a/ydb/core/mon_alloc/profiler.cpp +++ b/ydb/core/mon_alloc/profiler.cpp @@ -12,7 +12,7 @@ #if defined(PROFILE_MEMORY_ALLOCATIONS) #include <library/cpp/lfalloc/alloc_profiler/profiler.h> -#include <library/cpp/ytalloc/api/ytalloc.h> +#include <library/cpp/ytalloc/api/ytalloc.h> #endif #if defined(_linux_) && !defined(WITH_VALGRIND) diff --git a/ydb/core/mon_alloc/stats.cpp b/ydb/core/mon_alloc/stats.cpp index 050822241c..856614f6c2 100644 --- a/ydb/core/mon_alloc/stats.cpp +++ b/ydb/core/mon_alloc/stats.cpp @@ -9,7 +9,7 @@ #include <library/cpp/lfalloc/dbg_info/dbg_info.h> #include <library/cpp/malloc/api/malloc.h> #include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/ytalloc/api/ytalloc.h> +#include <library/cpp/ytalloc/api/ytalloc.h> #include <util/datetime/base.h> diff --git a/ydb/core/mon_alloc/ya.make b/ydb/core/mon_alloc/ya.make index 972ea082f3..8bc5902477 100644 --- a/ydb/core/mon_alloc/ya.make +++ b/ydb/core/mon_alloc/ya.make @@ -22,7 +22,7 @@ PEERDIR( library/cpp/lfalloc/dbg_info library/cpp/malloc/api library/cpp/monlib/service/pages - library/cpp/ytalloc/api + library/cpp/ytalloc/api ydb/core/base ydb/core/control ) |