jaulib v1.5.0
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
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 <jau/basic_types.hpp>
29#include <jau/callocator.hpp>
30#include <jau/string_cfmt.hpp>
31
32namespace jau {
33
34/**
35 * Performance counter jau::callocator specialization.
36 * <p>
37 * This class shall be compliant with <i>C++ named requirements for Allocator</i>.
38 * </p>
39 * <p>
40 * Not overriding deprecated (C++17) and removed (C++20)
41 * methods: address(), max_size(), construct() and destroy().
42 * </p>
43 */
44template <class T>
46{
47 public:
48 template <class U> struct rebind {typedef counting_callocator<U> other;};
49
50 // typedefs' for C++ named requirements: Allocator
51 typedef T value_type;
52
53 // std::size_t id;
55 std::size_t memory_usage;
56 std::size_t alloc_count;
57 std::size_t dealloc_count;
58 std::size_t realloc_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 realloc_count = 0;
83 alloc_balance = 0;
84 }
85 }
86
87 public:
88 std::string toString() {
89 return jau_format_string("CCAlloc[%'zu bytes, alloc[balance %'zd = %'zu - %'zu, realloc %'zu]]",
91 }
92
95 // id(next_id++),
96 old_stats(false),
98 { } // C++11
99
100#if __cplusplus > 201703L
101 constexpr counting_callocator(const counting_callocator& other) noexcept
103 // id(next_id++),
104 old_stats(true),
105 memory_usage(other.memory_usage),
106 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
107 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
108 {} // C++20
109#else
112 // id(next_id++),
113 old_stats(true),
114 memory_usage(other.memory_usage),
115 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
116 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
117 { }
118#endif
119
120#if __cplusplus > 201703L
121 template <typename U>
122 constexpr counting_callocator(const counting_callocator<U>& other) noexcept
124 // id(next_id++),
125 old_stats(true),
126 memory_usage(other.memory_usage),
127 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
128 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
129 {} // C++20
130#else
131 template <typename U>
134 // id(next_id++),
135 old_stats(true),
136 memory_usage(other.memory_usage),
137 alloc_count(other.alloc_count), dealloc_count(other.dealloc_count),
138 realloc_count(other.realloc_count), alloc_balance(other.alloc_balance)
139 { }
140#endif
141
142#if __cplusplus > 201703L
143 constexpr ~counting_callocator() {} // C++20
144#else
146#endif
147
148#if __cplusplus <= 201703L
149 value_type* allocate(std::size_t n, const void * hint) { // C++17 deprecated; C++20 removed
150 flush_stats();
151 memory_usage += n * sizeof(value_type);
152 ++alloc_count;
155 }
156#endif
157
158#if __cplusplus > 201703L
159 [[nodiscard]] constexpr value_type* allocate(std::size_t n) { // C++20
160 flush_stats();
161 memory_usage += n * sizeof(value_type);
162 ++alloc_count;
165 }
166#else
167 value_type* allocate(std::size_t n) { // C++17
168 flush_stats();
169 memory_usage += n * sizeof(value_type);
170 ++alloc_count;
173 }
174#endif
175
176 [[nodiscard]] constexpr value_type* reallocate(value_type* p, std::size_t old_size, std::size_t new_size) {
177 value_type * const res = reinterpret_cast<value_type*>(
178 jau::callocator<value_type>::reallocate( p, old_size, new_size ) );
179 if( nullptr != res ) {
180 memory_usage -= old_size * sizeof(value_type);
181 memory_usage += new_size * sizeof(value_type);
183 } // else realloc does not free storage on failure (nullptr)
184 return res;
185 }
186
187#if __cplusplus > 201703L
188 constexpr void deallocate(value_type* p, std::size_t n ) {
189 flush_stats();
190 memory_usage -= n * sizeof(value_type);
194 }
195#else
196 void deallocate(value_type* p, std::size_t n ) {
197 flush_stats();
198 memory_usage -= n * sizeof(value_type);
202 }
203#endif
204};
205
206
207#if __cplusplus > 201703L
208template <class T1, class T2>
209 constexpr bool operator==(const counting_callocator<T1>& lhs, const counting_callocator<T2>& rhs) noexcept {
210#if 0
211 if( &lhs == &rhs ) {
212 return true;
213 }
214 return lhs.memory_usage == rhs.memory_usage;
215#else
216 (void)lhs;
217 (void)rhs;
218 return true;
219#endif
220 }
221#else
222 template <class T1, class T2>
223 bool operator==(const counting_callocator<T1>& lhs, const counting_callocator<T2>& rhs) noexcept {
224#if 0
225 if( &lhs == &rhs ) {
226 return true;
227 }
228 return lhs.memory_usage == rhs.memory_usage;
229#else
230 (void)lhs;
231 (void)rhs;
232 return true;
233#endif
234 }
235 template <class T1, class T2>
236 bool operator!=(const counting_callocator<T1>& lhs, const counting_callocator<T2>& rhs) noexcept {
237 return !(lhs==rhs);
238 }
239#endif
240
241} /* namespace jau */
242
243#endif // COUNTING_CALLOCATOR_HPP
244
#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
A simple allocator using POSIX C functions: ::malloc(), ::free() and ::realloc().
callocator() noexcept=default
void deallocate(value_type *p, std::size_t) noexcept
constexpr value_type * reallocate(value_type *p, std::size_t, std::size_t new_size)
value_type * allocate(std::size_t n, const void *)
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
void deallocate(value_type *p, std::size_t n)
value_type * allocate(std::size_t n)