BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_managedallocator.h
Go to the documentation of this file.
1/// @file bdlma_managedallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_managedallocator.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_MANAGEDALLOCATOR
9#define INCLUDED_BDLMA_MANAGEDALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_managedallocator bdlma_managedallocator
15/// @brief Provide a protocol for memory allocators that support `release`.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_managedallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_managedallocator-purpose"> Purpose</a>
25/// * <a href="#bdlma_managedallocator-classes"> Classes </a>
26/// * <a href="#bdlma_managedallocator-description"> Description </a>
27/// * <a href="#bdlma_managedallocator-usage"> Usage </a>
28/// * <a href="#bdlma_managedallocator-example-1-implementing-the-bdlma-managedallocator-protocol"> Example 1: Implementing the bdlma::ManagedAllocator Protocol </a>
29/// * <a href="#bdlma_managedallocator-example-2-using-the-bdlma-managedallocator-protocol"> Example 2: Using the bdlma::ManagedAllocator Protocol </a>
30///
31/// # Purpose {#bdlma_managedallocator-purpose}
32/// Provide a protocol for memory allocators that support `release`.
33///
34/// # Classes {#bdlma_managedallocator-classes}
35///
36/// - bdlma::ManagedAllocator: protocol for allocators with `release` capability
37///
38/// @see bdlma_bufferedsequentialallocator
39///
40/// # Description {#bdlma_managedallocator-description}
41/// This component provides a `class`, `bdlma::ManagedAllocator`,
42/// that extends the `bslma::Allocator` protocol to allocators that support the
43/// ability to `release` all memory currently allocated through the protocol
44/// back to the memory supplier of the derived concrete allocator object.
45/// @code
46/// ,-----------------------.
47/// ( bdlma::ManagedAllocator )
48/// `-----------------------'
49/// | release
50/// |
51/// v
52/// ,----------------.
53/// ( bslma::Allocator )
54/// `----------------'
55/// allocate
56/// deallocate
57/// @endcode
58///
59/// ## Usage {#bdlma_managedallocator-usage}
60///
61///
62/// This section illustrates intended use of this component.
63///
64/// ### Example 1: Implementing the bdlma::ManagedAllocator Protocol {#bdlma_managedallocator-example-1-implementing-the-bdlma-managedallocator-protocol}
65///
66///
67/// The `bdlma::ManagedAllocator` interface is especially useful for allocators
68/// that are based on an underlying pooling mechanism (e.g., `bdlma::Multipool`
69/// or `bdlma::BufferedSequentialPool`). In particular, such an allocator that
70/// implements the `bdlma::ManagedAllocator` interface can release, via the
71/// `release` method, all outstanding (pooled) memory back to the underlying
72/// allocator making the memory available for subsequent reuse. Moreover, use
73/// of the `release` method can also often render superfluous the running of
74/// destructors on the objects making use of a managed allocator. In this first
75/// usage example, we define the `my_BufferAllocator` class, an allocator that
76/// implements the `bdlma::ManagedAllocator` interface. `my_BufferAllocator` is
77/// a considerably pared down version of `bdlma::BufferedSequentialAllocator`,
78/// and is intended for illustration purposes only. Please see the
79/// @ref bdlma_bufferedsequentialallocator component for full documentation of
80/// `bdlma::BufferedSequentialAllocator`, a managed allocator meant for
81/// production use.
82///
83/// First, we define the interface of the `my_BufferAllocator` class:
84/// @code
85/// // my_bufferallocator.h
86///
87/// class my_BufferAllocator : public bdlma::ManagedAllocator {
88/// // This 'class' provides a concrete buffer allocator that implements
89/// // the 'bdlma::ManagedAllocator' protocol.
90///
91/// // DATA
92/// char *d_buffer_p; // external buffer (held, not
93/// // owned)
94///
95/// bsls::Types::size_type d_bufferSize; // size (in bytes) of external
96/// // buffer
97///
98/// bsls::Types::IntPtr d_cursor; // offset to next available byte
99/// // in buffer
100///
101/// private:
102/// // NOT IMPLEMENTED
103/// my_BufferAllocator(const my_BufferAllocator&);
104/// my_BufferAllocator& operator=(const my_BufferAllocator&);
105///
106/// public:
107/// // CREATORS
108/// my_BufferAllocator(char *buffer, bsls::Types::size_type bufferSize);
109/// // Create a buffer allocator for allocating maximally-aligned
110/// // memory blocks from the specified external 'buffer' having the
111/// // specified 'bufferSize' (in bytes).
112///
113/// ~my_BufferAllocator();
114/// // Destroy this buffer allocator.
115///
116/// // MANIPULATORS
117/// void *allocate(bsls::Types::size_type size);
118/// // Return the address of a maximally-aligned contiguous block of
119/// // memory of the specified 'size' (in bytes) on success, and 0 if
120/// // the allocation request exceeds the remaining free memory space
121/// // in the external buffer.
122///
123/// void deallocate(void *address);
124/// // This method has no effect for this buffer allocator.
125///
126/// void release();
127/// // Release all memory allocated through this object. This
128/// // allocator is reset to the state it was in immediately following
129/// // construction.
130/// };
131/// @endcode
132/// Next, we define the `inline` methods of `my_BufferAllocator`. Note that the
133/// `release` method resets the internal cursor to 0, effectively making the
134/// memory from the entire external buffer supplied at construction available
135/// for subsequent allocations, but has no effect on the contents of the buffer:
136/// @code
137/// // CREATORS
138/// inline
139/// my_BufferAllocator::my_BufferAllocator(char *buffer,
140/// bsls::Types::size_type bufferSize)
141/// : d_buffer_p(buffer)
142/// , d_bufferSize(bufferSize)
143/// , d_cursor(0)
144/// {
145/// }
146///
147/// // MANIPULATORS
148/// inline
149/// void my_BufferAllocator::deallocate(void *)
150/// {
151/// }
152///
153/// inline
154/// void my_BufferAllocator::release()
155/// {
156/// d_cursor = 0;
157/// }
158/// @endcode
159/// Finally, we provide the implementation of the `my_BufferAllocator` methods
160/// that are defined in the `.cpp` file. A `static` helper function,
161/// `allocateFromBufferImp`, provides the bulk of the implementation of the
162/// `allocate` method:
163/// @code
164/// // my_bufferallocator.cpp
165///
166/// // STATIC HELPER FUNCTIONS
167/// static
168/// void *allocateFromBufferImp(bsls::Types::IntPtr *cursor,
169/// char *buffer,
170/// bsls::Types::size_type bufferSize,
171/// bsls::Types::size_type size)
172/// // Allocate a maximally-aligned memory block of the specified 'size'
173/// // (in bytes) from the specified 'buffer' having the specified
174/// // 'bufferSize' (in bytes) at the specified 'cursor' position. Return
175/// // the address of the allocated memory block if 'buffer' contains
176/// // sufficient available memory, and 0 otherwise. The 'cursor' is set
177/// // to the first byte position immediately after the allocated memory if
178/// // there is sufficient memory, and not modified otherwise. The
179/// // behavior is undefined unless '0 < size', '0 <= *cursor', and
180/// // '*cursor <= bufferSize'.
181///
182/// {
183/// const int offset = bsls::AlignmentUtil::calculateAlignmentOffset(
184/// buffer + *cursor,
185/// bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT);
186///
187/// if (*cursor + offset + size > bufferSize) { // insufficient space
188/// return 0; // RETURN
189/// }
190///
191/// void *result = &buffer[*cursor + offset];
192/// *cursor += offset + size;
193///
194/// return result;
195/// }
196///
197/// // CREATORS
198/// my_BufferAllocator::~my_BufferAllocator()
199/// {
200/// }
201///
202/// // MANIPULATORS
203/// void *my_BufferAllocator::allocate(bsls::Types::size_type size)
204/// {
205/// return 0 == size ? 0 : allocateFromBufferImp(&d_cursor,
206/// d_buffer_p,
207/// d_bufferSize,
208/// static_cast<int>(size));
209/// }
210/// @endcode
211///
212/// ### Example 2: Using the bdlma::ManagedAllocator Protocol {#bdlma_managedallocator-example-2-using-the-bdlma-managedallocator-protocol}
213///
214///
215/// In this second usage example, we illustrate how the managed allocator that
216/// was defined in Example 1, `my_BufferAllocator`, may be used. Note that
217/// substantial portions of the sample implementation are elided as they would
218/// only add unnecessary complications to the usage example. The portions shown
219/// are sufficient to illustrate the use of `bdlma::ManagedAllocator`.
220///
221/// The domain of our example is financial markets. Suppose that we are given a
222/// list of market indices (e.g., Dow Jones Industrial Average, S&P 500, etc.),
223/// and we want to perform some computation on each index, in turn. In this
224/// example, the essential attributes of an index are held in a `bsl::pair`
225/// consisting of the name of the index (e.g., "DJIA") and the number of
226/// securities that comprise the index (e.g., 30 in the case of the DJIA). The
227/// collection of market indices that we wish to process is given by a vector of
228/// such pairs. Thus, we make use of these types related to indices:
229/// @code
230/// typedef bsl::pair<const char *, int> IndexAttributes;
231/// typedef bsl::vector<IndexAttributes> IndexCollection;
232/// @endcode
233/// In our example, a security is defined by the unconstrained attribute type
234/// `my_SecurityAttributes`, the interface and implementation of which is elided
235/// except we note that it uses `bslma` allocators:
236/// @code
237/// class my_SecurityAttributes {
238/// // ...
239///
240/// public:
241/// // TRAITS
242/// BSLMF_NESTED_TRAIT_DECLARATION(my_SecurityAttributes,
243/// bslma::UsesBslmaAllocator);
244///
245/// // ...
246/// };
247/// @endcode
248/// For the collection of securities comprising an index we use a vector of
249/// `my_SecurityAttributes`:
250/// @code
251/// typedef bsl::vector<my_SecurityAttributes> SecurityCollection;
252/// @endcode
253/// Since some indices are quite large (e.g., Russell 3000, Wilshire 5000), for
254/// performance reasons it is advantageous for a `SecurityCollection` to use an
255/// efficient memory allocation strategy. This is where `my_BufferAllocator`
256/// comes into play, which we will see shortly.
257///
258/// The top-level function in our example takes a `bdlma::ManagedAllocator *`
259/// and the collection of market indices that we wish to process:
260/// @code
261/// static
262/// void processIndices(bdlma::ManagedAllocator *managedAllocator,
263/// const IndexCollection& indices);
264/// // Process the specified market 'indices' using the specified
265/// // 'managedAllocator' to supply memory.
266/// @endcode
267/// `processIndices` makes use of two helper functions to process each index:
268/// @code
269/// static
270/// void loadIndex(SecurityCollection *securities,
271/// bdlma::ManagedAllocator *managedAllocator,
272/// const IndexAttributes& index);
273/// // Load into the specified collection of 'securities' the attributes of
274/// // the securities comprising the specified market 'index' using the
275/// // specified 'managedAllocator' to supply memory.
276///
277/// static
278/// void processIndex(const SecurityCollection& securities,
279/// const IndexAttributes& index);
280/// // Process the specified collection of 'securities' that comprise the
281/// // specified market 'index'.
282/// @endcode
283/// Since we plan to use `my_BufferAllocator` as our managed allocator, we need
284/// to supply it with an external buffer. The `calculateMaxBufferSize` function
285/// computes the size of the buffer required to store the `SecurityCollection`
286/// corresponding to the largest index to be processed by a given call to
287/// `processIndices`:
288/// @code
289/// int calculateMaxBufferSize(const IndexCollection& indices);
290/// // Return the maximum buffer size (in bytes) required to process the
291/// // specified collection of market 'indices'.
292/// @endcode
293/// Before showing the implementation of `processIndices`, where the most
294/// interesting use of our managed allocator takes place, we show the site of
295/// the call to `processIndices`.
296///
297/// First, assume that we have been given an `IndexCollection` that has been
298/// populated with one or more `IndexAttributes`:
299/// @code
300/// IndexCollection indices; // assume populated
301/// @endcode
302/// Next, we calculate the size of the buffer that is needed, allocate the
303/// memory for the buffer from the default allocator, create our concrete
304/// managed allocator (namely, an instance of `my_BufferAllocator`), and call
305/// `processIndices`:
306/// @code
307/// const int bufferSize = calculateMaxBufferSize(indices);
308///
309/// bslma::Allocator *allocator = bslma::Default::defaultAllocator();
310/// char *buffer = static_cast<char *>(allocator->allocate(bufferSize));
311///
312/// my_BufferAllocator bufferAllocator(buffer, bufferSize);
313///
314/// processIndices(&bufferAllocator, indices);
315/// @endcode
316/// Next, we show the implementation of `processIndices`, within which we
317/// iterate over the market `indices` that are passed to it:
318/// @code
319/// static
320/// void processIndices(bdlma::ManagedAllocator *managedAllocator,
321/// const IndexCollection& indices)
322/// // Process the specified market 'indices' using the specified
323/// // 'managedAllocator' to supply memory.
324/// {
325/// for (IndexCollection::const_iterator citer = indices.begin();
326/// citer != indices.end(); ++citer) {
327///
328/// @endcode
329/// For each index, the `SecurityCollection` comprising that index is created.
330/// All of the memory needs of the `SecurityCollection` are provided by the
331/// `managedAllocator`. Note that even the memory for the footprint of the
332/// collection comes from the `managedAllocator`:
333/// @code
334/// SecurityCollection *securities =
335/// new (managedAllocator->allocate(sizeof(SecurityCollection)))
336/// SecurityCollection(managedAllocator);
337///
338/// @endcode
339/// Next, we call `loadIndex` to populate `securities`, followed by the call to
340/// `processIndex`. `loadIndex` also uses the `managedAllocator`, the details
341/// of which are not shown here:
342/// @code
343/// loadIndex(securities, managedAllocator, *citer);
344///
345/// processIndex(*securities, *citer);
346/// @endcode
347/// After the index is processed, `release` is called on the managed allocator
348/// making all of the buffer supplied to the allocator at construction available
349/// for reuse:
350/// @code
351/// managedAllocator->release();
352/// }
353/// @endcode
354/// Finally, we let the `SecurityCollection` used to process the index go out of
355/// scope intentionally without deleting `securities`. The call to `release`
356/// renders superfluous the need to call the `SecurityCollection` destructor as
357/// well as the destructor of the contained `my_SecurityAttributes` elements.
358/// @code
359/// }
360/// @endcode
361/// @}
362/** @} */
363/** @} */
364
365/** @addtogroup bdl
366 * @{
367 */
368/** @addtogroup bdlma
369 * @{
370 */
371/** @addtogroup bdlma_managedallocator
372 * @{
373 */
374
375#include <bdlscm_version.h>
376
377#include <bslma_allocator.h>
378
379
380namespace bdlma {
381
382 // ======================
383 // class ManagedAllocator
384 // ======================
385
386/// This protocol class extends `bslma::Allocator` for allocators with the
387/// ability to `release` all memory currently allocated through the protocol
388/// back to the memory supplier of the derived concrete allocator object.
389///
390/// See @ref bdlma_managedallocator
392
393 public:
394 // MANIPULATORS
395
396 /// Release all memory currently allocated through this allocator. The
397 /// effect of using a pointer after this call that was obtained from
398 /// this allocator before this call is undefined.
399 virtual void release() = 0;
400};
401
402} // close package namespace
403
404
405#endif
406
407// ----------------------------------------------------------------------------
408// Copyright 2016 Bloomberg Finance L.P.
409//
410// Licensed under the Apache License, Version 2.0 (the "License");
411// you may not use this file except in compliance with the License.
412// You may obtain a copy of the License at
413//
414// http://www.apache.org/licenses/LICENSE-2.0
415//
416// Unless required by applicable law or agreed to in writing, software
417// distributed under the License is distributed on an "AS IS" BASIS,
418// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
419// See the License for the specific language governing permissions and
420// limitations under the License.
421// ----------------------------- END-OF-FILE ----------------------------------
422
423/** @} */
424/** @} */
425/** @} */
Definition bdlma_managedallocator.h:391
virtual void release()=0
Definition bslma_allocator.h:457
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlma_alignedallocator.h:276