1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/container for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10
11 #ifndef BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP
12 #define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP
13
14 #if defined (_MSC_VER)
15 # pragma once
16 #endif
17
18 #include <boost/config.hpp>
19 #include <boost/move/detail/type_traits.hpp>
20 #include <boost/move/utility_core.hpp>
21 #include <boost/container/detail/dispatch_uses_allocator.hpp>
22 #include <boost/container/new_allocator.hpp>
23 #include <boost/container/pmr/memory_resource.hpp>
24 #include <boost/container/pmr/global_resource.hpp>
25
26 #include <cstddef>
27
28 namespace boost {
29 namespace container {
30 namespace pmr {
31
32 //! A specialization of class template `polymorphic_allocator` conforms to the Allocator requirements.
33 //! Constructed with different memory resources, different instances of the same specialization of
34 //! `polymorphic_allocator` can exhibit entirely different allocation behavior. This runtime
35 //! polymorphism allows objects that use polymorphic_allocator to behave as if they used different
36 //! allocator types at run time even though they use the same static allocator type.
37 template <class T>
38 class polymorphic_allocator
39 {
40 public:
41 typedef T value_type;
42
43 //! <b>Effects</b>: Sets m_resource to
44 //! `get_default_resource()`.
polymorphic_allocator()45 polymorphic_allocator() BOOST_NOEXCEPT
46 : m_resource(::boost::container::pmr::get_default_resource())
47 {}
48
49 //! <b>Requires</b>: r is non-null.
50 //!
51 //! <b>Effects</b>: Sets m_resource to r.
52 //!
53 //! <b>Throws</b>: Nothing
54 //!
55 //! <b>Notes</b>: This constructor provides an implicit conversion from memory_resource*.
polymorphic_allocator(memory_resource * r)56 polymorphic_allocator(memory_resource* r)
57 : m_resource(r)
58 { BOOST_ASSERT(r != 0); }
59
60 //! <b>Effects</b>: Sets m_resource to
61 //! other.resource().
polymorphic_allocator(const polymorphic_allocator & other)62 polymorphic_allocator(const polymorphic_allocator& other)
63 : m_resource(other.m_resource)
64 {}
65
66 //! <b>Effects</b>: Sets m_resource to
67 //! other.resource().
68 template <class U>
polymorphic_allocator(const polymorphic_allocator<U> & other)69 polymorphic_allocator(const polymorphic_allocator<U>& other) BOOST_NOEXCEPT
70 : m_resource(other.resource())
71 {}
72
73 //! <b>Effects</b>: Sets m_resource to
74 //! other.resource().
operator =(const polymorphic_allocator & other)75 polymorphic_allocator& operator=(const polymorphic_allocator& other)
76 { m_resource = other.m_resource; return *this; }
77
78 //! <b>Returns</b>: Equivalent to
79 //! `static_cast<T*>(m_resource->allocate(n * sizeof(T), alignof(T)))`.
allocate(size_t n)80 T* allocate(size_t n)
81 { return static_cast<T*>(m_resource->allocate(n*sizeof(T), ::boost::move_detail::alignment_of<T>::value)); }
82
83 //! <b>Requires</b>: p was allocated from a memory resource, x, equal to *m_resource,
84 //! using `x.allocate(n * sizeof(T), alignof(T))`.
85 //!
86 //! <b>Effects</b>: Equivalent to m_resource->deallocate(p, n * sizeof(T), alignof(T)).
87 //!
88 //! <b>Throws</b>: Nothing.
deallocate(T * p,size_t n)89 void deallocate(T* p, size_t n)
90 { m_resource->deallocate(p, n*sizeof(T), ::boost::move_detail::alignment_of<T>::value); }
91
92 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
93 //! <b>Requires</b>: Uses-allocator construction of T with allocator
94 //! `*this` and constructor arguments `std::forward<Args>(args)...`
95 //! is well-formed. [Note: uses-allocator construction is always well formed for
96 //! types that do not use allocators. - end note]
97 //!
98 //! <b>Effects</b>: Construct a T object at p by uses-allocator construction with allocator
99 //! `*this` and constructor arguments `std::forward<Args>(args)...`.
100 //!
101 //! <b>Throws</b>: Nothing unless the constructor for T throws.
102 template < typename U, class ...Args>
construct(U * p,BOOST_FWD_REF (Args)...args)103 void construct(U* p, BOOST_FWD_REF(Args)...args)
104 {
105 new_allocator<U> na;
106 dtl::dispatch_uses_allocator
107 (na, *this, p, ::boost::forward<Args>(args)...);
108 }
109
110 #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
111
112 //Disable this overload if the first argument is pair as some compilers have
113 //overload selection problems when the first parameter is a pair.
114 #define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE(N) \
115 template < typename U BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\
116 void construct(U* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\
117 {\
118 new_allocator<U> na;\
119 dtl::dispatch_uses_allocator\
120 (na, *this, p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
121 }\
122 //
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE)123 BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE)
124 #undef BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE
125
126 #endif //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
127
128 //! <b>Effects</b>:
129 //! p->~U().
130 template <class U>
131 void destroy(U* p)
132 { (void)p; p->~U(); }
133
134 //! <b>Returns</b>: Equivalent to
135 //! `polymorphic_allocator()`.
select_on_container_copy_construction() const136 polymorphic_allocator select_on_container_copy_construction() const
137 { return polymorphic_allocator(); }
138
139 //! <b>Returns</b>:
140 //! m_resource.
resource() const141 memory_resource* resource() const
142 { return m_resource; }
143
144 private:
145 memory_resource* m_resource;
146 };
147
148 //! <b>Returns</b>:
149 //! `*a.resource() == *b.resource()`.
150 template <class T1, class T2>
operator ==(const polymorphic_allocator<T1> & a,const polymorphic_allocator<T2> & b)151 bool operator==(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) BOOST_NOEXCEPT
152 { return *a.resource() == *b.resource(); }
153
154
155 //! <b>Returns</b>:
156 //! `! (a == b)`.
157 template <class T1, class T2>
operator !=(const polymorphic_allocator<T1> & a,const polymorphic_allocator<T2> & b)158 bool operator!=(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) BOOST_NOEXCEPT
159 { return *a.resource() != *b.resource(); }
160
161 } //namespace pmr {
162 } //namespace container {
163 } //namespace boost {
164
165 #endif //BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP
166