1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2015-2015. 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 #include <boost/container/pmr/resource_adaptor.hpp>
11 #include <boost/core/lightweight_test.hpp>
12 #include "propagation_test_allocator.hpp"
13 #include "derived_from_memory_resource.hpp"
14 #include <boost/container/new_allocator.hpp>
15 #include <memory>
16 
17 using namespace boost::container::pmr;
18 
19 static const std::size_t max_alignment_value = boost::move_detail::alignment_of<boost::move_detail::max_align_t>::value;
20 
test_default_constructor()21 void test_default_constructor()
22 {
23    typedef propagation_test_allocator<char, 0> alloc_t;
24    resource_adaptor<alloc_t> ra;
25    BOOST_TEST(ra.get_allocator().m_default_contructed == true);
26 }
27 
test_copy_constructor()28 void test_copy_constructor()
29 {
30    typedef propagation_test_allocator<char, 0> alloc_t;
31    resource_adaptor<alloc_t> ra;
32    BOOST_TEST(ra.get_allocator().m_default_contructed == true);
33    resource_adaptor<alloc_t> rb(ra);
34    BOOST_TEST(rb.get_allocator().m_default_contructed == false);
35    BOOST_TEST(rb.get_allocator().m_move_contructed == false);
36 }
37 
test_move_constructor()38 void test_move_constructor()
39 {
40    typedef propagation_test_allocator<char, 0> alloc_t;
41    resource_adaptor<alloc_t> ra;
42    BOOST_TEST(ra.get_allocator().m_default_contructed == true);
43    resource_adaptor<alloc_t> rb(::boost::move(ra));
44    BOOST_TEST(rb.get_allocator().m_default_contructed == false);
45    BOOST_TEST(rb.get_allocator().m_move_contructed == true);
46 }
47 
test_lvalue_alloc_constructor()48 void test_lvalue_alloc_constructor()
49 {
50    typedef propagation_test_allocator<char, 0> alloc_t;
51    alloc_t a;
52    resource_adaptor<alloc_t> ra(a);
53    BOOST_TEST(ra.get_allocator().m_default_contructed == false);
54    BOOST_TEST(ra.get_allocator().m_move_contructed == false);
55 }
56 
test_rvalue_alloc_constructor()57 void test_rvalue_alloc_constructor()
58 {
59    typedef propagation_test_allocator<char, 0> alloc_t;
60    alloc_t a;
61    resource_adaptor<alloc_t> ra(::boost::move(a));
62    BOOST_TEST(ra.get_allocator().m_default_contructed == false);
63    BOOST_TEST(ra.get_allocator().m_move_contructed == true);
64 }
65 
test_copy_assign()66 void test_copy_assign()
67 {
68    typedef propagation_test_allocator<char, 0> alloc_t;
69    resource_adaptor<alloc_t> ra;
70    BOOST_TEST(ra.get_allocator().m_default_contructed == true);
71    resource_adaptor<alloc_t> rb;
72    BOOST_TEST(ra.get_allocator().m_default_contructed == true);
73    rb = ra;
74    BOOST_TEST(rb.get_allocator().m_move_contructed == false);
75    BOOST_TEST(rb.get_allocator().m_move_assigned == false);
76 }
77 
test_move_assign()78 void test_move_assign()
79 {
80    typedef propagation_test_allocator<char, 0> alloc_t;
81    resource_adaptor<alloc_t> ra;
82    BOOST_TEST(ra.get_allocator().m_default_contructed == true);
83    resource_adaptor<alloc_t> rb;
84    BOOST_TEST(ra.get_allocator().m_default_contructed == true);
85    rb = ::boost::move(ra);
86    BOOST_TEST(rb.get_allocator().m_move_contructed == false);
87    BOOST_TEST(rb.get_allocator().m_move_assigned == true);
88 }
89 
90 struct stateful
91 {
92    public:
93    typedef char value_type;
94 
95    template<class U>
96    struct rebind
97    {  typedef stateful other; };
98 
statefulstateful99    stateful()
100       : m_u(0u)
101    {}
102 
allocatestateful103    char *allocate(std::size_t n)
104    {  allocate_size = n;   return allocate_return;  }
105 
deallocatestateful106    void deallocate(char *p, std::size_t n)
107    {  deallocate_p = p;    deallocate_size = n; }
108 
operator ==(const stateful & l,const stateful & r)109    friend bool operator==(const stateful &l, const stateful &r)
110    {  return l.m_u == r.m_u;   }
111 
operator !=(const stateful & l,const stateful & r)112    friend bool operator!=(const stateful &l, const stateful &r)
113    {  return l.m_u != r.m_u;   }
114 
115    public:
116    unsigned m_u;
117    std::size_t allocate_size;
118    char *allocate_return;
119    std::size_t deallocate_size;
120    char *deallocate_p;
121 };
122 
test_get_allocator()123 void test_get_allocator()
124 {
125    stateful a;
126    a.m_u = 999;
127    resource_adaptor<stateful> ra(a);
128    const resource_adaptor<stateful> & cra = ra;
129    BOOST_TEST( ra.get_allocator().m_u == 999);
130    BOOST_TEST(cra.get_allocator().m_u == 999);
131 }
132 
133 typedef resource_adaptor<stateful> stateful_resource_adaptor_t;
134 
135 struct derived_from_resource_adaptor_stateful
136    : public stateful_resource_adaptor_t
137 {
138    public:
139    typedef stateful_resource_adaptor_t base_t;
140    using base_t::do_allocate;
141    using base_t::do_deallocate;
142    using base_t::do_is_equal;
143 };
144 
test_do_allocate_deallocate()145 void test_do_allocate_deallocate()
146 {
147    {
148       derived_from_resource_adaptor_stateful dra;
149       char dummy = 0;
150       dra.get_allocator().allocate_return = &dummy;
151       void *allocate_ret = dra.do_allocate(998, 1);
152       BOOST_TEST(allocate_ret == &dummy);
153       BOOST_TEST(dra.get_allocator().allocate_size == 998);
154    }
155    {
156       derived_from_resource_adaptor_stateful dra;
157       char dummy = 0;
158       dra.do_deallocate(&dummy, 1234, 1);
159       BOOST_TEST(dra.get_allocator().deallocate_p == &dummy);
160       BOOST_TEST(dra.get_allocator().deallocate_size == 1234);
161    }
162    {
163       //Overaligned allocation
164       derived_from_resource_adaptor_stateful dra;
165       const std::size_t alignment = max_alignment_value*2u;
166       const std::size_t bytes = alignment/2;
167       char dummy[alignment*2u+sizeof(void*)];
168       dra.get_allocator().allocate_return = dummy;
169 
170       //First allocate
171       void *allocate_ret = dra.do_allocate(bytes, alignment);
172       BOOST_TEST( (char*)allocate_ret >= (dummy+sizeof(void*)) && (char*)allocate_ret < (dummy + sizeof(dummy)) );
173       BOOST_TEST( (std::size_t(allocate_ret) & (alignment - 1u)) == 0 );
174       BOOST_TEST( dra.get_allocator().allocate_size >= (alignment/2+sizeof(void*)) );
175 
176       //Then allocate
177       dra.do_deallocate(allocate_ret, bytes, alignment);
178       BOOST_TEST(dra.get_allocator().deallocate_p == dummy);
179       BOOST_TEST(dra.get_allocator().deallocate_size == dra.get_allocator().allocate_size);
180    }
181    {
182       typedef resource_adaptor< boost::container::new_allocator<int> > new_resource_alloc_t;
183       new_resource_alloc_t ra;
184       boost::container::pmr::memory_resource &mr = ra;
185 
186       //new_allocator, low alignment
187       mr.deallocate(mr.allocate(16, 1), 16, 1);
188 
189       //new_allocator, high alignment
190       mr.deallocate(mr.allocate(16, max_alignment_value*4u), 16, max_alignment_value*4u);
191    }
192    {
193       typedef resource_adaptor<std ::allocator<int> > new_resource_alloc_t;
194       new_resource_alloc_t ra;
195       boost::container::pmr::memory_resource &mr = ra;
196 
197       //std::allocator, low alignment
198       mr.deallocate(mr.allocate(16, 1), 16, 1);
199 
200       //std::allocator, high alignment
201       mr.deallocate(mr.allocate(16, max_alignment_value*4u), 16, max_alignment_value*4u);
202    }
203 }
204 
test_do_is_equal()205 void test_do_is_equal()
206 {
207    derived_from_resource_adaptor_stateful dra;
208    derived_from_memory_resource dmr;
209    //Different dynamic type must return false
210    BOOST_TEST(dra.do_is_equal(dmr) == false);
211 
212    //Same dynamic type with same state must return true
213    derived_from_resource_adaptor_stateful dra2;
214    BOOST_TEST(dra.do_is_equal(dra2) == true);
215 
216    //Same dynamic type with different state must return false
217    dra2.get_allocator().m_u = 1234;
218    BOOST_TEST(dra.do_is_equal(dra2) == false);
219 }
220 
main()221 int main()
222 {
223    test_default_constructor();
224    test_copy_constructor();
225    test_move_constructor();
226    test_lvalue_alloc_constructor();
227    test_rvalue_alloc_constructor();
228    test_copy_assign();
229    test_move_assign();
230    test_get_allocator();
231    test_do_allocate_deallocate();
232    test_do_is_equal();
233    return ::boost::report_errors();
234 }
235