1 2 // Copyright 2006-2009 Daniel James. 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #if !defined(BOOST_UNORDERED_TEST_MEMORY_HEADER) 7 #define BOOST_UNORDERED_TEST_MEMORY_HEADER 8 9 #include <memory> 10 #include <map> 11 #include <boost/assert.hpp> 12 #include <boost/unordered/detail/allocate.hpp> 13 #include "../helpers/test.hpp" 14 15 namespace test 16 { 17 namespace detail 18 { 19 struct memory_area { 20 void const* start; 21 void const* end; 22 memory_areatest::detail::memory_area23 memory_area(void const* s, void const* e) 24 : start(s), end(e) 25 { 26 BOOST_ASSERT(start != end); 27 } 28 }; 29 30 struct memory_track { memory_tracktest::detail::memory_track31 explicit memory_track(int tag = -1) : 32 constructed_(0), 33 tag_(tag) {} 34 35 int constructed_; 36 int tag_; 37 }; 38 39 // This is a bit dodgy as it defines overlapping 40 // areas as 'equal', so this isn't a total ordering. 41 // But it is for non-overlapping memory regions - which 42 // is what'll be stored. 43 // 44 // All searches will be for areas entirely contained by 45 // a member of the set - so it should find the area that contains 46 // the region that is searched for. 47 48 struct memory_area_compare { operator ()test::detail::memory_area_compare49 bool operator()(memory_area const& x, memory_area const& y) const { 50 return x.end <= y.start; 51 } 52 }; 53 54 struct memory_tracker { 55 typedef std::map<memory_area, memory_track, memory_area_compare, 56 std::allocator<std::pair<memory_area const, memory_track> > 57 > allocated_memory_type; 58 59 allocated_memory_type allocated_memory; 60 unsigned int count_allocators; 61 unsigned int count_allocations; 62 unsigned int count_constructions; 63 memory_trackertest::detail::memory_tracker64 memory_tracker() : 65 count_allocators(0), count_allocations(0), 66 count_constructions(0) 67 {} 68 allocator_reftest::detail::memory_tracker69 void allocator_ref() 70 { 71 if(count_allocators == 0) { 72 count_allocations = 0; 73 count_constructions = 0; 74 allocated_memory.clear(); 75 } 76 ++count_allocators; 77 } 78 allocator_unreftest::detail::memory_tracker79 void allocator_unref() 80 { 81 BOOST_TEST(count_allocators > 0); 82 if(count_allocators > 0) { 83 --count_allocators; 84 if(count_allocators == 0) { 85 bool no_allocations_left = (count_allocations == 0); 86 bool no_constructions_left = (count_constructions == 0); 87 bool allocated_memory_empty = allocated_memory.empty(); 88 89 // Clearing the data before the checks terminate the 90 // tests. 91 count_allocations = 0; 92 count_constructions = 0; 93 allocated_memory.clear(); 94 95 BOOST_TEST(no_allocations_left); 96 BOOST_TEST(no_constructions_left); 97 BOOST_TEST(allocated_memory_empty); 98 } 99 } 100 } 101 track_allocatetest::detail::memory_tracker102 void track_allocate(void *ptr, std::size_t n, std::size_t size, 103 int tag) 104 { 105 if(n == 0) { 106 BOOST_ERROR("Allocating 0 length array."); 107 } 108 else { 109 ++count_allocations; 110 allocated_memory.insert( 111 std::pair<memory_area const, memory_track>( 112 memory_area(ptr, (char*) ptr + n * size), 113 memory_track(tag))); 114 } 115 } 116 track_deallocatetest::detail::memory_tracker117 void track_deallocate(void* ptr, std::size_t n, std::size_t size, 118 int tag, bool check_tag_ = true) 119 { 120 allocated_memory_type::iterator pos = 121 allocated_memory.find( 122 memory_area(ptr, (char*) ptr + n * size)); 123 if(pos == allocated_memory.end()) { 124 BOOST_ERROR("Deallocating unknown pointer."); 125 } else { 126 BOOST_TEST(pos->first.start == ptr); 127 BOOST_TEST(pos->first.end == (char*) ptr + n * size); 128 if (check_tag_) BOOST_TEST(pos->second.tag_ == tag); 129 allocated_memory.erase(pos); 130 } 131 BOOST_TEST(count_allocations > 0); 132 if(count_allocations > 0) --count_allocations; 133 } 134 track_constructtest::detail::memory_tracker135 void track_construct(void* /*ptr*/, std::size_t /*size*/, 136 int /*tag*/) 137 { 138 ++count_constructions; 139 } 140 track_destroytest::detail::memory_tracker141 void track_destroy(void* /*ptr*/, std::size_t /*size*/, 142 int /*tag*/) 143 { 144 BOOST_TEST(count_constructions > 0); 145 if(count_constructions > 0) --count_constructions; 146 } 147 }; 148 } 149 150 namespace detail 151 { 152 // This won't be a problem as I'm only using a single compile unit 153 // in each test (this is actually required by the minimal test 154 // framework). 155 // 156 // boostinspect:nounnamed 157 namespace { 158 test::detail::memory_tracker tracker; 159 } 160 } 161 } 162 163 #endif 164