diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2021-12-23 00:47:15 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-01-10 21:48:11 +0000 |
commit | d9d35bd709dbe4a8981218c2f0500d6bcfecc329 (patch) | |
tree | 23152c9881b2439c9eb831c7df85aac40cdeb6b2 | |
parent | 53ff83884eb4e6595778ed895467b4d4b218566a (diff) | |
download | mongo-d9d35bd709dbe4a8981218c2f0500d6bcfecc329.tar.gz |
SERVER-62074 De-duplicate Decorable and DecorableCopyable
This change eliminates the DecorableCopyable type in favor of making
Decorable<D> copyable whenever D is copyable. With this change,
Decorable<D>::declareDecorable<T> requires T be copyable if D is copyable.
-rw-r--r-- | src/mongo/db/catalog/collection.h | 9 | ||||
-rw-r--r-- | src/mongo/util/decorable.h | 103 | ||||
-rw-r--r-- | src/mongo/util/decorable_test.cpp | 171 | ||||
-rw-r--r-- | src/mongo/util/decoration_container.h | 33 |
4 files changed, 105 insertions, 211 deletions
diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index 7ecc9e7bf08..e1c87fd14d3 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -161,9 +161,14 @@ private: * associated with all of the Collection instances for a collection, sharing whatever data may * decorate it across all point in time views of the collection. */ -class SharedCollectionDecorations : public Decorable<SharedCollectionDecorations> {}; +class SharedCollectionDecorations : public Decorable<SharedCollectionDecorations> { +public: + SharedCollectionDecorations() = default; + SharedCollectionDecorations(const SharedCollectionDecorations&) = delete; + SharedCollectionDecorations& operator=(const SharedCollectionDecorations&) = delete; +}; -class Collection : public DecorableCopyable<Collection> { +class Collection : public Decorable<Collection> { public: enum class StoreDeletedDoc { Off, On }; diff --git a/src/mongo/util/decorable.h b/src/mongo/util/decorable.h index 0b7a082cb17..721604bbe6d 100644 --- a/src/mongo/util/decorable.h +++ b/src/mongo/util/decorable.h @@ -62,19 +62,23 @@ #include "mongo/util/decoration_container.h" #include "mongo/util/decoration_registry.h" +#include <type_traits> namespace mongo { template <typename D> class Decorable { - Decorable(const Decorable&) = delete; - Decorable& operator=(const Decorable&) = delete; +private: + struct DecorationConstructionTag {}; public: template <typename T> class Decoration { public: Decoration() = delete; + Decoration(DecorationConstructionTag ignored, + typename DecorationContainer<D>::template DecorationDescriptorWithType<T> raw) + : _raw(std::move(raw)) {} T& operator()(D& d) const { return static_cast<Decorable&>(d)._decorations.getDecoration(this->_raw); @@ -118,104 +122,25 @@ public: return const_cast<Decorable*>(getOwnerImpl(const_cast<const T*>(t))); } - friend class Decorable; - - explicit Decoration( - typename DecorationContainer<D>::template DecorationDescriptorWithType<T> raw) - : _raw(std::move(raw)) {} - typename DecorationContainer<D>::template DecorationDescriptorWithType<T> _raw; }; template <typename T> static Decoration<T> declareDecoration() { - return Decoration<T>(getRegistry()->template declareDecoration<T>()); + if constexpr (std::is_copy_constructible_v<D> || std::is_copy_assignable_v<D>) { + return {DecorationConstructionTag{}, + getRegistry()->template declareDecorationCopyable<T>()}; + } else { + return {DecorationConstructionTag{}, getRegistry()->template declareDecoration<T>()}; + } } protected: Decorable() : _decorations(this, getRegistry()) {} ~Decorable() = default; -private: - static DecorationRegistry<D>* getRegistry() { - static DecorationRegistry<D>* theRegistry = new DecorationRegistry<D>(); - return theRegistry; - } - - DecorationContainer<D> _decorations; -}; - -template <typename D> -class DecorableCopyable { -public: - template <typename T> - class Decoration { - public: - Decoration() = delete; - - T& operator()(D& d) const { - return static_cast<DecorableCopyable&>(d)._decorations.getDecoration(this->_raw); - } - - T& operator()(D* const d) const { - return (*this)(*d); - } - - const T& operator()(const D& d) const { - return static_cast<const DecorableCopyable&>(d)._decorations.getDecoration(this->_raw); - } - - const T& operator()(const D* const d) const { - return (*this)(*d); - } - - const D* owner(const T* const t) const { - return static_cast<const D*>(getOwnerImpl(t)); - } - - D* owner(T* const t) const { - return static_cast<D*>(getOwnerImpl(t)); - } - - const D& owner(const T& t) const { - return *owner(&t); - } - - D& owner(T& t) const { - return *owner(&t); - } - - private: - const DecorableCopyable* getOwnerImpl(const T* const t) const { - return *reinterpret_cast<const DecorableCopyable* const*>( - reinterpret_cast<const unsigned char* const>(t) - _raw._raw._index); - } - - DecorableCopyable* getOwnerImpl(T* const t) const { - return const_cast<DecorableCopyable*>(getOwnerImpl(const_cast<const T*>(t))); - } - - friend class DecorableCopyable; - - explicit Decoration( - typename DecorationContainer<D>::template DecorationDescriptorWithType<T> raw) - : _raw(std::move(raw)) {} - - typename DecorationContainer<D>::template DecorationDescriptorWithType<T> _raw; - }; - - template <typename T> - static Decoration<T> declareDecoration() { - return Decoration<T>(getRegistry()->template declareDecorationCopyable<T>()); - } - -protected: - DecorableCopyable() : _decorations(this, getRegistry()) {} - ~DecorableCopyable() = default; - - DecorableCopyable(const DecorableCopyable& other) - : _decorations(this, getRegistry(), other._decorations) {} - DecorableCopyable& operator=(const DecorableCopyable& rhs) { + Decorable(const Decorable& other) : _decorations(this, getRegistry(), other._decorations) {} + Decorable& operator=(const Decorable& rhs) { getRegistry()->copyAssign(&_decorations, &rhs._decorations); return *this; } diff --git a/src/mongo/util/decorable_test.cpp b/src/mongo/util/decorable_test.cpp index cf53bf9ceb8..52d7d0f8387 100644 --- a/src/mongo/util/decorable_test.cpp +++ b/src/mongo/util/decorable_test.cpp @@ -29,12 +29,14 @@ #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest +#include <type_traits> #include "mongo/unittest/unittest.h" #include "mongo/util/assert_util.h" #include "mongo/util/decorable.h" namespace mongo { + namespace { static int numConstructedAs; @@ -70,104 +72,78 @@ public: int value; }; -template <template <typename...> typename DCT> -struct DecorableTester : mongo::unittest::Test { - template <typename... Args> - using DecorableMixInType = DCT<Args...>; - - static void simpleDecorationTest() { - struct MyDecorable : DecorableMixInType<MyDecorable> {}; - numConstructedAs = 0; - numDestructedAs = 0; - static const auto dd1 = MyDecorable::template declareDecoration<A>(); - static const auto dd2 = MyDecorable::template declareDecoration<A>(); - static const auto dd3 = MyDecorable::template declareDecoration<int>(); - - { - MyDecorable decorable1; - ASSERT_EQ(2, numConstructedAs); - ASSERT_EQ(0, numDestructedAs); - MyDecorable decorable2; - ASSERT_EQ(4, numConstructedAs); - ASSERT_EQ(0, numDestructedAs); - - ASSERT_EQ(0, dd1(decorable1).value); - ASSERT_EQ(0, dd2(decorable1).value); - ASSERT_EQ(0, dd1(decorable2).value); - ASSERT_EQ(0, dd2(decorable2).value); - ASSERT_EQ(0, dd3(decorable2)); - dd1(decorable1).value = 1; - dd2(decorable1).value = 2; - dd1(decorable2).value = 3; - dd2(decorable2).value = 4; - dd3(decorable2) = 5; - ASSERT_EQ(1, dd1(decorable1).value); - ASSERT_EQ(2, dd2(decorable1).value); - ASSERT_EQ(3, dd1(decorable2).value); - ASSERT_EQ(4, dd2(decorable2).value); - ASSERT_EQ(5, dd3(decorable2)); - } - ASSERT_EQ(4, numDestructedAs); - } - - static void testThrowingConstructor() { - struct MyDecorable : DecorableMixInType<MyDecorable> {}; - numConstructedAs = 0; - numDestructedAs = 0; - static const auto dd1 [[maybe_unused]] = MyDecorable::template declareDecoration<A>(); - static const auto dd2 [[maybe_unused]] = MyDecorable::template declareDecoration<ThrowA>(); - static const auto dd3 [[maybe_unused]] = MyDecorable::template declareDecoration<A>(); - - try { - MyDecorable decorable; - } catch (const AssertionException& ex) { - ASSERT_EQ(ErrorCodes::Unauthorized, ex.code()); - } - ASSERT_EQ(1, numConstructedAs); - ASSERT_EQ(1, numDestructedAs); - } - - static void testAlignment() { - struct MyDecorable : DecorableMixInType<MyDecorable> {}; - static const auto firstChar [[maybe_unused]] = - MyDecorable::template declareDecoration<char>(); - static const auto firstInt = MyDecorable::template declareDecoration<int>(); - static const auto secondChar [[maybe_unused]] = - MyDecorable::template declareDecoration<char>(); - static const auto secondInt = MyDecorable::template declareDecoration<int>(); - - MyDecorable d; - ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(&firstInt(d)) % alignof(int)); - ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(&secondInt(d)) % alignof(int)); - } +struct NonCopyableA { + A a; + NonCopyableA() = default; + NonCopyableA(const NonCopyableA&) = delete; + NonCopyableA& operator=(const NonCopyableA&) = delete; }; -using DecorableTest = DecorableTester<Decorable>; -using DecorableCopyableTest = DecorableTester<DecorableCopyable>; - -TEST_F(DecorableTest, SimpleDecoration) { - simpleDecorationTest(); -} +TEST(DecorableTest, SimpleDecoration) { + struct MyDecorable : Decorable<MyDecorable> {}; + numConstructedAs = 0; + numDestructedAs = 0; + static const auto dd1 = MyDecorable::template declareDecoration<A>(); + static const auto dd2 = MyDecorable::template declareDecoration<A>(); + static const auto dd3 = MyDecorable::template declareDecoration<int>(); -TEST_F(DecorableCopyableTest, SimpleDecoration) { - simpleDecorationTest(); + { + MyDecorable decorable1; + ASSERT_EQ(2, numConstructedAs); + ASSERT_EQ(0, numDestructedAs); + MyDecorable decorable2; + ASSERT_EQ(4, numConstructedAs); + ASSERT_EQ(0, numDestructedAs); + + ASSERT_EQ(0, dd1(decorable1).value); + ASSERT_EQ(0, dd2(decorable1).value); + ASSERT_EQ(0, dd1(decorable2).value); + ASSERT_EQ(0, dd2(decorable2).value); + ASSERT_EQ(0, dd3(decorable2)); + dd1(decorable1).value = 1; + dd2(decorable1).value = 2; + dd1(decorable2).value = 3; + dd2(decorable2).value = 4; + dd3(decorable2) = 5; + ASSERT_EQ(1, dd1(decorable1).value); + ASSERT_EQ(2, dd2(decorable1).value); + ASSERT_EQ(3, dd1(decorable2).value); + ASSERT_EQ(4, dd2(decorable2).value); + ASSERT_EQ(5, dd3(decorable2)); + } + ASSERT_EQ(4, numDestructedAs); } -TEST_F(DecorableTest, ThrowingConstructor) { - testThrowingConstructor(); +TEST(DecorableTest, ThrowingConstructor) { + struct MyDecorable : Decorable<MyDecorable> {}; + numConstructedAs = 0; + numDestructedAs = 0; + static const auto dd1 [[maybe_unused]] = MyDecorable::template declareDecoration<A>(); + static const auto dd2 [[maybe_unused]] = MyDecorable::template declareDecoration<ThrowA>(); + static const auto dd3 [[maybe_unused]] = MyDecorable::template declareDecoration<A>(); + + try { + MyDecorable decorable; + FAIL("didn't throw"); + } catch (const AssertionException& ex) { + ASSERT_EQ(ErrorCodes::Unauthorized, ex.code()); + } + ASSERT_EQ(1, numConstructedAs); + ASSERT_EQ(1, numDestructedAs); } -TEST_F(DecorableCopyableTest, ThrowingConstructor) { - testThrowingConstructor(); -} +TEST(DecorableTest, Alignment) { + struct MyDecorable : Decorable<MyDecorable> {}; + static const auto firstChar [[maybe_unused]] = MyDecorable::template declareDecoration<char>(); + static const auto firstInt = MyDecorable::template declareDecoration<int>(); + static const auto secondChar [[maybe_unused]] = MyDecorable::template declareDecoration<char>(); + static const auto secondInt = MyDecorable::template declareDecoration<int>(); -TEST_F(DecorableTest, Alignment) { - testAlignment(); + MyDecorable d; + ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(&firstInt(d)) % alignof(int)); + ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(&secondInt(d)) % alignof(int)); } -TEST_F(DecorableCopyableTest, Alignment) { - testAlignment(); -} struct DecoratedOwnerChecker : public Decorable<DecoratedOwnerChecker> { const char answer[100] = "The answer to life the universe and everything is 42"; }; @@ -233,12 +209,27 @@ TEST(DecorableTest, DecorationWithOwner) { ASSERT_EQ(&owner, &DecorationWithOwner::get.owner(decoration)); } -TEST(DecorableCopyableTest, CopyADecorableCopyable) { - struct MyCopyableDecorable : DecorableCopyable<MyCopyableDecorable> {}; +TEST(DecorableTest, NonCopyableDecorable) { + struct MyDecorable : Decorable<MyDecorable> { + MyDecorable() = default; + MyDecorable(const MyDecorable&) = delete; + MyDecorable& operator=(const MyDecorable&) = delete; + }; + + numCopyConstructedAs = 0; + numCopyAssignedAs = 0; + static const auto dd1 = MyDecorable::declareDecoration<NonCopyableA>(); + MyDecorable decorable; + dd1(decorable).a.value = 1; +} + +TEST(DecorableTest, CopyableDecorable) { + struct MyCopyableDecorable : Decorable<MyCopyableDecorable> {}; numCopyConstructedAs = 0; numCopyAssignedAs = 0; static const auto dd1 = MyCopyableDecorable::declareDecoration<A>(); static const auto dd2 = MyCopyableDecorable::declareDecoration<int>(); + { MyCopyableDecorable decorable1; dd1(decorable1).value = 1; diff --git a/src/mongo/util/decoration_container.h b/src/mongo/util/decoration_container.h index 373b199e056..4b2f7bf0619 100644 --- a/src/mongo/util/decoration_container.h +++ b/src/mongo/util/decoration_container.h @@ -40,9 +40,6 @@ class DecorationRegistry; template <typename DecoratedType> class Decorable; -template <typename DecoratedType> -class DecorableCopyable; - /** * An container for decorations. */ @@ -64,7 +61,6 @@ public: friend DecorationContainer; friend DecorationRegistry<DecoratedType>; friend Decorable<DecoratedType>; - friend DecorableCopyable<DecoratedType>; explicit DecorationDescriptor(size_t index) : _index(index) {} @@ -85,7 +81,6 @@ public: friend DecorationContainer; friend DecorationRegistry<DecoratedType>; friend Decorable<DecoratedType>; - friend DecorableCopyable<DecoratedType>; explicit DecorationDescriptorWithType(DecorationDescriptor raw) : _raw(std::move(raw)) {} @@ -108,28 +103,7 @@ public: // buffer to the type which owns those decorations. We place a pointer to ourselves, a // "back link" in the front of this storage buffer, as this is the easiest "well known // location" to compute. - Decorable<DecoratedType>** const backLink = - reinterpret_cast<Decorable<DecoratedType>**>(_decorationData.get()); - *backLink = decorated; - _registry->construct(this); - } - - /** - * Constructs a copyable decorable built based on the given "registry." - * - * See above for more details - */ - explicit DecorationContainer(DecorableCopyable<DecoratedType>* const decorated, - const DecorationRegistry<DecoratedType>* const registry) - : _registry(registry), - _decorationData(new unsigned char[registry->getDecorationBufferSizeBytes()]) { - // Because the decorations live in the externally allocated storage buffer at - // `_decorationData`, there needs to be a way to get back from a known location within this - // buffer to the type which owns those decorations. We place a pointer to ourselves, a - // "back link" in the front of this storage buffer, as this is the easiest "well known - // location" to compute. - DecorableCopyable<DecoratedType>** const backLink = - reinterpret_cast<DecorableCopyable<DecoratedType>**>(_decorationData.get()); + auto const backLink = reinterpret_cast<Decorable<DecoratedType>**>(_decorationData.get()); *backLink = decorated; _registry->construct(this); } @@ -139,7 +113,7 @@ public: * * All decorations are copy constructed from provided DecorationContainer. */ - explicit DecorationContainer(DecorableCopyable<DecoratedType>* const decorated, + explicit DecorationContainer(Decorable<DecoratedType>* const decorated, const DecorationRegistry<DecoratedType>* const registry, const DecorationContainer& other) : _registry(registry), @@ -149,8 +123,7 @@ public: // buffer to the type which owns those decorations. We place a pointer to ourselves, a // "back link" in the front of this storage buffer, as this is the easiest "well known // location" to compute. - DecorableCopyable<DecoratedType>** const backLink = - reinterpret_cast<DecorableCopyable<DecoratedType>**>(_decorationData.get()); + auto const backLink = reinterpret_cast<Decorable<DecoratedType>**>(_decorationData.get()); *backLink = decorated; _registry->copyConstruct(this, &other); } |