1 ////////////////////////////////////////////////////////////////////////////// 2 // 3 // (C) Copyright Ion Gaztanaga 2007-2013. 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_ALLOCATOR_HPP 12 #define BOOST_CONTAINER_ALLOCATOR_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 #include <boost/container/container_fwd.hpp> 25 #include <boost/container/detail/version_type.hpp> 26 #include <boost/container/throw_exception.hpp> 27 #include <boost/container/detail/dlmalloc.hpp> 28 #include <boost/container/detail/multiallocation_chain.hpp> 29 #include <boost/static_assert.hpp> 30 #include <cstddef> 31 #include <cassert> 32 33 //!\file 34 35 namespace boost { 36 namespace container { 37 38 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 39 40 template<unsigned Version, unsigned int AllocationDisableMask> 41 class allocator<void, Version, AllocationDisableMask> 42 { 43 typedef allocator<void, Version, AllocationDisableMask> self_t; 44 public: 45 typedef void value_type; 46 typedef void * pointer; 47 typedef const void* const_pointer; 48 typedef int & reference; 49 typedef const int & const_reference; 50 typedef std::size_t size_type; 51 typedef std::ptrdiff_t difference_type; 52 typedef boost::container::dtl:: 53 version_type<self_t, Version> version; 54 55 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 56 typedef boost::container::dtl:: 57 basic_multiallocation_chain<void*> multiallocation_chain; 58 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 59 60 //!Obtains an allocator that allocates 61 //!objects of type T2 62 template<class T2> 63 struct rebind 64 { 65 typedef allocator< T2 66 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 67 , Version, AllocationDisableMask 68 #endif 69 > other; 70 }; 71 72 //!Default constructor 73 //!Never throws allocator()74 allocator() 75 {} 76 77 //!Constructor from other allocator. 78 //!Never throws allocator(const allocator &)79 allocator(const allocator &) 80 {} 81 82 //!Constructor from related allocator. 83 //!Never throws 84 template<class T2> allocator(const allocator<T2,Version,AllocationDisableMask> &)85 allocator(const allocator<T2, Version, AllocationDisableMask> &) 86 {} 87 }; 88 89 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 90 91 //! This class is an extended STL-compatible that offers advanced allocation mechanism 92 //!(in-place expansion, shrinking, burst-allocation...) 93 //! 94 //! This allocator is a wrapper around a modified DLmalloc. 95 //! If Version is 1, the allocator is a STL conforming allocator. If Version is 2, 96 //! the allocator offers advanced expand in place and burst allocation capabilities. 97 //! 98 //! AllocationDisableMask works only if Version is 2 and it can be an inclusive OR 99 //! of allocation types the user wants to disable. 100 template< class T 101 , unsigned Version BOOST_CONTAINER_DOCONLY(=2) 102 , unsigned int AllocationDisableMask BOOST_CONTAINER_DOCONLY(=0)> 103 class allocator 104 { 105 typedef unsigned int allocation_type; 106 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 107 private: 108 109 //Self type 110 typedef allocator<T, Version, AllocationDisableMask> self_t; 111 112 //Not assignable from related allocator 113 template<class T2, unsigned int Version2, unsigned int AllocationDisableMask2> 114 allocator& operator=(const allocator<T2, Version2, AllocationDisableMask2>&); 115 116 static const unsigned int ForbiddenMask = 117 BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BWD | BOOST_CONTAINER_EXPAND_FWD ; 118 119 //The mask can't disable all the allocation types 120 BOOST_STATIC_ASSERT(( (AllocationDisableMask & ForbiddenMask) != ForbiddenMask )); 121 122 //The mask is only valid for version 2 allocators 123 BOOST_STATIC_ASSERT(( Version != 1 || (AllocationDisableMask == 0) )); 124 125 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 126 127 public: 128 typedef T value_type; 129 typedef T * pointer; 130 typedef const T * const_pointer; 131 typedef T & reference; 132 typedef const T & const_reference; 133 typedef std::size_t size_type; 134 typedef std::ptrdiff_t difference_type; 135 136 typedef boost::container::dtl:: 137 version_type<self_t, Version> version; 138 139 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 140 typedef boost::container::dtl:: 141 basic_multiallocation_chain<void*> void_multiallocation_chain; 142 143 typedef boost::container::dtl:: 144 transform_multiallocation_chain 145 <void_multiallocation_chain, T> multiallocation_chain; 146 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 147 148 //!Obtains an allocator that allocates 149 //!objects of type T2 150 template<class T2> 151 struct rebind 152 { 153 typedef allocator<T2, Version, AllocationDisableMask> other; 154 }; 155 156 //!Default constructor 157 //!Never throws allocator()158 allocator() BOOST_NOEXCEPT_OR_NOTHROW 159 {} 160 161 //!Constructor from other allocator. 162 //!Never throws allocator(const allocator &)163 allocator(const allocator &) BOOST_NOEXCEPT_OR_NOTHROW 164 {} 165 166 //!Constructor from related allocator. 167 //!Never throws 168 template<class T2> allocator(const allocator<T2,Version,AllocationDisableMask> &)169 allocator(const allocator<T2 170 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 171 , Version, AllocationDisableMask 172 #endif 173 > &) BOOST_NOEXCEPT_OR_NOTHROW 174 {} 175 176 //!Allocates memory for an array of count elements. 177 //!Throws std::bad_alloc if there is no enough memory 178 //!If Version is 2, this allocated memory can only be deallocated 179 //!with deallocate() or (for Version == 2) deallocate_many() allocate(size_type count,const void * hint=0)180 pointer allocate(size_type count, const void * hint= 0) 181 { 182 (void)hint; 183 if(count > size_type(-1)/(2u*sizeof(T))) 184 boost::container::throw_bad_alloc(); 185 void *ret = dlmalloc_malloc(count*sizeof(T)); 186 if(!ret) 187 boost::container::throw_bad_alloc(); 188 return static_cast<pointer>(ret); 189 } 190 191 //!Deallocates previously allocated memory. 192 //!Never throws deallocate(pointer ptr,size_type)193 BOOST_CONTAINER_FORCEINLINE void deallocate(pointer ptr, size_type) BOOST_NOEXCEPT_OR_NOTHROW 194 { dlmalloc_free(ptr); } 195 196 //!Returns the maximum number of elements that could be allocated. 197 //!Never throws max_size() const198 BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW 199 { return size_type(-1)/(2u*sizeof(T)); } 200 201 //!Swaps two allocators, does nothing 202 //!because this allocator is stateless swap(self_t &,self_t &)203 BOOST_CONTAINER_FORCEINLINE friend void swap(self_t &, self_t &) BOOST_NOEXCEPT_OR_NOTHROW 204 {} 205 206 //!An allocator always compares to true, as memory allocated with one 207 //!instance can be deallocated by another instance operator ==(const allocator &,const allocator &)208 friend bool operator==(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW 209 { return true; } 210 211 //!An allocator always compares to false, as memory allocated with one 212 //!instance can be deallocated by another instance operator !=(const allocator &,const allocator &)213 BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW 214 { return false; } 215 216 //!An advanced function that offers in-place expansion shrink to fit and new allocation 217 //!capabilities. Memory allocated with this function can only be deallocated with deallocate() 218 //!or deallocate_many(). 219 //!This function is available only with Version == 2 allocation_command(allocation_type command,size_type limit_size,size_type & prefer_in_recvd_out_size,pointer & reuse)220 pointer allocation_command(allocation_type command, 221 size_type limit_size, 222 size_type &prefer_in_recvd_out_size, 223 pointer &reuse) 224 { 225 BOOST_STATIC_ASSERT(( Version > 1 )); 226 const allocation_type mask(AllocationDisableMask); 227 command &= ~mask; 228 pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); 229 if(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION)) 230 boost::container::throw_bad_alloc(); 231 return ret; 232 } 233 234 //!Returns maximum the number of objects the previously allocated memory 235 //!pointed by p can hold. 236 //!Memory must not have been allocated with 237 //!allocate_one or allocate_individual. 238 //!This function is available only with Version == 2 size(pointer p) const239 size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW 240 { 241 BOOST_STATIC_ASSERT(( Version > 1 )); 242 return dlmalloc_size(p); 243 } 244 245 //!Allocates just one object. Memory allocated with this function 246 //!must be deallocated only with deallocate_one(). 247 //!Throws bad_alloc if there is no enough memory 248 //!This function is available only with Version == 2 allocate_one()249 BOOST_CONTAINER_FORCEINLINE pointer allocate_one() 250 { 251 BOOST_STATIC_ASSERT(( Version > 1 )); 252 return this->allocate(1); 253 } 254 255 //!Allocates many elements of size == 1. 256 //!Elements must be individually deallocated with deallocate_one() 257 //!This function is available only with Version == 2 allocate_individual(std::size_t num_elements,multiallocation_chain & chain)258 BOOST_CONTAINER_FORCEINLINE void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) 259 { 260 BOOST_STATIC_ASSERT(( Version > 1 )); 261 this->allocate_many(1, num_elements, chain); 262 } 263 264 //!Deallocates memory previously allocated with allocate_one(). 265 //!You should never use deallocate_one to deallocate memory allocated 266 //!with other functions different from allocate_one() or allocate_individual. 267 //Never throws deallocate_one(pointer p)268 void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW 269 { 270 BOOST_STATIC_ASSERT(( Version > 1 )); 271 return this->deallocate(p, 1); 272 } 273 274 //!Deallocates memory allocated with allocate_one() or allocate_individual(). 275 //!This function is available only with Version == 2 deallocate_individual(multiallocation_chain & chain)276 BOOST_CONTAINER_FORCEINLINE void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW 277 { 278 BOOST_STATIC_ASSERT(( Version > 1 )); 279 return this->deallocate_many(chain); 280 } 281 282 //!Allocates many elements of size elem_size. 283 //!Elements must be individually deallocated with deallocate() 284 //!This function is available only with Version == 2 allocate_many(size_type elem_size,std::size_t n_elements,multiallocation_chain & chain)285 void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) 286 { 287 BOOST_STATIC_ASSERT(( Version > 1 )); 288 dlmalloc_memchain ch; 289 BOOST_CONTAINER_MEMCHAIN_INIT(&ch); 290 if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ 291 boost::container::throw_bad_alloc(); 292 } 293 chain.incorporate_after(chain.before_begin() 294 ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) 295 ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) 296 ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); 297 /* 298 if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast<dlmalloc_memchain *>(&chain))){ 299 boost::container::throw_bad_alloc(); 300 }*/ 301 } 302 303 //!Allocates n_elements elements, each one of size elem_sizes[i] 304 //!Elements must be individually deallocated with deallocate() 305 //!This function is available only with Version == 2 allocate_many(const size_type * elem_sizes,size_type n_elements,multiallocation_chain & chain)306 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) 307 { 308 BOOST_STATIC_ASSERT(( Version > 1 )); 309 dlmalloc_memchain ch; 310 BOOST_CONTAINER_MEMCHAIN_INIT(&ch); 311 if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ 312 boost::container::throw_bad_alloc(); 313 } 314 chain.incorporate_after(chain.before_begin() 315 ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) 316 ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) 317 ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); 318 /* 319 if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast<dlmalloc_memchain *>(&chain))){ 320 boost::container::throw_bad_alloc(); 321 }*/ 322 } 323 324 //!Deallocates several elements allocated by 325 //!allocate_many(), allocate(), or allocation_command(). 326 //!This function is available only with Version == 2 deallocate_many(multiallocation_chain & chain)327 void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW 328 { 329 BOOST_STATIC_ASSERT(( Version > 1 )); 330 dlmalloc_memchain ch; 331 void *beg(&*chain.begin()), *last(&*chain.last()); 332 size_t size(chain.size()); 333 BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); 334 dlmalloc_multidealloc(&ch); 335 //dlmalloc_multidealloc(reinterpret_cast<dlmalloc_memchain *>(&chain)); 336 } 337 338 private: 339 priv_allocation_command(allocation_type command,std::size_t limit_size,size_type & prefer_in_recvd_out_size,pointer & reuse_ptr)340 pointer priv_allocation_command 341 (allocation_type command, std::size_t limit_size 342 ,size_type &prefer_in_recvd_out_size 343 ,pointer &reuse_ptr) 344 { 345 std::size_t const preferred_size = prefer_in_recvd_out_size; 346 dlmalloc_command_ret_t ret = {0 , 0}; 347 if((limit_size > this->max_size()) | (preferred_size > this->max_size())){ 348 return pointer(); 349 } 350 std::size_t l_size = limit_size*sizeof(T); 351 std::size_t p_size = preferred_size*sizeof(T); 352 std::size_t r_size; 353 { 354 void* reuse_ptr_void = reuse_ptr; 355 ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); 356 reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0; 357 } 358 prefer_in_recvd_out_size = r_size/sizeof(T); 359 return (pointer)ret.first; 360 } 361 }; 362 363 } //namespace container { 364 } //namespace boost { 365 366 #include <boost/container/detail/config_end.hpp> 367 368 #endif //BOOST_CONTAINER_ALLOCATOR_HPP 369 370