• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2000, 2001 Stephen Cleary
2  * Copyright (C) 2011 Kwan Ting Chan
3  *
4  * Use, modification and distribution is subject to the
5  * Boost Software License, Version 1.0. (See accompanying
6  * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
7  */
8 
9 #include "random_shuffle.hpp"
10 #include <boost/pool/pool_alloc.hpp>
11 #include <boost/pool/object_pool.hpp>
12 
13 #include <boost/detail/lightweight_test.hpp>
14 
15 #include <algorithm>
16 #include <deque>
17 #include <list>
18 #include <set>
19 #include <stdexcept>
20 #include <vector>
21 
22 #include <cstdlib>
23 #include <ctime>
24 
25 // Each "tester" object below checks into and out of the "cdtor_checker",
26 //  which will check for any problems related to the construction/destruction of
27 //  "tester" objects.
28 class cdtor_checker
29 {
30 private:
31     // Each constructed object registers its "this" pointer into "objs"
32     std::set<void*> objs;
33 
34 public:
35     // True iff all objects that have checked in have checked out
ok() const36     bool ok() const { return objs.empty(); }
37 
~cdtor_checker()38     ~cdtor_checker()
39     {
40         BOOST_TEST(ok());
41     }
42 
check_in(void * const This)43     void check_in(void * const This)
44     {
45         BOOST_TEST(objs.find(This) == objs.end());
46         objs.insert(This);
47     }
48 
check_out(void * const This)49     void check_out(void * const This)
50     {
51         BOOST_TEST(objs.find(This) != objs.end());
52         objs.erase(This);
53     }
54 };
55 static cdtor_checker mem;
56 
57 struct tester
58 {
testertester59     tester(bool throw_except = false)
60     {
61         if(throw_except)
62         {
63             throw std::logic_error("Deliberate constructor exception");
64         }
65 
66         mem.check_in(this);
67     }
68 
testertester69     tester(const tester &)
70     {
71         mem.check_in(this);
72     }
73 
~testertester74     ~tester()
75     {
76         mem.check_out(this);
77     }
78 };
79 
80 // This is a wrapper around a UserAllocator. It just registers alloc/dealloc
81 //  to/from the system memory. It's used to make sure pool's are allocating
82 //  and deallocating system memory properly.
83 // Do NOT use this class with static or singleton pools.
84 template <typename UserAllocator>
85 struct TrackAlloc
86 {
87     typedef typename UserAllocator::size_type size_type;
88     typedef typename UserAllocator::difference_type difference_type;
89 
90     static std::set<char *> allocated_blocks;
91 
mallocTrackAlloc92     static char * malloc(const size_type bytes)
93     {
94         char * const ret = UserAllocator::malloc(bytes);
95         allocated_blocks.insert(ret);
96         return ret;
97     }
98 
freeTrackAlloc99     static void free(char * const block)
100     {
101         BOOST_TEST(allocated_blocks.find(block) != allocated_blocks.end());
102         allocated_blocks.erase(block);
103         UserAllocator::free(block);
104     }
105 
okTrackAlloc106     static bool ok()
107     {
108         return allocated_blocks.empty();
109     }
110 };
111 template <typename UserAllocator>
112 std::set<char *> TrackAlloc<UserAllocator>::allocated_blocks;
113 
114 typedef TrackAlloc<boost::default_user_allocator_new_delete> track_alloc;
115 
test()116 void test()
117 {
118     {
119         // Do nothing pool
120         boost::object_pool<tester> pool;
121     }
122 
123     {
124         // Construct several tester objects. Don't delete them (i.e.,
125         //  test pool's garbage collection).
126         boost::object_pool<tester> pool;
127         for(int i=0; i < 10; ++i)
128         {
129             pool.construct();
130         }
131     }
132 
133     {
134         // Construct several tester objects. Delete some of them.
135         boost::object_pool<tester> pool;
136         std::vector<tester *> v;
137         for(int i=0; i < 10; ++i)
138         {
139             v.push_back(pool.construct());
140         }
141         pool_test_random_shuffle(v.begin(), v.end());
142         for(int j=0; j < 5; ++j)
143         {
144             pool.destroy(v[j]);
145         }
146     }
147 
148     {
149         // Test how pool reacts with constructors that throw exceptions.
150         //  Shouldn't have any memory leaks.
151         boost::object_pool<tester> pool;
152         for(int i=0; i < 5; ++i)
153         {
154             pool.construct();
155         }
156         for(int j=0; j < 5; ++j)
157         {
158             try
159             {
160                 // The following constructions will raise an exception.
161                 pool.construct(true);
162             }
163             catch(const std::logic_error &) {}
164         }
165     }
166 }
167 
test_alloc()168 void test_alloc()
169 {
170     {
171         // Allocate several tester objects. Delete one.
172         std::vector<tester, boost::pool_allocator<tester> > l;
173         for(int i=0; i < 10; ++i)
174         {
175             l.push_back(tester());
176         }
177         l.pop_back();
178     }
179 
180     {
181         // Allocate several tester objects. Delete two.
182         std::deque<tester, boost::pool_allocator<tester> > l;
183         for(int i=0; i < 10; ++i)
184         {
185             l.push_back(tester());
186         }
187         l.pop_back();
188         l.pop_front();
189     }
190 
191     {
192         // Allocate several tester objects. Delete two.
193         std::list<tester, boost::fast_pool_allocator<tester> > l;
194         // lists rebind their allocators, so dumping is useless
195         for(int i=0; i < 10; ++i)
196         {
197             l.push_back(tester());
198         }
199         l.pop_back();
200         l.pop_front();
201     }
202 
203     tester * tmp;
204     {
205         // Create a memory leak on purpose. (Allocator doesn't have
206         //  garbage collection)
207         // (Note: memory leak)
208         boost::pool_allocator<tester> a;
209         tmp = a.allocate(1, 0);
210         new (tmp) tester();
211     }
212     if(mem.ok())
213     {
214         BOOST_ERROR("Pool allocator cleaned up itself");
215     }
216     // Remove memory checker entry (to avoid error later) and
217     //  clean up memory leak
218     tmp->~tester();
219     boost::pool_allocator<tester>::deallocate(tmp, 1);
220 
221     // test allocating zero elements
222     {
223         boost::pool_allocator<tester> alloc;
224         tester* ip = alloc.allocate(0);
225         alloc.deallocate(ip, 0);
226     }
227 }
228 
test_mem_usage()229 void test_mem_usage()
230 {
231     typedef boost::pool<track_alloc> pool_type;
232 
233     {
234         // Constructor should do nothing; no memory allocation
235         pool_type pool(sizeof(int));
236         BOOST_TEST(track_alloc::ok());
237         BOOST_TEST(!pool.release_memory());
238         BOOST_TEST(!pool.purge_memory());
239 
240         // Should allocate from system
241         pool.free(pool.malloc());
242         BOOST_TEST(!track_alloc::ok());
243 
244         // Ask pool to give up memory it's not using; this should succeed
245         BOOST_TEST(pool.release_memory());
246         BOOST_TEST(track_alloc::ok());
247 
248         // Should allocate from system again
249         pool.malloc(); // loses the pointer to the returned chunk (*A*)
250 
251         // Ask pool to give up memory it's not using; this should fail
252         BOOST_TEST(!pool.release_memory());
253 
254         // Force pool to give up memory it's not using; this should succeed
255         // This will clean up the memory leak from (*A*)
256         BOOST_TEST(pool.purge_memory());
257         BOOST_TEST(track_alloc::ok());
258 
259         // Should allocate from system again
260         pool.malloc(); // loses the pointer to the returned chunk (*B*)
261 
262         // pool's destructor should purge the memory
263         //  This will clean up the memory leak from (*B*)
264     }
265 
266     BOOST_TEST(track_alloc::ok());
267 }
268 
test_void()269 void test_void()
270 {
271     typedef boost::pool_allocator<void> void_allocator;
272     typedef boost::fast_pool_allocator<void> fast_void_allocator;
273 
274     typedef void_allocator::rebind<int>::other int_allocator;
275     typedef fast_void_allocator::rebind<int>::other fast_int_allocator;
276 
277     std::vector<int, int_allocator> v1;
278     std::vector<int, fast_int_allocator> v2;
279 }
280 
main()281 int main()
282 {
283     std::srand(static_cast<unsigned>(std::time(0)));
284 
285     test();
286     test_alloc();
287     test_mem_usage();
288     test_void();
289 
290     return boost::report_errors();
291 }
292