• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
test_allocation(Allocator & a)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>
test_allocation_shrink(Allocator & a)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>
test_allocation_expand(Allocator & a)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>
test_allocation_shrink_and_expand(Allocator & a)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>
test_allocation_deallocation_expand(Allocator & a)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>
test_allocation_with_reuse(Allocator & a)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>
test_aligned_allocation(Allocator & a)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>
test_continuous_aligned_allocation(Allocator & a)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>
test_clear_free_memory(Allocator & a)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>
test_grow_shrink_to_fit(Allocator & a)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>
test_many_equal_allocation(Allocator & a)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>
test_many_different_allocation(Allocator & a)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>
test_many_deallocation(Allocator & a)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>
test_all_allocation(Allocator & a)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 
1037