Skip to content

Instantly share code, notes, and snippets.

@ThePhD
Last active February 21, 2022 17:45
Show Gist options
  • Save ThePhD/eda823f034775b144f328f8b916c49b5 to your computer and use it in GitHub Desktop.
Save ThePhD/eda823f034775b144f328f8b916c49b5 to your computer and use it in GitHub Desktop.
A tracking allocator for mostly testing purposes.
#include <memory>
#include <cstddef>
#include <type_traits>
template<typename Allocator>
class tracking_allocator
{
private:
template <typename>
friend class tracking_allocator;
using base_alloc_traits = std::allocator_traits<Allocator>;
public:
using allocator_type = tracking_allocator;
using value_type = typename base_alloc_traits::value_type;
using pointer = typename base_alloc_traits::pointer;
using const_pointer = typename base_alloc_traits::const_pointer;
using void_pointer = typename base_alloc_traits::void_pointer;
using const_void_pointer = typename base_alloc_traits::const_void_pointer;
using difference_type = typename base_alloc_traits::difference_type;
using size_type = typename base_alloc_traits::size_type;
using propagate_on_container_copy_assignment =
typename base_alloc_traits::propagate_on_container_copy_assignment;
using propagate_on_container_move_assignment =
typename base_alloc_traits::propagate_on_container_move_assignment;
using propogate_on_container_swap =
typename base_alloc_traits::propagate_on_container_swap;
using is_always_equal = typename base_alloc_traits::is_always_equal;
template<typename T>
struct rebind { using other = tracking_allocator<typename base_alloc_traits::template rebind_alloc<T>>; };
tracking_allocator() = default;
tracking_allocator(const tracking_allocator&) = default;
tracking_allocator(tracking_allocator&&) = default;
tracking_allocator&
operator=(const tracking_allocator&) = default;
tracking_allocator&
operator=(tracking_allocator&&) = default;
tracking_allocator(const Allocator& alloc) : _M_allocator(alloc)
{
}
tracking_allocator(Allocator&& alloc) : _M_allocator(::std::move(alloc))
{
}
template <typename RightAlloc, ::std::enable_if_t<!::std::is_same_v<Allocator, RightAlloc>>* = nullptr>
tracking_allocator(const tracking_allocator<RightAlloc>& family) : _M_allocator(family._M_allocator)
{
}
template <typename RightAlloc, ::std::enable_if_t<!::std::is_same_v<Allocator, RightAlloc>>* = nullptr>
tracking_allocator(tracking_allocator<RightAlloc>&& family) : _M_allocator(::std::move(family._M_allocator))
{
}
template<typename P, typename... Args>
void
construct(P* at, Args&&... args)
{
base_alloc_traits::construct(this->get_allocator(), at, std::forward<Args>(args)...);
++constructions_;
}
template<typename P>
void
destroy(P* at)
{
base_alloc_traits::destroy(this->get_allocator(), at);
++this->destructions_;
}
pointer
allocate(size_type n)
{
pointer p = base_alloc_traits::allocate(this->get_allocator(), n);
++this->allocations_;
return p;
}
pointer
allocate(size_type n, const_void_pointer hint)
{
pointer p = base_alloc_traits::allocate(this->get_allocator(), n, hint);
++this->allocations_;
return p;
}
void
deallocate(pointer at, size_type n)
{
base_alloc_traits::deallocate(this->get_allocator(), at, n);
++this->deallocations_;
}
difference_type
alive() const
{
return this->constructions_ - this->destructions_;
}
difference_type
allocations_alive() const
{
return this->allocations_ - this->deallocations_;
}
difference_type
allocations() const
{
return this->allocations_;
}
difference_type
deallocations() const
{
return this->deallocations_;
}
difference_type
constructions() const
{
return this->constructions_;
}
difference_type
destructions() const
{
return this->destructions_;
}
private:
difference_type allocations_ = 0;
difference_type deallocations_ = 0;
difference_type constructions_ = 0;
difference_type destructions_ = 0;
Allocator _M_allocator;
Allocator&
get_allocator()
{
return this->_M_allocator;
}
const Allocator&
get_allocator() const
{
return this->_M_allocator;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment