]>
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_CONTAINER_SMALL_VECTOR_HPP | |
12 | #define BOOST_CONTAINER_CONTAINER_SMALL_VECTOR_HPP | |
13 | ||
14 | #ifndef BOOST_CONFIG_HPP | |
15 | # include <boost/config.hpp> | |
16 | #endif | |
17 | ||
18 | #if defined(BOOST_HAS_PRAGMA_ONCE) | |
19 | # pragma once | |
20 | #endif | |
21 | ||
22 | #include <boost/container/detail/config_begin.hpp> | |
23 | #include <boost/container/detail/workaround.hpp> | |
24 | ||
25 | // container | |
26 | #include <boost/container/container_fwd.hpp> | |
27 | #include <boost/container/vector.hpp> | |
28 | #include <boost/container/allocator_traits.hpp> | |
29 | #include <boost/container/new_allocator.hpp> //new_allocator | |
30 | // container/detail | |
31 | #include <boost/container/detail/type_traits.hpp> | |
32 | #include <boost/container/detail/version_type.hpp> | |
33 | ||
34 | //move | |
35 | #include <boost/move/adl_move_swap.hpp> | |
36 | #include <boost/move/iterator.hpp> | |
37 | ||
38 | //move/detail | |
39 | #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) | |
40 | #include <boost/move/detail/fwd_macros.hpp> | |
41 | #endif | |
42 | ||
43 | //std | |
44 | #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) | |
45 | #include <initializer_list> //for std::initializer_list | |
46 | #endif | |
47 | ||
48 | namespace boost { | |
49 | namespace container { | |
50 | ||
92f5a8d4 | 51 | namespace dtl{ |
7c673cae | 52 | |
92f5a8d4 TL |
53 | template<class Options> |
54 | struct get_small_vector_opt | |
55 | { | |
56 | typedef Options type; | |
57 | }; | |
7c673cae | 58 | |
92f5a8d4 TL |
59 | template<> |
60 | struct get_small_vector_opt<void> | |
61 | { | |
62 | typedef small_vector_null_opt type; | |
63 | }; | |
64 | ||
65 | template<class Options> | |
66 | struct get_vopt_from_svopt | |
67 | : get_small_vector_opt<Options>::type | |
68 | { | |
69 | typedef typename get_small_vector_opt<Options>::type options_t; | |
70 | typedef vector_opt< typename options_t::growth_factor_type, void> type; | |
71 | }; | |
72 | ||
73 | template<> | |
74 | struct get_vopt_from_svopt<void> | |
75 | { | |
76 | typedef void type; | |
77 | }; | |
78 | ||
79 | template <class T, class SecondaryAllocator, class Options> | |
80 | struct vector_for_small_vector | |
81 | { | |
82 | typedef vector | |
83 | < T | |
84 | , small_vector_allocator | |
85 | < T | |
86 | , typename allocator_traits<typename real_allocator<T, SecondaryAllocator>::type>::template portable_rebind_alloc<void>::type | |
87 | , Options> | |
88 | , typename dtl::get_vopt_from_svopt<Options>::type | |
89 | > type; | |
90 | }; | |
91 | ||
92 | } //namespace dtl | |
7c673cae FG |
93 | |
94 | //! A non-standard allocator used to implement `small_vector`. | |
95 | //! Users should never use it directly. It is described here | |
96 | //! for documentation purposes. | |
97 | //! | |
98 | //! This allocator inherits from a standard-conforming allocator | |
99 | //! and forwards member functions to the standard allocator except | |
100 | //! when internal storage is being used as memory source. | |
101 | //! | |
102 | //! This allocator is a "partially_propagable" allocator and | |
103 | //! defines `is_partially_propagable` as true_type. | |
104 | //! | |
105 | //! A partially propagable allocator means that not all storage | |
106 | //! allocatod by an instance of `small_vector_allocator` can be | |
107 | //! deallocated by another instance of this type, even if both | |
108 | //! instances compare equal or an instance is propagated to another | |
109 | //! one using the copy/move constructor or assignment. The storage that | |
110 | //! can never be propagated is identified by `storage_is_unpropagable(p)`. | |
111 | //! | |
112 | //! `boost::container::vector` supports partially propagable allocators | |
113 | //! fallbacking to deep copy/swap/move operations when internal storage | |
114 | //! is being used to store vector elements. | |
115 | //! | |
116 | //! `small_vector_allocator` assumes that will be instantiated as | |
92f5a8d4 | 117 | //! `boost::container::vector< T, small_vector_allocator<T, Allocator> >` |
7c673cae FG |
118 | //! and internal storage can be obtained downcasting that vector |
119 | //! to `small_vector_base<T>`. | |
92f5a8d4 | 120 | template<class T, class VoidAllocator BOOST_CONTAINER_DOCONLY(= void), class Options BOOST_CONTAINER_DOCONLY(= void)> |
7c673cae | 121 | class small_vector_allocator |
92f5a8d4 | 122 | : public allocator_traits<typename real_allocator<T, VoidAllocator>::type>::template portable_rebind_alloc<T>::type |
7c673cae FG |
123 | { |
124 | typedef unsigned int allocation_type; | |
125 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
126 | private: | |
127 | ||
92f5a8d4 TL |
128 | typedef typename allocator_traits<typename real_allocator<T, VoidAllocator>::type>::template portable_rebind_alloc<T>::type allocator_type; |
129 | ||
7c673cae FG |
130 | BOOST_COPYABLE_AND_MOVABLE(small_vector_allocator) |
131 | ||
92f5a8d4 TL |
132 | BOOST_CONTAINER_FORCEINLINE const allocator_type &as_base() const BOOST_NOEXCEPT |
133 | { return static_cast<const allocator_type&>(*this); } | |
7c673cae | 134 | |
92f5a8d4 TL |
135 | BOOST_CONTAINER_FORCEINLINE allocator_type &as_base() BOOST_NOEXCEPT |
136 | { return static_cast<allocator_type&>(*this); } | |
7c673cae FG |
137 | |
138 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
139 | ||
140 | public: | |
141 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
92f5a8d4 | 142 | typedef allocator_traits<allocator_type> allocator_traits_type; |
7c673cae FG |
143 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED |
144 | ||
92f5a8d4 TL |
145 | typedef typename allocator_traits<allocator_type>::value_type value_type; |
146 | typedef typename allocator_traits<allocator_type>::pointer pointer; | |
147 | typedef typename allocator_traits<allocator_type>::const_pointer const_pointer; | |
148 | typedef typename allocator_traits<allocator_type>::reference reference; | |
149 | typedef typename allocator_traits<allocator_type>::const_reference const_reference; | |
150 | typedef typename allocator_traits<allocator_type>::size_type size_type; | |
151 | typedef typename allocator_traits<allocator_type>::difference_type difference_type; | |
152 | typedef typename allocator_traits<allocator_type>::void_pointer void_pointer; | |
153 | typedef typename allocator_traits<allocator_type>::const_void_pointer const_void_pointer; | |
154 | ||
155 | typedef typename allocator_traits<allocator_type>::propagate_on_container_copy_assignment propagate_on_container_copy_assignment; | |
156 | typedef typename allocator_traits<allocator_type>::propagate_on_container_move_assignment propagate_on_container_move_assignment; | |
157 | typedef typename allocator_traits<allocator_type>::propagate_on_container_swap propagate_on_container_swap; | |
7c673cae | 158 | //! An integral constant with member `value == false` |
11fdf7f2 | 159 | typedef BOOST_CONTAINER_IMPDEF(dtl::bool_<false>) is_always_equal; |
7c673cae | 160 | //! An integral constant with member `value == true` |
11fdf7f2 | 161 | typedef BOOST_CONTAINER_IMPDEF(dtl::bool_<true>) is_partially_propagable; |
7c673cae | 162 | |
11fdf7f2 | 163 | BOOST_CONTAINER_DOCIGN(typedef dtl::version_type<small_vector_allocator BOOST_CONTAINER_I 1> version;) |
7c673cae FG |
164 | |
165 | //!Obtains an small_vector_allocator that allocates | |
166 | //!objects of type T2 | |
167 | template<class T2> | |
168 | struct rebind | |
169 | { | |
92f5a8d4 | 170 | typedef typename allocator_traits<allocator_type>::template portable_rebind_alloc<T2>::type other; |
7c673cae FG |
171 | }; |
172 | ||
92f5a8d4 TL |
173 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator() BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value) |
174 | {} | |
7c673cae FG |
175 | |
176 | //!Constructor from other small_vector_allocator. | |
177 | //!Never throws | |
178 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator | |
179 | (const small_vector_allocator &other) BOOST_NOEXCEPT_OR_NOTHROW | |
92f5a8d4 | 180 | : allocator_type(other.as_base()) |
7c673cae FG |
181 | {} |
182 | ||
183 | //!Move constructor from small_vector_allocator. | |
184 | //!Never throws | |
185 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator | |
186 | (BOOST_RV_REF(small_vector_allocator) other) BOOST_NOEXCEPT_OR_NOTHROW | |
92f5a8d4 | 187 | : allocator_type(::boost::move(other.as_base())) |
7c673cae FG |
188 | {} |
189 | ||
190 | //!Constructor from related small_vector_allocator. | |
191 | //!Never throws | |
92f5a8d4 | 192 | template<class U, class OtherVoidAllocator, class OtherOptions> |
7c673cae | 193 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator |
92f5a8d4 TL |
194 | (const small_vector_allocator<U, OtherVoidAllocator, OtherOptions> &other) BOOST_NOEXCEPT_OR_NOTHROW |
195 | : allocator_type(other.as_base()) | |
7c673cae FG |
196 | {} |
197 | ||
198 | //!Move constructor from related small_vector_allocator. | |
199 | //!Never throws | |
92f5a8d4 | 200 | template<class U, class OtherVoidAllocator, class OtherOptions> |
7c673cae | 201 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator |
92f5a8d4 TL |
202 | (BOOST_RV_REF(small_vector_allocator<U BOOST_MOVE_I OtherVoidAllocator BOOST_MOVE_I OtherOptions>) other) BOOST_NOEXCEPT_OR_NOTHROW |
203 | : allocator_type(::boost::move(other.as_base())) | |
204 | {} | |
205 | ||
206 | //!Constructor from allocator_type. | |
207 | //!Never throws | |
208 | BOOST_CONTAINER_FORCEINLINE explicit small_vector_allocator | |
209 | (const allocator_type &other) BOOST_NOEXCEPT_OR_NOTHROW | |
210 | : allocator_type(other) | |
7c673cae FG |
211 | {} |
212 | ||
213 | //!Assignment from other small_vector_allocator. | |
214 | //!Never throws | |
215 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator & | |
216 | operator=(BOOST_COPY_ASSIGN_REF(small_vector_allocator) other) BOOST_NOEXCEPT_OR_NOTHROW | |
92f5a8d4 | 217 | { return static_cast<small_vector_allocator&>(this->allocator_type::operator=(other.as_base())); } |
7c673cae | 218 | |
92f5a8d4 | 219 | //!Move assignment from other small_vector_allocator. |
7c673cae FG |
220 | //!Never throws |
221 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator & | |
222 | operator=(BOOST_RV_REF(small_vector_allocator) other) BOOST_NOEXCEPT_OR_NOTHROW | |
92f5a8d4 | 223 | { return static_cast<small_vector_allocator&>(this->allocator_type::operator=(::boost::move(other.as_base()))); } |
7c673cae FG |
224 | |
225 | //!Assignment from related small_vector_allocator. | |
226 | //!Never throws | |
92f5a8d4 | 227 | template<class U, class OtherVoidAllocator> |
7c673cae | 228 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator & |
92f5a8d4 TL |
229 | operator=(BOOST_COPY_ASSIGN_REF(small_vector_allocator<U BOOST_MOVE_I OtherVoidAllocator BOOST_MOVE_I Options>) other) BOOST_NOEXCEPT_OR_NOTHROW |
230 | { return static_cast<small_vector_allocator&>(this->allocator_type::operator=(other.as_base())); } | |
7c673cae FG |
231 | |
232 | //!Move assignment from related small_vector_allocator. | |
233 | //!Never throws | |
92f5a8d4 | 234 | template<class U, class OtherVoidAllocator> |
7c673cae | 235 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator & |
92f5a8d4 TL |
236 | operator=(BOOST_RV_REF(small_vector_allocator<U BOOST_MOVE_I OtherVoidAllocator BOOST_MOVE_I Options>) other) BOOST_NOEXCEPT_OR_NOTHROW |
237 | { return static_cast<small_vector_allocator&>(this->allocator_type::operator=(::boost::move(other.as_base()))); } | |
238 | ||
239 | //!Move assignment from allocator_type. | |
240 | //!Never throws | |
241 | BOOST_CONTAINER_FORCEINLINE small_vector_allocator & | |
242 | operator=(const allocator_type &other) BOOST_NOEXCEPT_OR_NOTHROW | |
243 | { return static_cast<small_vector_allocator&>(this->allocator_type::operator=(other)); } | |
7c673cae FG |
244 | |
245 | //!Allocates storage from the standard-conforming allocator | |
246 | BOOST_CONTAINER_FORCEINLINE pointer allocate(size_type count, const_void_pointer hint = const_void_pointer()) | |
247 | { return allocator_traits_type::allocate(this->as_base(), count, hint); } | |
248 | ||
249 | //!Deallocates previously allocated memory. | |
250 | //!Never throws | |
251 | void deallocate(pointer ptr, size_type n) BOOST_NOEXCEPT_OR_NOTHROW | |
252 | { | |
253 | if(!this->is_internal_storage(ptr)) | |
254 | allocator_traits_type::deallocate(this->as_base(), ptr, n); | |
255 | } | |
256 | ||
257 | //!Returns the maximum number of elements that could be allocated. | |
258 | //!Never throws | |
259 | BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW | |
260 | { return allocator_traits_type::max_size(this->as_base()); } | |
261 | ||
262 | small_vector_allocator select_on_container_copy_construction() const | |
263 | { return small_vector_allocator(allocator_traits_type::select_on_container_copy_construction(this->as_base())); } | |
264 | ||
265 | bool storage_is_unpropagable(pointer p) const | |
266 | { return this->is_internal_storage(p) || allocator_traits_type::storage_is_unpropagable(this->as_base(), p); } | |
267 | ||
268 | //!Swaps two allocators, does nothing | |
269 | //!because this small_vector_allocator is stateless | |
270 | BOOST_CONTAINER_FORCEINLINE friend void swap(small_vector_allocator &l, small_vector_allocator &r) BOOST_NOEXCEPT_OR_NOTHROW | |
271 | { boost::adl_move_swap(l.as_base(), r.as_base()); } | |
272 | ||
273 | //!An small_vector_allocator always compares to true, as memory allocated with one | |
274 | //!instance can be deallocated by another instance (except for unpropagable storage) | |
275 | BOOST_CONTAINER_FORCEINLINE friend bool operator==(const small_vector_allocator &l, const small_vector_allocator &r) BOOST_NOEXCEPT_OR_NOTHROW | |
276 | { return allocator_traits_type::equal(l.as_base(), r.as_base()); } | |
277 | ||
278 | //!An small_vector_allocator always compares to false, as memory allocated with one | |
279 | //!instance can be deallocated by another instance | |
280 | BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const small_vector_allocator &l, const small_vector_allocator &r) BOOST_NOEXCEPT_OR_NOTHROW | |
281 | { return !(l == r); } | |
282 | ||
283 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
284 | /* | |
285 | //!An advanced function that offers in-place expansion shrink to fit and new allocation | |
286 | //!capabilities. Memory allocated with this function can only be deallocated with deallocate() | |
287 | //!or deallocate_many(). | |
288 | //!This function is available only with Version == 2 | |
289 | pointer allocation_command(allocation_type command, | |
290 | size_type limit_size, | |
291 | size_type &prefer_in_recvd_out_size, | |
292 | pointer &reuse) | |
293 | { return allocator_traits_type::allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); } | |
294 | ||
295 | //!Returns maximum the number of objects the previously allocated memory | |
296 | //!pointed by p can hold. | |
297 | //!Memory must not have been allocated with | |
298 | //!allocate_one or allocate_individual. | |
299 | //!This function is available only with Version == 2 | |
300 | size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW | |
301 | { return allocator_traits_type::size(p); } | |
302 | */ | |
303 | private: | |
304 | /* | |
305 | //!Allocates just one object. Memory allocated with this function | |
306 | //!must be deallocated only with deallocate_one(). | |
307 | //!Throws bad_alloc if there is no enough memory | |
308 | //!This function is available only with Version == 2 | |
92f5a8d4 TL |
309 | using allocator_type::allocate_one; |
310 | using allocator_type::allocate_individual; | |
311 | using allocator_type::deallocate_one; | |
312 | using allocator_type::deallocate_individual; | |
313 | using allocator_type::allocate_many; | |
314 | using allocator_type::deallocate_many;*/ | |
315 | ||
316 | typedef vector_alloc_holder< small_vector_allocator, size_type > vector_alloc_holder_t; | |
317 | typedef typename dtl::vector_for_small_vector<T, allocator_type, Options>::type vector_base; | |
318 | typedef small_vector_base<value_type, allocator_type, Options> derived_type; | |
319 | ||
320 | BOOST_CONTAINER_FORCEINLINE bool is_internal_storage(const_pointer p) const | |
7c673cae FG |
321 | { return this->internal_storage() == p; } |
322 | ||
92f5a8d4 TL |
323 | BOOST_CONTAINER_FORCEINLINE |
324 | const_pointer internal_storage() const | |
7c673cae | 325 | { |
7c673cae FG |
326 | const vector_alloc_holder_t &v_holder = static_cast<const vector_alloc_holder_t &>(*this); |
327 | const vector_base &v_base = reinterpret_cast<const vector_base &>(v_holder); | |
328 | const derived_type &d_base = static_cast<const derived_type &>(v_base); | |
329 | return d_base.internal_storage(); | |
330 | } | |
92f5a8d4 TL |
331 | |
332 | BOOST_CONTAINER_FORCEINLINE | |
333 | pointer internal_storage() | |
334 | { | |
335 | vector_alloc_holder_t &v_holder = static_cast<vector_alloc_holder_t &>(*this); | |
336 | vector_base &v_base = reinterpret_cast<vector_base &>(v_holder); | |
337 | derived_type &d_base = static_cast<derived_type &>(v_base); | |
338 | return d_base.internal_storage(); | |
339 | } | |
7c673cae FG |
340 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED |
341 | }; | |
342 | ||
343 | //! This class consists of common code from all small_vector<T, N> types that don't depend on the | |
344 | //! "N" template parameter. This class is non-copyable and non-destructible, so this class typically | |
345 | //! used as reference argument to functions that read or write small vectors. Since `small_vector<T, N>` | |
346 | //! derives from `small_vector_base<T>`, the conversion to `small_vector_base` is implicit | |
347 | //! <pre> | |
348 | //! | |
349 | //! //Clients can pass any small_vector<Foo, N>. | |
350 | //! void read_any_small_vector_of_foo(const small_vector_base<Foo> &in_parameter); | |
351 | //! | |
352 | //! void modify_any_small_vector_of_foo(small_vector_base<Foo> &in_out_parameter); | |
353 | //! | |
354 | //! void some_function() | |
355 | //! { | |
356 | //! | |
357 | //! small_vector<Foo, 8> myvector; | |
358 | //! | |
359 | //! read_any_small_vector_of_foo(myvector); // Reads myvector | |
360 | //! | |
361 | //! modify_any_small_vector_of_foo(myvector); // Modifies myvector | |
362 | //! | |
363 | //! } | |
364 | //! </pre> | |
365 | //! | |
366 | //! All `boost::container:vector` member functions are inherited. See `vector` documentation for details. | |
367 | //! | |
92f5a8d4 | 368 | template <class T, class SecondaryAllocator, class Options> |
7c673cae | 369 | class small_vector_base |
92f5a8d4 | 370 | : public dtl::vector_for_small_vector<T, SecondaryAllocator, Options>::type |
7c673cae | 371 | { |
92f5a8d4 | 372 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKEDVECTOR |
7c673cae FG |
373 | public: |
374 | //Make it public as it will be inherited by small_vector and container | |
375 | //must have this public member | |
92f5a8d4 TL |
376 | typedef typename real_allocator<T, SecondaryAllocator>::type secondary_allocator_t; |
377 | typedef typename allocator_traits<secondary_allocator_t>:: | |
378 | template portable_rebind_alloc<void>::type void_allocator_t; | |
379 | typedef typename dtl::get_small_vector_opt<Options>::type options_t; | |
380 | typedef typename dtl::vector_for_small_vector | |
381 | <T, SecondaryAllocator, Options>::type base_type; | |
382 | typedef typename allocator_traits<secondary_allocator_t>::pointer pointer; | |
383 | typedef typename allocator_traits<secondary_allocator_t>::const_pointer const_pointer; | |
384 | typedef typename allocator_traits<secondary_allocator_t>::void_pointer void_pointer; | |
385 | typedef typename allocator_traits<secondary_allocator_t>::const_void_pointer const_void_pointer; | |
386 | typedef small_vector_allocator<T, void_allocator_t, Options> allocator_type; | |
7c673cae FG |
387 | |
388 | private: | |
389 | BOOST_COPYABLE_AND_MOVABLE(small_vector_base) | |
390 | ||
92f5a8d4 TL |
391 | friend class small_vector_allocator<T, void_allocator_t, Options>; |
392 | ||
393 | BOOST_CONTAINER_FORCEINLINE | |
394 | const_pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW | |
395 | { | |
396 | typedef typename boost::intrusive::pointer_traits<const_pointer>::template | |
397 | rebind_pointer<const unsigned char>::type const_char_pointer; | |
398 | const_void_pointer void_p = boost::intrusive::pointer_traits<const_char_pointer>:: | |
399 | pointer_to(*m_storage_start.data); | |
400 | return boost::intrusive::pointer_traits<const_pointer>::static_cast_from(void_p); | |
401 | } | |
7c673cae | 402 | |
92f5a8d4 TL |
403 | BOOST_CONTAINER_FORCEINLINE |
404 | pointer internal_storage() BOOST_NOEXCEPT_OR_NOTHROW | |
7c673cae | 405 | { |
92f5a8d4 TL |
406 | typedef typename boost::intrusive::pointer_traits<pointer>::template |
407 | rebind_pointer<unsigned char>::type char_pointer; | |
408 | void_pointer void_p = boost::intrusive::pointer_traits<char_pointer>:: | |
409 | pointer_to(*m_storage_start.data); | |
410 | return boost::intrusive::pointer_traits<pointer>::static_cast_from(void_p); | |
7c673cae FG |
411 | } |
412 | ||
7c673cae FG |
413 | base_type &as_base() { return static_cast<base_type&>(*this); } |
414 | const base_type &as_base() const { return static_cast<const base_type&>(*this); } | |
415 | ||
92f5a8d4 TL |
416 | static const std::size_t final_alignment = |
417 | options_t::inplace_alignment ? options_t::inplace_alignment : dtl::alignment_of<T>::value; | |
7c673cae | 418 | public: |
92f5a8d4 | 419 | |
11fdf7f2 | 420 | typedef typename dtl::aligned_storage |
92f5a8d4 | 421 | <sizeof(T), final_alignment>::type storage_type; |
7c673cae FG |
422 | |
423 | protected: | |
7c673cae FG |
424 | |
425 | BOOST_CONTAINER_FORCEINLINE explicit small_vector_base(initial_capacity_t, std::size_t initial_capacity) | |
426 | : base_type(initial_capacity_t(), this->internal_storage(), initial_capacity) | |
427 | {} | |
428 | ||
429 | template<class AllocFwd> | |
430 | BOOST_CONTAINER_FORCEINLINE explicit small_vector_base(initial_capacity_t, std::size_t capacity, BOOST_FWD_REF(AllocFwd) a) | |
431 | : base_type(initial_capacity_t(), this->internal_storage(), capacity, ::boost::forward<AllocFwd>(a)) | |
432 | {} | |
433 | ||
434 | //~small_vector_base(){} | |
435 | ||
436 | private: | |
437 | //The only member | |
438 | storage_type m_storage_start; | |
439 | ||
440 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
441 | ||
442 | public: | |
443 | BOOST_CONTAINER_FORCEINLINE small_vector_base& operator=(BOOST_COPY_ASSIGN_REF(small_vector_base) other) | |
444 | { return static_cast<small_vector_base&>(this->base_type::operator=(static_cast<base_type const&>(other))); } | |
445 | ||
446 | BOOST_CONTAINER_FORCEINLINE small_vector_base& operator=(BOOST_RV_REF(small_vector_base) other) | |
447 | { return static_cast<small_vector_base&>(this->base_type::operator=(BOOST_MOVE_BASE(base_type, other))); } | |
448 | ||
449 | BOOST_CONTAINER_FORCEINLINE void swap(small_vector_base &other) | |
450 | { return this->base_type::swap(other); } | |
451 | ||
452 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
453 | protected: | |
454 | void move_construct_impl(base_type &x, const allocator_type &a) | |
455 | { | |
456 | if(base_type::is_propagable_from(x.get_stored_allocator(), x.data(), a, true)){ | |
457 | this->steal_resources(x); | |
458 | } | |
459 | else{ | |
b32b8144 FG |
460 | this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) |
461 | , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end ())) | |
7c673cae FG |
462 | ); |
463 | } | |
464 | } | |
465 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
466 | }; | |
467 | ||
468 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
469 | ||
470 | ///////////////////////////////////////////////////// | |
471 | // | |
472 | // small_vector_storage_calculator | |
473 | // | |
474 | ///////////////////////////////////////////////////// | |
475 | template<std::size_t Needed, std::size_t Hdr, std::size_t SSize, bool NeedsZero = (0u == Needed || Needed <= Hdr)> | |
476 | struct small_vector_storage_calculator_helper | |
477 | { | |
478 | static const std::size_t value = (Needed - Hdr - 1u)/SSize + 1u; | |
479 | }; | |
480 | ||
481 | template<std::size_t Needed, std::size_t Hdr, std::size_t SSize> | |
482 | struct small_vector_storage_calculator_helper<Needed, Hdr, SSize, true> | |
483 | { | |
484 | static const std::size_t value = 0u; | |
485 | }; | |
486 | ||
92f5a8d4 | 487 | template<class Storage, class Allocator, class T, std::size_t N, class Options> |
7c673cae FG |
488 | struct small_vector_storage_calculator |
489 | { | |
92f5a8d4 TL |
490 | typedef small_vector_base<T, Allocator, Options> svh_type; |
491 | typedef typename real_allocator<T, Allocator>::type value_allocator_t; | |
492 | typedef typename allocator_traits<value_allocator_t>::template portable_rebind_alloc<void>::type void_allocator_t; | |
493 | typedef typename dtl::vector_for_small_vector<T, void_allocator_t, Options>::type svhb_type; | |
494 | ||
11fdf7f2 | 495 | static const std::size_t s_align = dtl::alignment_of<Storage>::value; |
7c673cae FG |
496 | static const std::size_t s_size = sizeof(Storage); |
497 | static const std::size_t svh_sizeof = sizeof(svh_type); | |
498 | static const std::size_t svhb_sizeof = sizeof(svhb_type); | |
499 | static const std::size_t s_start = ((svhb_sizeof-1)/s_align+1)*s_align; | |
500 | static const std::size_t header_bytes = svh_sizeof-s_start; | |
501 | static const std::size_t needed_bytes = sizeof(T)*N; | |
502 | static const std::size_t needed_extra_storages = | |
503 | small_vector_storage_calculator_helper<needed_bytes, header_bytes, s_size>::value; | |
504 | }; | |
505 | ||
506 | ///////////////////////////////////////////////////// | |
507 | // | |
508 | // small_vector_storage_definer | |
509 | // | |
510 | ///////////////////////////////////////////////////// | |
511 | template<class Storage, std::size_t N> | |
512 | struct small_vector_storage | |
513 | { | |
514 | Storage m_rest_of_storage[N]; | |
515 | }; | |
516 | ||
517 | template<class Storage> | |
518 | struct small_vector_storage<Storage, 0> | |
519 | {}; | |
520 | ||
92f5a8d4 | 521 | template<class T, class Allocator, std::size_t N, class Options> |
7c673cae FG |
522 | struct small_vector_storage_definer |
523 | { | |
92f5a8d4 TL |
524 | typedef T value_type; |
525 | typedef typename small_vector_base<value_type, Allocator, Options>::storage_type storage_type; | |
7c673cae | 526 | static const std::size_t needed_extra_storages = |
92f5a8d4 | 527 | small_vector_storage_calculator<storage_type, Allocator, value_type, N, Options>::needed_extra_storages; |
7c673cae FG |
528 | typedef small_vector_storage<storage_type, needed_extra_storages> type; |
529 | }; | |
530 | ||
531 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
532 | ||
533 | //! small_vector is a vector-like container optimized for the case when it contains few elements. | |
534 | //! It contains some preallocated elements in-place, which can avoid the use of dynamic storage allocation | |
535 | //! when the actual number of elements is below that preallocated threshold. | |
536 | //! | |
92f5a8d4 | 537 | //! `small_vector<T, N, Allocator, Options>` is convertible to `small_vector_base<T, Allocator, Options>` that is independent |
7c673cae FG |
538 | //! from the preallocated element capacity, so client code does not need to be templated on that N argument. |
539 | //! | |
540 | //! All `boost::container::vector` member functions are inherited. See `vector` documentation for details. | |
541 | //! | |
542 | //! \tparam T The type of object that is stored in the small_vector | |
543 | //! \tparam N The number of preallocated elements stored inside small_vector. It shall be less than Allocator::max_size(); | |
92f5a8d4 TL |
544 | //! \tparam Allocator The allocator used for memory management when the number of elements exceeds N. Use void |
545 | //! for the default allocator | |
546 | //! |tparam Options A type produced from \c boost::container::small_vector_options. | |
547 | template <class T, std::size_t N, class Allocator BOOST_CONTAINER_DOCONLY(= void), class Options BOOST_CONTAINER_DOCONLY(= void) > | |
548 | class small_vector : public small_vector_base<T, Allocator, Options> | |
7c673cae | 549 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED |
92f5a8d4 | 550 | , private small_vector_storage_definer<T, Allocator, N, Options>::type |
7c673cae FG |
551 | #endif |
552 | { | |
553 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
92f5a8d4 TL |
554 | typedef small_vector_base<T, Allocator, Options> base_type; |
555 | typedef typename small_vector_storage_definer | |
556 | <T, Allocator, N, Options>::type remaining_storage_holder; | |
7c673cae FG |
557 | |
558 | BOOST_COPYABLE_AND_MOVABLE(small_vector) | |
559 | ||
7c673cae FG |
560 | typedef allocator_traits<typename base_type::allocator_type> allocator_traits_type; |
561 | ||
562 | public: | |
92f5a8d4 TL |
563 | typedef small_vector_storage_calculator |
564 | < typename small_vector_base<T, Allocator, Options>::storage_type | |
565 | , Allocator, T, N, Options> storage_test; | |
7c673cae FG |
566 | |
567 | static const std::size_t needed_extra_storages = storage_test::needed_extra_storages; | |
568 | static const std::size_t needed_bytes = storage_test::needed_bytes; | |
569 | static const std::size_t header_bytes = storage_test::header_bytes; | |
570 | static const std::size_t s_start = storage_test::s_start; | |
571 | ||
572 | typedef typename base_type::allocator_type allocator_type; | |
573 | typedef typename base_type::size_type size_type; | |
574 | typedef typename base_type::value_type value_type; | |
575 | ||
576 | BOOST_CONTAINER_FORCEINLINE static std::size_t internal_capacity() | |
577 | { return (sizeof(small_vector) - storage_test::s_start)/sizeof(T); } | |
578 | ||
579 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
580 | ||
581 | //! @brief The capacity/max size of the container | |
582 | static const size_type static_capacity = N; | |
583 | ||
584 | public: | |
585 | BOOST_CONTAINER_FORCEINLINE small_vector() | |
92f5a8d4 | 586 | BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value) |
7c673cae FG |
587 | : base_type(initial_capacity_t(), internal_capacity()) |
588 | {} | |
589 | ||
590 | BOOST_CONTAINER_FORCEINLINE explicit small_vector(const allocator_type &a) | |
591 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
592 | {} | |
593 | ||
594 | BOOST_CONTAINER_FORCEINLINE explicit small_vector(size_type n) | |
595 | : base_type(initial_capacity_t(), internal_capacity()) | |
596 | { this->resize(n); } | |
597 | ||
598 | BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, const allocator_type &a) | |
599 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
600 | { this->resize(n); } | |
601 | ||
602 | BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, default_init_t) | |
603 | : base_type(initial_capacity_t(), internal_capacity()) | |
604 | { this->resize(n, default_init_t()); } | |
605 | ||
606 | BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, default_init_t, const allocator_type &a) | |
607 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
608 | { this->resize(n, default_init_t()); } | |
609 | ||
610 | BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, const value_type &v) | |
611 | : base_type(initial_capacity_t(), internal_capacity()) | |
612 | { this->resize(n, v); } | |
613 | ||
614 | BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, const value_type &v, const allocator_type &a) | |
615 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
616 | { this->resize(n, v); } | |
617 | ||
618 | template <class InIt> | |
619 | BOOST_CONTAINER_FORCEINLINE small_vector(InIt first, InIt last | |
11fdf7f2 TL |
620 | BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_c |
621 | < dtl::is_convertible<InIt BOOST_MOVE_I size_type>::value | |
622 | BOOST_MOVE_I dtl::nat >::type * = 0) | |
7c673cae FG |
623 | ) |
624 | : base_type(initial_capacity_t(), internal_capacity()) | |
625 | { this->assign(first, last); } | |
626 | ||
627 | template <class InIt> | |
628 | BOOST_CONTAINER_FORCEINLINE small_vector(InIt first, InIt last, const allocator_type& a | |
11fdf7f2 TL |
629 | BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_c |
630 | < dtl::is_convertible<InIt BOOST_MOVE_I size_type>::value | |
631 | BOOST_MOVE_I dtl::nat >::type * = 0) | |
7c673cae FG |
632 | ) |
633 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
634 | { this->assign(first, last); } | |
635 | ||
636 | BOOST_CONTAINER_FORCEINLINE small_vector(const small_vector &other) | |
637 | : base_type( initial_capacity_t(), internal_capacity() | |
638 | , allocator_traits_type::select_on_container_copy_construction(other.get_stored_allocator())) | |
639 | { this->assign(other.cbegin(), other.cend()); } | |
640 | ||
641 | BOOST_CONTAINER_FORCEINLINE small_vector(const small_vector &other, const allocator_type &a) | |
642 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
643 | { this->assign(other.cbegin(), other.cend()); } | |
644 | ||
645 | BOOST_CONTAINER_FORCEINLINE explicit small_vector(const base_type &other) | |
646 | : base_type( initial_capacity_t(), internal_capacity() | |
647 | , allocator_traits_type::select_on_container_copy_construction(other.get_stored_allocator())) | |
648 | { this->assign(other.cbegin(), other.cend()); } | |
649 | ||
650 | BOOST_CONTAINER_FORCEINLINE explicit small_vector(BOOST_RV_REF(base_type) other) | |
651 | : base_type(initial_capacity_t(), internal_capacity(), ::boost::move(other.get_stored_allocator())) | |
652 | { this->move_construct_impl(other, other.get_stored_allocator()); } | |
653 | ||
654 | BOOST_CONTAINER_FORCEINLINE small_vector(BOOST_RV_REF(small_vector) other) | |
92f5a8d4 | 655 | BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_assignable<value_type>::value) |
7c673cae FG |
656 | : base_type(initial_capacity_t(), internal_capacity(), ::boost::move(other.get_stored_allocator())) |
657 | { this->move_construct_impl(other, other.get_stored_allocator()); } | |
658 | ||
659 | BOOST_CONTAINER_FORCEINLINE small_vector(BOOST_RV_REF(small_vector) other, const allocator_type &a) | |
660 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
661 | { this->move_construct_impl(other, a); } | |
662 | ||
663 | #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) | |
664 | BOOST_CONTAINER_FORCEINLINE small_vector(std::initializer_list<value_type> il, const allocator_type& a = allocator_type()) | |
665 | : base_type(initial_capacity_t(), internal_capacity(), a) | |
666 | { | |
667 | this->assign(il.begin(), il.end()); | |
668 | } | |
669 | #endif | |
670 | ||
671 | BOOST_CONTAINER_FORCEINLINE small_vector& operator=(BOOST_COPY_ASSIGN_REF(small_vector) other) | |
672 | { return static_cast<small_vector&>(this->base_type::operator=(static_cast<base_type const&>(other))); } | |
673 | ||
674 | BOOST_CONTAINER_FORCEINLINE small_vector& operator=(BOOST_RV_REF(small_vector) other) | |
92f5a8d4 TL |
675 | BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_assignable<value_type>::value |
676 | && (allocator_traits_type::propagate_on_container_move_assignment::value | |
677 | || allocator_traits_type::is_always_equal::value)) | |
7c673cae FG |
678 | { return static_cast<small_vector&>(this->base_type::operator=(BOOST_MOVE_BASE(base_type, other))); } |
679 | ||
680 | BOOST_CONTAINER_FORCEINLINE small_vector& operator=(const base_type &other) | |
681 | { return static_cast<small_vector&>(this->base_type::operator=(other)); } | |
682 | ||
683 | BOOST_CONTAINER_FORCEINLINE small_vector& operator=(BOOST_RV_REF(base_type) other) | |
684 | { return static_cast<small_vector&>(this->base_type::operator=(boost::move(other))); } | |
685 | ||
686 | BOOST_CONTAINER_FORCEINLINE void swap(small_vector &other) | |
687 | { return this->base_type::swap(other); } | |
688 | }; | |
689 | ||
690 | }} | |
691 | ||
692 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
693 | /* | |
694 | namespace boost { | |
695 | ||
696 | //!has_trivial_destructor_after_move<> == true_type | |
697 | //!specialization for optimizations | |
698 | template <class T, class Allocator> | |
699 | struct has_trivial_destructor_after_move<boost::container::vector<T, Allocator> > | |
700 | { | |
701 | typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer; | |
702 | static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value && | |
703 | ::boost::has_trivial_destructor_after_move<pointer>::value; | |
704 | }; | |
705 | ||
706 | } | |
707 | */ | |
708 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
709 | ||
710 | #include <boost/container/detail/config_end.hpp> | |
711 | ||
712 | #endif // #ifndef BOOST_CONTAINER_CONTAINER_SMALL_VECTOR_HPP |