// Copyright 2006 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_OBJECTS_HEADER) #define BOOST_UNORDERED_TEST_OBJECTS_HEADER #include #include #include #include "../helpers/fwd.hpp" #include #include namespace test { // Note that the default hash function will work for any equal_to (but not // very well). class object; class hash; class less; class equal_to; template class allocator; class object { friend class hash; friend class equal_to; friend class less; int tag1_, tag2_; public: explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {} friend bool operator==(object const& x1, object const& x2) { return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_; } friend bool operator!=(object const& x1, object const& x2) { return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_; } friend bool operator<(object const& x1, object const& x2) { return x1.tag1_ < x2.tag1_ || (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); } friend object generate(object const*) { int* x = 0; return object(generate(x), generate(x)); } friend std::ostream& operator<<(std::ostream& out, object const& o) { return out<<"("< allocated_memory; unsigned int count_allocators = 0; unsigned int count_allocations = 0; unsigned int 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) { // TODO: This is unspecified - not undefined, so what to do? } else { ++count_allocations; allocated_memory[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) { std::map::iterator pos = allocated_memory.find(memory_area(ptr, ptr)); if(pos == allocated_memory.end()) { BOOST_ERROR("Deallocating unknown pointer."); } else { // TODO: Not exception safe. BOOST_TEST(pos->first.start == ptr); BOOST_TEST(pos->first.end == (char*) ptr + n * size); BOOST_TEST(pos->second.tag_ == tag); BOOST_TEST(pos->second.constructed_ == 0); 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) { std::map::iterator pos = allocated_memory.find(memory_area(ptr, ptr)); if(pos == allocated_memory.end()) BOOST_ERROR("Constructing unknown pointer."); BOOST_TEST(pos->second.tag_ == tag); //TODO: Track the number of allocations, and make sure the number // of constructions doesn't exceed it. If you're feeling keen, // perhaps track the individual objects in the array. ++count_constructions; ++pos->second.constructed_; } void track_destroy(void* ptr, std::size_t size, int tag) { std::map::iterator pos = allocated_memory.find(memory_area(ptr, ptr)); if(pos == allocated_memory.end()) BOOST_ERROR("Destroying unknown pointer."); BOOST_TEST(count_constructions > 0); BOOST_TEST(pos->second.tag_ == tag); BOOST_TEST(pos->second.constructed_ > 0); if(count_constructions > 0) --count_constructions; if(pos->second.constructed_ > 0) --pos->second.constructed_; } } template class allocator { # ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS public: # else template friend class allocator; # endif int tag_; public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef T const* const_pointer; typedef T& reference; typedef T const& const_reference; typedef T value_type; template struct rebind { typedef allocator other; }; explicit allocator(int t = 0) : tag_(t) { detail::allocator_ref(); } template allocator(allocator const& x) : tag_(x.tag_) { detail::allocator_ref(); } allocator(allocator const& x) : tag_(x.tag_) { detail::allocator_ref(); } ~allocator() { detail::allocator_unref(); } // TODO: Shall I check these? pointer address(reference r) { return pointer(&r); } const_pointer address(const_reference r) { return const_pointer(&r); } pointer allocate(size_type n) { pointer ptr(static_cast(::operator new(n * sizeof(T)))); detail::track_allocate((void*) ptr, n, sizeof(T), tag_); return ptr; } pointer allocate(size_type n, const_pointer u) { pointer ptr(static_cast(::operator new(n * sizeof(T)))); detail::track_allocate((void*) ptr, n, sizeof(T), tag_); return ptr; } void deallocate(pointer p, size_type n) { detail::track_deallocate((void*) p, n, sizeof(T), tag_); ::operator delete((void*) p); } void construct(pointer p, T const& t) { detail::track_construct((void*) p, sizeof(T), tag_); new(p) T(t); } void destroy(pointer p) { detail::track_destroy((void*) p, sizeof(T), tag_); p->~T(); } size_type max_size() const { return (std::numeric_limits::max)(); } bool operator==(allocator const& x) const { return tag_ == x.tag_; } bool operator!=(allocator const& x) const { return tag_ != x.tag_; } }; template bool equivalent_impl(allocator const& x, allocator const& y, test::derived_type) { return x == y; } } #endif