]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/interprocess/test/memory_algorithm_test_template.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / interprocess / test / memory_algorithm_test_template.hpp
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2006-2012. 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/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10
11 #ifndef BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
12 #define BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
13
14 #include <boost/interprocess/detail/config_begin.hpp>
15
16 #include <boost/interprocess/containers/vector.hpp>
17
18 #include <vector>
19 #include <iostream>
20 #include <new> //std::nothrow
21 #include <cstring> //std::memset
22
23 namespace boost { namespace interprocess { namespace test {
24
25 enum deallocation_type { DirectDeallocation, InverseDeallocation, MixedDeallocation, EndDeallocationType };
26
27 //This test allocates until there is no more memory
28 //and after that deallocates all in the inverse order
29 template<class Allocator>
30 bool test_allocation(Allocator &a)
31 {
32 for( deallocation_type t = DirectDeallocation
33 ; t != EndDeallocationType
34 ; t = (deallocation_type)((int)t + 1)){
35 std::vector<void*> buffers;
36 typename Allocator::size_type free_memory = a.get_free_memory();
37
38 for(int i = 0; true; ++i){
39 void *ptr = a.allocate(i, std::nothrow);
40 if(!ptr)
41 break;
42 std::size_t size = a.size(ptr);
43 std::memset(ptr, 0, size);
44 buffers.push_back(ptr);
45 }
46
47 switch(t){
48 case DirectDeallocation:
49 {
50 for(int j = 0, max = (int)buffers.size()
51 ;j < max
52 ;++j){
53 a.deallocate(buffers[j]);
54 }
55 }
56 break;
57 case InverseDeallocation:
58 {
59 for(int j = (int)buffers.size()
60 ;j--
61 ;){
62 a.deallocate(buffers[j]);
63 }
64 }
65 break;
66 case MixedDeallocation:
67 {
68 for(int j = 0, max = (int)buffers.size()
69 ;j < max
70 ;++j){
71 int pos = (j%4)*((int)buffers.size())/4;
72 a.deallocate(buffers[pos]);
73 buffers.erase(buffers.begin()+pos);
74 }
75 }
76 break;
77 default:
78 break;
79 }
80 bool ok = free_memory == a.get_free_memory() &&
81 a.all_memory_deallocated() && a.check_sanity();
82 if(!ok) return ok;
83 }
84 return true;
85 }
86
87 //This test allocates until there is no more memory
88 //and after that tries to shrink all the buffers to the
89 //half of the original size
90 template<class Allocator>
91 bool test_allocation_shrink(Allocator &a)
92 {
93 std::vector<void*> buffers;
94
95 //Allocate buffers with extra memory
96 for(int i = 0; true; ++i){
97 void *ptr = a.allocate(i*2, std::nothrow);
98 if(!ptr)
99 break;
100 std::size_t size = a.size(ptr);
101 std::memset(ptr, 0, size);
102 buffers.push_back(ptr);
103 }
104
105 //Now shrink to half
106 for(int i = 0, max = (int)buffers.size()
107 ;i < max
108 ; ++i){
109 typename Allocator::size_type received_size;
110 char *reuse = static_cast<char*>(buffers[i]);
111 if(a.template allocation_command<char>
112 ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, i*2
113 , received_size = i, reuse)){
114 if(received_size > std::size_t(i*2)){
115 return false;
116 }
117 if(received_size < std::size_t(i)){
118 return false;
119 }
120 std::memset(buffers[i], 0, a.size(buffers[i]));
121 }
122 }
123
124 //Deallocate it in non sequential order
125 for(int j = 0, max = (int)buffers.size()
126 ;j < max
127 ;++j){
128 int pos = (j%4)*((int)buffers.size())/4;
129 a.deallocate(buffers[pos]);
130 buffers.erase(buffers.begin()+pos);
131 }
132
133 return a.all_memory_deallocated() && a.check_sanity();
134 }
135
136 //This test allocates until there is no more memory
137 //and after that tries to expand all the buffers to
138 //avoid the wasted internal fragmentation
139 template<class Allocator>
140 bool test_allocation_expand(Allocator &a)
141 {
142 std::vector<void*> buffers;
143
144 //Allocate buffers with extra memory
145 for(int i = 0; true; ++i){
146 void *ptr = a.allocate(i, std::nothrow);
147 if(!ptr)
148 break;
149 std::size_t size = a.size(ptr);
150 std::memset(ptr, 0, size);
151 buffers.push_back(ptr);
152 }
153
154 //Now try to expand to the double of the size
155 for(int i = 0, max = (int)buffers.size()
156 ;i < max
157 ;++i){
158 typename Allocator::size_type received_size;
159 std::size_t min_size = i+1;
160 std::size_t preferred_size = i*2;
161 preferred_size = min_size > preferred_size ? min_size : preferred_size;
162
163 char *reuse = static_cast<char*>(buffers[i]);
164 while(a.template allocation_command<char>
165 ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
166 , received_size = preferred_size, reuse)){
167 //Check received size is bigger than minimum
168 if(received_size < min_size){
169 return false;
170 }
171 //Now, try to expand further
172 min_size = received_size+1;
173 preferred_size = min_size*2;
174 }
175 }
176
177 //Deallocate it in non sequential order
178 for(int j = 0, max = (int)buffers.size()
179 ;j < max
180 ;++j){
181 int pos = (j%4)*((int)buffers.size())/4;
182 a.deallocate(buffers[pos]);
183 buffers.erase(buffers.begin()+pos);
184 }
185
186 return a.all_memory_deallocated() && a.check_sanity();
187 }
188
189 //This test allocates until there is no more memory
190 //and after that tries to expand all the buffers to
191 //avoid the wasted internal fragmentation
192 template<class Allocator>
193 bool test_allocation_shrink_and_expand(Allocator &a)
194 {
195 std::vector<void*> buffers;
196 std::vector<typename Allocator::size_type> received_sizes;
197 std::vector<bool> size_reduced;
198
199 //Allocate buffers wand store received sizes
200 for(int i = 0; true; ++i){
201 typename Allocator::size_type received_size;
202 char *reuse = 0;
203 void *ptr = a.template allocation_command<char>
204 ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, i, received_size = i*2, reuse);
205 if(!ptr){
206 ptr = a.template allocation_command<char>
207 ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, 1, received_size = i*2, reuse);
208 if(!ptr)
209 break;
210 }
211 buffers.push_back(ptr);
212 received_sizes.push_back(received_size);
213 }
214
215 //Now shrink to half
216 for(int i = 0, max = (int)buffers.size()
217 ; i < max
218 ; ++i){
219 typename Allocator::size_type received_size;
220 char *reuse = static_cast<char*>(buffers[i]);
221 if(a.template allocation_command<char>
222 ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_sizes[i]
223 , received_size = i, reuse)){
224 if(received_size > std::size_t(received_sizes[i])){
225 return false;
226 }
227 if(received_size < std::size_t(i)){
228 return false;
229 }
230 size_reduced.push_back(received_size != received_sizes[i]);
231 }
232 }
233
234 //Now try to expand to the original size
235 for(int i = 0, max = (int)buffers.size()
236 ;i < max
237 ;++i){
238 typename Allocator::size_type received_size;
239 std::size_t request_size = received_sizes[i];
240 char *reuse = static_cast<char*>(buffers[i]);
241 if(a.template allocation_command<char>
242 ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, request_size
243 , received_size = request_size, reuse)){
244 if(received_size != received_sizes[i]){
245 return false;
246 }
247 }
248 else{
249 return false;
250 }
251 }
252
253 //Deallocate it in non sequential order
254 for(int j = 0, max = (int)buffers.size()
255 ;j < max
256 ;++j){
257 int pos = (j%4)*((int)buffers.size())/4;
258 a.deallocate(buffers[pos]);
259 buffers.erase(buffers.begin()+pos);
260 }
261
262 return a.all_memory_deallocated() && a.check_sanity();
263 }
264
265 //This test allocates until there is no more memory
266 //and after that deallocates the odd buffers to
267 //make room for expansions. The expansion will probably
268 //success since the deallocation left room for that.
269 template<class Allocator>
270 bool test_allocation_deallocation_expand(Allocator &a)
271 {
272 std::vector<void*> buffers;
273
274 //Allocate buffers with extra memory
275 for(int i = 0; true; ++i){
276 void *ptr = a.allocate(i, std::nothrow);
277 if(!ptr)
278 break;
279 std::size_t size = a.size(ptr);
280 std::memset(ptr, 0, size);
281 buffers.push_back(ptr);
282 }
283
284 //Now deallocate the half of the blocks
285 //so expand maybe can merge new free blocks
286 for(int i = 0, max = (int)buffers.size()
287 ;i < max
288 ;++i){
289 if(i%2){
290 a.deallocate(buffers[i]);
291 buffers[i] = 0;
292 }
293 }
294
295 //Now try to expand to the double of the size
296 for(int i = 0, max = (int)buffers.size()
297 ;i < max
298 ;++i){
299 //
300 if(buffers[i]){
301 typename Allocator::size_type received_size;
302 std::size_t min_size = i+1;
303 std::size_t preferred_size = i*2;
304 preferred_size = min_size > preferred_size ? min_size : preferred_size;
305
306 char *reuse = static_cast<char*>(buffers[i]);
307 while(a.template allocation_command<char>
308 ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
309 , received_size = preferred_size, reuse)){
310 //Check received size is bigger than minimum
311 if(received_size < min_size){
312 return false;
313 }
314 //Now, try to expand further
315 min_size = received_size+1;
316 preferred_size = min_size*2;
317 }
318 }
319 }
320
321 //Now erase null values from the vector
322 buffers.erase( std::remove(buffers.begin(), buffers.end(), static_cast<void*>(0))
323 , buffers.end());
324
325 //Deallocate it in non sequential order
326 for(int j = 0, max = (int)buffers.size()
327 ;j < max
328 ;++j){
329 int pos = (j%4)*((int)buffers.size())/4;
330 a.deallocate(buffers[pos]);
331 buffers.erase(buffers.begin()+pos);
332 }
333
334 return a.all_memory_deallocated() && a.check_sanity();
335 }
336
337 //This test allocates until there is no more memory
338 //and after that deallocates all except the last.
339 //If the allocation algorithm is a bottom-up algorithm
340 //the last buffer will be in the end of the segment.
341 //Then the test will start expanding backwards, until
342 //the buffer fills all the memory
343 template<class Allocator>
344 bool test_allocation_with_reuse(Allocator &a)
345 {
346 //We will repeat this test for different sized elements
347 for(int sizeof_object = 1; sizeof_object < 20; ++sizeof_object){
348 std::vector<void*> buffers;
349
350 //Allocate buffers with extra memory
351 for(int i = 0; true; ++i){
352 void *ptr = a.allocate(i*sizeof_object, std::nothrow);
353 if(!ptr)
354 break;
355 std::size_t size = a.size(ptr);
356 std::memset(ptr, 0, size);
357 buffers.push_back(ptr);
358 }
359
360 //Now deallocate all except the latest
361 //Now try to expand to the double of the sizeof_object
362 for(int i = 0, max = (int)buffers.size() - 1
363 ;i < max
364 ;++i){
365 a.deallocate(buffers[i]);
366 }
367
368 //Save the unique buffer and clear vector
369 void *ptr = buffers.back();
370 buffers.clear();
371
372 //Now allocate with reuse
373 typename Allocator::size_type received_size = 0;
374 for(int i = 0; true; ++i){
375 std::size_t min_size = (received_size + 1);
376 std::size_t prf_size = (received_size + (i+1)*2);
377 void *reuse = ptr;
378 void *ret = a.raw_allocation_command
379 ( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size
380 , received_size = prf_size, reuse, sizeof_object);
381 if(!ret)
382 break;
383 //If we have memory, this must be a buffer reuse
384 if(!reuse)
385 return 1;
386 if(received_size < min_size)
387 return 1;
388 ptr = ret;
389 }
390 //There is only a single block so deallocate it
391 a.deallocate(ptr);
392
393 if(!a.all_memory_deallocated() || !a.check_sanity())
394 return false;
395 }
396 return true;
397 }
398
399
400 //This test allocates memory with different alignments
401 //and checks returned memory is aligned.
402 template<class Allocator>
403 bool test_aligned_allocation(Allocator &a)
404 {
405 //Allocate aligned buffers in a loop
406 //and then deallocate it
407 bool continue_loop = true;
408 for(unsigned int i = 1; continue_loop; i <<= 1){
409 for(unsigned int j = 1; true; j <<= 1){
410 void *ptr = a.allocate_aligned(i-1, j, std::nothrow);
411 if(!ptr){
412 if(j == 1)
413 continue_loop = false;
414 break;
415 }
416
417 if(((std::size_t)ptr & (j - 1)) != 0)
418 return false;
419 a.deallocate(ptr);
420 if(!a.all_memory_deallocated() || !a.check_sanity()){
421 return false;
422 }
423 }
424 }
425
426 return a.all_memory_deallocated() && a.check_sanity();
427 }
428
429 //This test allocates memory with different alignments
430 //and checks returned memory is aligned.
431 template<class Allocator>
432 bool test_continuous_aligned_allocation(Allocator &a)
433 {
434 std::vector<void*> buffers;
435 //Allocate aligned buffers in a loop
436 //and then deallocate it
437 bool continue_loop = true;
438 for(unsigned i = 1; continue_loop && i; i <<= 1){
439 for(unsigned int j = 1; j; j <<= 1){
440 for(bool any_allocated = false; 1;){
441 void *ptr = a.allocate_aligned(i-1, j, std::nothrow);
442 buffers.push_back(ptr);
443 if(!ptr){
444 if(j == 1 && !any_allocated){
445 continue_loop = false;
446 }
447 break;
448 }
449 else{
450 any_allocated = true;
451 }
452
453 if(((std::size_t)ptr & (j - 1)) != 0)
454 return false;
455 }
456 //Deallocate all
457 for(unsigned int k = (int)buffers.size(); k--;){
458 a.deallocate(buffers[k]);
459 }
460 buffers.clear();
461 if(!a.all_memory_deallocated() && a.check_sanity())
462 return false;
463 if(!continue_loop)
464 break;
465 }
466 }
467
468 return a.all_memory_deallocated() && a.check_sanity();
469 }
470
471 //This test allocates memory, writes it with a non-zero value and
472 //tests zero_free_memory initializes to zero for the next allocation
473 template<class Allocator>
474 bool test_clear_free_memory(Allocator &a)
475 {
476 std::vector<void*> buffers;
477
478 //Allocate memory
479 for(int i = 0; true; ++i){
480 void *ptr = a.allocate(i, std::nothrow);
481 if(!ptr)
482 break;
483 std::size_t size = a.size(ptr);
484 std::memset(ptr, 1, size);
485 buffers.push_back(ptr);
486 }
487
488 //Mark it
489 for(int i = 0, max = buffers.size(); i < max; ++i){
490 std::memset(buffers[i], 1, i);
491 }
492
493 //Deallocate all
494 for(int j = (int)buffers.size()
495 ;j--
496 ;){
497 a.deallocate(buffers[j]);
498 }
499 buffers.clear();
500
501 if(!a.all_memory_deallocated() && a.check_sanity())
502 return false;
503
504 //Now clear all free memory
505 a.zero_free_memory();
506
507 if(!a.all_memory_deallocated() && a.check_sanity())
508 return false;
509
510 //Now test all allocated memory is zero
511 //Allocate memory
512 const char *first_addr = 0;
513 for(int i = 0; true; ++i){
514 void *ptr = a.allocate(i, std::nothrow);
515 if(!ptr)
516 break;
517 if(i == 0){
518 first_addr = (char*)ptr;
519 }
520 std::size_t memsize = a.size(ptr);
521 buffers.push_back(ptr);
522
523 for(int j = 0; j < (int)memsize; ++j){
524 if(static_cast<char*>((char*)ptr)[j]){
525 std::cout << "Zero memory test failed. in buffer " << i
526 << " byte " << j << " first address " << (void*) first_addr << " offset " << ((char*)ptr+j) - (char*)first_addr << " memsize: " << memsize << std::endl;
527 return false;
528 }
529 }
530 }
531
532 //Deallocate all
533 for(int j = (int)buffers.size()
534 ;j--
535 ;){
536 a.deallocate(buffers[j]);
537 }
538 if(!a.all_memory_deallocated() && a.check_sanity())
539 return false;
540
541 return true;
542 }
543
544
545 //This test uses tests grow and shrink_to_fit functions
546 template<class Allocator>
547 bool test_grow_shrink_to_fit(Allocator &a)
548 {
549 std::vector<void*> buffers;
550
551 typename Allocator::size_type original_size = a.get_size();
552 typename Allocator::size_type original_free = a.get_free_memory();
553
554 a.shrink_to_fit();
555
556 if(!a.all_memory_deallocated() && a.check_sanity())
557 return false;
558
559 typename Allocator::size_type shrunk_size = a.get_size();
560 typename Allocator::size_type shrunk_free_memory = a.get_free_memory();
561 if(shrunk_size != a.get_min_size())
562 return 1;
563
564 a.grow(original_size - shrunk_size);
565
566 if(!a.all_memory_deallocated() && a.check_sanity())
567 return false;
568
569 if(original_size != a.get_size())
570 return false;
571 if(original_free != a.get_free_memory())
572 return false;
573
574 //Allocate memory
575 for(int i = 0; true; ++i){
576 void *ptr = a.allocate(i, std::nothrow);
577 if(!ptr)
578 break;
579 std::size_t size = a.size(ptr);
580 std::memset(ptr, 0, size);
581 buffers.push_back(ptr);
582 }
583
584 //Now deallocate the half of the blocks
585 //so expand maybe can merge new free blocks
586 for(int i = 0, max = (int)buffers.size()
587 ;i < max
588 ;++i){
589 if(i%2){
590 a.deallocate(buffers[i]);
591 buffers[i] = 0;
592 }
593 }
594
595 //Deallocate the rest of the blocks
596
597 //Deallocate it in non sequential order
598 for(int j = 0, max = (int)buffers.size()
599 ;j < max
600 ;++j){
601 int pos = (j%5)*((int)buffers.size())/4;
602 if(pos == int(buffers.size()))
603 --pos;
604 a.deallocate(buffers[pos]);
605 buffers.erase(buffers.begin()+pos);
606 typename Allocator::size_type old_free = a.get_free_memory();
607 a.shrink_to_fit();
608 if(!a.check_sanity()) return false;
609 if(original_size < a.get_size()) return false;
610 if(old_free < a.get_free_memory()) return false;
611
612 a.grow(original_size - a.get_size());
613
614 if(!a.check_sanity()) return false;
615 if(original_size != a.get_size()) return false;
616 if(old_free != a.get_free_memory()) return false;
617 }
618
619 //Now shrink it to the maximum
620 a.shrink_to_fit();
621
622 if(a.get_size() != a.get_min_size())
623 return 1;
624
625 if(shrunk_free_memory != a.get_free_memory())
626 return 1;
627
628 if(!a.all_memory_deallocated() && a.check_sanity())
629 return false;
630
631 a.grow(original_size - shrunk_size);
632
633 if(original_size != a.get_size())
634 return false;
635 if(original_free != a.get_free_memory())
636 return false;
637
638 if(!a.all_memory_deallocated() && a.check_sanity())
639 return false;
640 return true;
641 }
642
643 //This test allocates multiple values until there is no more memory
644 //and after that deallocates all in the inverse order
645 template<class Allocator>
646 bool test_many_equal_allocation(Allocator &a)
647 {
648 for( deallocation_type t = DirectDeallocation
649 ; t != EndDeallocationType
650 ; t = (deallocation_type)((int)t + 1)){
651 typename Allocator::size_type free_memory = a.get_free_memory();
652
653 std::vector<void*> buffers2;
654
655 //Allocate buffers with extra memory
656 for(int i = 0; true; ++i){
657 void *ptr = a.allocate(i, std::nothrow);
658 if(!ptr)
659 break;
660 std::size_t size = a.size(ptr);
661 std::memset(ptr, 0, size);
662 if(!a.check_sanity())
663 return false;
664 buffers2.push_back(ptr);
665 }
666
667 //Now deallocate the half of the blocks
668 //so expand maybe can merge new free blocks
669 for(int i = 0, max = (int)buffers2.size()
670 ;i < max
671 ;++i){
672 if(i%2){
673 a.deallocate(buffers2[i]);
674 buffers2[i] = 0;
675 }
676 }
677
678 if(!a.check_sanity())
679 return false;
680
681 typedef typename Allocator::multiallocation_chain multiallocation_chain;
682 std::vector<void*> buffers;
683 for(int i = 0; true; ++i){
684 multiallocation_chain chain;
685 a.allocate_many(std::nothrow, i+1, (i+1)*2, chain);
686 if(chain.empty())
687 break;
688
689 typename multiallocation_chain::size_type n = chain.size();
690 while(!chain.empty()){
691 buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front()));
692 }
693 if(n != std::size_t((i+1)*2))
694 return false;
695 }
696
697 if(!a.check_sanity())
698 return false;
699
700 switch(t){
701 case DirectDeallocation:
702 {
703 for(int j = 0, max = (int)buffers.size()
704 ;j < max
705 ;++j){
706 a.deallocate(buffers[j]);
707 }
708 }
709 break;
710 case InverseDeallocation:
711 {
712 for(int j = (int)buffers.size()
713 ;j--
714 ;){
715 a.deallocate(buffers[j]);
716 }
717 }
718 break;
719 case MixedDeallocation:
720 {
721 for(int j = 0, max = (int)buffers.size()
722 ;j < max
723 ;++j){
724 int pos = (j%4)*((int)buffers.size())/4;
725 a.deallocate(buffers[pos]);
726 buffers.erase(buffers.begin()+pos);
727 }
728 }
729 break;
730 default:
731 break;
732 }
733
734 //Deallocate the rest of the blocks
735
736 //Deallocate it in non sequential order
737 for(int j = 0, max = (int)buffers2.size()
738 ;j < max
739 ;++j){
740 int pos = (j%4)*((int)buffers2.size())/4;
741 a.deallocate(buffers2[pos]);
742 buffers2.erase(buffers2.begin()+pos);
743 }
744
745 bool ok = free_memory == a.get_free_memory() &&
746 a.all_memory_deallocated() && a.check_sanity();
747 if(!ok) return ok;
748 }
749 return true;
750 }
751
752 //This test allocates multiple values until there is no more memory
753 //and after that deallocates all in the inverse order
754 template<class Allocator>
755 bool test_many_different_allocation(Allocator &a)
756 {
757 typedef typename Allocator::multiallocation_chain multiallocation_chain;
758 const std::size_t ArraySize = 11;
759 typename Allocator::size_type requested_sizes[ArraySize];
760 for(std::size_t i = 0; i < ArraySize; ++i){
761 requested_sizes[i] = 4*i;
762 }
763
764 for( deallocation_type t = DirectDeallocation
765 ; t != EndDeallocationType
766 ; t = (deallocation_type)((int)t + 1)){
767 typename Allocator::size_type free_memory = a.get_free_memory();
768
769 std::vector<void*> buffers2;
770
771 //Allocate buffers with extra memory
772 for(int i = 0; true; ++i){
773 void *ptr = a.allocate(i, std::nothrow);
774 if(!ptr)
775 break;
776 std::size_t size = a.size(ptr);
777 std::memset(ptr, 0, size);
778 buffers2.push_back(ptr);
779 }
780
781 //Now deallocate the half of the blocks
782 //so expand maybe can merge new free blocks
783 for(int i = 0, max = (int)buffers2.size()
784 ;i < max
785 ;++i){
786 if(i%2){
787 a.deallocate(buffers2[i]);
788 buffers2[i] = 0;
789 }
790 }
791
792 std::vector<void*> buffers;
793 for(int i = 0; true; ++i){
794 multiallocation_chain chain;
795 a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
796 if(chain.empty())
797 break;
798 typename multiallocation_chain::size_type n = chain.size();
799 while(!chain.empty()){
800 buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front()));
801 }
802 if(n != ArraySize)
803 return false;
804 }
805
806 switch(t){
807 case DirectDeallocation:
808 {
809 for(int j = 0, max = (int)buffers.size()
810 ;j < max
811 ;++j){
812 a.deallocate(buffers[j]);
813 }
814 }
815 break;
816 case InverseDeallocation:
817 {
818 for(int j = (int)buffers.size()
819 ;j--
820 ;){
821 a.deallocate(buffers[j]);
822 }
823 }
824 break;
825 case MixedDeallocation:
826 {
827 for(int j = 0, max = (int)buffers.size()
828 ;j < max
829 ;++j){
830 int pos = (j%4)*((int)buffers.size())/4;
831 a.deallocate(buffers[pos]);
832 buffers.erase(buffers.begin()+pos);
833 }
834 }
835 break;
836 default:
837 break;
838 }
839
840 //Deallocate the rest of the blocks
841
842 //Deallocate it in non sequential order
843 for(int j = 0, max = (int)buffers2.size()
844 ;j < max
845 ;++j){
846 int pos = (j%4)*((int)buffers2.size())/4;
847 a.deallocate(buffers2[pos]);
848 buffers2.erase(buffers2.begin()+pos);
849 }
850
851 bool ok = free_memory == a.get_free_memory() &&
852 a.all_memory_deallocated() && a.check_sanity();
853 if(!ok) return ok;
854 }
855 return true;
856 }
857
858 //This test allocates multiple values until there is no more memory
859 //and after that deallocates all in the inverse order
860 template<class Allocator>
861 bool test_many_deallocation(Allocator &a)
862 {
863 typedef typename Allocator::multiallocation_chain multiallocation_chain;
864
865 typedef typename Allocator::multiallocation_chain multiallocation_chain;
866 const std::size_t ArraySize = 11;
867 vector<multiallocation_chain> buffers;
868 typename Allocator::size_type requested_sizes[ArraySize];
869 for(std::size_t i = 0; i < ArraySize; ++i){
870 requested_sizes[i] = 4*i;
871 }
872 typename Allocator::size_type free_memory = a.get_free_memory();
873
874 {
875 for(int i = 0; true; ++i){
876 multiallocation_chain chain;
877 a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
878 if(chain.empty())
879 break;
880 buffers.push_back(boost::move(chain));
881 }
882 for(int i = 0, max = (int)buffers.size(); i != max; ++i){
883 a.deallocate_many(buffers[i]);
884 }
885 buffers.clear();
886 bool ok = free_memory == a.get_free_memory() &&
887 a.all_memory_deallocated() && a.check_sanity();
888 if(!ok) return ok;
889 }
890
891 {
892 for(int i = 0; true; ++i){
893 multiallocation_chain chain;
894 a.allocate_many(std::nothrow, i*4, ArraySize, chain);
895 if(chain.empty())
896 break;
897 buffers.push_back(boost::move(chain));
898 }
899 for(int i = 0, max = (int)buffers.size(); i != max; ++i){
900 a.deallocate_many(buffers[i]);
901 }
902 buffers.clear();
903
904 bool ok = free_memory == a.get_free_memory() &&
905 a.all_memory_deallocated() && a.check_sanity();
906 if(!ok) return ok;
907 }
908
909 return true;
910 }
911
912
913 //This function calls all tests
914 template<class Allocator>
915 bool test_all_allocation(Allocator &a)
916 {
917 std::cout << "Starting test_allocation. Class: "
918 << typeid(a).name() << std::endl;
919
920 if(!test_allocation(a)){
921 std::cout << "test_allocation_direct_deallocation failed. Class: "
922 << typeid(a).name() << std::endl;
923 return false;
924 }
925
926 std::cout << "Starting test_many_equal_allocation. Class: "
927 << typeid(a).name() << std::endl;
928
929 if(!test_many_equal_allocation(a)){
930 std::cout << "test_many_equal_allocation failed. Class: "
931 << typeid(a).name() << std::endl;
932 return false;
933 }
934
935 std::cout << "Starting test_many_different_allocation. Class: "
936 << typeid(a).name() << std::endl;
937
938 if(!test_many_different_allocation(a)){
939 std::cout << "test_many_different_allocation failed. Class: "
940 << typeid(a).name() << std::endl;
941 return false;
942 }
943
944 if(!test_many_deallocation(a)){
945 std::cout << "test_many_deallocation failed. Class: "
946 << typeid(a).name() << std::endl;
947 return false;
948 }
949
950 std::cout << "Starting test_allocation_shrink. Class: "
951 << typeid(a).name() << std::endl;
952
953 if(!test_allocation_shrink(a)){
954 std::cout << "test_allocation_shrink failed. Class: "
955 << typeid(a).name() << std::endl;
956 return false;
957 }
958
959 if(!test_allocation_shrink_and_expand(a)){
960 std::cout << "test_allocation_shrink_and_expand failed. Class: "
961 << typeid(a).name() << std::endl;
962 return false;
963 }
964
965 std::cout << "Starting test_allocation_expand. Class: "
966 << typeid(a).name() << std::endl;
967
968 if(!test_allocation_expand(a)){
969 std::cout << "test_allocation_expand failed. Class: "
970 << typeid(a).name() << std::endl;
971 return false;
972 }
973
974 std::cout << "Starting test_allocation_deallocation_expand. Class: "
975 << typeid(a).name() << std::endl;
976
977 if(!test_allocation_deallocation_expand(a)){
978 std::cout << "test_allocation_deallocation_expand failed. Class: "
979 << typeid(a).name() << std::endl;
980 return false;
981 }
982
983 std::cout << "Starting test_allocation_with_reuse. Class: "
984 << typeid(a).name() << std::endl;
985
986 if(!test_allocation_with_reuse(a)){
987 std::cout << "test_allocation_with_reuse failed. Class: "
988 << typeid(a).name() << std::endl;
989 return false;
990 }
991
992 std::cout << "Starting test_aligned_allocation. Class: "
993 << typeid(a).name() << std::endl;
994
995 if(!test_aligned_allocation(a)){
996 std::cout << "test_aligned_allocation failed. Class: "
997 << typeid(a).name() << std::endl;
998 return false;
999 }
1000
1001 std::cout << "Starting test_continuous_aligned_allocation. Class: "
1002 << typeid(a).name() << std::endl;
1003
1004 if(!test_continuous_aligned_allocation(a)){
1005 std::cout << "test_continuous_aligned_allocation failed. Class: "
1006 << typeid(a).name() << std::endl;
1007 return false;
1008 }
1009
1010 std::cout << "Starting test_clear_free_memory. Class: "
1011 << typeid(a).name() << std::endl;
1012
1013 if(!test_clear_free_memory(a)){
1014 std::cout << "test_clear_free_memory failed. Class: "
1015 << typeid(a).name() << std::endl;
1016 return false;
1017 }
1018
1019 std::cout << "Starting test_grow_shrink_to_fit. Class: "
1020 << typeid(a).name() << std::endl;
1021
1022 if(!test_grow_shrink_to_fit(a)){
1023 std::cout << "test_grow_shrink_to_fit failed. Class: "
1024 << typeid(a).name() << std::endl;
1025 return false;
1026 }
1027
1028 return true;
1029 }
1030
1031 }}} //namespace boost { namespace interprocess { namespace test {
1032
1033 #include <boost/interprocess/detail/config_end.hpp>
1034
1035 #endif //BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
1036