diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2015-01-29 14:38:47 -0500 |
---|---|---|
committer | Andy Schwerin <schwerin@mongodb.com> | 2015-04-03 15:49:15 -0400 |
commit | 364cc79cc3480fd04249d4fcdb65b55e6dd58faa (patch) | |
tree | 4349b35bda478ac7f9d44576f947389d3f34708c | |
parent | cf80412b4c6c9849941e1062c0d1278538d8c4c5 (diff) | |
download | mongo-364cc79cc3480fd04249d4fcdb65b55e6dd58faa.tar.gz |
SERVER-17816 Implementation of a generic decoration facility.
-rw-r--r-- | src/mongo/util/SConscript | 34 | ||||
-rw-r--r-- | src/mongo/util/decorable.h | 121 | ||||
-rw-r--r-- | src/mongo/util/decorable_test.cpp | 179 | ||||
-rw-r--r-- | src/mongo/util/decoration_container.cpp | 48 | ||||
-rw-r--r-- | src/mongo/util/decoration_container.h | 131 | ||||
-rw-r--r-- | src/mongo/util/decoration_registry.cpp | 95 | ||||
-rw-r--r-- | src/mongo/util/decoration_registry.h | 138 |
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(®istry); + ASSERT_EQ(2, numConstructedAs); + ASSERT_EQ(0, numDestructedAs); + DecorationContainer decorable2(®istry); + 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(®istry); + } + 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(®istry); + 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 |