1#ifndef LIBSBX_MEMORY_COUNTING_RESOURCE_HPP_
2#define LIBSBX_MEMORY_COUNTING_RESOURCE_HPP_
4#include <memory_resource>
11template<
typename Type>
14template<
typename Type>
15struct is_atomic<std::atomic<Type>> : std::true_type {};
17template<
typename Type>
20template<
typename Counter>
23template<
typename Type>
26template<
typename Type>
29template<
typename Counter>
30using counter_value_t =
typename counter_value<Counter>::type;
34template<
typename Counter>
35constexpr auto load(
const Counter& counter)
noexcept -> counter_value_t<Counter> {
36 if constexpr (is_atomic_v<Counter>) {
37 return counter.load(std::memory_order_relaxed);
43template<
typename Counter>
44constexpr void store(Counter& counter, counter_value_t<Counter> value)
noexcept {
45 if constexpr (is_atomic_v<Counter>) {
46 counter.store(value, std::memory_order_relaxed);
52template<
typename Counter>
53constexpr auto add(Counter& counter, counter_value_t<Counter> value)
noexcept -> counter_value_t<Counter> {
54 if constexpr (is_atomic_v<Counter>) {
55 return counter.fetch_add(value, std::memory_order_relaxed) + value;
63template<
typename Counter>
64constexpr void subtract(Counter& counter, counter_value_t<Counter> value)
noexcept {
65 if constexpr (is_atomic_v<Counter>) {
66 counter.fetch_sub(value, std::memory_order_relaxed);
72template<
typename Counter>
73constexpr void increment(Counter& counter)
noexcept {
74 if constexpr (is_atomic_v<Counter>) {
75 counter.fetch_add(1, std::memory_order_relaxed);
81template<
typename Counter>
82constexpr void update_peak(Counter& peak, counter_value_t<Counter> now)
noexcept {
83 if constexpr (is_atomic_v<Counter>) {
84 auto current = peak.load(std::memory_order_relaxed);
86 while (now > current && !peak.compare_exchange_weak(current, now, std::memory_order_relaxed, std::memory_order_relaxed)) { }
96template<
typename Counter>
97requires (std::is_unsigned_v<counter_value_t<Counter>>)
102 using counter_type = Counter;
103 using value_type = counter_value_t<counter_type>;
106 : _upstream{upstream} {}
108 void reset()
noexcept {
109 detail::store(_bytes_outstanding, 0);
110 detail::store(_peak_outstanding, 0);
111 detail::store(_alloc_count, 0);
112 detail::store(_dealloc_count, 0);
115 auto outstanding()
const noexcept -> value_type {
116 return detail::load(_bytes_outstanding);
119 auto peak()
const noexcept -> value_type {
120 return detail::load(_peak_outstanding);
123 auto allocs()
const noexcept -> value_type {
124 return detail::load(_alloc_count);
127 auto deallocs()
const noexcept -> value_type {
128 return detail::load(_dealloc_count);
133 auto do_allocate(std::size_t bytes, std::size_t alignment) ->
void*
override {
134 void* ptr = _upstream->allocate(bytes, alignment);
136 detail::increment(_alloc_count);
138 const auto count =
static_cast<value_type
>(bytes);
139 const auto now = detail::add(_bytes_outstanding, count);
141 detail::update_peak(_peak_outstanding, now);
146 auto do_deallocate(
void* ptr, std::size_t bytes, std::size_t alignment) ->
void override {
147 detail::increment(_dealloc_count);
148 detail::subtract(_bytes_outstanding,
static_cast<value_type
>(bytes));
150 _upstream->deallocate(ptr, bytes, alignment);
153 auto do_is_equal(
const std::pmr::memory_resource& other)
const noexcept ->
bool override {
154 return this == &other;
157 std::pmr::memory_resource* _upstream;
159 counter_type _bytes_outstanding{0};
160 counter_type _peak_outstanding{0};
161 counter_type _alloc_count{0};
162 counter_type _dealloc_count{0};
166template<std::
unsigned_
integral Type>
Definition: counting_resource.hpp:98
Definition: counting_resource.hpp:27
Definition: counting_resource.hpp:12