summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@mongodb.com>2015-01-29 14:38:47 -0500
committerAndy Schwerin <schwerin@mongodb.com>2015-04-03 15:49:15 -0400
commit364cc79cc3480fd04249d4fcdb65b55e6dd58faa (patch)
tree4349b35bda478ac7f9d44576f947389d3f34708c
parentcf80412b4c6c9849941e1062c0d1278538d8c4c5 (diff)
downloadmongo-364cc79cc3480fd04249d4fcdb65b55e6dd58faa.tar.gz
SERVER-17816 Implementation of a generic decoration facility.
-rw-r--r--src/mongo/util/SConscript34
-rw-r--r--src/mongo/util/decorable.h121
-rw-r--r--src/mongo/util/decorable_test.cpp179
-rw-r--r--src/mongo/util/decoration_container.cpp48
-rw-r--r--src/mongo/util/decoration_container.h131
-rw-r--r--src/mongo/util/decoration_registry.cpp95
-rw-r--r--src/mongo/util/decoration_registry.h138
7 files changed, 740 insertions, 6 deletions
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript
index 493d17aa752..150ad2842af 100644
--- a/src/mongo/util/SConscript
+++ b/src/mongo/util/SConscript
@@ -1,12 +1,14 @@
+# -*- mode: python -*-
+
Import("env")
Import("has_option")
env.Library(
- target= 'intrusive_counter',
- source= [
+ target='intrusive_counter',
+ source=[
'intrusive_counter.cpp',
],
- LIBDEPS= [
+ LIBDEPS=[
'$BUILD_DIR/mongo/foundation',
]
)
@@ -16,9 +18,29 @@ if has_option("gdbserver"):
debuggerEnv.Append(CPPDEFINES=["USE_GDBSERVER"])
debuggerEnv.Library(
- target= 'debugger',
- source= [
+ target='debugger',
+ source=[
'debugger.cpp',
],
- LIBDEPS= []
+ LIBDEPS=[]
)
+
+env.Library(
+ target='decorable',
+ source=[
+ 'decoration_container.cpp',
+ 'decoration_registry.cpp',
+ ],
+ LIBDEPS=[]
+ )
+
+env.CppUnitTest(
+ target='decorable_test',
+ source=[
+ 'decorable_test.cpp'
+ ],
+ LIBDEPS=[
+ 'decorable',
+ ]
+ )
+
diff --git a/src/mongo/util/decorable.h b/src/mongo/util/decorable.h
new file mode 100644
index 00000000000..c4cccc8cffe
--- /dev/null
+++ b/src/mongo/util/decorable.h
@@ -0,0 +1,121 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+/**
+ * This header describes a mechanism for making "decorable" types.
+ *
+ * A decorable type is one to which various subsystems may attach subsystem-private data, so long as
+ * they declare what that data will be before any instances of the decorable type are created.
+ *
+ * For example, suppose you had a class Client, representing on a server a network connection to a
+ * client process. Suppose that your server has an authentication module, that attaches data to the
+ * client about authentication. If class Client looks something like this:
+ *
+ * class Client : public Decorable<Client>{
+ * ...
+ * };
+ *
+ * Then the authentication module, before the first client object is created, calls
+ *
+ * const auto authDataDescriptor = Client::declareDecoration<AuthenticationPrivateData>();
+ *
+ * And stores authDataDescriptor in a module-global variable,
+ *
+ * And later, when it has a Client object, client, and wants to get at the per-client
+ * AuthenticationPrivateData object, it calls
+ *
+ * authDataDescriptor(client)
+ *
+ * to get a reference to the AuthenticationPrivateData for that client object.
+ *
+ * With this approach, individual subsystems get to privately augment the client object via
+ * declarations local to the subsystem, rather than in the global client header.
+ */
+
+#pragma once
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/util/decoration_container.h"
+#include "mongo/util/decoration_registry.h"
+
+namespace mongo {
+
+ template <typename D>
+ class Decorable {
+ MONGO_DISALLOW_COPYING(Decorable);
+ public:
+ template <typename T>
+ class Decoration {
+ public:
+ Decoration() = default;
+
+ T& operator()(D& d) const {
+ return static_cast<Decorable&>(d)._decorations.getDecoration(_raw);
+ }
+
+ T& operator()(D* d) const {
+ return static_cast<Decorable*>(d)->_decorations.getDecoration(_raw);
+ }
+
+ const T& operator()(const D& d) const {
+ return static_cast<const Decorable&>(d)._decorations.getDecoration(_raw);
+ }
+
+ const T& operator()(const D* d) const {
+ return static_cast<const Decorable*>(d)->_decorations.getDecoration(_raw);
+ }
+
+ private:
+ friend class Decorable;
+
+ explicit Decoration(DecorationContainer::DecorationDescriptorWithType<T> raw) :
+ _raw(std::move(raw)) {
+ }
+
+ DecorationContainer::DecorationDescriptorWithType<T> _raw;
+ };
+
+ template <typename T>
+ static Decoration<T> declareDecoration() {
+ return Decoration<T>(getRegistry()->declareDecoration<T>());
+ }
+
+ protected:
+ Decorable() : _decorations(getRegistry()) {}
+ ~Decorable() = default;
+
+ private:
+ static DecorationRegistry* getRegistry() {
+ static DecorationRegistry* theRegistry = new DecorationRegistry();
+ return theRegistry;
+ }
+
+ DecorationContainer _decorations;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/util/decorable_test.cpp b/src/mongo/util/decorable_test.cpp
new file mode 100644
index 00000000000..bad3d0422bd
--- /dev/null
+++ b/src/mongo/util/decorable_test.cpp
@@ -0,0 +1,179 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
+
+#include "mongo/platform/basic.h"
+
+#include <boost/utility.hpp>
+
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/decorable.h"
+#include "mongo/util/decoration_container.h"
+#include "mongo/util/decoration_registry.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+namespace {
+
+ static int numConstructedAs;
+ static int numDestructedAs;
+
+ class A {
+ public:
+ A() : value(0) {
+ ++numConstructedAs;
+ }
+ ~A() {
+ ++numDestructedAs;
+ }
+ int value;
+ };
+
+ class ThrowA {
+ public:
+ ThrowA() : value(0) {
+ uasserted(ErrorCodes::Unauthorized, "Throwing in a constructor");
+ }
+
+ int value;
+ };
+
+ TEST(DecorableTest, DecorableType) {
+ class MyDecorable : public Decorable<MyDecorable> {
+ };
+ const auto dd1 = MyDecorable::declareDecoration<A>();
+ const auto dd2 = MyDecorable::declareDecoration<A>();
+ const auto dd3 = MyDecorable::declareDecoration<int>();
+ numConstructedAs = 0;
+ numDestructedAs = 0;
+ {
+ 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(DecorableTest, SimpleDecoration) {
+ numConstructedAs = 0;
+ numDestructedAs = 0;
+ DecorationRegistry registry;
+ const auto dd1 = registry.declareDecoration<A>();
+ const auto dd2 = registry.declareDecoration<A>();
+ const auto dd3 = registry.declareDecoration<int>();
+
+ {
+ DecorationContainer decorable1(&registry);
+ ASSERT_EQ(2, numConstructedAs);
+ ASSERT_EQ(0, numDestructedAs);
+ DecorationContainer decorable2(&registry);
+ ASSERT_EQ(4, numConstructedAs);
+ ASSERT_EQ(0, numDestructedAs);
+
+ ASSERT_EQ(0, decorable1.getDecoration(dd1).value);
+ ASSERT_EQ(0, decorable1.getDecoration(dd2).value);
+ ASSERT_EQ(0, decorable2.getDecoration(dd1).value);
+ ASSERT_EQ(0, decorable2.getDecoration(dd2).value);
+ ASSERT_EQ(0, decorable2.getDecoration(dd3));
+ decorable1.getDecoration(dd1).value = 1;
+ decorable1.getDecoration(dd2).value = 2;
+ decorable2.getDecoration(dd1).value = 3;
+ decorable2.getDecoration(dd2).value = 4;
+ decorable2.getDecoration(dd3) = 5;
+ ASSERT_EQ(1, decorable1.getDecoration(dd1).value);
+ ASSERT_EQ(2, decorable1.getDecoration(dd2).value);
+ ASSERT_EQ(3, decorable2.getDecoration(dd1).value);
+ ASSERT_EQ(4, decorable2.getDecoration(dd2).value);
+ ASSERT_EQ(5, decorable2.getDecoration(dd3));
+ }
+ ASSERT_EQ(4, numDestructedAs);
+ }
+
+ TEST(DecorableTest, ThrowingConstructor) {
+ numConstructedAs = 0;
+ numDestructedAs = 0;
+
+ DecorationRegistry registry;
+ registry.declareDecoration<A>();
+ registry.declareDecoration<ThrowA>();
+ registry.declareDecoration<A>();
+
+ try {
+ DecorationContainer d(&registry);
+ }
+ catch (const UserException& ex) {
+ ASSERT_EQ(ErrorCodes::Unauthorized, ex.getCode());
+ }
+ ASSERT_EQ(1, numConstructedAs);
+ ASSERT_EQ(1, numDestructedAs);
+ }
+
+ TEST(DecorableTest, Alignment) {
+ DecorationRegistry registry;
+ const auto firstChar = registry.declareDecoration<char>();
+ const auto firstInt = registry.declareDecoration<int>();
+ const auto secondChar = registry.declareDecoration<int>();
+ const auto secondInt = registry.declareDecoration<int>();
+ DecorationContainer d(&registry);
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(firstChar)) %
+ std::alignment_of<char>::value);
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(secondChar)) %
+ std::alignment_of<char>::value);
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(firstInt)) %
+ std::alignment_of<int>::value);
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(secondInt)) %
+ std::alignment_of<int>::value);
+ }
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/util/decoration_container.cpp b/src/mongo/util/decoration_container.cpp
new file mode 100644
index 00000000000..1e1be74a8de
--- /dev/null
+++ b/src/mongo/util/decoration_container.cpp
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/util/decoration_container.h"
+
+#include "mongo/util/decoration_registry.h"
+
+namespace mongo {
+
+ DecorationContainer::DecorationContainer(const DecorationRegistry* registry) :
+ _registry(registry),
+ _decorationData(new unsigned char[registry->getDecorationBufferSizeBytes()]) {
+
+ _registry->construct(this);
+ }
+
+ DecorationContainer::~DecorationContainer() {
+ _registry->destruct(this);
+ }
+
+} // namespace mongo
diff --git a/src/mongo/util/decoration_container.h b/src/mongo/util/decoration_container.h
new file mode 100644
index 00000000000..4ef784d0d7e
--- /dev/null
+++ b/src/mongo/util/decoration_container.h
@@ -0,0 +1,131 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/platform/cstdint.h"
+
+namespace mongo {
+
+ class DecorationRegistry;
+
+ /**
+ * An container for decorations.
+ */
+ class DecorationContainer {
+ MONGO_DISALLOW_COPYING(DecorationContainer);
+ public:
+
+ /**
+ * Opaque descriptor of a decoration. It is an identifier to a field on the
+ * DecorationContainer that is private to those modules that have access to the descriptor.
+ */
+ class DecorationDescriptor {
+ public:
+ DecorationDescriptor() = default;
+
+ private:
+ friend class DecorationContainer;
+ friend class DecorationRegistry;
+
+ explicit DecorationDescriptor(size_t index) : _index(index) {}
+
+ size_t _index;
+ };
+
+ /**
+ * Opaque description of a decoration of specified type T. It is an identifier to a field
+ * on the DecorationContainer that is private to those modules that have access to the
+ * descriptor.
+ */
+ template <typename T>
+ class DecorationDescriptorWithType {
+ public:
+ DecorationDescriptorWithType() = default;
+
+ private:
+ friend class DecorationContainer;
+ friend class DecorationRegistry;
+
+ explicit DecorationDescriptorWithType(DecorationDescriptor raw) :
+ _raw(std::move(raw)) {}
+
+ DecorationDescriptor _raw;
+ };
+
+ /**
+ * Constructs a decorable built based on the given "registry."
+ *
+ * The registry must stay in scope for the lifetime of the DecorationContainer, and must not
+ * have any declareDecoration() calls made on it while a DecorationContainer dependent on it
+ * is in scope.
+ */
+ explicit DecorationContainer(const DecorationRegistry* registry);
+ ~DecorationContainer();
+
+ /**
+ * Gets the decorated value for the given descriptor.
+ *
+ * The descriptor must be one returned from this DecorationContainer's associated _registry.
+ */
+ void* getDecoration(DecorationDescriptor descriptor) {
+ return _decorationData.get() + descriptor._index;
+ }
+
+ /**
+ * Same as the non-const form above, but returns a const result.
+ */
+ const void* getDecoration(DecorationDescriptor descriptor) const {
+ return _decorationData.get() + descriptor._index;
+ }
+
+ /**
+ * Gets the decorated value or the given typed descriptor.
+ */
+ template <typename T>
+ T& getDecoration(DecorationDescriptorWithType<T> descriptor) {
+ return *static_cast<T*>(getDecoration(descriptor._raw));
+ }
+
+ /**
+ * Same as the non-const form above, but returns a const result.
+ */
+ template <typename T>
+ const T& getDecoration(DecorationDescriptorWithType<T> descriptor) const {
+ return *static_cast<const T*>(getDecoration(descriptor._raw));
+ }
+
+ private:
+ const DecorationRegistry* const _registry;
+ const std::unique_ptr<unsigned char[]> _decorationData;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/util/decoration_registry.cpp b/src/mongo/util/decoration_registry.cpp
new file mode 100644
index 00000000000..ab15fd3347b
--- /dev/null
+++ b/src/mongo/util/decoration_registry.cpp
@@ -0,0 +1,95 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/util/decoration_registry.h"
+
+namespace mongo {
+
+ DecorationContainer::DecorationDescriptor DecorationRegistry::declareDecoration(
+ const size_t sizeBytes,
+ const size_t alignBytes,
+ const DecorationConstructorFn constructor,
+ const DecorationDestructorFn destructor) {
+
+ const size_t misalignment = _totalSizeBytes % alignBytes;
+ if (misalignment) {
+ _totalSizeBytes += alignBytes - misalignment;
+ }
+ DecorationContainer::DecorationDescriptor result(_totalSizeBytes);
+ _decorationInfo.push_back(DecorationInfo(result, constructor, destructor));
+ _totalSizeBytes += sizeBytes;
+ return result;
+ }
+
+ void DecorationRegistry::construct(DecorationContainer* decorable) const {
+ auto iter = _decorationInfo.cbegin();
+ try {
+ for (; iter != _decorationInfo.cend(); ++iter) {
+ iter->constructor(decorable->getDecoration(iter->descriptor));
+ }
+ }
+ catch (...) {
+ try {
+ while (iter != _decorationInfo.cbegin()) {
+ --iter;
+ iter->destructor(decorable->getDecoration(iter->descriptor));
+ }
+ }
+ catch (...) {
+ std::terminate();
+ }
+ throw;
+ }
+ }
+
+ void DecorationRegistry::destruct(DecorationContainer* decorable) const {
+ try {
+ for (DecorationInfoVector::const_reverse_iterator iter = _decorationInfo.rbegin(),
+ end = _decorationInfo.rend();
+ iter != end;
+ ++iter) {
+
+ iter->destructor(decorable->getDecoration(iter->descriptor));
+ }
+ }
+ catch (...) {
+ std::terminate();
+ }
+ }
+
+ DecorationRegistry::DecorationInfo::DecorationInfo(
+ DecorationContainer::DecorationDescriptor inDescriptor,
+ DecorationConstructorFn inConstructor,
+ DecorationDestructorFn inDestructor) :
+ descriptor(std::move(inDescriptor)),
+ constructor(std::move(inConstructor)),
+ destructor(std::move(inDestructor)) {}
+
+} // namespace mongo
diff --git a/src/mongo/util/decoration_registry.h b/src/mongo/util/decoration_registry.h
new file mode 100644
index 00000000000..dc1674339e4
--- /dev/null
+++ b/src/mongo/util/decoration_registry.h
@@ -0,0 +1,138 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <type_traits>
+#include <vector>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/stdx/functional.h"
+#include "mongo/util/decoration_container.h"
+
+namespace mongo {
+
+ /**
+ * Registry of decorations.
+ *
+ * A decoration registry corresponds to the "type" of a DecorationContainer. For example, if
+ * you have two registries, r1 and r2, a DecorationContainer constructed from r1 has instances
+ * the decorations declared on r1, and a DecorationContainer constructed from r2 has instances
+ * of the decorations declared on r2.
+ */
+ class DecorationRegistry {
+ MONGO_DISALLOW_COPYING(DecorationRegistry);
+ public:
+ DecorationRegistry() = default;
+
+ /**
+ * Declares a decoration of type T, constructed with T's default constructor, and
+ * returns a descriptor for accessing that decoration.
+ *
+ * NOTE: T's destructor must not throw exceptions.
+ */
+ template <typename T>
+ DecorationContainer::DecorationDescriptorWithType<T> declareDecoration() {
+#if not defined(_MSC_VER) or (_MSC_VER > 1800) // Try again with MSVC 2015.
+ static_assert(std::is_nothrow_destructible<T>::value,
+ "Decorations must be nothrow destructible");
+#endif
+ return { std::move(declareDecoration(sizeof(T),
+ std::alignment_of<T>::value,
+ &constructAt<T>,
+ &destructAt<T>)) };
+ }
+
+ size_t getDecorationBufferSizeBytes() const { return _totalSizeBytes; }
+
+ /**
+ * Constructs the decorations declared in this registry on the given instance of
+ * "decorable".
+ *
+ * Called by the DecorationContainer constructor. Do not call directly.
+ */
+ void construct(DecorationContainer* decorable) const;
+
+ /**
+ * Destroys the decorations declared in this registry on the given instance of "decorable".
+ *
+ * Called by the DecorationContainer destructor. Do not call directly.
+ */
+ void destruct(DecorationContainer* decorable) const;
+
+ private:
+ /**
+ * Function that constructs (initializes) a single instance of a decoration.
+ */
+ using DecorationConstructorFn = stdx::function<void (void*)>;
+
+ /**
+ * Function that destructs (deinitializes) a single instance of a decoration.
+ */
+ using DecorationDestructorFn = stdx::function<void (void*)>;
+
+ struct DecorationInfo {
+ DecorationInfo() {}
+ DecorationInfo(DecorationContainer::DecorationDescriptor descriptor,
+ DecorationConstructorFn constructor,
+ DecorationDestructorFn destructor);
+
+ DecorationContainer::DecorationDescriptor descriptor;
+ DecorationConstructorFn constructor;
+ DecorationDestructorFn destructor;
+ };
+
+ using DecorationInfoVector = std::vector<DecorationInfo>;
+
+ template <typename T>
+ static void constructAt(void* location) {
+ new (location) T();
+ }
+
+ template <typename T>
+ static void destructAt(void* location) {
+ static_cast<T*>(location)->~T();
+ }
+
+ /**
+ * Declares a decoration with given "constructor" and "destructor" functions,
+ * of "sizeBytes" bytes.
+ *
+ * NOTE: "destructor" must not throw exceptions.
+ */
+ DecorationContainer::DecorationDescriptor declareDecoration(
+ size_t sizeBytes,
+ size_t alignBytes,
+ DecorationConstructorFn constructor,
+ DecorationDestructorFn destructor);
+
+ DecorationInfoVector _decorationInfo;
+ size_t _totalSizeBytes { 0 };
+ };
+
+} // namespace mongo