Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
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 
34 namespace 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  */
46 template <class T>
47 struct 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;
56  bool old_stats;
57  std::size_t memory_usage;
58  std::size_t alloc_count;
59  std::size_t dealloc_count;
60  ssize_t alloc_balance;
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 
94  counting_allocator() noexcept
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
111  counting_allocator(const counting_allocator& other) noexcept
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++;
154  alloc_balance++;
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++;
164  alloc_balance++;
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++;
172  alloc_balance++;
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);
181  dealloc_count++;
182  alloc_balance--;
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);
189  dealloc_count++;
190  alloc_balance--;
191  std::allocator<value_type>::deallocate(p, n);
192  }
193 #endif
194 };
195 
196 #if __cplusplus > 201703L
197 template <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 
jau::counting_allocator::counting_allocator
counting_allocator(const counting_allocator &other) noexcept
Definition: counting_allocator.hpp:111
jau::to_decstring
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.
Definition: string_util.hpp:143
jau
Definition: basic_algos.hpp:34
jau::counting_allocator
Performance counter std::allocator specialization.
Definition: counting_allocator.hpp:48
jau::counting_allocator::allocate
value_type * allocate(std::size_t n, const void *hint)
Definition: counting_allocator.hpp:150
jau::counting_allocator::rebind::other
counting_allocator< U > other
Definition: counting_allocator.hpp:50
jau::counting_allocator::alloc_count
std::size_t alloc_count
Definition: counting_allocator.hpp:58
jau::counting_allocator::deallocate
void deallocate(value_type *p, std::size_t n)
Definition: counting_allocator.hpp:186
jau::counting_allocator::rebind
Definition: counting_allocator.hpp:50
jau::counting_allocator::counting_allocator
counting_allocator() noexcept
Definition: counting_allocator.hpp:94
jau::nsize_t
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:44
jau::counting_allocator::memory_usage
std::size_t memory_usage
Definition: counting_allocator.hpp:57
jau::counting_allocator::toString
std::string toString(const nsize_t mem_width=0, const nsize_t count_width=0)
Definition: counting_allocator.hpp:88
jau::counting_allocator::~counting_allocator
~counting_allocator()
Definition: counting_allocator.hpp:146
jau::counting_allocator::allocate
value_type * allocate(std::size_t n)
Definition: counting_allocator.hpp:168
jau::counting_allocator::old_stats
bool old_stats
Definition: counting_allocator.hpp:56
jau::operator!=
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:155
basic_types.hpp
jau::counting_allocator::dealloc_count
std::size_t dealloc_count
Definition: counting_allocator.hpp:59
jau::counting_allocator::counting_allocator
counting_allocator(const counting_allocator< U > &other) noexcept
Definition: counting_allocator.hpp:133
jau::counting_allocator::value_type
T value_type
Definition: counting_allocator.hpp:53
jau::counting_allocator::alloc_balance
ssize_t alloc_balance
Definition: counting_allocator.hpp:60
jau::operator==
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:142