| |
| // Copyright 2006-2009 Daniel James. |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #if !defined(BOOST_UNORDERED_TEST_MEMORY_HEADER) |
| #define BOOST_UNORDERED_TEST_MEMORY_HEADER |
| |
| #include <memory> |
| #include <map> |
| #include <boost/mpl/apply.hpp> |
| #include <boost/assert.hpp> |
| #include <boost/unordered/detail/allocator_helpers.hpp> |
| #include <boost/mpl/aux_/config/eti.hpp> |
| #include "../helpers/test.hpp" |
| |
| namespace test |
| { |
| namespace detail |
| { |
| struct memory_area { |
| void const* start; |
| void const* end; |
| |
| memory_area(void const* s, void const* e) |
| : start(s), end(e) |
| { |
| BOOST_ASSERT(start != end); |
| } |
| }; |
| |
| struct memory_track { |
| explicit memory_track(int tag = -1) : |
| constructed_(0), |
| tag_(tag) {} |
| |
| int constructed_; |
| int tag_; |
| }; |
| |
| // This is a bit dodgy as it defines overlapping |
| // areas as 'equal', so this isn't a total ordering. |
| // But it is for non-overlapping memory regions - which |
| // is what'll be stored. |
| // |
| // All searches will be for areas entirely contained by |
| // a member of the set - so it should find the area that contains |
| // the region that is searched for. |
| |
| struct memory_area_compare { |
| bool operator()(memory_area const& x, memory_area const& y) const { |
| return x.end <= y.start; |
| } |
| }; |
| |
| template <class Alloc> |
| struct allocator_memory_type_gen { |
| typedef std::map<memory_area, memory_track, memory_area_compare, |
| Alloc> type; |
| }; |
| |
| #if defined(BOOST_MPL_CFG_MSVC_ETI_BUG) |
| template <> |
| struct allocator_memory_type_gen<int> { |
| typedef std::map<memory_area, memory_track, memory_area_compare> |
| type; |
| }; |
| #endif |
| |
| template <class Alloc = std::allocator<int> > |
| struct memory_tracker { |
| typedef BOOST_DEDUCED_TYPENAME |
| boost::unordered_detail::rebind_wrap<Alloc, |
| std::pair<memory_area const, memory_track> >::type |
| allocator_type; |
| |
| typedef BOOST_DEDUCED_TYPENAME |
| allocator_memory_type_gen<allocator_type>::type |
| allocated_memory_type; |
| |
| allocated_memory_type allocated_memory; |
| unsigned int count_allocators; |
| unsigned int count_allocations; |
| unsigned int count_constructions; |
| |
| memory_tracker() : |
| count_allocators(0), count_allocations(0), |
| count_constructions(0) |
| {} |
| |
| void allocator_ref() |
| { |
| if(count_allocators == 0) { |
| count_allocations = 0; |
| count_constructions = 0; |
| allocated_memory.clear(); |
| } |
| ++count_allocators; |
| } |
| |
| void allocator_unref() |
| { |
| BOOST_TEST(count_allocators > 0); |
| if(count_allocators > 0) { |
| --count_allocators; |
| if(count_allocators == 0) { |
| bool no_allocations_left = (count_allocations == 0); |
| bool no_constructions_left = (count_constructions == 0); |
| bool allocated_memory_empty = allocated_memory.empty(); |
| |
| // Clearing the data before the checks terminate the |
| // tests. |
| count_allocations = 0; |
| count_constructions = 0; |
| allocated_memory.clear(); |
| |
| BOOST_TEST(no_allocations_left); |
| BOOST_TEST(no_constructions_left); |
| BOOST_TEST(allocated_memory_empty); |
| } |
| } |
| } |
| |
| void track_allocate(void *ptr, std::size_t n, std::size_t size, |
| int tag) |
| { |
| if(n == 0) { |
| BOOST_ERROR("Allocating 0 length array."); |
| } |
| else { |
| ++count_allocations; |
| allocated_memory.insert( |
| std::pair<memory_area const, memory_track>( |
| memory_area(ptr, (char*) ptr + n * size), |
| memory_track(tag))); |
| } |
| } |
| |
| void track_deallocate(void* ptr, std::size_t n, std::size_t size, |
| int tag) |
| { |
| BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos = |
| allocated_memory.find( |
| memory_area(ptr, (char*) ptr + n * size)); |
| if(pos == allocated_memory.end()) { |
| BOOST_ERROR("Deallocating unknown pointer."); |
| } else { |
| BOOST_TEST(pos->first.start == ptr); |
| BOOST_TEST(pos->first.end == (char*) ptr + n * size); |
| BOOST_TEST(pos->second.tag_ == tag); |
| allocated_memory.erase(pos); |
| } |
| BOOST_TEST(count_allocations > 0); |
| if(count_allocations > 0) --count_allocations; |
| } |
| |
| void track_construct(void* /*ptr*/, std::size_t /*size*/, |
| int /*tag*/) |
| { |
| ++count_constructions; |
| } |
| |
| void track_destroy(void* /*ptr*/, std::size_t /*size*/, |
| int /*tag*/) |
| { |
| BOOST_TEST(count_constructions > 0); |
| if(count_constructions > 0) --count_constructions; |
| } |
| }; |
| } |
| } |
| |
| #endif |