jaulib v1.3.0
Jau Support Library (C++, Java, ..)
counting_callocator.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021 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_CALLOCATOR_HPP
26#define COUNTING_CALLOCATOR_HPP
27
28#include <cinttypes>
29#include <memory>
30
31#include <jau/basic_types.hpp>
32#include <jau/callocator.hpp>
33
34namespace jau {
35
36/**
37 * Performance counter jau::callocator 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>
48{
49 public:
50 template <class U> struct rebind {typedef counting_callocator<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;
60 std::size_t realloc_count;
62
63 private:
64 // inline static relaxed_atomic_size_t next_id = 1;
65
66 /**
67 * vector<value_type>::get_allocator() returns a copy of the allocator instance,
68 * where we desire to access the copied statistics.
69 * <p>
70 * However, vector<value_type>(const vector<value_type>&) also copies the allocator instance,
71 * but here the copied statistics shall be flushed since the elements are
72 * copied into the new vector<value_type> instance using the new allocator.<br>
73 * Without flushing the stats, we would see a size + size allocator stats,
74 * the former size from the copied allocator and the latter from the
75 * copied elements into the new vector<value_type> instance.
76 * </p>
77 */
78 constexpr void flush_stats() noexcept {
79 if( old_stats ) {
80 old_stats = false;
81 memory_usage = 0;
82 alloc_count = 0;
83 dealloc_count = 0;
84 realloc_count = 0;
85 alloc_balance = 0;
86 }
87 }
88
89 public:
90 std::string toString(const nsize_t mem_width=0, const nsize_t count_width=0) {
91 return "CAlloc["/*+std::to_string(id)+", "*/+to_decstring(memory_usage, ',', mem_width)+" bytes, alloc[balance "+
92 to_decstring(alloc_balance, ',', count_width)+" = "+
93 to_decstring(alloc_count, ',', count_width)+" - "+to_decstring(dealloc_count, ',', count_width)+
94 ", realloc = "+to_decstring(realloc_count, ',', count_width)+"]]";
95 }
96
99 // id(next_id++),
100 old_stats(false),
102 { } // C++11
103
104#if __cplusplus > 201703L
105 constexpr counting_callocator(const counting_callocator& other) noexcept
107 // id(next_id++),
108 old_stats(true),
109 memory_usage(other.memory_usage),
110 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
111 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
112 {} // C++20
113#else
116 // id(next_id++),
117 old_stats(true),
118 memory_usage(other.memory_usage),
119 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
120 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
121 { }
122#endif
123
124#if __cplusplus > 201703L
125 template <typename U>
126 constexpr counting_callocator(const counting_callocator<U>& other) noexcept
128 // id(next_id++),
129 old_stats(true),
130 memory_usage(other.memory_usage),
131 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
132 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
133 {} // C++20
134#else
135 template <typename U>
138 // id(next_id++),
139 old_stats(true),
140 memory_usage(other.memory_usage),
141 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
142 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
143 { }
144#endif
145
146#if __cplusplus > 201703L
147 constexpr ~counting_callocator() {} // C++20
148#else
150#endif
151
152#if __cplusplus <= 201703L
153 value_type* allocate(std::size_t n, const void * hint) { // C++17 deprecated; C++20 removed
154 flush_stats();
155 memory_usage += n * sizeof(value_type);
156 ++alloc_count;
159 }
160#endif
161
162#if __cplusplus > 201703L
163 [[nodiscard]] constexpr value_type* allocate(std::size_t n) { // C++20
164 flush_stats();
165 memory_usage += n * sizeof(value_type);
166 ++alloc_count;
169 }
170#else
171 value_type* allocate(std::size_t n) { // C++17
172 flush_stats();
173 memory_usage += n * sizeof(value_type);
174 ++alloc_count;
177 }
178#endif
179
180 [[nodiscard]] constexpr value_type* reallocate(value_type* p, std::size_t old_size, std::size_t new_size) {
181 value_type * const res = reinterpret_cast<value_type*>(
182 jau::callocator<value_type>::reallocate( p, old_size, new_size ) );
183 if( nullptr != res ) {
184 memory_usage -= old_size * sizeof(value_type);
185 memory_usage += new_size * sizeof(value_type);
187 } // else realloc does not free storage on failure (nullptr)
188 return res;
189 }
190
191#if __cplusplus > 201703L
192 constexpr void deallocate(value_type* p, std::size_t n ) {
193 flush_stats();
194 memory_usage -= n * sizeof(value_type);
198 }
199#else
200 void deallocate(value_type* p, std::size_t n ) {
201 flush_stats();
202 memory_usage -= n * sizeof(value_type);
206 }
207#endif
208};
209
210
211#if __cplusplus > 201703L
212template <class T1, class T2>
213 constexpr bool operator==(const counting_callocator<T1>& lhs, const counting_callocator<T2>& rhs) noexcept {
214#if 0
215 if( &lhs == &rhs ) {
216 return true;
217 }
218 return lhs.memory_usage == rhs.memory_usage;
219#else
220 (void)lhs;
221 (void)rhs;
222 return true;
223#endif
224 }
225#else
226 template <class T1, class T2>
227 bool operator==(const counting_callocator<T1>& lhs, const counting_callocator<T2>& rhs) noexcept {
228#if 0
229 if( &lhs == &rhs ) {
230 return true;
231 }
232 return lhs.memory_usage == rhs.memory_usage;
233#else
234 (void)lhs;
235 (void)rhs;
236 return true;
237#endif
238 }
239 template <class T1, class T2>
240 bool operator!=(const counting_callocator<T1>& lhs, const counting_callocator<T2>& rhs) noexcept {
241 return !(lhs==rhs);
242 }
243#endif
244
245} /* namespace jau */
246
247#endif // COUNTING_CALLOCATOR_HPP
248
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
A simple allocator using POSIX C functions: ::malloc(), ::free() and ::realloc().
Definition: callocator.hpp:50
constexpr value_type * reallocate(value_type *p, std::size_t, std::size_t new_size)
Definition: callocator.hpp:116
value_type * allocate(std::size_t n, const void *)
Definition: callocator.hpp:101
void deallocate(value_type *p, std::size_t)
Definition: callocator.hpp:126
Performance counter jau::callocator specialization.
constexpr value_type * reallocate(value_type *p, std::size_t old_size, std::size_t new_size)
value_type * allocate(std::size_t n, const void *hint)
counting_callocator(const counting_callocator< U > &other) noexcept
counting_callocator(const counting_callocator &other) noexcept
std::string toString(const nsize_t mem_width=0, const nsize_t count_width=0)
void deallocate(value_type *p, std::size_t n)
value_type * allocate(std::size_t n)