jaulib v1.3.0
Jau Support Library (C++, Java, ..)
counting_allocator.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef COUNTING_ALLOCATOR_HPP
26#define COUNTING_ALLOCATOR_HPP
27
28#include <cinttypes>
29#include <memory>
30
31#include <jau/basic_types.hpp>
32// #include <jau/ordered_atomic.hpp>
33
34namespace jau {
35
36/**
37 * Performance counter std::allocator specialization.
38 * <p>
39 * This class shall be compliant with <i>C++ named requirements for Allocator</i>.
40 * </p>
41 * <p>
42 * Not overriding deprecated (C++17) and removed (C++20)
43 * methods: address(), max_size(), construct() and destroy().
44 * </p>
45 */
46template <class T>
47struct counting_allocator : public std::allocator<T>
48{
49 public:
50 template <class U> struct rebind {typedef counting_allocator<U> other;};
51
52 // typedefs' for C++ named requirements: Allocator
53 typedef T value_type;
54
55 // std::size_t id;
57 std::size_t memory_usage;
58 std::size_t alloc_count;
59 std::size_t dealloc_count;
61
62 private:
63 // inline static relaxed_atomic_size_t next_id = 1;
64
65 /**
66 * vector<value_type>::get_allocator() returns a copy of the allocator instance,
67 * where we desire to access the copied statistics.
68 * <p>
69 * However, vector<value_type>(const vector<value_type>&) also copies the allocator instance,
70 * but here the copied statistics shall be flushed since the elements are
71 * copied into the new vector<value_type> instance using the new allocator.<br>
72 * Without flushing the stats, we would see a size + size allocator stats,
73 * the former size from the copied allocator and the latter from the
74 * copied elements into the new vector<value_type> instance.
75 * </p>
76 */
77 constexpr void flush_stats() noexcept {
78 if( old_stats ) {
79 old_stats = false;
80 memory_usage = 0;
81 alloc_count = 0;
82 dealloc_count = 0;
83 alloc_balance = 0;
84 }
85 }
86
87 public:
88 std::string toString(const nsize_t mem_width=0, const nsize_t count_width=0) {
89 return "CAlloc["/*+std::to_string(id)+", "*/+to_decstring(memory_usage, ',', mem_width)+" bytes, alloc[balance "+
90 to_decstring(alloc_balance, ',', count_width)+" = "+
91 to_decstring(alloc_count, ',', count_width)+" - "+to_decstring(dealloc_count, ',', count_width)+"]]";
92 }
93
95 : std::allocator<value_type>(),
96 // id(next_id++),
97 old_stats(false),
99 { } // C++11
100
101#if __cplusplus > 201703L
102 constexpr counting_allocator(const counting_allocator& other) noexcept
103 : std::allocator<value_type>(other),
104 // id(next_id++),
105 old_stats(true),
106 memory_usage(other.memory_usage),
107 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
108 alloc_balance(other.alloc_balance)
109 {} // C++20
110#else
112 : std::allocator<value_type>(other),
113 // id(next_id++),
114 old_stats(true),
115 memory_usage(other.memory_usage),
116 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
117 alloc_balance(other.alloc_balance)
118 { }
119#endif
120
121#if __cplusplus > 201703L
122 template <typename U>
123 constexpr counting_allocator(const counting_allocator<U>& other) noexcept
124 : std::allocator<value_type>(other),
125 // id(next_id++),
126 old_stats(true),
127 memory_usage(other.memory_usage),
128 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
129 alloc_balance(other.alloc_balance)
130 {} // C++20
131#else
132 template <typename U>
134 : std::allocator<value_type>(other),
135 // id(next_id++),
136 old_stats(true),
137 memory_usage(other.memory_usage),
138 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
139 alloc_balance(other.alloc_balance)
140 { }
141#endif
142
143#if __cplusplus > 201703L
144 constexpr ~counting_allocator() {} // C++20
145#else
147#endif
148
149#if __cplusplus <= 201703L
150 value_type* allocate(std::size_t n, const void * hint) { // C++17 deprecated; C++20 removed
151 flush_stats();
152 memory_usage += n * sizeof(value_type);
153 alloc_count++;
155 return std::allocator<value_type>::allocate(n, hint);
156 }
157#endif
158
159#if __cplusplus > 201703L
160 [[nodiscard]] constexpr value_type* allocate(std::size_t n) { // C++20
161 flush_stats();
162 memory_usage += n * sizeof(value_type);
163 alloc_count++;
165 return std::allocator<value_type>::allocate(n);
166 }
167#else
168 value_type* allocate(std::size_t n) { // C++17
169 flush_stats();
170 memory_usage += n * sizeof(value_type);
171 alloc_count++;
173 return std::allocator<value_type>::allocate(n);
174 }
175#endif
176
177#if __cplusplus > 201703L
178 constexpr void deallocate(value_type* p, std::size_t n ) {
179 flush_stats();
180 memory_usage -= n * sizeof(value_type);
183 std::allocator<value_type>::deallocate(p, n);
184 }
185#else
186 void deallocate(value_type* p, std::size_t n ) {
187 flush_stats();
188 memory_usage -= n * sizeof(value_type);
191 std::allocator<value_type>::deallocate(p, n);
192 }
193#endif
194};
195
196#if __cplusplus > 201703L
197template <class T1, class T2>
198 constexpr bool operator==(const counting_allocator<T1>& lhs, const counting_allocator<T2>& rhs) noexcept {
199#if 0
200 if( &lhs == &rhs ) {
201 return true;
202 }
203 return lhs.memory_usage == rhs.memory_usage;
204#else
205 (void)lhs;
206 (void)rhs;
207 return true;
208#endif
209 }
210#else
211 template <class T1, class T2>
212 bool operator==(const counting_allocator<T1>& lhs, const counting_allocator<T2>& rhs) noexcept {
213#if 0
214 if( &lhs == &rhs ) {
215 return true;
216 }
217 return lhs.memory_usage == rhs.memory_usage;
218#else
219 (void)lhs;
220 (void)rhs;
221 return true;
222#endif
223 }
224 template <class T1, class T2>
225 bool operator!=(const counting_allocator<T1>& lhs, const counting_allocator<T2>& rhs) noexcept {
226 return !(lhs==rhs);
227 }
228#endif
229
230} /* namespace jau */
231
232#endif // COUNTING_ALLOCATOR_HPP
233
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:53
std::string to_decstring(const value_type &v, const char separator=',', const nsize_t width=0) noexcept
Produce a decimal string representation of an integral integer value.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:150
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:163
STL namespace.
Performance counter std::allocator specialization.
value_type * allocate(std::size_t n)
void deallocate(value_type *p, std::size_t n)
counting_allocator(const counting_allocator &other) noexcept
value_type * allocate(std::size_t n, const void *hint)
counting_allocator(const counting_allocator< U > &other) noexcept
std::string toString(const nsize_t mem_width=0, const nsize_t count_width=0)