diff options
author | Randolph Tan <randolph@10gen.com> | 2017-03-22 17:19:42 -0400 |
---|---|---|
committer | Randolph Tan <randolph@10gen.com> | 2017-03-22 17:19:42 -0400 |
commit | 7b4770c1dbbc2a264a10f4fcfc87025ce832b680 (patch) | |
tree | a0e9e473e65bd8371ef09b47afbd87897a0f0ca1 /src/mongo/base | |
parent | 6c5938b9fcedf740f292533ea1c637fd0eccf9f4 (diff) | |
download | mongo-7b4770c1dbbc2a264a10f4fcfc87025ce832b680.tar.gz |
Revert "SERVER-26025 Smart pointer with clone on copy"
This reverts commit 5d141bce7219aeb34d3de8cfae68d643bf9a3a16.
Diffstat (limited to 'src/mongo/base')
-rw-r--r-- | src/mongo/base/SConscript | 9 | ||||
-rw-r--r-- | src/mongo/base/clonable_ptr.h | 656 | ||||
-rw-r--r-- | src/mongo/base/clonable_ptr_test.cpp | 954 | ||||
-rw-r--r-- | src/mongo/base/concept/README | 5 | ||||
-rw-r--r-- | src/mongo/base/concept/assignable.h | 13 | ||||
-rw-r--r-- | src/mongo/base/concept/clonable.h | 20 | ||||
-rw-r--r-- | src/mongo/base/concept/clone_factory.h | 21 | ||||
-rw-r--r-- | src/mongo/base/concept/constructible.h | 38 | ||||
-rw-r--r-- | src/mongo/base/concept/convertible_to.h | 14 | ||||
-rw-r--r-- | src/mongo/base/concept/copy_assignable.h | 18 | ||||
-rw-r--r-- | src/mongo/base/concept/copy_constructible.h | 14 | ||||
-rw-r--r-- | src/mongo/base/concept/unique_ptr.h | 41 |
12 files changed, 0 insertions, 1803 deletions
diff --git a/src/mongo/base/SConscript b/src/mongo/base/SConscript index af40fdab72a..848aca3b7f0 100644 --- a/src/mongo/base/SConscript +++ b/src/mongo/base/SConscript @@ -55,15 +55,6 @@ env.CppUnitTest( ], ) -env.CppUnitTest( - target=[ - 'clonable_ptr_test', - ], - source=[ - 'clonable_ptr_test.cpp', - ], -) - env.Library( target=[ 'secure_allocator' diff --git a/src/mongo/base/clonable_ptr.h b/src/mongo/base/clonable_ptr.h deleted file mode 100644 index fc5c6bb39a4..00000000000 --- a/src/mongo/base/clonable_ptr.h +++ /dev/null @@ -1,656 +0,0 @@ -// clonable_ptr.h - -/*- - * Copyright (C) 2016 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 <cstddef> -#include <memory> -#include <tuple> -#include <type_traits> - -namespace mongo { -namespace clonable_ptr_detail { -// This is the default `CloneFactory` conforming to `mongo::concept::CloneFactory` for -// `clonable_ptr`. -template <typename Clonable> -struct CloneFactory { - auto operator()(const Clonable& c) const -> decltype(c.clone()) { - return c.clone(); - } -}; - -// TODO: Move some of these traits detection structs to a template metaprogramming header. -template <typename T> -struct detect_clone_factory_type_member_impl { - struct Fallback { - struct clone_factory_type {}; - }; - - struct Derived : T, Fallback {}; - - using Yes = char[2]; - using No = char[1]; - - template <typename U> - static No& test(typename U::clone_factory_type*); - - template <typename U> - static Yes& test(U*); - - static constexpr bool value = sizeof(test<Derived>(0)) == sizeof(Yes); - - using type = typename std::integral_constant<bool, value>::type; -}; - -template <typename T> -struct detect_clone_factory_type_member : std::conditional<std::is_class<T>::value, - detect_clone_factory_type_member_impl<T>, - std::false_type>::type {}; - -template <typename T, bool has_clone_factory_member = detect_clone_factory_type_member<T>::value> -struct clonable_traits_impl; - -template <typename T> -struct clonable_traits_impl<T, false> { - using clone_factory_type = CloneFactory<T>; -}; - -template <typename T> -struct clonable_traits_impl<T, true> { - using clone_factory_type = typename T::clone_factory_type; -}; -} // namespace clonable_ptr_detail - -/** - * The 'clonable_traits' class is a specializable traits class for clonable-like types. By - * specializing this traits class for a type it is possible to change the global default - * `CloneFactory` type for a specific type. Types which conform to `mongo::concept::Clonable` - * will get a default `CloneFactory` type whch invokes their specific `Clonable::clone` function. A - * specialization can be used to make a type use a different clone factory function. A type `T` may - * specify `T::clone_factory_type` instead of specializing this traits type. - */ -template <typename T> -struct clonable_traits : clonable_ptr_detail::clonable_traits_impl<T> {}; - -/** - * The `clonable_ptr` represents a value-like type held at a distance. The `clonable_ptr` class is - * a smart-pointer type which functions like a `std::unique_ptr` with the added ability to create - * new copies of the pointee on copy construction. The default CloneFactory assumes that `T` is a - * type which models the Concept `mongo::concept::Clonable`. The supplied type may supply an - * alternative default `CloneFactory` type by either of two means: - * - * * `T` may define a member `T::clone_factory_type` which conforms to - * `mongo::concept::CloneFactory` - * * `T` may have an accompanying specialization of `mongo::clonable_traits< T >` which - * defines `clonable_factory_type`. - * - * NOTE: The `CloneFactory` type is permitted to be stateful, but must be copy constructible and - * copy assignable. - * NOTE: The `CloneFactory` member does NOT participate in value comparisons for a `clonable_ptr`, - * even when it has state. - * - * `T`: The type of the object being managed. - * `CloneFactory`: A type which models the Concept `mongo::concept::CloneFactory`. - * `UniquePtr`: A type which models the Concept `mongo::concept::UniquePtr` - */ -template <typename T, - typename CloneFactory = typename clonable_traits<T>::clone_factory_type, - template <typename, typename...> class UniquePtr = std::unique_ptr> -class clonable_ptr { -private: - // `std::tuple` is used to avoid allocating storage for `cloneFactory` if it is a non-storage - // type. - std::tuple<CloneFactory, UniquePtr<T>> data; - - inline const CloneFactory& cloneFactory() const { - return std::get<0>(data); - } - - inline const UniquePtr<T>& ptr() const { - return std::get<1>(data); - } - - inline UniquePtr<T>& ptr() { - return std::get<1>(data); - } - - inline const auto& _makeEqualityLens() const noexcept { - return this->ptr(); - } - - inline const auto& _makeStrictWeakOrderLens() const noexcept { - return this->ptr(); - } - - static inline UniquePtr<T> clone_with_factory_impl(const T& copy, const CloneFactory& factory) { - return UniquePtr<T>{factory(copy)}; - } - - template <typename Pointerlike> - static inline UniquePtr<T> clone_with_factory(Pointerlike&& copy, const CloneFactory& factory) { - if (!copy) - return nullptr; - return clone_with_factory_impl(*copy, factory); - } - - struct internal_construction {}; - - explicit inline clonable_ptr(UniquePtr<T>&& p, - const CloneFactory* const f, - const internal_construction&) - : data(*f, std::move(p)) {} - - explicit inline clonable_ptr(UniquePtr<T>&& p, CloneFactory&& f, const internal_construction&) - : data(std::move(f), std::move(p)) {} - -public: - /*! Destroys this pointer. Functions like `std::unique_ptr`. */ - inline ~clonable_ptr() noexcept = default; - - /*! Moves a value, by pointer. Functions like `std::unique_ptr`. */ - inline clonable_ptr(clonable_ptr&&) noexcept( - noexcept(CloneFactory{std::declval<CloneFactory>()}) && - noexcept(UniquePtr<T>{std::declval<UniquePtr<T>>()})) = default; - - /*! Moves a value, by pointer. Functions like `std::unique_ptr`. */ - inline clonable_ptr& operator=(clonable_ptr&&) & - noexcept(noexcept(std::declval<CloneFactory>() = std::declval<CloneFactory>()) && - noexcept(std::declval<UniquePtr<T>>() = std::declval<UniquePtr<T>>())) = default; - - /*! - * Constructs a pointer referring to a new copy of an original value. The old object owned by - * `*this` will be deleted, and `*this` will manage a new copy of `copy`, as created by - * `copy->clone()`. If `copy` is not managing anything (its internal pointer is `nullptr`), - * then this new copy will also be nullptr. - * - * POST: `copy != nullptr ? copy != *this : copy == *this` -- If `copy` stores a pointer to a - * value, then `*this` will have an independent pointer. If `copy` stores `nullptr`, then - * `*this` will also store `nullptr`. - * - * `copy`: The original value to copy. - * THROWS: Any exceptions thrown by `cloneFactory( *copy )`. - * TODO: Consider adding a noexcept deduction specifier to this copy operation. - */ - inline clonable_ptr(const clonable_ptr& copy) - : data{copy.cloneFactory(), clone_with_factory(copy, copy.cloneFactory())} {} - - /*! - * Constructs a pointer referring to a new copy of an original value. The old object owned by - * `*this` will be deleted, and `*this` will manage a new copy of `copy`, as created by - * `copy->clone()`. If `copy` is not managing anything (its internal pointer is `nullptr`), - * then this new copy will also be nullptr. - * - * POST: `copy != nullptr ? copy != *this : copy == *this` -- If `copy` stores a pointer to a - * value, then `*this` will have an independent pointer. If `copy` stores `nullptr`, then - * `*this` will also store `nullptr`. - * - * NOTE: The `CloneFactory` will be copied from the `copy` poiner, by default. - * - * `copy`: The original value to copy. - * `factory`: The factory to use for cloning. Defaults to the source's factory. - * THROWS: Any exceptions thrown by `factory( *copy )`. - * TODO: Consider adding a noexcept deduction specifier to this copy operation. - */ - inline clonable_ptr(const clonable_ptr& copy, const CloneFactory& factory) - : data{factory, clone_with_factory(copy, factory)} {} - - /*! - * Changes the value of this pointer, by creating a new object having the same value as `copy`. - * The old object owned by `*this` will be deleted, and `*this` will manage a new copy of - * `copy`, as created by `copy->clone()`. If `copy` is not managing anything (its internal - * pointer is `nullptr`), then this new copy will also be nullptr. - * - * NOTE: This operation cannot be conducted on an xvalue or prvalue instance. (This prevents - * silliness such as: `func_returning_ptr()= some_other_func_returning_ptr();`) - * - * NOTE: `copy`'s `CloneFactory` will be used to copy. - * - * POST: `copy != nullptr ? copy != *this : copy == *this` -- If `copy` stores a pointer to a - * value, then `*this` will have an independent pointer. If `copy` stores `nullptr`, then - * `*this` will also store `nullptr`. - * - * `copy`: The value to make a copy of. - * RETURNS: A reference to this pointer, after modification. - * TODO: Consider adding a noexcept deduction specifier to this copy operation. - */ - inline clonable_ptr& operator=(const clonable_ptr& copy) & { - return *this = clonable_ptr{copy}; - } - - // Maintenance note: The two enable_if overloads of `clonable_ptr( std::nullptr_t )` are - // necessary, due to the fact that `std::nullptr_t` is capable of implicit conversion to a - // built-in pointer type. If the stateful form being deleted causes the `nullptr` to convert, - // this could cause binding to another ctor which may be undesired. - - /*! - * `nullptr` construct a clonable pointer (to `nullptr`), if the `CloneFactory` type is - * stateless. - * The value will be a pointer to nothing, with a default `CloneFactory`. - * NOTE: This constructor is only available for types with a stateless `CloneFactory` type. - */ - template <typename CloneFactory_ = CloneFactory> - inline clonable_ptr( - typename std::enable_if<std::is_empty<CloneFactory_>::value, std::nullptr_t>::type) {} - - /*! - * Disable `nullptr` construction of clonable pointer (to `nullptr`), if the `CloneFactory` type - * is stateful. - * NOTE: This constructor is disabled for types with a stateless `CloneFactory` type. - */ - template <typename CloneFactory_ = CloneFactory> - inline clonable_ptr(typename std::enable_if<!std::is_empty<CloneFactory_>::value, - std::nullptr_t>::type) = delete; - - /*! - * Constructs a pointer to nothing, with a default `CloneFactory`. - * This function is unavailable when `CloneFactory` is stateful. - */ - template <typename CloneFactory_ = CloneFactory, - typename = typename std::enable_if<std::is_empty<CloneFactory_>::value>::type> - explicit inline clonable_ptr() noexcept {} - - /*! Constructs a pointer to nothing, with the specified `CloneFactory`. */ - explicit inline clonable_ptr(CloneFactory factory) : data{factory, nullptr} {} - - /*! - * Constructs a `clonable_ptr` which owns `p`, initializing the stored pointer with `p`. - * This function is unavailable when `CloneFactory` is stateful. - * `p`: The pointer to take ownership of. - */ - template <typename CloneFactory_ = CloneFactory> - explicit inline clonable_ptr( - typename std::enable_if<std::is_empty<CloneFactory_>::value, T* const>::type p) - : clonable_ptr(UniquePtr<T>{p}) {} - - /*! - * Disable single-argument construction of clonable pointer (with a raw pointer), if the - * `CloneFactory` type is stateful. - * NOTE: This constructor is disabled for types with a stateless `CloneFactory` type. - */ - template <typename CloneFactory_ = CloneFactory> - explicit inline clonable_ptr( - typename std::enable_if<!std::is_empty<CloneFactory_>::value, T* const>::type) = delete; - - // The reason that we have two overloads for clone factory is to ensure that we avoid as many - // exception-unsafe uses as possible. The const-lvalue-reference variant in conjunction with - // the rvalue-reference variant lets us separate the cases of "constructed in place" from - // "passed from a local". In the latter case, we can't make our type any safer, since the - // timing of the construction of the local and the timing of the `new` on the raw pointer are - // out of our control. At least we prevent an accidental use which SEEMS exception safe but - // isn't -- hopefully highlighting exception unsafe code, by making it more explicit. In the - // former, "constructed in place", case, we are able to successfully move construct without - // exception problems, if it's nothrow move constructible. If it isn't we flag a compiler - // error. In this case, too, we prevent accidental use which SEEMS exception safe and hopefully - // will similarly highlight exception unsafe code. - - /*! - * Constructs a `clonable_ptr` which owns `p`, initializing the stored pointer with `p`. The - * `factory` parameter will be used as the `CloneFactory` - * `p`: The pointer to take ownership of. - * `factory`: The clone factory to use in future copies. - * NOTE: It is not recommended to use this constructor, as the following is not exception safe - * code: - * ~~~ - * std::function<T* ()> cloner= [](const T& p){ return p; }; - * auto getCloner= [=]{ return cloner; }; - * clonable_ptr<T, std::function<T* ()>> bad{new T, getCloner()}; // BAD IDEA!!! - * ~~~ - * Even if the above could be made exception safe, there are other more complicated use cases - * which would not be exception safe. (The above is not exception safe, because the `new T` - * expression can be evaluated before the `getCloner()` expression is evaluated. `getCloner()` - * is allowed to throw, thus leaving `new T` to be abandoned. - */ - explicit inline clonable_ptr(T* const p, const CloneFactory& factory) - : clonable_ptr{UniquePtr<T>{p}, std::addressof(factory), internal_construction{}} {} - - /*! - * Constructs a `clonable_ptr` which owns `p`, initializing the stored pointer with `p`. The - * `factory` parameter will be used as the `CloneFactory` for future copies. - * `p`: The pointer to take ownership of. - * `factory`: The clone factory to use in future copies. - * NOTE: It is not recommended to use this constructor, as the following is not exception safe - * code: - * ~~~ - * clonable_ptr<T, std::function<T* ()>> bad{new T, [](const T& p){ return p; }}; // BAD IDEA!!! - * ~~~ - * Even if the above could be made exception safe, there are other more complicated use cases - * which would not be exception safe. (The above is not exception safe, because the `new T` - * expression can be evaluated before the lambda expression is evaluated and converted to a - * `std::function`. The `std::function` constructor is allowed to throw, thus leaving `new T` - * to be abandoned. - */ - explicit inline clonable_ptr(T* const p, CloneFactory&& factory) - : clonable_ptr{UniquePtr<T>{p}, std::move(factory), internal_construction{}} { - static_assert(std::is_nothrow_move_constructible<CloneFactory>::value, - "The `CloneFactory` type must be nothrow constructible to use as an r-value " - "in an initialization expression with a raw pointer."); - } - - /*! - * Constructs a `clonable_ptr` by transferring ownership from `p` to `*this`. A default - * `CloneFactory` will be provided for future copies. - * `p`: The pointer to take ownership of. - * NOTE: This constructor allows for implicit conversion from a `UniquePtr` (xvalue) object. - * NOTE: This constructor is unavailable when `CloneFactory` is stateful. - * NOTE: This usage should be preferred over the raw-pointer construction forms, when using - * factories as constructor arguments, as in the following exception safe code: - * ~~~ - * clonable_ptr<T, std::function<T* ()>> good{std::make_unique<T>(), - * [](const T& p){ return p; }}; // GOOD IDEA!!! - * ~~~ - */ - template <typename CloneFactory_ = CloneFactory, - typename Derived, - typename = typename std::enable_if<std::is_empty<CloneFactory_>::value>::type> - inline clonable_ptr(UniquePtr<Derived> p) : data{CloneFactory{}, std::move(p)} {} - - /*! - * Constructs a `clonable_ptr` by transferring ownership from `p` to `*this`. The `factory` - * parameter will be used as the `CloneFactory` for future copies. - * NOTE: This constructor allows for implicit conversion from a `UniquePtr` (xvalue) object. - * `p`: The pointer to take ownership of. - * `factory`: The clone factory to use in future copies. - * NOTE: This usage should be preferred over the raw-pointer construction forms, when using - * factories as constructor arguments, as in the following exception safe code: - * ~~~ - * clonable_ptr<T, std::function<T* ()>> good{std::make_unique<T>(), - * [](const T& p){ return p; }}; // GOOD IDEA!!! - * ~~~ - */ - template <typename Derived> - inline clonable_ptr(UniquePtr<Derived> p, CloneFactory factory) - : data{std::move(factory), std::move(p)} {} - - /*! - * Changes the value of this pointer, by creating a new object having the same value as `copy`. - * The old object owned by `*this` will be deleted, and `*this` will manage a new copy of - * `copy`, as created by `copy->clone()`. If `copy` is not managing anything (its internal - * pointer is `nullptr`), then this new copy will also be nullptr. - * - * NOTE: This operation cannot be performed on an xvalue or prvalue instance. (This prevents - * silliness such as: `func_returning_ptr()= some_other_func_returning_ptr();`) - * - * NOTE: `copy`'s `CloneFactory` will be used to copy. - * - * POST: `copy != nullptr ? copy != *this : copy == *this` -- If `copy` stores a pointer to a - * value, then `*this` will have an independent pointer. If `copy` stores `nullptr`, then - * `*this` will also store `nullptr`. - * - * `copy`: The value to make a copy of. - * RETURNS: A reference to this pointer, after modification. - */ - inline clonable_ptr& operator=(UniquePtr<T> copy) & { - return *this = std::move(clonable_ptr{std::move(copy), this->cloneFactory()}); - } - - template <typename Derived> - inline clonable_ptr& operator=(UniquePtr< Derived > copy) & { - return *this = std::move(clonable_ptr{std::move(copy), this->cloneFactory()}); - } - - /*! - * Change the `CloneFactory` for `*this` to `factory`. - * NOTE: This operation cannot be performed on an xvalue or prvalue instance. (This prevents - * silliness such as: `func_returning_ptr().setCloneFactory( factory );`.) - */ - template <typename FactoryType> - inline void setCloneFactory(FactoryType&& factory) & { - this->cloneFactory() = std::forward<FactoryType>(factory); - } - - /*! - * Dereferences the pointer owned by `*this`. - * NOTE: The behavior is undefined if `this->get() == nullptr`. - * RETURNS: The object owned by `*this`, equivalent to `*get()`. - */ - inline auto& operator*() const noexcept(noexcept(*this->ptr())) { - return *this->ptr(); - } - - /*! - * Dereferences the pointer owned by `*this`. - * NOTE: The behavior is undefined if `this->get() == nullptr`. - * RETURNS: A pointer to the object owned by `*this`, equivalent to `get()`. - */ - inline auto* operator-> () const noexcept(noexcept(this->ptr().operator->())) { - return this->ptr().operator->(); - } - - /*! - * Returns `true` if `*this` owns a pointer to a value, and `false` otherwise. - * RETURNS: A value equivalent to `static_cast< bool >( this->get() )`. - */ - explicit inline operator bool() const noexcept { - return this->ptr().get(); - } - - /*! - * Converts `*this` to a `UniquePtr< T >` by transferring ownership. This function will retire - * ownership of the pointer owned by `*this`. This is a safe operation, as this function cannot - * be called from an lvalue context -- rvalue operations are used to represent transfer of - * ownership semantics. - * - * NOTE: This function is only applicable in `rvalue` contexts. - * NOTE: This function has transfer of ownership semantics. - * - * RETURNS: A `UniquePtr< T >` which owns the pointer formerly managed by `*this`. - */ - inline operator UniquePtr<T>() && { - return std::move(this->ptr()); - } - - /*! Provides a constant `UniquePtr< T >` view of the object owned by `*this`. */ - inline operator const UniquePtr<T>&() const& { - return this->ptr(); - } - - /*! Provides a mutable `UniquePtr< T >` view of the object owned by `*this`. */ - inline operator UniquePtr<T>&() & { - return this->ptr(); - } - - /*! Provides a C-style `T *` pointer to the object owned by `*this`. */ - inline T* get() const noexcept(noexcept(this->ptr().get())) { - return this->ptr().get(); - } - - inline void reset() & noexcept { - this->ptr().reset(); - } - - inline void reset(T* const p) & noexcept(noexcept(this->ptr().reset(p))) { - this->ptr().reset(p); - } - - // Equality - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator==(const clonable_ptr<C, F, U>& lhs, - const clonable_ptr<C, F, U>& rhs) { - return lhs._makeEqualityLens() == rhs._makeEqualityLens(); - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator==(const U<C>& lhs, const clonable_ptr<C, F, U>& rhs) { - return lhs == rhs._makeEqualityLens(); - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator==(const clonable_ptr<C, F, U>& lhs, const U<C>& rhs) { - return lhs._makeEqualityLens() == rhs; - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator==(const std::nullptr_t& lhs, const clonable_ptr<C, F, U>& rhs) { - return lhs == rhs._makeEqualityLens(); - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator==(const clonable_ptr<C, F, U>& lhs, const std::nullptr_t& rhs) { - return lhs._makeEqualityLens() == rhs; - } - - // Strict weak order - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator<(const clonable_ptr<C, F, U>& lhs, - const clonable_ptr<C, F, U>& rhs) { - return lhs._makeStrictWeakOrderLens() < rhs._makeStrictWeakOrderLens(); - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator<(const U<C>& lhs, const clonable_ptr<C, F, U>& rhs) { - return lhs < rhs._makeStrictWeakOrderLens(); - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator<(const clonable_ptr<C, F, U>& lhs, const U<C>& rhs) { - return lhs._makeStrictWeakOrderLens() < rhs; - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator<(const std::nullptr_t& lhs, const clonable_ptr<C, F, U>& rhs) { - return lhs < rhs._makeStrictWeakOrderLens(); - } - - template <typename C, typename F, template <typename, typename...> class U> - inline friend bool operator<(const clonable_ptr<C, F, U>& lhs, const std::nullptr_t& rhs) { - return lhs._makeStrictWeakOrderLens() < rhs; - } -}; - -// Inequality - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator!=(const clonable_ptr<C, F, U>& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs == rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator!=(const U<C>& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs == rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator!=(const clonable_ptr<C, F, U>& lhs, const U<C>& rhs) { - return !(lhs == rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator!=(const std::nullptr_t& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs == rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator!=(const clonable_ptr<C, F, U>& lhs, const std::nullptr_t& rhs) { - return !(lhs == rhs); -} - -// Greater than - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>(const clonable_ptr<C, F, U>& lhs, const clonable_ptr<C, F, U>& rhs) { - return rhs < lhs; -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>(const U<C>& lhs, const clonable_ptr<C, F, U>& rhs) { - return rhs < lhs; -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>(const clonable_ptr<C, F, U>& lhs, const U<C>& rhs) { - return rhs < lhs; -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>(const std::nullptr_t& lhs, const clonable_ptr<C, F, U>& rhs) { - return rhs < lhs; -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>(const clonable_ptr<C, F, U>& lhs, const std::nullptr_t& rhs) { - return rhs < lhs; -} - -// Equal or Less - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator<=(const clonable_ptr<C, F, U>& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs > rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator<=(const U<C>& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs > rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator<=(const clonable_ptr<C, F, U>& lhs, const U<C>& rhs) { - return !(lhs > rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator<=(const std::nullptr_t& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs > rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator<=(const clonable_ptr<C, F, U>& lhs, const std::nullptr_t& rhs) { - return !(lhs > rhs); -} - -// Equal or greater - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>=(const clonable_ptr<C, F, U>& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs < rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>=(const U<C>& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs < rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>=(const clonable_ptr<C, F, U>& lhs, const U<C>& rhs) { - return !(lhs < rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>=(const std::nullptr_t& lhs, const clonable_ptr<C, F, U>& rhs) { - return !(lhs < rhs); -} - -template <typename C, typename F, template <typename, typename...> class U> -inline bool operator>=(const clonable_ptr<C, F, U>& lhs, const std::nullptr_t& rhs) { - return !(lhs < rhs); -} -} // namespace mongo diff --git a/src/mongo/base/clonable_ptr_test.cpp b/src/mongo/base/clonable_ptr_test.cpp deleted file mode 100644 index 80b28b49d4d..00000000000 --- a/src/mongo/base/clonable_ptr_test.cpp +++ /dev/null @@ -1,954 +0,0 @@ -// clonable_ptr.t.cpp - -/*- - * Copyright (C) 2016 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 "clonable_ptr.h" - -#include "mongo/stdx/memory.h" -#include "mongo/unittest/unittest.h" - -#include <boost/lexical_cast.hpp> - -namespace { -// These testing helper classes model various kinds of class which should be compatible with -// `mongo::clonable_ptr`. The basic use cases satisfied by each class are described in each class's -// documentation. - -// This class models the `Clonable` concept, and is used to test the simple case of `clonable_ptr`. -class ClonableTest { -private: - std::string data = - "This is the string data which is stored to make Functor Clonable need a complicated copy " - "ctor."; - -public: - std::unique_ptr<ClonableTest> clone() const { - return mongo::stdx::make_unique<ClonableTest>(); - } -}; - -// This class provides a member structure which models `CloneFactory<AltClonableTest>`. The member -// structure is available under the expected member name of `clone_factory_type`. The -// `CloneFactory` is stateless. -class AltClonableTest { -private: - std::string data = - "This is the string data which is stored to make Functor Clonable need a complicated copy " - "ctor."; - -public: - struct clone_factory_type { - std::unique_ptr<AltClonableTest> operator()(const AltClonableTest&) const { - return mongo::stdx::make_unique<AltClonableTest>(); - } - }; -}; - -// This class requires a companion cloning function models `CloneFactory<Alt2ClonableTest>`. There -// is an attendant specialization of the `mongo::clonable_traits` metafunction to provide the clone -// factory for this type. That `CloneFactory` is stateless. -class Alt2ClonableTest { -private: - std::string data = - "This is the string data which is stored to make Functor Clonable need a complicated copy " - "ctor."; -}; -} // namespace - -namespace mongo { -// This specialization of the `mongo::clonable_traits` metafunction provides a model of a stateless -// `CloneFactory<Alt2ClonableTest>` -template <> -struct clonable_traits<::Alt2ClonableTest> { - struct clone_factory_type { - std::unique_ptr<Alt2ClonableTest> operator()(const Alt2ClonableTest&) const { - return mongo::stdx::make_unique<Alt2ClonableTest>(); - } - }; -}; -} // namespace mongo - -namespace { -// This class uses a stateful cloning function provided by the `getCloningFunction` static member. -// This stateful `CloneFactory<FunctorClonable>` must be passed to constructors of the -// `cloning_ptr`. -class FunctorClonable { -private: - std::string data = - "This is the string data which is stored to make Functor Clonable need a complicated copy " - "ctor."; - -public: - using CloningFunctionType = - std::function<std::unique_ptr<FunctorClonable>(const FunctorClonable&)>; - - static CloningFunctionType getCloningFunction() { - return - [](const FunctorClonable& c) { return mongo::stdx::make_unique<FunctorClonable>(c); }; - } -}; - -// This class uses a stateful cloning function provided by the `getCloningFunction` static member. -// This stateful `CloneFactory<FunctorWithDynamicStateClonable>` must be passed to constructors of -// the `cloning_ptr`. The `CloneFactory` for this type dynamically updates its internal state. -// This is used to test cloning of objects that have dynamically changing clone factories. -class FunctorWithDynamicStateClonable { -private: - std::string data = - "This is the string data which is stored to make Functor Clonable need a complicated copy " - "ctor."; - -public: - FunctorWithDynamicStateClonable(const FunctorWithDynamicStateClonable&) = delete; - FunctorWithDynamicStateClonable() = default; - - FunctorWithDynamicStateClonable(const std::string& s) : data(s) {} - - using CloningFunctionType = std::function<std::unique_ptr<FunctorWithDynamicStateClonable>( - const FunctorWithDynamicStateClonable&)>; - - static CloningFunctionType getCloningFunction() { - return [calls = 0](const FunctorWithDynamicStateClonable& c) mutable { - return mongo::stdx::make_unique<FunctorWithDynamicStateClonable>( - c.data + boost::lexical_cast<std::string>(++calls)); - }; - } -}; - -// This class models `Clonable`, with a return from clone which is -// `Constructible<std::unique_ptr<RawPointerClonable>>` but isn't -// `std::unique_ptr<RawPointerClonable>`. This is used to test that the `clonable_ptr` class does -// not expect `RawPointerClonable::clone() const` to return a model of -// `UniquePtr<RawPointerClonable>` -class RawPointerClonable { -public: - RawPointerClonable* clone() const { - return new RawPointerClonable; - } -}; - -// This class models `Clonable`, with a return from clone which is -// `Constructible<std::unique_ptr<UniquePtrClonable>>` because it is -// `std::unique_ptr<UniquePtrClonable>`. This is used to test that the `clonable_ptr` class can -// use a `UniquePtrClonable::clone() const` that returns a model of -// `UniquePtr<UniquePtrClonable>` -class UniquePtrClonable { -public: - std::unique_ptr<UniquePtrClonable> clone() const { - return mongo::stdx::make_unique<UniquePtrClonable>(); - } -}; - -TEST(ClonablePtrTest, syntax_smoke_test) { - { - mongo::clonable_ptr<ClonableTest> p; - - p = mongo::stdx::make_unique<ClonableTest>(); - - mongo::clonable_ptr<ClonableTest> p2 = p; - - ASSERT_TRUE(p != p2); - - static_assert(sizeof(p) == sizeof(ClonableTest*), - "`mongo::clonable_ptr< T >` should be `sizeof` a pointer when there is no " - "CloneFactory"); - } - - { - mongo::clonable_ptr<AltClonableTest> p; - - p = mongo::stdx::make_unique<AltClonableTest>(); - - mongo::clonable_ptr<AltClonableTest> p2 = p; - - ASSERT_TRUE(p != p2); - } - - { - mongo::clonable_ptr<Alt2ClonableTest> p; - - p = mongo::stdx::make_unique<Alt2ClonableTest>(); - - mongo::clonable_ptr<Alt2ClonableTest> p2 = p; - - ASSERT_TRUE(p != p2); - } - - { - mongo::clonable_ptr<FunctorClonable, FunctorClonable::CloningFunctionType> p{ - FunctorClonable::getCloningFunction()}; - - p = mongo::stdx::make_unique<FunctorClonable>(); - - mongo::clonable_ptr<FunctorClonable, FunctorClonable::CloningFunctionType> p2 = p; - - ASSERT_TRUE(p != p2); - - mongo::clonable_ptr<FunctorClonable, FunctorClonable::CloningFunctionType> p3{ - FunctorClonable::getCloningFunction()}; - - auto tmp = mongo::stdx::make_unique<FunctorClonable>(); - p3 = std::move(tmp); - - ASSERT_TRUE(p != p2); - ASSERT_TRUE(p2 != p3); - ASSERT_TRUE(p != p3); - } -} - -// These tests check that all expected valid syntactic forms of use for the -// `mongo::clonable_ptr<Clonable>` are valid. These tests assert nothing but provide a single -// unified place to check the syntax of this component. Build failures in these parts indicate that -// a change to the component has broken an expected valid syntactic usage. Any expected valid usage -// which is not in this list should be added. -namespace SyntaxTests { -template <typename Clonable> -void construction() { - // Test default construction - { mongo::clonable_ptr<Clonable>{}; } - - // Test construction from a nullptr - { mongo::clonable_ptr<Clonable>{nullptr}; } - - // Test construction from a Clonable pointer. - { - Clonable* const local = nullptr; - mongo::clonable_ptr<Clonable>{local}; - } - - // Test move construction. - { mongo::clonable_ptr<Clonable>{mongo::clonable_ptr<Clonable>{}}; } - - // Test copy construction. - { - mongo::clonable_ptr<Clonable> a; - mongo::clonable_ptr<Clonable> b{a}; - } - - // Test move assignment. - { - mongo::clonable_ptr<Clonable> a; - a = mongo::clonable_ptr<Clonable>{}; - } - - // Test copy assignment. - { - mongo::clonable_ptr<Clonable> a; - mongo::clonable_ptr<Clonable> b; - b = a; - } - - // Test unique pointer construction - { mongo::clonable_ptr<Clonable>{mongo::stdx::make_unique<Clonable>()}; } - - // Test unique pointer construction (conversion) - { - auto acceptor = [](const mongo::clonable_ptr<Clonable>&) {}; - acceptor(mongo::stdx::make_unique<Clonable>()); - } - - // Test non-conversion pointer construction - { static_assert(!std::is_convertible<Clonable*, mongo::clonable_ptr<Clonable>>::value, ""); } - - // Test conversion unique pointer construction - { - static_assert( - std::is_convertible<std::unique_ptr<Clonable>, mongo::clonable_ptr<Clonable>>::value, - ""); - } -} - -// Tests that syntactic forms that require augmented construction are proper -template <typename Clonable, typename CloneFactory> -void augmentedConstruction() { - // Test default construction - { - static_assert( - !std::is_default_constructible<mongo::clonable_ptr<Clonable, CloneFactory>>::value, ""); - } - - // Test Clone Factory construction - { mongo::clonable_ptr<Clonable, CloneFactory>{Clonable::getCloningFunction()}; } - - // Test non-construction from a nullptr - { - static_assert(!std::is_constructible<mongo::clonable_ptr<Clonable, CloneFactory>, - std::nullptr_t>::value, - ""); - } - - // Test construction from a nullptr with factory - { mongo::clonable_ptr<Clonable, CloneFactory>{nullptr, Clonable::getCloningFunction()}; } - - // Test construction from a Clonable pointer. - { - static_assert( - !std::is_constructible<mongo::clonable_ptr<Clonable, CloneFactory>, Clonable*>::value, - ""); - } - - - // Test construction from a Clonable pointer with factory. - { - Clonable* const local = nullptr; - mongo::clonable_ptr<Clonable, CloneFactory>{local, Clonable::getCloningFunction()}; - } - - // Test move construction. - { - mongo::clonable_ptr<Clonable, CloneFactory>{ - mongo::clonable_ptr<Clonable, CloneFactory>{Clonable::getCloningFunction()}}; - } - - // Test copy construction. - { - mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()}; - mongo::clonable_ptr<Clonable, CloneFactory> b{a}; - } - - // Test augmented copy construction. - { - mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()}; - mongo::clonable_ptr<Clonable, CloneFactory> b{a, Clonable::getCloningFunction()}; - } - - - // Test move assignment. - { - mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()}; - a = mongo::clonable_ptr<Clonable, CloneFactory>{Clonable::getCloningFunction()}; - } - - // Test copy assignment. - { - mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()}; - mongo::clonable_ptr<Clonable, CloneFactory> b{Clonable::getCloningFunction()}; - b = a; - } - - // Test unique pointer construction - { - mongo::clonable_ptr<Clonable, CloneFactory>{mongo::stdx::make_unique<Clonable>(), - Clonable::getCloningFunction()}; - } - - // Test augmented unique pointer construction - { - mongo::clonable_ptr<Clonable, CloneFactory>{mongo::stdx::make_unique<Clonable>(), - Clonable::getCloningFunction()}; - } - - // Test non-conversion pointer construction - { - static_assert( - !std::is_convertible<Clonable*, mongo::clonable_ptr<Clonable, CloneFactory>>::value, - ""); - Clonable* p = nullptr; - mongo::clonable_ptr<Clonable, CloneFactory> x(p, CloneFactory{}); - } - - // Test conversion unique pointer construction - { - static_assert(!std::is_convertible<std::unique_ptr<Clonable>, - mongo::clonable_ptr<Clonable, CloneFactory>>::value, - ""); - } -} - -template <typename Clonable> -void pointerOperations() { - mongo::clonable_ptr<Clonable> a; - - // Test `.get()` functionality: - { - Clonable* p = a.get(); - (void)p; - } - - // Test `->` functionality - { - // We don't actually want to call the dtor, but we want the compiler to check that we - // have. - if (false) { - a->~Clonable(); - } - } - - // Test `*` functionality - { - Clonable& r = *a; - (void)r; - } - - // Test reset functionality - { - a.reset(); - a.reset(nullptr); - a.reset(new Clonable); - } -} - -template <typename Clonable> -void equalityOperations() { - mongo::clonable_ptr<Clonable> a; - mongo::clonable_ptr<Clonable> b; - - std::unique_ptr<Clonable> ua; - - // Test equality expressions - { - (void)(a == a); - (void)(a == b); - (void)(b == a); - - (void)(a == ua); - (void)(ua == a); - - (void)(nullptr == a); - (void)(a == nullptr); - } - - // Test inequality expressions - { - (void)(a != a); - (void)(a != b); - (void)(b != a); - - (void)(a != ua); - (void)(ua != a); - - (void)(nullptr == a); - (void)(a == nullptr); - } -} -} // namespace SyntaxTests - -TEST(ClonablePtrSyntaxTests, construction) { - SyntaxTests::construction<ClonableTest>(); - SyntaxTests::construction<AltClonableTest>(); - SyntaxTests::construction<Alt2ClonableTest>(); - SyntaxTests::construction<RawPointerClonable>(); - SyntaxTests::construction<UniquePtrClonable>(); -} - -TEST(ClonablePtrSyntaxTests, augmentedConstruction) { - SyntaxTests::augmentedConstruction<FunctorClonable, FunctorClonable::CloningFunctionType>(); - SyntaxTests::augmentedConstruction<FunctorWithDynamicStateClonable, - FunctorWithDynamicStateClonable::CloningFunctionType>(); -} - -TEST(ClonablePtrSyntaxTests, pointerOperations) { - SyntaxTests::pointerOperations<ClonableTest>(); - SyntaxTests::pointerOperations<AltClonableTest>(); - SyntaxTests::pointerOperations<Alt2ClonableTest>(); - SyntaxTests::pointerOperations<RawPointerClonable>(); - SyntaxTests::pointerOperations<UniquePtrClonable>(); -} - -TEST(ClonablePtrSyntaxTests, equalityOperations) { - SyntaxTests::equalityOperations<ClonableTest>(); - SyntaxTests::equalityOperations<AltClonableTest>(); - SyntaxTests::equalityOperations<Alt2ClonableTest>(); - SyntaxTests::equalityOperations<RawPointerClonable>(); - SyntaxTests::equalityOperations<UniquePtrClonable>(); -} - -namespace BehaviorTests { -class DetectDestruction { -public: - static int activeCount; - - static void resetCount() { - activeCount = 0; - } - - ~DetectDestruction() { - --activeCount; - } - - DetectDestruction(const DetectDestruction&) { - ++activeCount; - } - - DetectDestruction& operator=(const DetectDestruction&) = delete; - - DetectDestruction(DetectDestruction&&) = delete; - DetectDestruction& operator=(DetectDestruction&&) = delete; - - DetectDestruction() { - ++activeCount; - } - - std::unique_ptr<DetectDestruction> clone() const { - return mongo::stdx::make_unique<DetectDestruction>(*this); - } -}; - -int DetectDestruction::activeCount = 0; - -struct DestructionGuard { - DestructionGuard(const DestructionGuard&) = delete; - DestructionGuard& operator=(const DestructionGuard&) = delete; - - DestructionGuard() { - DetectDestruction::resetCount(); - } - - ~DestructionGuard() { - ASSERT_EQ(DetectDestruction::activeCount, 0); - } -}; - -TEST(ClonablePtrTest, basic_construction_test) { - // Do not default construct the object - { - DestructionGuard check; - mongo::clonable_ptr<DetectDestruction> p; - ASSERT_EQ(DetectDestruction::activeCount, 0); - } - - // Do not make unnecessary copies of the object from ptr - { - DestructionGuard check; - mongo::clonable_ptr<DetectDestruction> p{new DetectDestruction}; - ASSERT_EQ(DetectDestruction::activeCount, 1); - } - - // Do not make unnecessary copies of the object from unique_ptr - { - DestructionGuard check; - mongo::clonable_ptr<DetectDestruction> p{mongo::stdx::make_unique<DetectDestruction>()}; - ASSERT_EQ(DetectDestruction::activeCount, 1); - } - { - DestructionGuard check; - mongo::clonable_ptr<DetectDestruction> p = mongo::stdx::make_unique<DetectDestruction>(); - ASSERT_EQ(DetectDestruction::activeCount, 1); - } - - // Two separate constructions are unlinked - { - DestructionGuard check; - - mongo::clonable_ptr<DetectDestruction> p1{mongo::stdx::make_unique<DetectDestruction>()}; - ASSERT_EQ(DetectDestruction::activeCount, 1); - - { - mongo::clonable_ptr<DetectDestruction> p2{ - mongo::stdx::make_unique<DetectDestruction>()}; - ASSERT_EQ(DetectDestruction::activeCount, 2); - } - ASSERT_EQ(DetectDestruction::activeCount, 1); - } - - // Two separate constructions can have opposite order and be unlinked - { - DestructionGuard check; - - auto p1 = mongo::stdx::make_unique<mongo::clonable_ptr<DetectDestruction>>( - mongo::stdx::make_unique<DetectDestruction>()); - ASSERT_EQ(DetectDestruction::activeCount, 1); - - auto p2 = mongo::stdx::make_unique<mongo::clonable_ptr<DetectDestruction>>( - mongo::stdx::make_unique<DetectDestruction>()); - ASSERT_EQ(DetectDestruction::activeCount, 2); - - p1.reset(); - ASSERT_EQ(DetectDestruction::activeCount, 1); - - p2.reset(); - ASSERT_EQ(DetectDestruction::activeCount, 0); - } -} - -// TODO: Bring in an "equivalence class for equality predicate testing" framework. -// Equals and Not Equals need to be tested independently -- It is not valid to assume that equals -// and not equals are correctly implemented as complimentary predicates. Equality must be -// reflexive, symmetric and transitive. This requres several instances that all have the same -// value. Simply testing "2 == 2" and "3 != 2" is insufficient. Every combination of position and -// equality must be tested to come out as expected. -// -// Consider that with equality it is important to make sure that `a == b` has the same meaning as `b -// == a`. It is also necessary to check that `a == b` and `b == c` and `a == c` is true, when all -// three are equal, and to do so in reverse: `b == a` and `c == b` and `c == a`. Further, the -// relationships above have to hold for multiple cases. Similar cases need to be tested for -// inequality. -// -// Further, equality is an incredibly important operation to test completely and thoroughly -- -// besides being a critical element in code using any value modeling type, it also is the keystone -// in any testing schedule for a copyable and movable value type. Almost all testing of behavior -// relies upon being able to detect fundamental differences in value. In order to provide this -// correctly, we provide a full battery of tests for equality in all mathematically relevant -// situations. For this equality testing schedule to be correct, we require a mechanism to -// initialize objects (and references to those objects) which have predictable value. These -// predictable values are then used to test known equality expressions for the correct evaluation. -// -// All other tests can then just use equality to verify that an object is in the desired state. -// This greatly simplifies testing and also makes tests more precise. -TEST(ClonablePtrTest, basicEqualityTest) { - DestructionGuard check; - - mongo::clonable_ptr<DetectDestruction> n1; - mongo::clonable_ptr<DetectDestruction> n2; - mongo::clonable_ptr<DetectDestruction> n3; - - mongo::clonable_ptr<DetectDestruction> a = mongo::stdx::make_unique<DetectDestruction>(); - mongo::clonable_ptr<DetectDestruction> b = mongo::stdx::make_unique<DetectDestruction>(); - mongo::clonable_ptr<DetectDestruction> c = mongo::stdx::make_unique<DetectDestruction>(); - - const mongo::clonable_ptr<DetectDestruction>& ap = a; - const mongo::clonable_ptr<DetectDestruction>& bp = b; - const mongo::clonable_ptr<DetectDestruction>& cp = c; - const mongo::clonable_ptr<DetectDestruction>& ap2 = a; - const mongo::clonable_ptr<DetectDestruction>& bp2 = b; - const mongo::clonable_ptr<DetectDestruction>& cp2 = c; - - // Equals operator - - // Identity checks - - ASSERT(n1 == n1); - ASSERT(n2 == n2); - ASSERT(n3 == n3); - - ASSERT(a == a); - ASSERT(b == b); - ASSERT(c == c); - - // Same value checks. (Because unique pointers should never be the same value, we have to use - // references.) - - ASSERT(n1 == n2); - ASSERT(n1 == n3); - - ASSERT(n2 == n1); - ASSERT(n2 == n3); - - ASSERT(n3 == n1); - ASSERT(n3 == n2); - - ASSERT(a == ap); - ASSERT(a == ap2); - ASSERT(ap == a); - ASSERT(ap == ap2); - ASSERT(ap2 == a); - ASSERT(ap2 == ap); - - ASSERT(b == bp); - ASSERT(b == bp2); - ASSERT(bp == b); - ASSERT(bp == bp2); - ASSERT(bp2 == b); - ASSERT(bp2 == bp); - - ASSERT(c == cp); - ASSERT(c == cp2); - ASSERT(cp == c); - ASSERT(cp == cp2); - ASSERT(cp2 == c); - ASSERT(cp2 == cp); - - // Different value checks: - - ASSERT(!(a == n1)); - ASSERT(!(b == n1)); - ASSERT(!(c == n1)); - ASSERT(!(a == n2)); - ASSERT(!(b == n2)); - ASSERT(!(c == n2)); - - ASSERT(!(n1 == a)); - ASSERT(!(n1 == b)); - ASSERT(!(n1 == c)); - ASSERT(!(n2 == a)); - ASSERT(!(n2 == b)); - ASSERT(!(n2 == c)); - - ASSERT(!(a == b)); - ASSERT(!(a == c)); - - ASSERT(!(b == a)); - ASSERT(!(b == c)); - - ASSERT(!(c == a)); - ASSERT(!(c == b)); - - // Not Equals operator - - // Identity checks - - ASSERT(!(n1 != n1)); - ASSERT(!(n2 != n2)); - ASSERT(!(n3 != n3)); - - ASSERT(!(a != a)); - ASSERT(!(b != b)); - ASSERT(!(c != c)); - - // Same value checks. (Because unique pointers should never be the same value, we have to use - // references.) - - ASSERT(!(n1 != n2)); - ASSERT(!(n1 != n3)); - - ASSERT(!(n2 != n1)); - ASSERT(!(n2 != n3)); - - ASSERT(!(n3 != n1)); - ASSERT(!(n3 != n2)); - - ASSERT(!(a != ap)); - ASSERT(!(a != ap2)); - ASSERT(!(ap != a)); - ASSERT(!(ap != ap2)); - ASSERT(!(ap2 != a)); - ASSERT(!(ap2 != ap)); - - ASSERT(!(b != bp)); - ASSERT(!(b != bp2)); - ASSERT(!(bp != b)); - ASSERT(!(bp != bp2)); - ASSERT(!(bp2 != b)); - ASSERT(!(bp2 != bp)); - - ASSERT(!(c != cp)); - ASSERT(!(c != cp2)); - ASSERT(!(cp != c)); - ASSERT(!(cp != cp2)); - ASSERT(!(cp2 != c)); - ASSERT(!(cp2 != cp)); - - // Different value checks: - - ASSERT(a != n1); - ASSERT(b != n1); - ASSERT(c != n1); - ASSERT(a != n2); - ASSERT(b != n2); - ASSERT(c != n2); - - ASSERT(n1 != a); - ASSERT(n1 != b); - ASSERT(n1 != c); - ASSERT(n2 != a); - ASSERT(n2 != b); - ASSERT(n2 != c); - - ASSERT(a != b); - ASSERT(a != c); - - ASSERT(b != a); - ASSERT(b != c); - - ASSERT(c != a); - ASSERT(c != b); -} - -// TODO: all other forms of equality with other types (`std::nullptr_t` and `std::unique_ptr< T >`) -// need testing still. - -TEST(ClonablePtrTest, ownershipStabilityTest) { - { - DestructionGuard check; - - auto ptr_init = mongo::stdx::make_unique<DetectDestruction>(); - const auto* rp = ptr_init.get(); - - mongo::clonable_ptr<DetectDestruction> cp = std::move(ptr_init); - - ASSERT(rp == cp.get()); - - mongo::clonable_ptr<DetectDestruction> cp2 = std::move(cp); - - ASSERT(rp == cp2.get()); - - mongo::clonable_ptr<DetectDestruction> cp3; - - ASSERT(nullptr == cp3); - - cp3 = std::move(cp2); - - ASSERT(rp == cp3.get()); - } - - { - auto ptr_init = mongo::stdx::make_unique<DetectDestruction>(); - const auto* rp = ptr_init.get(); - - mongo::clonable_ptr<DetectDestruction> cp{ptr_init.release()}; - - ASSERT(rp == cp.get()); - - mongo::clonable_ptr<DetectDestruction> cp2 = std::move(cp); - - ASSERT(rp == cp2.get()); - - mongo::clonable_ptr<DetectDestruction> cp3; - - ASSERT(nullptr == cp3.get()); - - cp3 = std::move(cp2); - - ASSERT(rp == cp3.get()); - } -} - -class ClonableObject { -private: - int value = 0; - -public: - // ClonableObject( const ClonableObject & ) { abort(); } - ClonableObject() = default; - explicit ClonableObject(const int v) : value(v) {} - - std::unique_ptr<ClonableObject> clone() const { - return mongo::stdx::make_unique<ClonableObject>(*this); - } - - auto make_equality_lens() const -> decltype(std::tie(this->value)) { - return std::tie(value); - } -}; - -bool operator==(const ClonableObject& lhs, const ClonableObject& rhs) { - return lhs.make_equality_lens() == rhs.make_equality_lens(); -} - -bool operator!=(const ClonableObject& lhs, const ClonableObject& rhs) { - return !(lhs == rhs); -} - -TEST(ClonablePtrTest, noObjectCopySemanticTest) { - mongo::clonable_ptr<ClonableObject> p; - - mongo::clonable_ptr<ClonableObject> p2 = p; - ASSERT(p == p2); - - mongo::clonable_ptr<ClonableObject> p3; - - p3 = p; - ASSERT(p == p3); -} - -TEST(ClonablePtrTest, objectCopySemanticTest) { - mongo::clonable_ptr<ClonableObject> p = mongo::stdx::make_unique<ClonableObject>(1); - mongo::clonable_ptr<ClonableObject> q = mongo::stdx::make_unique<ClonableObject>(2); - ASSERT(p != q); - ASSERT(*p != *q); - - mongo::clonable_ptr<ClonableObject> p2 = p; - ASSERT(p != p2); - ASSERT(*p == *p2); - - mongo::clonable_ptr<ClonableObject> q2 = q; - ASSERT(q2 != q); - ASSERT(q2 != p); - ASSERT(q2 != p2); - ASSERT(*q2 == *q); - - q2 = p2; - ASSERT(q2 != q); - ASSERT(q2 != p); - ASSERT(q2 != p2); - ASSERT(*q2 == *p2); -} - -class Interface { -public: - virtual ~Interface() = default; - virtual void consumeText(const std::string& message) = 0; - virtual std::string produceText() = 0; - - std::unique_ptr<Interface> clone() const { - return std::unique_ptr<Interface>{this->clone_impl()}; - } - -private: - virtual Interface* clone_impl() const = 0; -}; - -class GeneratorImplementation : public Interface { -private: - const std::string root; - int generation = 0; - - GeneratorImplementation* clone_impl() const { - return new GeneratorImplementation{*this}; - } - -public: - explicit GeneratorImplementation(const std::string& m) : root(m) {} - - void consumeText(const std::string&) override {} - - std::string produceText() override { - return root + boost::lexical_cast<std::string>(++generation); - } -}; - -class StorageImplementation : public Interface { -private: - std::string store; - - StorageImplementation* clone_impl() const { - return new StorageImplementation{*this}; - } - -public: - void consumeText(const std::string& m) override { - store = m; - } - std::string produceText() override { - return store; - } -}; - - -TEST(ClonablePtrSimpleTest, simpleUsageExample) { - mongo::clonable_ptr<Interface> source; - mongo::clonable_ptr<Interface> sink; - - mongo::clonable_ptr<Interface> instance = std::make_unique<StorageImplementation>(); - - sink = instance; - - ASSERT(instance.get() != sink.get()); - - instance = std::make_unique<GeneratorImplementation>("base message"); - - - source = std::move(instance); - - - sink->consumeText(source->produceText()); -} - -} // namespace BehaviorTests -} // namespace diff --git a/src/mongo/base/concept/README b/src/mongo/base/concept/README deleted file mode 100644 index bc2c74fabe4..00000000000 --- a/src/mongo/base/concept/README +++ /dev/null @@ -1,5 +0,0 @@ -This directory contains a number of C++ headers which describe concepts for -C++ types used by and with the Mongo library. These headers do not describe -instantiable types, but instead are used to concisely describe models of C++ -type concepts. When C++ grows a proper `Concepts` feature, these files can be -converted to proper concepts. diff --git a/src/mongo/base/concept/assignable.h b/src/mongo/base/concept/assignable.h deleted file mode 100644 index 8cf3f0e9ab5..00000000000 --- a/src/mongo/base/concept/assignable.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "mongo/base/concept/copy_assignable.h" -#include "mongo/base/concept/copy_constructible.h" - -namespace mongo { -namespace concept { -/*! - * The Assignable concept models a type which can be copy assigned and copy constructed. - */ -struct Assignable : CopyConstructible, CopyAssignable {}; -} // namespace concept -} // namespace mongo diff --git a/src/mongo/base/concept/clonable.h b/src/mongo/base/concept/clonable.h deleted file mode 100644 index 96354333c0d..00000000000 --- a/src/mongo/base/concept/clonable.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "mongo/base/concept/constructible.h" -#include "mongo/base/concept/unique_ptr.h" - -namespace mongo { -namespace concept { -/*! - * Objects conforming to the Clonable concept can be dynamically copied, using `this->clone()`. - * The Clonable concept does not specify the return type of the `clone()` function. - */ -struct Clonable { - /*! Clonable objects must be safe to destroy, by pointer. */ - virtual ~Clonable() noexcept = 0; - - /*! Clonable objects can be cloned without knowing the actual dynamic type. */ - Constructible<UniquePtr<Clonable>> clone() const; -}; -} // namespace concept -} // namespace mongo diff --git a/src/mongo/base/concept/clone_factory.h b/src/mongo/base/concept/clone_factory.h deleted file mode 100644 index 17e7be07cc3..00000000000 --- a/src/mongo/base/concept/clone_factory.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "mongo/base/concept/assignable.h" -#include "mongo/base/concept/constructible.h" -#include "mongo/base/concept/unique_ptr.h" - -namespace mongo { -namespace concept { -/*! - * Objects conforming to the `CloneFactory` concept are function-like constructs which return - * objects that are dynamically allocated copies of their inputs. - * These copies can be made without knowing the actual dynamic type. The `CloneFactory` type itself - * must be `Assignable`, in that it can be used with automatically generated copy constructors and - * copy assignment operators. - */ -template <typename T> -struct CloneFactory : Assignable { - Constructible<UniquePtr<T>> operator()(const T*) const; -}; -} // namespace concept -} // namespace mongo diff --git a/src/mongo/base/concept/constructible.h b/src/mongo/base/concept/constructible.h deleted file mode 100644 index b6e5211e6f1..00000000000 --- a/src/mongo/base/concept/constructible.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include <type_traits> - -#include "mongo/stdx/type_traits.h" - -namespace mongo { -namespace concept { - -/** - * The Constructable trait indicates whether `T` is constructible from `Constructible`. - * - * RETURNS: true if `T{ std::declval< Constructible >() }` is a valid expression and false - * otherwise. - */ -template <typename T, typename Constructible, typename = void> -struct is_constructible : std::false_type {}; - -template <typename T, typename Constructible> -struct is_constructible<T, - Constructible, - stdx::void_t<decltype(T{std::declval<Constructible<T>>()})>> - : std::true_type {}; - -/** - * The Constructable concept models a type which can be passed to a single-argument constructor of - * `T`. - * This is not possible to describe in the type `Constructible`. - * - * The expression: `T{ std::declval< Constructible< T > >() }` should be valid. - * - * This concept is more broadly applicable than `ConvertibleTo`. `ConvertibleTo` uses implicit - * conversion, whereas `Constructible` uses direct construction. - */ -template <typename T> -struct Constructible {}; -} // namespace concept -} // namespace mongo diff --git a/src/mongo/base/concept/convertible_to.h b/src/mongo/base/concept/convertible_to.h deleted file mode 100644 index 57e733418cf..00000000000 --- a/src/mongo/base/concept/convertible_to.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -namespace mongo { -namespace concept { -/** - * The ConvertibleTo concept models a type which can be converted implicitly into a `T`. - * The code: `T x; x= ConvertibleTo< T >{};` should be valid. - */ -template <typename T> -struct ConvertibleTo { - operator T(); -} -} // namespace concept -} // namespace mongo diff --git a/src/mongo/base/concept/copy_assignable.h b/src/mongo/base/concept/copy_assignable.h deleted file mode 100644 index 2b29e96eb82..00000000000 --- a/src/mongo/base/concept/copy_assignable.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -namespace mongo { -namespace concept { -/** - * The CopyAssignable concept models a type which can be copy assigned. - * - * The expression: `copyAssignable= copyAssignable` should be valid. - */ -struct CopyAssignable { - /** - * The copy assignment operator is required by `CopyAssignable`. - * NOTE: Copy Assignment is only required on lvalue targets of `CopyAssignable`. - */ - CopyAssignable& operator=(const CopyAssignable&) &; -}; -} // namespace concept -} // namespace mongo diff --git a/src/mongo/base/concept/copy_constructible.h b/src/mongo/base/concept/copy_constructible.h deleted file mode 100644 index c96856cc485..00000000000 --- a/src/mongo/base/concept/copy_constructible.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -namespace mongo { -namespace concept { -/** - * The CopyConstructable concept models a type which can be copy constructed. - * - * The expression: `CopyConstructible{ copyConstructible }` should be valid. - */ -struct CopyConstructible { - CopyConstructible(const CopyConstructible&); -}; -} // namespace concept -} // namespace mongo diff --git a/src/mongo/base/concept/unique_ptr.h b/src/mongo/base/concept/unique_ptr.h deleted file mode 100644 index 1edd552a93f..00000000000 --- a/src/mongo/base/concept/unique_ptr.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "mongo/base/concept/convertible_to.h" - -namespace mongo { -namespace concept { -/** - * The `UniquePtr` Concept models a movable owning pointer of an object. - * `std::unique_ptr< T >` is a model of `mongo::concept::UniquePtr< T >`. - */ -template <typename T> -struct UniquePtr { - /** The `UniquePtr< T >` must retire its pointer to `T` on destruction. */ - ~UniquePtr() noexcept; - - UniquePtr(UniquePtr&& p); - UniquePtr& operator=(UniquePtr&& p); - - UniquePtr(); - UniquePtr(T* p); - - ConvertibleTo<T*> operator->() const; - T& operator*() const; - - explicit operator bool() const; - - ConvertibleTo<T*> get() const; - - void reset() noexcept; - void reset(ConvertibleTo<T*>); -}; - -/*! A `UniquePtr` object must be equality comparable. */ -template <typename T> -bool operator==(const UniquePtr<T>& lhs, const UniquePtr<T>& rhs); - -/*! A `UniquePtr` object must be inequality comparable. */ -template <typename T> -bool operator!=(const UniquePtr<T>& lhs, const UniquePtr<T>& rhs); -} // namespace concept -} // namespace mongo |