forked from boostorg/unordered
		
	
		
			
				
	
	
		
			174 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| // Copyright 2006-2009 Daniel James.
 | |
| // 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)
 | |
| 
 | |
| #if !defined(BOOST_UNORDERED_TEST_MEMORY_HEADER)
 | |
| #define BOOST_UNORDERED_TEST_MEMORY_HEADER
 | |
| 
 | |
| #include <memory>
 | |
| #include <map>
 | |
| #include <boost/mpl/apply.hpp>
 | |
| #include <boost/assert.hpp>
 | |
| #include <boost/unordered/detail/allocator_helpers.hpp>
 | |
| #include <boost/mpl/aux_/config/eti.hpp>
 | |
| #include "../helpers/test.hpp"
 | |
| 
 | |
| namespace test
 | |
| {
 | |
|     namespace detail
 | |
|     {
 | |
|         struct memory_area {
 | |
|             void const* start;
 | |
|             void const* end;
 | |
| 
 | |
|             memory_area(void const* s, void const* e)
 | |
|                 : start(s), end(e)
 | |
|             {
 | |
|                 BOOST_ASSERT(start != end);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct memory_track {
 | |
|             explicit memory_track(int tag = -1) :
 | |
|                 constructed_(0),
 | |
|                 tag_(tag) {}
 | |
| 
 | |
|             int constructed_;
 | |
|             int tag_;
 | |
|         };
 | |
| 
 | |
|         // This is a bit dodgy as it defines overlapping
 | |
|         // areas as 'equal', so this isn't a total ordering.
 | |
|         // But it is for non-overlapping memory regions - which
 | |
|         // is what'll be stored.
 | |
|         //
 | |
|         // All searches will be for areas entirely contained by
 | |
|         // a member of the set - so it should find the area that contains
 | |
|         // the region that is searched for.
 | |
| 
 | |
|         struct memory_area_compare {
 | |
|             bool operator()(memory_area const& x, memory_area const& y) const {
 | |
|                 return x.end <= y.start;
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <class Alloc>
 | |
|         struct allocator_memory_type_gen {
 | |
|             typedef std::map<memory_area, memory_track, memory_area_compare,
 | |
|                 Alloc> type;
 | |
|         };
 | |
| 
 | |
| #if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
 | |
|         template <>
 | |
|         struct allocator_memory_type_gen<int> {
 | |
|             typedef std::map<memory_area, memory_track, memory_area_compare>
 | |
|                 type;
 | |
|         };
 | |
| #endif
 | |
| 
 | |
|         template <class Alloc = std::allocator<int> >
 | |
|         struct memory_tracker {
 | |
|             typedef BOOST_DEDUCED_TYPENAME
 | |
|                 boost::unordered_detail::rebind_wrap<Alloc,
 | |
|                     std::pair<memory_area const, memory_track> >::type
 | |
|                 allocator_type;
 | |
| 
 | |
|             typedef BOOST_DEDUCED_TYPENAME
 | |
|                 allocator_memory_type_gen<allocator_type>::type
 | |
|                 allocated_memory_type;
 | |
| 
 | |
|             allocated_memory_type allocated_memory;
 | |
|             unsigned int count_allocators;
 | |
|             unsigned int count_allocations;
 | |
|             unsigned int count_constructions;
 | |
| 
 | |
|             memory_tracker() :
 | |
|                 count_allocators(0), count_allocations(0),
 | |
|                 count_constructions(0)
 | |
|             {}
 | |
| 
 | |
|             void allocator_ref()
 | |
|             {
 | |
|                 if(count_allocators == 0) {
 | |
|                     count_allocations = 0;
 | |
|                     count_constructions = 0;
 | |
|                     allocated_memory.clear();
 | |
|                 }
 | |
|                 ++count_allocators;
 | |
|             }
 | |
| 
 | |
|             void allocator_unref()
 | |
|             {
 | |
|                 BOOST_TEST(count_allocators > 0);
 | |
|                 if(count_allocators > 0) {
 | |
|                     --count_allocators;
 | |
|                     if(count_allocators == 0) {
 | |
|                         bool no_allocations_left = (count_allocations == 0);
 | |
|                         bool no_constructions_left = (count_constructions == 0);
 | |
|                         bool allocated_memory_empty = allocated_memory.empty();
 | |
| 
 | |
|                         // Clearing the data before the checks terminate the
 | |
|                         // tests.
 | |
|                         count_allocations = 0;
 | |
|                         count_constructions = 0;
 | |
|                         allocated_memory.clear();
 | |
| 
 | |
|                         BOOST_TEST(no_allocations_left);
 | |
|                         BOOST_TEST(no_constructions_left);
 | |
|                         BOOST_TEST(allocated_memory_empty);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             void track_allocate(void *ptr, std::size_t n, std::size_t size,
 | |
|                 int tag)
 | |
|             {
 | |
|                 if(n == 0) {
 | |
|                     BOOST_ERROR("Allocating 0 length array.");
 | |
|                 }
 | |
|                 else {
 | |
|                     ++count_allocations;
 | |
|                     allocated_memory.insert(
 | |
|                         std::pair<memory_area const, memory_track>(
 | |
|                             memory_area(ptr, (char*) ptr + n * size),
 | |
|                             memory_track(tag)));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             void track_deallocate(void* ptr, std::size_t n, std::size_t size,
 | |
|                 int tag)
 | |
|             {
 | |
|                 BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
 | |
|                     allocated_memory.find(
 | |
|                         memory_area(ptr, (char*) ptr + n * size));
 | |
|                 if(pos == allocated_memory.end()) {
 | |
|                     BOOST_ERROR("Deallocating unknown pointer.");
 | |
|                 } else {
 | |
|                     BOOST_TEST(pos->first.start == ptr);
 | |
|                     BOOST_TEST(pos->first.end == (char*) ptr + n * size);
 | |
|                     BOOST_TEST(pos->second.tag_ == tag);
 | |
|                     allocated_memory.erase(pos);
 | |
|                 }
 | |
|                 BOOST_TEST(count_allocations > 0);
 | |
|                 if(count_allocations > 0) --count_allocations;
 | |
|             }
 | |
| 
 | |
|             void track_construct(void* /*ptr*/, std::size_t /*size*/,
 | |
|                 int /*tag*/)
 | |
|             {
 | |
|                 ++count_constructions;
 | |
|             }
 | |
| 
 | |
|             void track_destroy(void* /*ptr*/, std::size_t /*size*/,
 | |
|                 int /*tag*/)
 | |
|             {
 | |
|                 BOOST_TEST(count_constructions > 0);
 | |
|                 if(count_constructions > 0) --count_constructions;
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif
 |