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 BOOST_CONTAINER_ATTRIBUTE_NODISCARD 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 208 BOOST_CONTAINER_ATTRIBUTE_NODISCARD operator ==(const allocator &,const allocator &)209 friend bool operator==(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW 210 { return true; } 211 212 //!An allocator always compares to false, as memory allocated with one 213 //!instance can be deallocated by another instance 214 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE operator !=(const allocator &,const allocator &)215 friend bool operator!=(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW 216 { return false; } 217 218 //!An advanced function that offers in-place expansion shrink to fit and new allocation 219 //!capabilities. Memory allocated with this function can only be deallocated with deallocate() 220 //!or deallocate_many(). 221 //!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)222 BOOST_CONTAINER_ATTRIBUTE_NODISCARD pointer allocation_command(allocation_type command, 223 size_type limit_size, 224 size_type &prefer_in_recvd_out_size, 225 pointer &reuse) 226 { 227 BOOST_STATIC_ASSERT(( Version > 1 )); 228 const allocation_type mask(AllocationDisableMask); 229 command &= ~mask; 230 pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); 231 if(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION)) 232 boost::container::throw_bad_alloc(); 233 return ret; 234 } 235 236 //!Returns maximum the number of objects the previously allocated memory 237 //!pointed by p can hold. 238 //!Memory must not have been allocated with 239 //!allocate_one or allocate_individual. 240 //!This function is available only with Version == 2 size(pointer p) const241 BOOST_CONTAINER_ATTRIBUTE_NODISCARD size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW 242 { 243 BOOST_STATIC_ASSERT(( Version > 1 )); 244 return dlmalloc_size(p); 245 } 246 247 //!Allocates just one object. Memory allocated with this function 248 //!must be deallocated only with deallocate_one(). 249 //!Throws bad_alloc if there is no enough memory 250 //!This function is available only with Version == 2 allocate_one()251 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE pointer allocate_one() 252 { 253 BOOST_STATIC_ASSERT(( Version > 1 )); 254 return this->allocate(1); 255 } 256 257 //!Allocates many elements of size == 1. 258 //!Elements must be individually deallocated with deallocate_one() 259 //!This function is available only with Version == 2 allocate_individual(std::size_t num_elements,multiallocation_chain & chain)260 BOOST_CONTAINER_FORCEINLINE void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) 261 { 262 BOOST_STATIC_ASSERT(( Version > 1 )); 263 this->allocate_many(1, num_elements, chain); 264 } 265 266 //!Deallocates memory previously allocated with allocate_one(). 267 //!You should never use deallocate_one to deallocate memory allocated 268 //!with other functions different from allocate_one() or allocate_individual. 269 //Never throws deallocate_one(pointer p)270 void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW 271 { 272 BOOST_STATIC_ASSERT(( Version > 1 )); 273 return this->deallocate(p, 1); 274 } 275 276 //!Deallocates memory allocated with allocate_one() or allocate_individual(). 277 //!This function is available only with Version == 2 278 BOOST_CONTAINER_FORCEINLINE deallocate_individual(multiallocation_chain & chain)279 void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW 280 { 281 BOOST_STATIC_ASSERT(( Version > 1 )); 282 return this->deallocate_many(chain); 283 } 284 285 //!Allocates many elements of size elem_size. 286 //!Elements must be individually deallocated with deallocate() 287 //!This function is available only with Version == 2 allocate_many(size_type elem_size,std::size_t n_elements,multiallocation_chain & chain)288 void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) 289 { 290 BOOST_STATIC_ASSERT(( Version > 1 )); 291 dlmalloc_memchain ch; 292 BOOST_CONTAINER_MEMCHAIN_INIT(&ch); 293 if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ 294 boost::container::throw_bad_alloc(); 295 } 296 chain.incorporate_after(chain.before_begin() 297 ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) 298 ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) 299 ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); 300 /* 301 if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast<dlmalloc_memchain *>(&chain))){ 302 boost::container::throw_bad_alloc(); 303 }*/ 304 } 305 306 //!Allocates n_elements elements, each one of size elem_sizes[i] 307 //!Elements must be individually deallocated with deallocate() 308 //!This function is available only with Version == 2 allocate_many(const size_type * elem_sizes,size_type n_elements,multiallocation_chain & chain)309 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) 310 { 311 BOOST_STATIC_ASSERT(( Version > 1 )); 312 dlmalloc_memchain ch; 313 BOOST_CONTAINER_MEMCHAIN_INIT(&ch); 314 if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ 315 boost::container::throw_bad_alloc(); 316 } 317 chain.incorporate_after(chain.before_begin() 318 ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) 319 ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) 320 ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); 321 /* 322 if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast<dlmalloc_memchain *>(&chain))){ 323 boost::container::throw_bad_alloc(); 324 }*/ 325 } 326 327 //!Deallocates several elements allocated by 328 //!allocate_many(), allocate(), or allocation_command(). 329 //!This function is available only with Version == 2 deallocate_many(multiallocation_chain & chain)330 void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW 331 { 332 BOOST_STATIC_ASSERT(( Version > 1 )); 333 dlmalloc_memchain ch; 334 void *beg(&*chain.begin()), *last(&*chain.last()); 335 size_t size(chain.size()); 336 BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); 337 dlmalloc_multidealloc(&ch); 338 //dlmalloc_multidealloc(reinterpret_cast<dlmalloc_memchain *>(&chain)); 339 } 340 341 private: 342 priv_allocation_command(allocation_type command,std::size_t limit_size,size_type & prefer_in_recvd_out_size,pointer & reuse_ptr)343 pointer priv_allocation_command 344 (allocation_type command, std::size_t limit_size 345 ,size_type &prefer_in_recvd_out_size 346 ,pointer &reuse_ptr) 347 { 348 std::size_t const preferred_size = prefer_in_recvd_out_size; 349 dlmalloc_command_ret_t ret = {0 , 0}; 350 if((limit_size > this->max_size()) | (preferred_size > this->max_size())){ 351 return pointer(); 352 } 353 std::size_t l_size = limit_size*sizeof(T); 354 std::size_t p_size = preferred_size*sizeof(T); 355 std::size_t r_size; 356 { 357 void* reuse_ptr_void = reuse_ptr; 358 ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); 359 reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0; 360 } 361 prefer_in_recvd_out_size = r_size/sizeof(T); 362 return (pointer)ret.first; 363 } 364 }; 365 366 } //namespace container { 367 } //namespace boost { 368 369 #include <boost/container/detail/config_end.hpp> 370 371 #endif //BOOST_CONTAINER_ALLOCATOR_HPP 372 373