1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036 |
- //////////////////////////////////////////////////////////////////////////////
- //
- // (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
- // Software License, Version 1.0. (See accompanying file
- // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // See http://www.boost.org/libs/interprocess for documentation.
- //
- //////////////////////////////////////////////////////////////////////////////
- #ifndef BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
- #define BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
- #include <boost/interprocess/detail/config_begin.hpp>
- #include <boost/interprocess/containers/vector.hpp>
- #include <vector>
- #include <iostream>
- #include <new> //std::nothrow
- #include <cstring> //std::memset
- namespace boost { namespace interprocess { namespace test {
- enum deallocation_type { DirectDeallocation, InverseDeallocation, MixedDeallocation, EndDeallocationType };
- //This test allocates until there is no more memory
- //and after that deallocates all in the inverse order
- template<class Allocator>
- bool test_allocation(Allocator &a)
- {
- for( deallocation_type t = DirectDeallocation
- ; t != EndDeallocationType
- ; t = (deallocation_type)((int)t + 1)){
- std::vector<void*> buffers;
- typename Allocator::size_type free_memory = a.get_free_memory();
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- buffers.push_back(ptr);
- }
- switch(t){
- case DirectDeallocation:
- {
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- a.deallocate(buffers[j]);
- }
- }
- break;
- case InverseDeallocation:
- {
- for(int j = (int)buffers.size()
- ;j--
- ;){
- a.deallocate(buffers[j]);
- }
- }
- break;
- case MixedDeallocation:
- {
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers.size())/4;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- }
- }
- break;
- default:
- break;
- }
- bool ok = free_memory == a.get_free_memory() &&
- a.all_memory_deallocated() && a.check_sanity();
- if(!ok) return ok;
- }
- return true;
- }
- //This test allocates until there is no more memory
- //and after that tries to shrink all the buffers to the
- //half of the original size
- template<class Allocator>
- bool test_allocation_shrink(Allocator &a)
- {
- std::vector<void*> buffers;
- //Allocate buffers with extra memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i*2, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- buffers.push_back(ptr);
- }
- //Now shrink to half
- for(int i = 0, max = (int)buffers.size()
- ;i < max
- ; ++i){
- typename Allocator::size_type received_size;
- char *reuse = static_cast<char*>(buffers[i]);
- if(a.template allocation_command<char>
- ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, i*2
- , received_size = i, reuse)){
- if(received_size > std::size_t(i*2)){
- return false;
- }
- if(received_size < std::size_t(i)){
- return false;
- }
- std::memset(buffers[i], 0, a.size(buffers[i]));
- }
- }
- //Deallocate it in non sequential order
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers.size())/4;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- }
- return a.all_memory_deallocated() && a.check_sanity();
- }
- //This test allocates until there is no more memory
- //and after that tries to expand all the buffers to
- //avoid the wasted internal fragmentation
- template<class Allocator>
- bool test_allocation_expand(Allocator &a)
- {
- std::vector<void*> buffers;
- //Allocate buffers with extra memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- buffers.push_back(ptr);
- }
- //Now try to expand to the double of the size
- for(int i = 0, max = (int)buffers.size()
- ;i < max
- ;++i){
- typename Allocator::size_type received_size;
- std::size_t min_size = i+1;
- std::size_t preferred_size = i*2;
- preferred_size = min_size > preferred_size ? min_size : preferred_size;
- char *reuse = static_cast<char*>(buffers[i]);
- while(a.template allocation_command<char>
- ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
- , received_size = preferred_size, reuse)){
- //Check received size is bigger than minimum
- if(received_size < min_size){
- return false;
- }
- //Now, try to expand further
- min_size = received_size+1;
- preferred_size = min_size*2;
- }
- }
- //Deallocate it in non sequential order
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers.size())/4;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- }
- return a.all_memory_deallocated() && a.check_sanity();
- }
- //This test allocates until there is no more memory
- //and after that tries to expand all the buffers to
- //avoid the wasted internal fragmentation
- template<class Allocator>
- bool test_allocation_shrink_and_expand(Allocator &a)
- {
- std::vector<void*> buffers;
- std::vector<typename Allocator::size_type> received_sizes;
- std::vector<bool> size_reduced;
- //Allocate buffers wand store received sizes
- for(int i = 0; true; ++i){
- typename Allocator::size_type received_size;
- char *reuse = 0;
- void *ptr = a.template allocation_command<char>
- ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, i, received_size = i*2, reuse);
- if(!ptr){
- ptr = a.template allocation_command<char>
- ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, 1, received_size = i*2, reuse);
- if(!ptr)
- break;
- }
- buffers.push_back(ptr);
- received_sizes.push_back(received_size);
- }
- //Now shrink to half
- for(int i = 0, max = (int)buffers.size()
- ; i < max
- ; ++i){
- typename Allocator::size_type received_size;
- char *reuse = static_cast<char*>(buffers[i]);
- if(a.template allocation_command<char>
- ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_sizes[i]
- , received_size = i, reuse)){
- if(received_size > std::size_t(received_sizes[i])){
- return false;
- }
- if(received_size < std::size_t(i)){
- return false;
- }
- size_reduced.push_back(received_size != received_sizes[i]);
- }
- }
- //Now try to expand to the original size
- for(int i = 0, max = (int)buffers.size()
- ;i < max
- ;++i){
- typename Allocator::size_type received_size;
- std::size_t request_size = received_sizes[i];
- char *reuse = static_cast<char*>(buffers[i]);
- if(a.template allocation_command<char>
- ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, request_size
- , received_size = request_size, reuse)){
- if(received_size != received_sizes[i]){
- return false;
- }
- }
- else{
- return false;
- }
- }
- //Deallocate it in non sequential order
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers.size())/4;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- }
- return a.all_memory_deallocated() && a.check_sanity();
- }
- //This test allocates until there is no more memory
- //and after that deallocates the odd buffers to
- //make room for expansions. The expansion will probably
- //success since the deallocation left room for that.
- template<class Allocator>
- bool test_allocation_deallocation_expand(Allocator &a)
- {
- std::vector<void*> buffers;
- //Allocate buffers with extra memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- buffers.push_back(ptr);
- }
- //Now deallocate the half of the blocks
- //so expand maybe can merge new free blocks
- for(int i = 0, max = (int)buffers.size()
- ;i < max
- ;++i){
- if(i%2){
- a.deallocate(buffers[i]);
- buffers[i] = 0;
- }
- }
- //Now try to expand to the double of the size
- for(int i = 0, max = (int)buffers.size()
- ;i < max
- ;++i){
- //
- if(buffers[i]){
- typename Allocator::size_type received_size;
- std::size_t min_size = i+1;
- std::size_t preferred_size = i*2;
- preferred_size = min_size > preferred_size ? min_size : preferred_size;
- char *reuse = static_cast<char*>(buffers[i]);
- while(a.template allocation_command<char>
- ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
- , received_size = preferred_size, reuse)){
- //Check received size is bigger than minimum
- if(received_size < min_size){
- return false;
- }
- //Now, try to expand further
- min_size = received_size+1;
- preferred_size = min_size*2;
- }
- }
- }
- //Now erase null values from the vector
- buffers.erase( std::remove(buffers.begin(), buffers.end(), static_cast<void*>(0))
- , buffers.end());
- //Deallocate it in non sequential order
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers.size())/4;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- }
- return a.all_memory_deallocated() && a.check_sanity();
- }
- //This test allocates until there is no more memory
- //and after that deallocates all except the last.
- //If the allocation algorithm is a bottom-up algorithm
- //the last buffer will be in the end of the segment.
- //Then the test will start expanding backwards, until
- //the buffer fills all the memory
- template<class Allocator>
- bool test_allocation_with_reuse(Allocator &a)
- {
- //We will repeat this test for different sized elements
- for(int sizeof_object = 1; sizeof_object < 20; ++sizeof_object){
- std::vector<void*> buffers;
- //Allocate buffers with extra memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i*sizeof_object, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- buffers.push_back(ptr);
- }
- //Now deallocate all except the latest
- //Now try to expand to the double of the sizeof_object
- for(int i = 0, max = (int)buffers.size() - 1
- ;i < max
- ;++i){
- a.deallocate(buffers[i]);
- }
- //Save the unique buffer and clear vector
- void *ptr = buffers.back();
- buffers.clear();
- //Now allocate with reuse
- typename Allocator::size_type received_size = 0;
- for(int i = 0; true; ++i){
- std::size_t min_size = (received_size + 1);
- std::size_t prf_size = (received_size + (i+1)*2);
- void *reuse = ptr;
- void *ret = a.raw_allocation_command
- ( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size
- , received_size = prf_size, reuse, sizeof_object);
- if(!ret)
- break;
- //If we have memory, this must be a buffer reuse
- if(!reuse)
- return 1;
- if(received_size < min_size)
- return 1;
- ptr = ret;
- }
- //There is only a single block so deallocate it
- a.deallocate(ptr);
- if(!a.all_memory_deallocated() || !a.check_sanity())
- return false;
- }
- return true;
- }
- //This test allocates memory with different alignments
- //and checks returned memory is aligned.
- template<class Allocator>
- bool test_aligned_allocation(Allocator &a)
- {
- //Allocate aligned buffers in a loop
- //and then deallocate it
- bool continue_loop = true;
- for(unsigned int i = 1; continue_loop; i <<= 1){
- for(unsigned int j = 1; true; j <<= 1){
- void *ptr = a.allocate_aligned(i-1, j, std::nothrow);
- if(!ptr){
- if(j == 1)
- continue_loop = false;
- break;
- }
- if(((std::size_t)ptr & (j - 1)) != 0)
- return false;
- a.deallocate(ptr);
- if(!a.all_memory_deallocated() || !a.check_sanity()){
- return false;
- }
- }
- }
- return a.all_memory_deallocated() && a.check_sanity();
- }
- //This test allocates memory with different alignments
- //and checks returned memory is aligned.
- template<class Allocator>
- bool test_continuous_aligned_allocation(Allocator &a)
- {
- std::vector<void*> buffers;
- //Allocate aligned buffers in a loop
- //and then deallocate it
- bool continue_loop = true;
- for(unsigned i = 1; continue_loop && i; i <<= 1){
- for(unsigned int j = 1; j; j <<= 1){
- for(bool any_allocated = false; 1;){
- void *ptr = a.allocate_aligned(i-1, j, std::nothrow);
- buffers.push_back(ptr);
- if(!ptr){
- if(j == 1 && !any_allocated){
- continue_loop = false;
- }
- break;
- }
- else{
- any_allocated = true;
- }
- if(((std::size_t)ptr & (j - 1)) != 0)
- return false;
- }
- //Deallocate all
- for(unsigned int k = (int)buffers.size(); k--;){
- a.deallocate(buffers[k]);
- }
- buffers.clear();
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- if(!continue_loop)
- break;
- }
- }
- return a.all_memory_deallocated() && a.check_sanity();
- }
- //This test allocates memory, writes it with a non-zero value and
- //tests zero_free_memory initializes to zero for the next allocation
- template<class Allocator>
- bool test_clear_free_memory(Allocator &a)
- {
- std::vector<void*> buffers;
- //Allocate memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 1, size);
- buffers.push_back(ptr);
- }
- //Mark it
- for(int i = 0, max = buffers.size(); i < max; ++i){
- std::memset(buffers[i], 1, i);
- }
- //Deallocate all
- for(int j = (int)buffers.size()
- ;j--
- ;){
- a.deallocate(buffers[j]);
- }
- buffers.clear();
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- //Now clear all free memory
- a.zero_free_memory();
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- //Now test all allocated memory is zero
- //Allocate memory
- const char *first_addr = 0;
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- if(i == 0){
- first_addr = (char*)ptr;
- }
- std::size_t memsize = a.size(ptr);
- buffers.push_back(ptr);
- for(int j = 0; j < (int)memsize; ++j){
- if(static_cast<char*>((char*)ptr)[j]){
- std::cout << "Zero memory test failed. in buffer " << i
- << " byte " << j << " first address " << (void*) first_addr << " offset " << ((char*)ptr+j) - (char*)first_addr << " memsize: " << memsize << std::endl;
- return false;
- }
- }
- }
- //Deallocate all
- for(int j = (int)buffers.size()
- ;j--
- ;){
- a.deallocate(buffers[j]);
- }
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- return true;
- }
- //This test uses tests grow and shrink_to_fit functions
- template<class Allocator>
- bool test_grow_shrink_to_fit(Allocator &a)
- {
- std::vector<void*> buffers;
- typename Allocator::size_type original_size = a.get_size();
- typename Allocator::size_type original_free = a.get_free_memory();
- a.shrink_to_fit();
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- typename Allocator::size_type shrunk_size = a.get_size();
- typename Allocator::size_type shrunk_free_memory = a.get_free_memory();
- if(shrunk_size != a.get_min_size())
- return 1;
- a.grow(original_size - shrunk_size);
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- if(original_size != a.get_size())
- return false;
- if(original_free != a.get_free_memory())
- return false;
- //Allocate memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- buffers.push_back(ptr);
- }
- //Now deallocate the half of the blocks
- //so expand maybe can merge new free blocks
- for(int i = 0, max = (int)buffers.size()
- ;i < max
- ;++i){
- if(i%2){
- a.deallocate(buffers[i]);
- buffers[i] = 0;
- }
- }
- //Deallocate the rest of the blocks
- //Deallocate it in non sequential order
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%5)*((int)buffers.size())/4;
- if(pos == int(buffers.size()))
- --pos;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- typename Allocator::size_type old_free = a.get_free_memory();
- a.shrink_to_fit();
- if(!a.check_sanity()) return false;
- if(original_size < a.get_size()) return false;
- if(old_free < a.get_free_memory()) return false;
- a.grow(original_size - a.get_size());
- if(!a.check_sanity()) return false;
- if(original_size != a.get_size()) return false;
- if(old_free != a.get_free_memory()) return false;
- }
- //Now shrink it to the maximum
- a.shrink_to_fit();
- if(a.get_size() != a.get_min_size())
- return 1;
- if(shrunk_free_memory != a.get_free_memory())
- return 1;
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- a.grow(original_size - shrunk_size);
- if(original_size != a.get_size())
- return false;
- if(original_free != a.get_free_memory())
- return false;
- if(!a.all_memory_deallocated() && a.check_sanity())
- return false;
- return true;
- }
- //This test allocates multiple values until there is no more memory
- //and after that deallocates all in the inverse order
- template<class Allocator>
- bool test_many_equal_allocation(Allocator &a)
- {
- for( deallocation_type t = DirectDeallocation
- ; t != EndDeallocationType
- ; t = (deallocation_type)((int)t + 1)){
- typename Allocator::size_type free_memory = a.get_free_memory();
- std::vector<void*> buffers2;
- //Allocate buffers with extra memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- if(!a.check_sanity())
- return false;
- buffers2.push_back(ptr);
- }
- //Now deallocate the half of the blocks
- //so expand maybe can merge new free blocks
- for(int i = 0, max = (int)buffers2.size()
- ;i < max
- ;++i){
- if(i%2){
- a.deallocate(buffers2[i]);
- buffers2[i] = 0;
- }
- }
- if(!a.check_sanity())
- return false;
- typedef typename Allocator::multiallocation_chain multiallocation_chain;
- std::vector<void*> buffers;
- for(int i = 0; true; ++i){
- multiallocation_chain chain;
- a.allocate_many(std::nothrow, i+1, (i+1)*2, chain);
- if(chain.empty())
- break;
- typename multiallocation_chain::size_type n = chain.size();
- while(!chain.empty()){
- buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front()));
- }
- if(n != std::size_t((i+1)*2))
- return false;
- }
- if(!a.check_sanity())
- return false;
- switch(t){
- case DirectDeallocation:
- {
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- a.deallocate(buffers[j]);
- }
- }
- break;
- case InverseDeallocation:
- {
- for(int j = (int)buffers.size()
- ;j--
- ;){
- a.deallocate(buffers[j]);
- }
- }
- break;
- case MixedDeallocation:
- {
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers.size())/4;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- }
- }
- break;
- default:
- break;
- }
- //Deallocate the rest of the blocks
- //Deallocate it in non sequential order
- for(int j = 0, max = (int)buffers2.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers2.size())/4;
- a.deallocate(buffers2[pos]);
- buffers2.erase(buffers2.begin()+pos);
- }
- bool ok = free_memory == a.get_free_memory() &&
- a.all_memory_deallocated() && a.check_sanity();
- if(!ok) return ok;
- }
- return true;
- }
- //This test allocates multiple values until there is no more memory
- //and after that deallocates all in the inverse order
- template<class Allocator>
- bool test_many_different_allocation(Allocator &a)
- {
- typedef typename Allocator::multiallocation_chain multiallocation_chain;
- const std::size_t ArraySize = 11;
- typename Allocator::size_type requested_sizes[ArraySize];
- for(std::size_t i = 0; i < ArraySize; ++i){
- requested_sizes[i] = 4*i;
- }
- for( deallocation_type t = DirectDeallocation
- ; t != EndDeallocationType
- ; t = (deallocation_type)((int)t + 1)){
- typename Allocator::size_type free_memory = a.get_free_memory();
- std::vector<void*> buffers2;
- //Allocate buffers with extra memory
- for(int i = 0; true; ++i){
- void *ptr = a.allocate(i, std::nothrow);
- if(!ptr)
- break;
- std::size_t size = a.size(ptr);
- std::memset(ptr, 0, size);
- buffers2.push_back(ptr);
- }
- //Now deallocate the half of the blocks
- //so expand maybe can merge new free blocks
- for(int i = 0, max = (int)buffers2.size()
- ;i < max
- ;++i){
- if(i%2){
- a.deallocate(buffers2[i]);
- buffers2[i] = 0;
- }
- }
- std::vector<void*> buffers;
- for(int i = 0; true; ++i){
- multiallocation_chain chain;
- a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
- if(chain.empty())
- break;
- typename multiallocation_chain::size_type n = chain.size();
- while(!chain.empty()){
- buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front()));
- }
- if(n != ArraySize)
- return false;
- }
- switch(t){
- case DirectDeallocation:
- {
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- a.deallocate(buffers[j]);
- }
- }
- break;
- case InverseDeallocation:
- {
- for(int j = (int)buffers.size()
- ;j--
- ;){
- a.deallocate(buffers[j]);
- }
- }
- break;
- case MixedDeallocation:
- {
- for(int j = 0, max = (int)buffers.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers.size())/4;
- a.deallocate(buffers[pos]);
- buffers.erase(buffers.begin()+pos);
- }
- }
- break;
- default:
- break;
- }
- //Deallocate the rest of the blocks
- //Deallocate it in non sequential order
- for(int j = 0, max = (int)buffers2.size()
- ;j < max
- ;++j){
- int pos = (j%4)*((int)buffers2.size())/4;
- a.deallocate(buffers2[pos]);
- buffers2.erase(buffers2.begin()+pos);
- }
- bool ok = free_memory == a.get_free_memory() &&
- a.all_memory_deallocated() && a.check_sanity();
- if(!ok) return ok;
- }
- return true;
- }
- //This test allocates multiple values until there is no more memory
- //and after that deallocates all in the inverse order
- template<class Allocator>
- bool test_many_deallocation(Allocator &a)
- {
- typedef typename Allocator::multiallocation_chain multiallocation_chain;
- typedef typename Allocator::multiallocation_chain multiallocation_chain;
- const std::size_t ArraySize = 11;
- vector<multiallocation_chain> buffers;
- typename Allocator::size_type requested_sizes[ArraySize];
- for(std::size_t i = 0; i < ArraySize; ++i){
- requested_sizes[i] = 4*i;
- }
- typename Allocator::size_type free_memory = a.get_free_memory();
- {
- for(int i = 0; true; ++i){
- multiallocation_chain chain;
- a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
- if(chain.empty())
- break;
- buffers.push_back(boost::move(chain));
- }
- for(int i = 0, max = (int)buffers.size(); i != max; ++i){
- a.deallocate_many(buffers[i]);
- }
- buffers.clear();
- bool ok = free_memory == a.get_free_memory() &&
- a.all_memory_deallocated() && a.check_sanity();
- if(!ok) return ok;
- }
- {
- for(int i = 0; true; ++i){
- multiallocation_chain chain;
- a.allocate_many(std::nothrow, i*4, ArraySize, chain);
- if(chain.empty())
- break;
- buffers.push_back(boost::move(chain));
- }
- for(int i = 0, max = (int)buffers.size(); i != max; ++i){
- a.deallocate_many(buffers[i]);
- }
- buffers.clear();
- bool ok = free_memory == a.get_free_memory() &&
- a.all_memory_deallocated() && a.check_sanity();
- if(!ok) return ok;
- }
- return true;
- }
- //This function calls all tests
- template<class Allocator>
- bool test_all_allocation(Allocator &a)
- {
- std::cout << "Starting test_allocation. Class: "
- << typeid(a).name() << std::endl;
- if(!test_allocation(a)){
- std::cout << "test_allocation_direct_deallocation failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_many_equal_allocation. Class: "
- << typeid(a).name() << std::endl;
- if(!test_many_equal_allocation(a)){
- std::cout << "test_many_equal_allocation failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_many_different_allocation. Class: "
- << typeid(a).name() << std::endl;
- if(!test_many_different_allocation(a)){
- std::cout << "test_many_different_allocation failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- if(!test_many_deallocation(a)){
- std::cout << "test_many_deallocation failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_allocation_shrink. Class: "
- << typeid(a).name() << std::endl;
- if(!test_allocation_shrink(a)){
- std::cout << "test_allocation_shrink failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- if(!test_allocation_shrink_and_expand(a)){
- std::cout << "test_allocation_shrink_and_expand failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_allocation_expand. Class: "
- << typeid(a).name() << std::endl;
- if(!test_allocation_expand(a)){
- std::cout << "test_allocation_expand failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_allocation_deallocation_expand. Class: "
- << typeid(a).name() << std::endl;
- if(!test_allocation_deallocation_expand(a)){
- std::cout << "test_allocation_deallocation_expand failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_allocation_with_reuse. Class: "
- << typeid(a).name() << std::endl;
- if(!test_allocation_with_reuse(a)){
- std::cout << "test_allocation_with_reuse failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_aligned_allocation. Class: "
- << typeid(a).name() << std::endl;
- if(!test_aligned_allocation(a)){
- std::cout << "test_aligned_allocation failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_continuous_aligned_allocation. Class: "
- << typeid(a).name() << std::endl;
- if(!test_continuous_aligned_allocation(a)){
- std::cout << "test_continuous_aligned_allocation failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_clear_free_memory. Class: "
- << typeid(a).name() << std::endl;
- if(!test_clear_free_memory(a)){
- std::cout << "test_clear_free_memory failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- std::cout << "Starting test_grow_shrink_to_fit. Class: "
- << typeid(a).name() << std::endl;
- if(!test_grow_shrink_to_fit(a)){
- std::cout << "test_grow_shrink_to_fit failed. Class: "
- << typeid(a).name() << std::endl;
- return false;
- }
- return true;
- }
- }}} //namespace boost { namespace interprocess { namespace test {
- #include <boost/interprocess/detail/config_end.hpp>
- #endif //BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
|