Imported Upstream version 1.64.0
[platform/upstream/boost.git] / libs / unordered / test / helpers / memory.hpp
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
22     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 {
30     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 {
47     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
64     memory_tracker()
65         : count_allocators(0), count_allocations(0), count_constructions(0)
66     {
67     }
68
69     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
79     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
102     void track_allocate(void* ptr, std::size_t n, std::size_t size, int tag)
103     {
104         if (n == 0) {
105             BOOST_ERROR("Allocating 0 length array.");
106         } else {
107             ++count_allocations;
108             allocated_memory.insert(std::pair<memory_area const, memory_track>(
109                 memory_area(ptr, (char*)ptr + n * size), memory_track(tag)));
110         }
111     }
112
113     void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag,
114         bool check_tag_ = true)
115     {
116         allocated_memory_type::iterator pos =
117             allocated_memory.find(memory_area(ptr, (char*)ptr + n * size));
118         if (pos == allocated_memory.end()) {
119             BOOST_ERROR("Deallocating unknown pointer.");
120         } else {
121             BOOST_TEST(pos->first.start == ptr);
122             BOOST_TEST(pos->first.end == (char*)ptr + n * size);
123             if (check_tag_)
124                 BOOST_TEST(pos->second.tag_ == tag);
125             allocated_memory.erase(pos);
126         }
127         BOOST_TEST(count_allocations > 0);
128         if (count_allocations > 0)
129             --count_allocations;
130     }
131
132     void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
133     {
134         ++count_constructions;
135     }
136
137     void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
138     {
139         BOOST_TEST(count_constructions > 0);
140         if (count_constructions > 0)
141             --count_constructions;
142     }
143 };
144 }
145
146 namespace detail {
147 // This won't be a problem as I'm only using a single compile unit
148 // in each test (this is actually required by the minimal test
149 // framework).
150 //
151 // boostinspect:nounnamed
152 namespace {
153 test::detail::memory_tracker tracker;
154 }
155 }
156 }
157
158 #endif