summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@mongodb.com>2021-12-23 00:47:15 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-01-10 21:48:11 +0000
commitd9d35bd709dbe4a8981218c2f0500d6bcfecc329 (patch)
tree23152c9881b2439c9eb831c7df85aac40cdeb6b2
parent53ff83884eb4e6595778ed895467b4d4b218566a (diff)
downloadmongo-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.h9
-rw-r--r--src/mongo/util/decorable.h103
-rw-r--r--src/mongo/util/decorable_test.cpp171
-rw-r--r--src/mongo/util/decoration_container.h33
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);
}