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