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