diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-05-07 23:59:20 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-05-08 00:06:27 +0300 |
commit | cb0413bfb0b157f87c36849ff8bf4786198936ee (patch) | |
tree | febe32dfb83220412fbcd27936b4bf73bfe2511b | |
parent | ef1337c1cae8e54957d58a069cb0578a5a82f04f (diff) | |
download | ydb-cb0413bfb0b157f87c36849ff8bf4786198936ee.tar.gz |
Intermediate changes
-rw-r--r-- | library/cpp/yt/memory/erased_storage-inl.h | 42 | ||||
-rw-r--r-- | library/cpp/yt/memory/erased_storage.h | 61 | ||||
-rw-r--r-- | library/cpp/yt/memory/unittests/erased_storage_ut.cpp | 130 | ||||
-rw-r--r-- | library/cpp/yt/memory/unittests/ya.make | 3 |
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 ) |