BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlma_countingallocator.h
Go to the documentation of this file.
1/// @file bdlma_countingallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_countingallocator.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_COUNTINGALLOCATOR
9#define INCLUDED_BDLMA_COUNTINGALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_countingallocator bdlma_countingallocator
15/// @brief Provide a memory allocator that counts allocated bytes.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_countingallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_countingallocator-purpose"> Purpose</a>
25/// * <a href="#bdlma_countingallocator-classes"> Classes </a>
26/// * <a href="#bdlma_countingallocator-description"> Description </a>
27/// * <a href="#bdlma_countingallocator-byte-counts"> Byte Counts </a>
28/// * <a href="#bdlma_countingallocator-thread-safety"> Thread Safety </a>
29/// * <a href="#bdlma_countingallocator-usage"> Usage </a>
30/// * <a href="#bdlma_countingallocator-example-1-tracking-a-container-s-dynamic-memory-use"> Example 1: Tracking a Container's Dynamic Memory Use </a>
31///
32/// # Purpose {#bdlma_countingallocator-purpose}
33/// Provide a memory allocator that counts allocated bytes.
34///
35/// # Classes {#bdlma_countingallocator-classes}
36///
37/// - bdlma::CountingAllocator: concrete allocator that counts allocated bytes
38///
39/// @see bslma_allocator, bslma_testallocator
40///
41/// # Description {#bdlma_countingallocator-description}
42/// This component provides a special-purpose counting allocator,
43/// `bdlma::CountingAllocator`, that implements the `bslma::Allocator` protocol
44/// and provides instrumentation to track: (1) the number of bytes currently in
45/// use (`numBytesInUse`), and (2) the cumulative number of bytes that have ever
46/// been allocated (`numBytesTotal`). The accumulated statistics are based
47/// solely on the number of bytes requested in calls to the `allocate` method.
48/// A `print` method is provided to output the current state of the allocator's
49/// byte counts to a specified `bsl::ostream`:
50/// @code
51/// ,------------------------.
52/// ( bdlma::CountingAllocator )
53/// `------------------------'
54/// | ctor/dtor
55/// | numBytesInUse
56/// | numBytesTotal
57/// | name
58/// | print
59/// V
60/// ,----------------.
61/// ( bslma::Allocator )
62/// `----------------'
63/// allocate
64/// deallocate
65/// @endcode
66/// Like many other allocators, `bdlma::CountingAllocator` relies on the
67/// currently installed default allocator (see @ref bslma_default ) at construction.
68/// Clients may, however, override this allocator by supplying (at construction)
69/// any other allocator implementing the `bslma::Allocator` protocol provided
70/// that it is fully thread-safe.
71///
72/// Note that a `bdlma::CountingAllocator` necessarily incurs some overhead in
73/// order to provide its byte-counting functionality. However, this overhead is
74/// *substantially* less than that incurred by the `bslma::TestAllocator` (see
75/// @ref bslma_testallocator ), which keeps track of the same two statistics that
76/// are maintained by a `bdlma::CountingAllocator`. Consequently, use of a
77/// `bdlma::CountingAllocator` may be appropriate in cases where the overhead of
78/// `bslma::TestAllocator` is too onerous. In particular, a counting allocator
79/// may be suitable even for production use in certain situations, whereas the
80/// test allocator is not intended for production use under any circumstance.
81///
82/// ## Byte Counts {#bdlma_countingallocator-byte-counts}
83///
84///
85/// The two byte counts maintained by `bdlma::CountingAllocator` are initialized
86/// to 0 at construction and increased with each call to `allocate` by `size`,
87/// i.e., by the actual number of bytes requested. Each call to `deallocate`
88/// decreases the `numBytesInUse` count by the same amount by which the byte
89/// count was increased in the original `allocate` call. The number of bytes
90/// currently in use is returned by `numBytesInUse` and the total number of
91/// bytes ever allocated is returned by `numBytesTotal`.
92///
93/// ## Thread Safety {#bdlma_countingallocator-thread-safety}
94///
95///
96/// The `bdlma::CountingAllocator` class is fully thread-safe (see
97/// @ref bsldoc_glossary ) provided that the underlying allocator (established at
98/// construction) is fully thread-safe.
99///
100/// ## Usage {#bdlma_countingallocator-usage}
101///
102///
103/// This section illustrates intended use of this component.
104///
105/// ## Example 1: Tracking a Container's Dynamic Memory Use {#bdlma_countingallocator-example-1-tracking-a-container-s-dynamic-memory-use}
106///
107///
108/// In this example, we demonstrate how a counting allocator may be used to
109/// track the amount of dynamic memory used by a container. The container used
110/// for illustration is `DoubleStack`, a stack of out-of-place `double` values.
111///
112/// First, we show the interface of the `DoubleStack` class:
113/// @code
114/// // doublestack.h
115///
116/// /// This class implements a stack of out-of-place `double` values.
117/// class DoubleStack {
118///
119/// // DATA
120/// double **d_stack_p; // dynamically allocated array of
121/// // 'd_capacity' elements
122///
123/// int d_capacity; // physical capacity of the stack
124/// // (in elements)
125///
126/// int d_length; // logical index of next available
127/// // stack element
128///
129/// bslma::Allocator *d_allocator_p; // memory allocator (held, not
130/// // owned)
131///
132/// private:
133/// // NOT IMPLEMENTED
134/// DoubleStack(const DoubleStack&);
135/// DoubleStack& operator=(const DoubleStack&);
136///
137/// private:
138/// // PRIVATE MANIPULATORS
139///
140/// /// Increase the capacity of this stack by at least one element.
141/// void increaseCapacity();
142///
143/// public:
144/// // CREATORS
145///
146/// /// Create a stack for 'double' values having an initial capacity to
147/// /// hold one element. Optionally specify a 'basicAllocator' used to
148/// /// supply memory. If 'basicAllocator' is 0, the currently
149/// /// installed default allocator is used.
150/// explicit
151/// DoubleStack(bslma::Allocator *basicAllocator = 0);
152///
153/// /// Delete this object.
154/// ~DoubleStack();
155///
156/// // MANIPULATORS
157///
158/// /// Add the specified 'value' to the top of this stack.
159/// void push(double value);
160///
161/// /// Remove the element at the top of this stack. The behavior is
162/// /// undefined unless this stack is non-empty.
163/// void pop();
164///
165/// // ACCESSORS
166/// // ...
167/// };
168/// @endcode
169/// Next, we show the (elided) implementation of `DoubleStack`.
170///
171/// The default constructor creates a stack having the capacity for one element
172/// (the implementation of the destructor is not shown):
173/// @code
174/// // doublestack.cpp
175/// // ...
176///
177/// // TYPES
178/// enum { k_INITIAL_CAPACITY = 1, k_GROWTH_FACTOR = 2 };
179///
180/// // CREATORS
181/// DoubleStack::DoubleStack(bslma::Allocator *basicAllocator)
182/// : d_stack_p(0)
183/// , d_capacity(k_INITIAL_CAPACITY)
184/// , d_length(0)
185/// , d_allocator_p(bslma::Default::allocator(basicAllocator))
186/// {
187/// d_stack_p = (double **)
188/// d_allocator_p->allocate(d_capacity * sizeof *d_stack_p);
189/// }
190/// @endcode
191/// The `push` method first ensures that the array has sufficient capacity to
192/// accommodate an additional value, then allocates a block in which to store
193/// that value:
194/// @code
195/// // MANIPULATORS
196/// void DoubleStack::push(double value)
197/// {
198/// if (d_length >= d_capacity) {
199/// increaseCapacity();
200/// }
201/// double *stackValue = (double *)d_allocator_p->allocate(sizeof(double));
202/// *stackValue = value;
203/// d_stack_p[d_length] = stackValue;
204/// ++d_length;
205/// }
206/// @endcode
207/// The `pop` method asserts that the stack is not empty before deallocating the
208/// block used to store the element at the top of the stack:
209/// @code
210/// void DoubleStack::pop()
211/// {
212/// BSLS_ASSERT(0 < d_length);
213///
214/// d_allocator_p->deallocate(d_stack_p[d_length - 1]);
215/// --d_length;
216/// }
217/// @endcode
218/// The `push` method (above) made use of the private `increaseCapacity` method,
219/// which, in turn, makes use of the `reallocate` helper function (`static` to
220/// the `.cpp` file). Note that `increaseCapacity` (below) increases the
221/// capacity of the `double *` array by a factor of 2 each time that it is
222/// called:
223/// @code
224/// // HELPER FUNCTIONS
225///
226/// /// Reallocate memory in the specified `array` to accommodate the
227/// /// specified `newCapacity` elements using the specified `allocator`.
228/// /// The specified `length` number of leading elements are preserved.
229/// /// The behavior is undefined unless `newCapacity > length`.
230/// static
231/// void reallocate(double ***array,
232/// int newCapacity,
233/// int length,
234/// bslma::Allocator *allocator)
235/// {
236/// BSLS_ASSERT(newCapacity > length);
237///
238/// double **tmp = *array;
239/// *array = (double **)allocator->allocate(newCapacity * sizeof **array);
240/// bsl::memcpy(*array, tmp, length * sizeof **array); // commit
241/// allocator->deallocate(tmp);
242/// }
243///
244/// // PRIVATE MANIPULATORS
245/// void DoubleStack::increaseCapacity()
246/// {
247/// const int newCapacity = d_capacity * k_GROWTH_FACTOR;
248/// // reallocate can throw
249/// reallocate(&d_stack_p, newCapacity, d_length, d_allocator_p);
250/// d_capacity = newCapacity; // commit
251/// }
252/// @endcode
253/// Now, we are ready to employ a `CountingAllocator` to illustrate the dynamic
254/// memory use of `DoubleStack`. We first define two constants that facilitate
255/// portability of this example across 32- and 64-bit platforms:
256/// @code
257/// const int DBLSZ = sizeof(double);
258/// const int PTRSZ = sizeof(double *);
259/// @endcode
260/// First, we define a `CountingAllocator`, `ca`. At construction, a counting
261/// allocator can be configured with an optional name and an optional allocator.
262/// In this case, we give `ca` a name to distinguish it from other counting
263/// allocators, but settle for using the default allocator:
264/// @code
265/// bdlma::CountingAllocator ca("'DoubleStack' Allocator");
266/// @endcode
267/// Next, we create a `DoubleStack`, supplying it with `ca`, and assert the
268/// expected memory use incurred by the default constructor:
269/// @code
270/// DoubleStack stack(&ca);
271/// assert(1 * PTRSZ == ca.numBytesInUse());
272/// assert(1 * PTRSZ == ca.numBytesTotal());
273/// @endcode
274/// Next, we push an element onto the stack. The first push incurs an
275/// additional allocation to store (out-of-place) the value being inserted:
276/// @code
277/// stack.push(1.54); assert(1 * PTRSZ + 1 * DBLSZ == ca.numBytesInUse());
278/// assert(1 * PTRSZ + 1 * DBLSZ == ca.numBytesTotal());
279/// @endcode
280/// Next, we push a second element onto the stack. In this case, two
281/// allocations result, one due to the resizing of the internal array and one
282/// required to store the new value out-of-place:
283/// @code
284/// stack.push(0.99); assert(2 * PTRSZ + 2 * DBLSZ == ca.numBytesInUse());
285/// assert(3 * PTRSZ + 2 * DBLSZ == ca.numBytesTotal());
286/// @endcode
287/// Next, we pop the top-most element from the stack. The number of bytes in
288/// use decreases by the amount used to store the popped element out-of-place:
289/// @code
290/// stack.pop(); assert(2 * PTRSZ + 1 * DBLSZ == ca.numBytesInUse());
291/// assert(3 * PTRSZ + 2 * DBLSZ == ca.numBytesTotal());
292/// @endcode
293/// Finally, we print the state of `ca` to standard output:
294/// @code
295/// ca.print(bsl::cout);
296/// @endcode
297/// which displays the following on a 32-bit platform:
298/// @code
299/// ----------------------------------------
300/// Counting Allocator State
301/// ----------------------------------------
302/// Allocator name: 'DoubleStack' Allocator
303/// Bytes in use: 16
304/// Bytes in total: 28
305/// @endcode
306/// @}
307/** @} */
308/** @} */
309
310/** @addtogroup bdl
311 * @{
312 */
313/** @addtogroup bdlma
314 * @{
315 */
316/** @addtogroup bdlma_countingallocator
317 * @{
318 */
319
320#include <bdlscm_version.h>
321
322#include <bslma_allocator.h>
323
324#include <bsls_atomic.h>
325#include <bsls_keyword.h>
326#include <bsls_types.h>
327
328#include <bsl_iosfwd.h>
329
330
331namespace bdlma {
332
333 // =======================
334 // class CountingAllocator
335 // =======================
336
337/// This class defines a concrete "counting" allocator mechanism that
338/// implements the `bslma::Allocator` protocol, and provides instrumentation
339/// to track: (1) the number of bytes currently in use, and (2) the
340/// cumulative number of bytes that have ever been allocated. The
341/// accumulated statistics are based solely on the number of bytes requested
342/// (see `allocate`).
343///
344///
345/// \note Note that, like many other allocators, this allocator relies on the
346/// currently installed default allocator (see @ref bslma_default ). Clients
347/// may, however, override this allocator by supplying (at construction) any
348/// other allocator implementing the `bslma::Allocator` protocol provided
349/// that it is fully thread-safe.
350///
351/// See @ref bdlma_countingallocator
353
354 // DATA
355 const char *d_name_p; // optionally specified name of this
356 // allocator object (or 0)
357
358 bsls::AtomicInt64 d_numBytesInUse; // number of bytes currently allocated
359 // from this object
360
361 bsls::AtomicInt64 d_numBytesTotal; // cumulative number of bytes ever
362 // allocated from this object
363
364 bslma::Allocator *d_allocator_p; // memory allocator (held, not owned)
365
366 private:
367 // NOT IMPLEMENTED
369 CountingAllocator& operator=(const CountingAllocator&);
370
371 public:
372 // CREATORS
373
374 /// Create a counting allocator. Optionally specify a `name`
375 /// (associated with this object) to be included in messages output by
376 /// the `print` method, thereby distinguishing this counting allocator
377 /// from others that might be used in the same program. If `name` is 0
378 /// (or not specified), no distinguishing name is incorporated in
379 /// `print` output. Optionally specify a `basicAllocator` used to
380 /// supply memory. If `basicAllocator` is 0, the currently installed
381 /// default allocator is used.
382 explicit
384 explicit
385 CountingAllocator(const char *name, bslma::Allocator *basicAllocator = 0);
386
387 /// Destroy this allocator object.
388 /// \note Note that destroying this allocator
389 /// has no effect on any outstanding allocated memory.
391
392 // MANIPULATORS
393
394 /// Return a newly-allocated block of memory of the specified `size` (in
395 /// bytes). If `size` is 0, a null pointer is returned with no other
396 /// effect (e.g., on allocation statistics). Otherwise, invoke the
397 /// `allocate` method of the allocator supplied at construction, and
398 /// increment the number of currently (and cumulatively) allocated bytes
399 /// by `size`.
401
402 /// Return the memory block at the specified `address` back to this
403 /// allocator. If `address` is 0, this function has no effect (e.g., on
404 /// allocation statistics). Otherwise, decrease the number of currently
405 /// allocated bytes by the size originally requested for the block.
406 ///
407 /// \pre The behavior is undefined unless `address` was allocated using this
408 /// allocator object and has not already been deallocated.
410
411 // ACCESSORS
412
413 /// Return the name of this counting allocator, or 0 if no name was
414 /// specified at construction.
415 const char *name() const;
416
417 /// Return the number of bytes currently allocated from this object.
418 ///
419 /// \note Note that `numBytesInUse() <= numBytesTotal()`.
420 bsls::Types::Int64 numBytesInUse() const;
421
422 /// Return the cumulative number of bytes ever allocated from this object.
423 ///
424 /// \note Note that `numBytesInUse() <= numBytesTotal()`.
425 bsls::Types::Int64 numBytesTotal() const;
426
427 /// Write the accumulated state information held in this allocator to
428 /// the specified `stream` in some reasonable (multi-line) format, and
429 /// return a reference to `stream`.
430 bsl::ostream& print(bsl::ostream& stream) const;
431};
432
433// ============================================================================
434// INLINE DEFINITIONS
435// ============================================================================
436
437 // -----------------------
438 // class CountingAllocator
439 // -----------------------
440
441// ACCESSORS
442inline
443const char *CountingAllocator::name() const
444{
445 return d_name_p;
446}
447
448inline
450{
451 return d_numBytesInUse.loadRelaxed();
452}
453
454inline
456{
457 return d_numBytesTotal.loadRelaxed();
458}
459
460} // close package namespace
461
462
463#endif
464
465// ----------------------------------------------------------------------------
466// Copyright 2016 Bloomberg Finance L.P.
467//
468// Licensed under the Apache License, Version 2.0 (the "License");
469// you may not use this file except in compliance with the License.
470// You may obtain a copy of the License at
471//
472// http://www.apache.org/licenses/LICENSE-2.0
473//
474// Unless required by applicable law or agreed to in writing, software
475// distributed under the License is distributed on an "AS IS" BASIS,
476// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
477// See the License for the specific language governing permissions and
478// limitations under the License.
479// ----------------------------- END-OF-FILE ----------------------------------
480
481/** @} */
482/** @} */
483/** @} */
Definition bdlma_countingallocator.h:352
void * allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE
CountingAllocator(bslma::Allocator *basicAllocator=0)
const char * name() const
Definition bdlma_countingallocator.h:443
bsls::Types::Int64 numBytesTotal() const
Definition bdlma_countingallocator.h:455
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE
~CountingAllocator() BSLS_KEYWORD_OVERRIDE
CountingAllocator(const char *name, bslma::Allocator *basicAllocator=0)
bsls::Types::Int64 numBytesInUse() const
Definition bdlma_countingallocator.h:449
Definition bslma_allocator.h:545
std::size_t size_type
Definition bslma_allocator.h:593
Definition bsls_atomic.h:896
Types::Int64 loadRelaxed() const
Definition bsls_atomic.h:1935
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition bdlma_alignedallocator.h:278
Definition bdlat_valuetypefunctions.h:939
Definition bdlt_iso8601util.h:707
long long Int64
Definition bsls_types.h:134