memory.hpp 5.3 KB

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