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 "../helpers/test.hpp" 10 #include <boost/assert.hpp> 11 #include <boost/unordered/detail/implementation.hpp> 12 #include <map> 13 #include <memory> 14 15 namespace test { 16 namespace detail { 17 struct memory_area 18 { 19 void const* start; 20 void const* end; 21 memory_areatest::detail::memory_area22 memory_area(void const* s, void const* e) : start(s), end(e) 23 { 24 BOOST_ASSERT(start != end); 25 } 26 }; 27 28 struct memory_track 29 { memory_tracktest::detail::memory_track30 explicit memory_track(int tag = -1) : constructed_(0), tag_(tag) {} 31 32 int constructed_; 33 int tag_; 34 }; 35 36 // This is a bit dodgy as it defines overlapping 37 // areas as 'equal', so this isn't a total ordering. 38 // But it is for non-overlapping memory regions - which 39 // is what'll be stored. 40 // 41 // All searches will be for areas entirely contained by 42 // a member of the set - so it should find the area that contains 43 // the region that is searched for. 44 45 struct memory_area_compare 46 { operator ()test::detail::memory_area_compare47 bool operator()(memory_area const& x, memory_area const& y) const 48 { 49 return x.end <= y.start; 50 } 51 }; 52 53 struct memory_tracker 54 { 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 bool tracking_constructions; 64 memory_trackertest::detail::memory_tracker65 memory_tracker() 66 : count_allocators(0), count_allocations(0), count_constructions(0), 67 tracking_constructions(true) 68 { 69 } 70 ~memory_trackertest::detail::memory_tracker71 ~memory_tracker() { BOOST_TEST(count_allocators == 0); } 72 allocator_reftest::detail::memory_tracker73 void allocator_ref() 74 { 75 if (count_allocators == 0) { 76 count_allocations = 0; 77 count_constructions = 0; 78 allocated_memory.clear(); 79 } 80 ++count_allocators; 81 } 82 allocator_unreftest::detail::memory_tracker83 void allocator_unref() 84 { 85 BOOST_TEST(count_allocators > 0); 86 if (count_allocators > 0) { 87 --count_allocators; 88 if (count_allocators == 0) { 89 bool no_allocations_left = (count_allocations == 0); 90 bool no_constructions_left = (count_constructions == 0); 91 bool allocated_memory_empty = allocated_memory.empty(); 92 93 // Clearing the data before the checks terminate the 94 // tests. 95 count_allocations = 0; 96 count_constructions = 0; 97 allocated_memory.clear(); 98 99 BOOST_TEST(no_allocations_left); 100 BOOST_TEST(no_constructions_left); 101 BOOST_TEST(allocated_memory_empty); 102 } 103 } 104 } 105 track_allocatetest::detail::memory_tracker106 void track_allocate(void* ptr, std::size_t n, std::size_t size, int tag) 107 { 108 if (n == 0) { 109 BOOST_ERROR("Allocating 0 length array."); 110 } else { 111 ++count_allocations; 112 allocated_memory.insert(std::pair<memory_area const, memory_track>( 113 memory_area(ptr, (char*)ptr + n * size), memory_track(tag))); 114 } 115 } 116 track_deallocatetest::detail::memory_tracker117 void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag, 118 bool check_tag_ = true) 119 { 120 allocated_memory_type::iterator pos = 121 allocated_memory.find(memory_area(ptr, (char*)ptr + n * size)); 122 if (pos == allocated_memory.end()) { 123 BOOST_ERROR("Deallocating unknown pointer."); 124 } else { 125 BOOST_TEST(pos->first.start == ptr); 126 BOOST_TEST(pos->first.end == (char*)ptr + n * size); 127 if (check_tag_) 128 BOOST_TEST(pos->second.tag_ == tag); 129 allocated_memory.erase(pos); 130 } 131 BOOST_TEST(count_allocations > 0); 132 if (count_allocations > 0) 133 --count_allocations; 134 } 135 track_constructtest::detail::memory_tracker136 void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/) 137 { 138 if (tracking_constructions) { 139 ++count_constructions; 140 } 141 } 142 track_destroytest::detail::memory_tracker143 void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/) 144 { 145 if (tracking_constructions) { 146 BOOST_TEST(count_constructions > 0); 147 if (count_constructions > 0) 148 --count_constructions; 149 } 150 } 151 }; 152 } 153 154 namespace detail { 155 // This won't be a problem as I'm only using a single compile unit 156 // in each test (this is actually required by the minimal test 157 // framework). 158 // 159 // boostinspect:nounnamed 160 namespace { 161 test::detail::memory_tracker tracker; 162 } 163 } 164 165 namespace detail { 166 struct disable_construction_tracking 167 { 168 bool old_value; 169 disable_construction_trackingtest::detail::disable_construction_tracking170 disable_construction_tracking() 171 : old_value(detail::tracker.tracking_constructions) 172 { 173 test::detail::tracker.tracking_constructions = false; 174 } 175 ~disable_construction_trackingtest::detail::disable_construction_tracking176 ~disable_construction_tracking() 177 { 178 test::detail::tracker.tracking_constructions = old_value; 179 } 180 181 private: 182 disable_construction_tracking(disable_construction_tracking const&); 183 disable_construction_tracking& operator=( 184 disable_construction_tracking const&); 185 }; 186 } 187 } 188 189 #endif 190