• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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