aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-05-07 23:59:20 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-05-08 00:06:27 +0300
commitcb0413bfb0b157f87c36849ff8bf4786198936ee (patch)
treefebe32dfb83220412fbcd27936b4bf73bfe2511b
parentef1337c1cae8e54957d58a069cb0578a5a82f04f (diff)
downloadydb-cb0413bfb0b157f87c36849ff8bf4786198936ee.tar.gz
Intermediate changes
-rw-r--r--library/cpp/yt/memory/erased_storage-inl.h42
-rw-r--r--library/cpp/yt/memory/erased_storage.h61
-rw-r--r--library/cpp/yt/memory/unittests/erased_storage_ut.cpp130
-rw-r--r--library/cpp/yt/memory/unittests/ya.make3
4 files changed, 236 insertions, 0 deletions
diff --git a/library/cpp/yt/memory/erased_storage-inl.h b/library/cpp/yt/memory/erased_storage-inl.h
new file mode 100644
index 0000000000..e4dc148e11
--- /dev/null
+++ b/library/cpp/yt/memory/erased_storage-inl.h
@@ -0,0 +1,42 @@
+#ifndef ERASED_STORAGE_INL_H_
+#error "Direct inclusion of this file is not allowed, include erased_storage.h"
+// For the sake of sane code completion.
+#include "erased_storage.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <CTriviallyErasable TDecayedConcrete>
+TErasedStorage::TErasedStorage(TDecayedConcrete concrete) noexcept
+{
+ std::construct_at(
+ &AsConcrete<TDecayedConcrete>(),
+ concrete);
+}
+
+template <CTriviallyErasable TDecayedConcrete>
+TDecayedConcrete& TErasedStorage::AsConcrete() & noexcept
+{
+ using TPtr = TDecayedConcrete*;
+ return *std::launder(reinterpret_cast<TPtr>(&Bytes_));
+}
+
+template <CTriviallyErasable TDecayedConcrete>
+const TDecayedConcrete& TErasedStorage::AsConcrete() const & noexcept
+{
+ using TPtr = const TDecayedConcrete*;
+ return *std::launder(reinterpret_cast<TPtr>(&Bytes_));
+}
+
+template <CTriviallyErasable TDecayedConcrete>
+TDecayedConcrete&& TErasedStorage::AsConcrete() && noexcept
+{
+ using TPtr = TDecayedConcrete*;
+ return std::move(*std::launder(reinterpret_cast<TPtr>(&Bytes_)));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/erased_storage.h b/library/cpp/yt/memory/erased_storage.h
new file mode 100644
index 0000000000..8e85430d0b
--- /dev/null
+++ b/library/cpp/yt/memory/erased_storage.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <concepts>
+#include <memory>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+constexpr size_t ErasedStorageMaxByteSize = 32;
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TErasedStorage;
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+concept CTriviallyErasable =
+ std::default_initializable<T> &&
+ std::is_trivially_destructible_v<T> &&
+ std::is_trivially_copyable_v<T> &&
+ (sizeof(T) <= ErasedStorageMaxByteSize) &&
+ (alignof(T) <= ErasedStorageMaxByteSize) &&
+ !std::is_reference_v<T> &&
+ !std::same_as<T, TErasedStorage>;
+
+////////////////////////////////////////////////////////////////////////////////
+
+// This class does not call dtor of erased object
+// thus we require trivial destructability.
+class TErasedStorage
+{
+public:
+ template <CTriviallyErasable TDecayedConcrete>
+ explicit TErasedStorage(TDecayedConcrete concrete) noexcept;
+
+ TErasedStorage(const TErasedStorage& other) = default;
+ TErasedStorage& operator=(const TErasedStorage& other) = default;
+
+ template <CTriviallyErasable TDecayedConcrete>
+ TDecayedConcrete& AsConcrete() & noexcept;
+
+ template <CTriviallyErasable TDecayedConcrete>
+ const TDecayedConcrete& AsConcrete() const & noexcept;
+
+ template <CTriviallyErasable TDecayedConcrete>
+ TDecayedConcrete&& AsConcrete() && noexcept;
+
+private:
+ // NB(arkady-e1ppa): aligned_storage is deprecated.
+ alignas(ErasedStorageMaxByteSize) std::byte Bytes_[ErasedStorageMaxByteSize];
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define ERASED_STORAGE_INL_H_
+#include "erased_storage-inl.h"
+#undef ERASED_STORAGE_INL_H_
diff --git a/library/cpp/yt/memory/unittests/erased_storage_ut.cpp b/library/cpp/yt/memory/unittests/erased_storage_ut.cpp
new file mode 100644
index 0000000000..194c8e7fce
--- /dev/null
+++ b/library/cpp/yt/memory/unittests/erased_storage_ut.cpp
@@ -0,0 +1,130 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/memory/erased_storage.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <library/cpp/yt/misc/guid.h>
+
+#include <util/generic/string.h>
+#include <util/system/types.h>
+
+#include <vector>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TWithFieldInitalizer
+{
+ // NB: This class is not trivially default constructible.
+ int Field{};
+};
+
+static_assert(!std::is_trivially_default_constructible_v<TWithFieldInitalizer>);
+
+struct TCopyWithSideEffects
+{
+ TCopyWithSideEffects(const TCopyWithSideEffects&)
+ { }
+};
+
+static_assert(!std::is_trivially_copy_constructible_v<TCopyWithSideEffects>);
+
+struct TWithSubStruct
+{
+ TWithFieldInitalizer Field;
+};
+
+class TWithPrivateMembers
+{
+public:
+ TWithPrivateMembers() = default;
+
+private:
+ [[maybe_unused]] std::array<std::byte, 8> Data_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TErasedStorageTest, Types)
+{
+ static_assert(CTriviallyErasable<int>);
+ static_assert(CTriviallyErasable<i32>);
+ static_assert(CTriviallyErasable<i64>);
+ static_assert(CTriviallyErasable<i128>);
+ static_assert(CTriviallyErasable<std::array<i128, 2>>);
+ static_assert(CTriviallyErasable<TGuid>);
+ static_assert(CTriviallyErasable<void*>);
+ static_assert(CTriviallyErasable<double>);
+ static_assert(CTriviallyErasable<const char*>);
+ static_assert(CTriviallyErasable<TWithFieldInitalizer>);
+ static_assert(CTriviallyErasable<TWithSubStruct>);
+ static_assert(CTriviallyErasable<TWithPrivateMembers>);
+ static_assert(CTriviallyErasable<char[8]>);
+
+ static_assert(!CTriviallyErasable<TString>);
+ static_assert(!CTriviallyErasable<std::vector<int>>);
+ static_assert(!CTriviallyErasable<std::array<i128, 3>>);
+ static_assert(!CTriviallyErasable<int&>);
+ static_assert(!CTriviallyErasable<const int&>);
+ static_assert(!CTriviallyErasable<int&&>);
+ static_assert(!CTriviallyErasable<TCopyWithSideEffects>);
+}
+
+TEST(TErasedStorageTest, JustWorks)
+{
+ int var = 42;
+
+ TErasedStorage stor(var);
+ EXPECT_EQ(stor.AsConcrete<int>(), 42);
+
+ var = 66;
+ EXPECT_EQ(stor.AsConcrete<int>(), 42);
+}
+
+TEST(TErasedStorageTest, CopyAssign)
+{
+ int var = 42;
+ TErasedStorage stor(var);
+ EXPECT_EQ(stor.AsConcrete<int>(), 42);
+
+ {
+ int anotherVar = 77;
+ stor = TErasedStorage(anotherVar);
+ }
+ EXPECT_EQ(stor.AsConcrete<int>(), 77);
+
+ double thirdVar = 9.92145214;
+ stor = TErasedStorage(thirdVar);
+ EXPECT_DOUBLE_EQ(stor.AsConcrete<double>(), 9.92145214);
+}
+
+TEST(TErasedStorageTest, Pointer)
+{
+ TString message("Hello world");
+ TErasedStorage stor(&message);
+
+ EXPECT_EQ(*stor.AsConcrete<TString*>(), TString("Hello world"));
+ message = "Goodbye world";
+
+ EXPECT_EQ(*stor.AsConcrete<TString*>(), "Goodbye world");
+}
+
+TEST(TErasedStorageTest, MutateStorage)
+{
+ int var = 0;
+ TErasedStorage stor(var);
+ EXPECT_EQ(stor.AsConcrete<int>(), 0);
+
+ auto& ref = stor.AsConcrete<int>();
+ ref = 88;
+
+ EXPECT_EQ(stor.AsConcrete<int>(), 88);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/memory/unittests/ya.make b/library/cpp/yt/memory/unittests/ya.make
index 4c3e4d5303..d2f098fa72 100644
--- a/library/cpp/yt/memory/unittests/ya.make
+++ b/library/cpp/yt/memory/unittests/ya.make
@@ -11,6 +11,7 @@ SRCS(
chunked_memory_pool_ut.cpp
chunked_memory_pool_allocator_ut.cpp
chunked_memory_pool_output_ut.cpp
+ erased_storage_ut.cpp
free_list_ut.cpp
function_view_ut.cpp
intrusive_ptr_ut.cpp
@@ -27,6 +28,8 @@ ENDIF()
PEERDIR(
library/cpp/testing/gtest
+ library/cpp/int128
+ library/cpp/yt/misc
library/cpp/yt/memory
)