jaulib v1.5.0
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
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 <memory>
29
30#include <jau/basic_types.hpp>
31#include <jau/string_cfmt.hpp>
32
33namespace jau {
34
35/**
36 * Performance counter std::allocator specialization.
37 * <p>
38 * This class shall be compliant with <i>C++ named requirements for Allocator</i>.
39 * </p>
40 * <p>
41 * Not overriding deprecated (C++17) and removed (C++20)
42 * methods: address(), max_size(), construct() and destroy().
43 * </p>
44 */
45template <class T>
46struct counting_allocator : public std::allocator<T>
47{
48 public:
49 template <class U> struct rebind {typedef counting_allocator<U> other;};
50
51 // typedefs' for C++ named requirements: Allocator
52 typedef T value_type;
53
54 // std::size_t id;
56 std::size_t memory_usage;
57 std::size_t alloc_count;
58 std::size_t dealloc_count;
60
61 private:
62 // inline static relaxed_atomic_size_t next_id = 1;
63
64 /**
65 * vector<value_type>::get_allocator() returns a copy of the allocator instance,
66 * where we desire to access the copied statistics.
67 * <p>
68 * However, vector<value_type>(const vector<value_type>&) also copies the allocator instance,
69 * but here the copied statistics shall be flushed since the elements are
70 * copied into the new vector<value_type> instance using the new allocator.<br>
71 * Without flushing the stats, we would see a size + size allocator stats,
72 * the former size from the copied allocator and the latter from the
73 * copied elements into the new vector<value_type> instance.
74 * </p>
75 */
76 constexpr void flush_stats() noexcept {
77 if( old_stats ) {
78 old_stats = false;
79 memory_usage = 0;
80 alloc_count = 0;
81 dealloc_count = 0;
82 alloc_balance = 0;
83 }
84 }
85
86 public:
87 std::string toString() {
88 return jau_format_string("CAlloc[%'zu bytes, alloc[balance %'zd = %'zu - %'zu]]",
90 }
91
93 : std::allocator<value_type>(),
94 // id(next_id++),
95 old_stats(false),
97 { } // C++11
98
99#if __cplusplus > 201703L
100 constexpr counting_allocator(const counting_allocator& other) noexcept
101 : std::allocator<value_type>(other),
102 // id(next_id++),
103 old_stats(true),
104 memory_usage(other.memory_usage),
105 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
106 alloc_balance(other.alloc_balance)
107 {} // C++20
108#else
110 : std::allocator<value_type>(other),
111 // id(next_id++),
112 old_stats(true),
113 memory_usage(other.memory_usage),
114 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
115 alloc_balance(other.alloc_balance)
116 { }
117#endif
118
119#if __cplusplus > 201703L
120 template <typename U>
121 constexpr counting_allocator(const counting_allocator<U>& other) noexcept
122 : std::allocator<value_type>(other),
123 // id(next_id++),
124 old_stats(true),
125 memory_usage(other.memory_usage),
126 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
127 alloc_balance(other.alloc_balance)
128 {} // C++20
129#else
130 template <typename U>
132 : std::allocator<value_type>(other),
133 // id(next_id++),
134 old_stats(true),
135 memory_usage(other.memory_usage),
136 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
137 alloc_balance(other.alloc_balance)
138 { }
139#endif
140
141#if __cplusplus > 201703L
142 constexpr ~counting_allocator() {} // C++20
143#else
145#endif
146
147#if __cplusplus <= 201703L
148 value_type* allocate(std::size_t n, const void * hint) { // C++17 deprecated; C++20 removed
149 flush_stats();
150 memory_usage += n * sizeof(value_type);
151 alloc_count++;
153 return std::allocator<value_type>::allocate(n, hint);
154 }
155#endif
156
157#if __cplusplus > 201703L
158 [[nodiscard]] constexpr value_type* allocate(std::size_t n) { // C++20
159 flush_stats();
160 memory_usage += n * sizeof(value_type); // NOLINT(bugprone-sizeof-expression): Intended pointer type if so chosen
161 alloc_count++;
163 return std::allocator<value_type>::allocate(n);
164 }
165#else
166 value_type* allocate(std::size_t n) { // C++17
167 flush_stats();
168 memory_usage += n * sizeof(value_type); // NOLINT(bugprone-sizeof-expression): Intended pointer type if so chosen
169 alloc_count++;
171 return std::allocator<value_type>::allocate(n);
172 }
173#endif
174
175#if __cplusplus > 201703L
176 constexpr void deallocate(value_type* p, std::size_t n ) {
177 flush_stats();
178 memory_usage -= n * sizeof(value_type); // NOLINT(bugprone-sizeof-expression): Intended pointer type if so chosen
181 std::allocator<value_type>::deallocate(p, n);
182 }
183#else
184 void deallocate(value_type* p, std::size_t n ) {
185 flush_stats();
186 memory_usage -= n * sizeof(value_type); // NOLINT(bugprone-sizeof-expression): Intended pointer type if so chosen
189 std::allocator<value_type>::deallocate(p, n);
190 }
191#endif
192};
193
194#if __cplusplus > 201703L
195template <class T1, class T2>
196 constexpr bool operator==(const counting_allocator<T1>& lhs, const counting_allocator<T2>& rhs) noexcept {
197#if 0
198 if( &lhs == &rhs ) {
199 return true;
200 }
201 return lhs.memory_usage == rhs.memory_usage;
202#else
203 (void)lhs;
204 (void)rhs;
205 return true;
206#endif
207 }
208#else
209 template <class T1, class T2>
210 bool operator==(const counting_allocator<T1>& lhs, const counting_allocator<T2>& rhs) noexcept {
211#if 0
212 if( &lhs == &rhs ) {
213 return true;
214 }
215 return lhs.memory_usage == rhs.memory_usage;
216#else
217 (void)lhs;
218 (void)rhs;
219 return true;
220#endif
221 }
222 template <class T1, class T2>
223 bool operator!=(const counting_allocator<T1>& lhs, const counting_allocator<T2>& rhs) noexcept {
224 return !(lhs==rhs);
225 }
226#endif
227
228} /* namespace jau */
229
230#endif // COUNTING_ALLOCATOR_HPP
231
#define jau_format_string(fmt,...)
Macro, safely returns a (non-truncated) string according to snprintf() formatting rules using a reser...
__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
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
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