| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost |
| // Software License, Version 1.0. (See accompanying file |
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // See http://www.boost.org/libs/container for documentation. |
| // |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #ifndef BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP |
| #define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP |
| |
| #if defined (_MSC_VER) |
| # pragma once |
| #endif |
| |
| #include <boost/config.hpp> |
| #include <boost/move/detail/type_traits.hpp> |
| #include <boost/move/utility_core.hpp> |
| #include <boost/container/detail/dispatch_uses_allocator.hpp> |
| #include <boost/container/new_allocator.hpp> |
| #include <boost/container/pmr/memory_resource.hpp> |
| #include <boost/container/pmr/global_resource.hpp> |
| |
| #include <cstddef> |
| |
| namespace boost { |
| namespace container { |
| namespace pmr { |
| |
| //! A specialization of class template `polymorphic_allocator` conforms to the Allocator requirements. |
| //! Constructed with different memory resources, different instances of the same specialization of |
| //! `polymorphic_allocator` can exhibit entirely different allocation behavior. This runtime |
| //! polymorphism allows objects that use polymorphic_allocator to behave as if they used different |
| //! allocator types at run time even though they use the same static allocator type. |
| template <class T> |
| class polymorphic_allocator |
| { |
| public: |
| typedef T value_type; |
| |
| //! <b>Effects</b>: Sets m_resource to |
| //! `get_default_resource()`. |
| polymorphic_allocator() BOOST_NOEXCEPT |
| : m_resource(::boost::container::pmr::get_default_resource()) |
| {} |
| |
| //! <b>Requires</b>: r is non-null. |
| //! |
| //! <b>Effects</b>: Sets m_resource to r. |
| //! |
| //! <b>Throws</b>: Nothing |
| //! |
| //! <b>Notes</b>: This constructor provides an implicit conversion from memory_resource*. |
| polymorphic_allocator(memory_resource* r) |
| : m_resource(r) |
| { BOOST_ASSERT(r != 0); } |
| |
| //! <b>Effects</b>: Sets m_resource to |
| //! other.resource(). |
| polymorphic_allocator(const polymorphic_allocator& other) |
| : m_resource(other.m_resource) |
| {} |
| |
| //! <b>Effects</b>: Sets m_resource to |
| //! other.resource(). |
| template <class U> |
| polymorphic_allocator(const polymorphic_allocator<U>& other) BOOST_NOEXCEPT |
| : m_resource(other.resource()) |
| {} |
| |
| //! <b>Effects</b>: Sets m_resource to |
| //! other.resource(). |
| polymorphic_allocator& operator=(const polymorphic_allocator& other) |
| { m_resource = other.m_resource; return *this; } |
| |
| //! <b>Returns</b>: Equivalent to |
| //! `static_cast<T*>(m_resource->allocate(n * sizeof(T), alignof(T)))`. |
| T* allocate(size_t n) |
| { return static_cast<T*>(m_resource->allocate(n*sizeof(T), ::boost::move_detail::alignment_of<T>::value)); } |
| |
| //! <b>Requires</b>: p was allocated from a memory resource, x, equal to *m_resource, |
| //! using `x.allocate(n * sizeof(T), alignof(T))`. |
| //! |
| //! <b>Effects</b>: Equivalent to m_resource->deallocate(p, n * sizeof(T), alignof(T)). |
| //! |
| //! <b>Throws</b>: Nothing. |
| void deallocate(T* p, size_t n) |
| { m_resource->deallocate(p, n*sizeof(T), ::boost::move_detail::alignment_of<T>::value); } |
| |
| #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| //! <b>Requires</b>: Uses-allocator construction of T with allocator |
| //! `*this` and constructor arguments `std::forward<Args>(args)...` |
| //! is well-formed. [Note: uses-allocator construction is always well formed for |
| //! types that do not use allocators. - end note] |
| //! |
| //! <b>Effects</b>: Construct a T object at p by uses-allocator construction with allocator |
| //! `*this` and constructor arguments `std::forward<Args>(args)...`. |
| //! |
| //! <b>Throws</b>: Nothing unless the constructor for T throws. |
| template < typename U, class ...Args> |
| void construct(U* p, BOOST_FWD_REF(Args)...args) |
| { |
| new_allocator<U> na; |
| dtl::dispatch_uses_allocator |
| (na, *this, p, ::boost::forward<Args>(args)...); |
| } |
| |
| #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| |
| //Disable this overload if the first argument is pair as some compilers have |
| //overload selection problems when the first parameter is a pair. |
| #define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE(N) \ |
| template < typename U BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\ |
| void construct(U* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\ |
| {\ |
| new_allocator<U> na;\ |
| dtl::dispatch_uses_allocator\ |
| (na, *this, p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\ |
| }\ |
| // |
| BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE) |
| #undef BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE |
| |
| #endif //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| |
| //! <b>Effects</b>: |
| //! p->~U(). |
| template <class U> |
| void destroy(U* p) |
| { (void)p; p->~U(); } |
| |
| //! <b>Returns</b>: Equivalent to |
| //! `polymorphic_allocator()`. |
| polymorphic_allocator select_on_container_copy_construction() const |
| { return polymorphic_allocator(); } |
| |
| //! <b>Returns</b>: |
| //! m_resource. |
| memory_resource* resource() const |
| { return m_resource; } |
| |
| private: |
| memory_resource* m_resource; |
| }; |
| |
| //! <b>Returns</b>: |
| //! `*a.resource() == *b.resource()`. |
| template <class T1, class T2> |
| bool operator==(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) BOOST_NOEXCEPT |
| { return *a.resource() == *b.resource(); } |
| |
| |
| //! <b>Returns</b>: |
| //! `! (a == b)`. |
| template <class T1, class T2> |
| bool operator!=(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) BOOST_NOEXCEPT |
| { return *a.resource() != *b.resource(); } |
| |
| } //namespace pmr { |
| } //namespace container { |
| } //namespace boost { |
| |
| #endif //BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP |