]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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_RESOURCE_ADAPTOR_HPP | |
12 | #define BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP | |
13 | ||
14 | #if defined (_MSC_VER) | |
15 | # pragma once | |
16 | #endif | |
17 | ||
92f5a8d4 TL |
18 | #include <boost/container/detail/config_begin.hpp> |
19 | #include <boost/container/detail/workaround.hpp> | |
20 | #include <boost/container/container_fwd.hpp> | |
21 | ||
7c673cae FG |
22 | #include <boost/container/pmr/memory_resource.hpp> |
23 | #include <boost/container/allocator_traits.hpp> | |
24 | #include <boost/intrusive/detail/ebo_functor_holder.hpp> | |
25 | #include <boost/move/utility_core.hpp> | |
92f5a8d4 TL |
26 | #include <boost/move/detail/type_traits.hpp> |
27 | #include <boost/container/detail/std_fwd.hpp> | |
28 | ||
29 | #include <cstring> | |
7c673cae FG |
30 | |
31 | namespace boost { | |
32 | namespace container { | |
92f5a8d4 TL |
33 | |
34 | namespace pmr_dtl { | |
35 | ||
36 | template<class T> | |
37 | struct max_allocator_alignment | |
38 | { | |
39 | static const std::size_t value = 1; | |
40 | }; | |
41 | ||
42 | template<class T> | |
43 | struct max_allocator_alignment< ::boost::container::new_allocator<T> > | |
44 | { | |
45 | static const std::size_t value = boost::move_detail::alignment_of<boost::move_detail::max_align_t>::value; | |
46 | }; | |
47 | ||
48 | template<class T> | |
49 | struct max_allocator_alignment< std::allocator<T> > | |
50 | { | |
51 | static const std::size_t value = boost::move_detail::alignment_of<boost::move_detail::max_align_t>::value; | |
52 | }; | |
53 | ||
54 | } //namespace pmr_dtl | |
55 | ||
7c673cae FG |
56 | namespace pmr { |
57 | ||
58 | //! An instance of resource_adaptor<Allocator> is an adaptor that wraps a memory_resource interface | |
59 | //! around Allocator. In order that resource_adaptor<X<T>> and resource_adaptor<X<U>> are the same | |
60 | //! type for any allocator template X and types T and U, resource_adaptor<Allocator> is rendered as | |
61 | //! an alias to this class template such that Allocator is rebound to a char value type in every | |
62 | //! specialization of the class template. The requirements on this class template are defined below. | |
63 | //! In addition to the Allocator requirements, the parameter to resource_adaptor shall meet | |
64 | //! the following additional requirements: | |
65 | //! | |
66 | //! - `typename allocator_traits<Allocator>:: pointer` shall be identical to | |
67 | //! `typename allocator_traits<Allocator>:: value_type*`. | |
68 | //! | |
69 | //! - `typename allocator_traits<Allocator>:: const_pointer` shall be identical to | |
70 | //! `typename allocator_traits<Allocator>:: value_type const*`. | |
71 | //! | |
72 | //! - `typename allocator_traits<Allocator>:: void_pointer` shall be identical to `void*`. | |
73 | //! | |
74 | //! - `typename allocator_traits<Allocator>:: const_void_pointer` shall be identical to `void const*`. | |
75 | template <class Allocator> | |
76 | class resource_adaptor_imp | |
77 | : public memory_resource | |
78 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
79 | , private ::boost::intrusive::detail::ebo_functor_holder<Allocator> | |
80 | #endif | |
81 | { | |
82 | #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED | |
83 | Allocator m_alloc; | |
84 | #else | |
85 | BOOST_COPYABLE_AND_MOVABLE(resource_adaptor_imp) | |
86 | typedef ::boost::intrusive::detail::ebo_functor_holder<Allocator> ebo_alloc_t; | |
87 | void static_assert_if_not_char_allocator() const | |
88 | { | |
89 | //This class can only be used with allocators type char | |
92f5a8d4 | 90 | BOOST_STATIC_ASSERT((boost::container::dtl::is_same<typename Allocator::value_type, char>::value)); |
7c673cae FG |
91 | } |
92 | #endif | |
93 | ||
94 | public: | |
95 | typedef Allocator allocator_type; | |
96 | ||
97 | //! <b>Effects</b>: Default constructs | |
98 | //! m_alloc. | |
99 | resource_adaptor_imp() | |
100 | { this->static_assert_if_not_char_allocator(); } | |
101 | ||
102 | //! <b>Effects</b>: Copy constructs | |
103 | //! m_alloc. | |
104 | resource_adaptor_imp(const resource_adaptor_imp &other) | |
105 | : ebo_alloc_t(other.ebo_alloc_t::get()) | |
106 | {} | |
107 | ||
108 | //! <b>Effects</b>: Move constructs | |
109 | //! m_alloc. | |
110 | resource_adaptor_imp(BOOST_RV_REF(resource_adaptor_imp) other) | |
111 | : ebo_alloc_t(::boost::move(other.get())) | |
112 | {} | |
113 | ||
114 | //! <b>Effects</b>: Initializes m_alloc with | |
115 | //! a2. | |
116 | explicit resource_adaptor_imp(const Allocator& a2) | |
117 | : ebo_alloc_t(a2) | |
118 | { this->static_assert_if_not_char_allocator(); } | |
119 | ||
120 | //! <b>Effects</b>: Initializes m_alloc with | |
121 | //! a2. | |
122 | explicit resource_adaptor_imp(BOOST_RV_REF(Allocator) a2) | |
123 | : ebo_alloc_t(::boost::move(a2)) | |
124 | { this->static_assert_if_not_char_allocator(); } | |
125 | ||
126 | //! <b>Effects</b>: Copy assigns | |
127 | //! m_alloc. | |
128 | resource_adaptor_imp& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor_imp) other) | |
129 | { this->ebo_alloc_t::get() = other.ebo_alloc_t::get(); return *this; } | |
130 | ||
131 | //! <b>Effects</b>: Move assigns | |
132 | //! m_alloc. | |
133 | resource_adaptor_imp& operator=(BOOST_RV_REF(resource_adaptor_imp) other) | |
134 | { this->ebo_alloc_t::get() = ::boost::move(other.ebo_alloc_t::get()); return *this; } | |
135 | ||
136 | //! <b>Effects</b>: Returns m_alloc. | |
137 | allocator_type &get_allocator() | |
138 | { return this->ebo_alloc_t::get(); } | |
139 | ||
140 | //! <b>Effects</b>: Returns m_alloc. | |
141 | const allocator_type &get_allocator() const | |
142 | { return this->ebo_alloc_t::get(); } | |
143 | ||
144 | protected: | |
145 | //! <b>Returns</b>: Allocated memory obtained by calling m_alloc.allocate. The size and alignment | |
146 | //! of the allocated memory shall meet the requirements for a class derived from memory_resource. | |
92f5a8d4 TL |
147 | virtual void* do_allocate(std::size_t bytes, std::size_t alignment) |
148 | { | |
149 | if (alignment <= priv_guaranteed_allocator_alignment()) | |
150 | return this->ebo_alloc_t::get().allocate(bytes); | |
151 | else | |
152 | return this->priv_aligned_alloc(bytes, alignment); | |
153 | } | |
7c673cae FG |
154 | |
155 | //! <b>Requires</b>: p was previously allocated using A.allocate, where A == m_alloc, and not | |
156 | //! subsequently deallocated. | |
157 | //! | |
158 | //! <b>Effects</b>: Returns memory to the allocator using m_alloc.deallocate(). | |
92f5a8d4 TL |
159 | virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) |
160 | { | |
161 | if (alignment <= priv_guaranteed_allocator_alignment()) | |
162 | this->ebo_alloc_t::get().deallocate((char*)p, bytes); | |
163 | else | |
164 | this->priv_aligned_dealloc(p, bytes, alignment); | |
165 | } | |
7c673cae FG |
166 | |
167 | //! Let p be dynamic_cast<const resource_adaptor_imp*>(&other). | |
168 | //! | |
169 | //! <b>Returns</b>: false if p is null, otherwise the value of m_alloc == p->m_alloc. | |
170 | virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT | |
171 | { | |
172 | const resource_adaptor_imp* p = dynamic_cast<const resource_adaptor_imp*>(&other); | |
173 | return p && p->ebo_alloc_t::get() == this->ebo_alloc_t::get(); | |
174 | } | |
92f5a8d4 TL |
175 | |
176 | private: | |
177 | void * priv_aligned_alloc(std::size_t bytes, std::size_t alignment) | |
178 | { | |
179 | //Allocate space for requested bytes, plus alignment, plus bookeeping data | |
180 | void *const p = this->ebo_alloc_t::get().allocate(bytes + priv_extra_bytes_for_overalignment(alignment)); | |
181 | ||
182 | if (0 != p) { | |
183 | //Obtain the aligned address after the bookeeping data | |
184 | void *const aligned_ptr = (void*)(((std::size_t)p + priv_extra_bytes_for_overalignment(alignment)) & ~(alignment - 1)); | |
185 | ||
186 | //Store bookeeping data. Use memcpy as the underlying memory might be unaligned for | |
187 | //a pointer (e.g. 2 byte alignment in 32 bit, 4 byte alignment in 64 bit) | |
188 | std::memcpy(priv_bookeeping_addr_from_aligned_ptr(aligned_ptr), &p, sizeof(p)); | |
189 | return aligned_ptr; | |
190 | } | |
191 | return 0; | |
192 | } | |
193 | ||
194 | void priv_aligned_dealloc(void *aligned_ptr, std::size_t bytes, std::size_t alignment) | |
195 | { | |
196 | //Obtain bookeeping data | |
197 | void *p; | |
198 | std::memcpy(&p, priv_bookeeping_addr_from_aligned_ptr(aligned_ptr), sizeof(p)); | |
199 | std::size_t s = bytes + priv_extra_bytes_for_overalignment(alignment); | |
200 | this->ebo_alloc_t::get().deallocate((char*)p, s); | |
201 | } | |
202 | ||
203 | static BOOST_CONTAINER_FORCEINLINE void *priv_bookeeping_addr_from_aligned_ptr(void *aligned_ptr) | |
204 | { | |
205 | return reinterpret_cast<void*>(reinterpret_cast<std::size_t>(aligned_ptr) - sizeof(void*)); | |
206 | } | |
207 | ||
208 | BOOST_CONTAINER_FORCEINLINE static std::size_t priv_extra_bytes_for_overalignment(std::size_t alignment) | |
209 | { | |
210 | return alignment - 1 + sizeof(void*); | |
211 | } | |
212 | ||
213 | BOOST_CONTAINER_FORCEINLINE static std::size_t priv_guaranteed_allocator_alignment() | |
214 | { | |
215 | return pmr_dtl::max_allocator_alignment<Allocator>::value; | |
216 | } | |
7c673cae FG |
217 | }; |
218 | ||
219 | #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) | |
220 | ||
221 | //! `resource_adaptor<Allocator>` is rendered as an alias to resource_adaptor_imp class template | |
222 | //! such that Allocator is rebound to a char value type. | |
223 | template <class Allocator> | |
224 | using resource_adaptor = resource_adaptor_imp | |
225 | <typename allocator_traits<Allocator>::template rebind_alloc<char> >; | |
226 | ||
227 | #else | |
228 | ||
229 | template <class Allocator> | |
230 | class resource_adaptor | |
231 | : public resource_adaptor_imp | |
232 | <typename allocator_traits<Allocator>::template portable_rebind_alloc<char>::type> | |
233 | { | |
234 | typedef resource_adaptor_imp | |
235 | <typename allocator_traits<Allocator>::template portable_rebind_alloc<char>::type> base_t; | |
236 | ||
237 | BOOST_COPYABLE_AND_MOVABLE(resource_adaptor) | |
238 | ||
239 | public: | |
240 | resource_adaptor() | |
241 | : base_t() | |
242 | {} | |
243 | ||
244 | resource_adaptor(const resource_adaptor &other) | |
245 | : base_t(other) | |
246 | {} | |
247 | ||
248 | resource_adaptor(BOOST_RV_REF(resource_adaptor) other) | |
249 | : base_t(BOOST_MOVE_BASE(base_t, other)) | |
250 | {} | |
251 | ||
252 | explicit resource_adaptor(const Allocator& a2) | |
253 | : base_t(a2) | |
254 | {} | |
255 | ||
256 | explicit resource_adaptor(BOOST_RV_REF(Allocator) a2) | |
92f5a8d4 | 257 | : base_t(::boost::move(a2)) |
7c673cae FG |
258 | {} |
259 | ||
260 | resource_adaptor& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor) other) | |
261 | { return static_cast<resource_adaptor&>(this->base_t::operator=(other)); } | |
262 | ||
263 | resource_adaptor& operator=(BOOST_RV_REF(resource_adaptor) other) | |
264 | { return static_cast<resource_adaptor&>(this->base_t::operator=(BOOST_MOVE_BASE(base_t, other))); } | |
265 | ||
266 | //get_allocator and protected functions are properly inherited | |
267 | }; | |
268 | ||
269 | #endif | |
270 | ||
271 | } //namespace pmr { | |
272 | } //namespace container { | |
273 | } //namespace boost { | |
274 | ||
92f5a8d4 TL |
275 | #include <boost/container/detail/config_end.hpp> |
276 | ||
7c673cae | 277 | #endif //BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP |