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

source code of boost/libs/interprocess/test/memory_algorithm_test_template.hpp