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