1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-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_EXPAND_BWD_TEST_ALLOCATOR_HPP
12 #define BOOST_CONTAINER_EXPAND_BWD_TEST_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 
26 #include <boost/container/throw_exception.hpp>
27 
28 #include <boost/container/detail/addressof.hpp>
29 #include <boost/container/detail/allocation_type.hpp>
30 #include <boost/container/detail/version_type.hpp>
31 
32 #include <boost/move/adl_move_swap.hpp>
33 
34 #include <boost/assert.hpp>
35 
36 #include <memory>
37 #include <algorithm>
38 #include <cstddef>
39 #include <cassert>
40 
41 namespace boost {
42 namespace container {
43 namespace test {
44 
45 //This allocator just allows two allocations. The first one will return
46 //mp_buffer + m_offset configured in the constructor. The second one
47 //will return mp_buffer.
48 template<class T>
49 class expand_bwd_test_allocator
50 {
51  private:
52    typedef expand_bwd_test_allocator<T> self_t;
53    typedef void *                   aux_pointer_t;
54    typedef const void *             cvoid_ptr;
55 
56    template<class T2>
57    expand_bwd_test_allocator& operator=(const expand_bwd_test_allocator<T2>&);
58 
59    expand_bwd_test_allocator& operator=(const expand_bwd_test_allocator&);
60 
61    public:
62    typedef T                                    value_type;
63    typedef T *                                  pointer;
64    typedef const T *                            const_pointer;
65    typedef typename container_detail::add_reference
66                      <value_type>::type         reference;
67    typedef typename container_detail::add_reference
68                      <const value_type>::type   const_reference;
69    typedef std::size_t                          size_type;
70    typedef std::ptrdiff_t                       difference_type;
71 
72    typedef boost::container::container_detail::version_type<expand_bwd_test_allocator, 2>   version;
73 
74    //Dummy multiallocation chain
75    struct multiallocation_chain{};
76 
77    template<class T2>
78    struct rebind
79    {  typedef expand_bwd_test_allocator<T2>   other;   };
80 
81    //!Constructor from the segment manager. Never throws
expand_bwd_test_allocator(T * buffer,size_type sz,difference_type offset)82    expand_bwd_test_allocator(T *buffer, size_type sz, difference_type offset)
83       : mp_buffer(buffer), m_size(sz)
84       , m_offset(offset),  m_allocations(0){ }
85 
86    //!Constructor from other expand_bwd_test_allocator. Never throws
expand_bwd_test_allocator(const expand_bwd_test_allocator & other)87    expand_bwd_test_allocator(const expand_bwd_test_allocator &other)
88       : mp_buffer(other.mp_buffer), m_size(other.m_size)
89       , m_offset(other.m_offset),  m_allocations(0){ }
90 
91    //!Constructor from related expand_bwd_test_allocator. Never throws
92    template<class T2>
expand_bwd_test_allocator(const expand_bwd_test_allocator<T2> & other)93    expand_bwd_test_allocator(const expand_bwd_test_allocator<T2> &other)
94       : mp_buffer(other.mp_buffer), m_size(other.m_size)
95       , m_offset(other.m_offset),  m_allocations(0){ }
96 
address(reference value)97    pointer address(reference value)
98    {  return pointer(container_detail::addressof(value));  }
99 
address(const_reference value) const100    const_pointer address(const_reference value) const
101    {  return const_pointer(container_detail::addressof(value));  }
102 
allocate(size_type,cvoid_ptr hint=0)103    pointer allocate(size_type , cvoid_ptr hint = 0)
104    {  (void)hint; return 0; }
105 
deallocate(const pointer &,size_type)106    void deallocate(const pointer &, size_type)
107    {}
108 
109    template<class Convertible>
construct(pointer ptr,const Convertible & value)110    void construct(pointer ptr, const Convertible &value)
111    {  new((void*)ptr) value_type(value);  }
112 
destroy(pointer ptr)113    void destroy(pointer ptr)
114    {  (*ptr).~value_type();  }
115 
max_size() const116    size_type max_size() const
117    {  return m_size;   }
118 
swap(self_t & alloc1,self_t & alloc2)119    friend void swap(self_t &alloc1, self_t &alloc2)
120    {
121       boost::adl_move_swap(alloc1.mp_buffer, alloc2.mp_buffer);
122       boost::adl_move_swap(alloc1.m_size,    alloc2.m_size);
123       boost::adl_move_swap(alloc1.m_offset,  alloc2.m_offset);
124    }
125 
126    //Experimental version 2 expand_bwd_test_allocator functions
127 
allocation_command(boost::container::allocation_type command,size_type limit_size,size_type & prefer_in_recvd_out_size,pointer & reuse)128    pointer allocation_command(boost::container::allocation_type command,
129                          size_type limit_size,size_type &prefer_in_recvd_out_size,pointer &reuse)
130    {
131       (void)reuse;   (void)command;
132       //This allocator only expands backwards!
133       assert(m_allocations == 0 || (command & boost::container::expand_bwd));
134 
135       prefer_in_recvd_out_size = limit_size;
136 
137       if(m_allocations == 0){
138          if((m_offset + limit_size) > m_size){
139             assert(0);
140          }
141          ++m_allocations;
142          reuse = 0;
143          return (mp_buffer + m_offset);
144       }
145       else if(m_allocations == 1){
146          if(limit_size > m_size){
147             assert(0);
148          }
149          ++m_allocations;
150          return mp_buffer;
151       }
152       else{
153          throw_bad_alloc();
154          return mp_buffer;
155       }
156    }
157 
158    //!Returns maximum the number of objects the previously allocated memory
159    //!pointed by p can hold.
size(const pointer & p) const160    size_type size(const pointer &p) const
161    {  (void)p; return m_size; }
162 
163    //!Allocates just one object. Memory allocated with this function
164    //!must be deallocated only with deallocate_one().
165    //!Throws boost::container::bad_alloc if there is no enough memory
allocate_one()166    pointer allocate_one()
167    {  return this->allocate(1);  }
168 
169    //!Deallocates memory previously allocated with allocate_one().
170    //!You should never use deallocate_one to deallocate memory allocated
171    //!with other functions different from allocate_one(). Never throws
deallocate_one(const pointer & p)172    void deallocate_one(const pointer &p)
173    {  return this->deallocate(p, 1);  }
174 
175    pointer           mp_buffer;
176    size_type         m_size;
177    difference_type   m_offset;
178    char              m_allocations;
179 };
180 
181 //!Equality test for same type of expand_bwd_test_allocator
182 template<class T> inline
operator ==(const expand_bwd_test_allocator<T> & alloc1,const expand_bwd_test_allocator<T> & alloc2)183 bool operator==(const expand_bwd_test_allocator<T>  &alloc1,
184                 const expand_bwd_test_allocator<T>  &alloc2)
185 {  return false; }
186 
187 //!Inequality test for same type of expand_bwd_test_allocator
188 template<class T> inline
operator !=(const expand_bwd_test_allocator<T> & alloc1,const expand_bwd_test_allocator<T> & alloc2)189 bool operator!=(const expand_bwd_test_allocator<T>  &alloc1,
190                 const expand_bwd_test_allocator<T>  &alloc2)
191 {  return true; }
192 
193 }  //namespace test {
194 }  //namespace container {
195 }  //namespace boost {
196 
197 #include <boost/container/detail/config_end.hpp>
198 
199 #endif   //BOOST_CONTAINER_EXPAND_BWD_TEST_ALLOCATOR_HPP
200 
201