mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-11 13:34:06 +00:00
Store nodes in a single linked list, with hash values so that their buckets can be found when needed. Iterators now only have to store a pointer to the node and don't have to iterate over empty buckets to reach the next node. This allows the container to meet the iterator requirements - fixing the speed issues with `equal_range` and `erase`. Also, define iterators in their own namespace, so that they don't accidentally pull in detail functions via ADL. I've simplified the code slightly by removing some of the special cases for empty containers. Renamed a few things as well and other minor changes that were made as I went along. [SVN r71327]
174 lines
5.7 KiB
C++
174 lines
5.7 KiB
C++
|
|
// 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
|