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