BDE 4.39.x 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/// /// This `class` provides a concrete buffer allocator that implements
88/// /// the `bdlma::ManagedAllocator` protocol.
89/// class my_BufferAllocator : public bdlma::ManagedAllocator {
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///
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/// my_BufferAllocator(char *buffer, bsls::Types::size_type bufferSize);
113///
114/// /// Destroy this buffer allocator.
115/// ~my_BufferAllocator();
116///
117/// // MANIPULATORS
118///
119/// /// Return the address of a maximally-aligned contiguous block of
120/// /// memory of the specified `size` (in bytes) on success, and 0 if
121/// /// the allocation request exceeds the remaining free memory space
122/// /// in the external buffer.
123/// void *allocate(bsls::Types::size_type size);
124///
125/// /// This method has no effect for this buffer allocator.
126/// void deallocate(void *address);
127///
128/// /// Release all memory allocated through this object. This allocator
129/// /// is reset to the state it was in immediately following construction.
130/// void release();
131/// };
132/// @endcode
133/// Next, we define the `inline` methods of `my_BufferAllocator`. Note that the
134/// `release` method resets the internal cursor to 0, effectively making the
135/// memory from the entire external buffer supplied at construction available
136/// for subsequent allocations, but has no effect on the contents of the buffer:
137/// @code
138/// // CREATORS
139/// inline
140/// my_BufferAllocator::my_BufferAllocator(char *buffer,
141/// bsls::Types::size_type bufferSize)
142/// : d_buffer_p(buffer)
143/// , d_bufferSize(bufferSize)
144/// , d_cursor(0)
145/// {
146/// }
147///
148/// // MANIPULATORS
149/// inline
150/// void my_BufferAllocator::deallocate(void *)
151/// {
152/// }
153///
154/// inline
155/// void my_BufferAllocator::release()
156/// {
157/// d_cursor = 0;
158/// }
159/// @endcode
160/// Finally, we provide the implementation of the `my_BufferAllocator` methods
161/// that are defined in the `.cpp` file. A `static` helper function,
162/// `allocateFromBufferImp`, provides the bulk of the implementation of the
163/// `allocate` method:
164/// @code
165/// // my_bufferallocator.cpp
166///
167/// // STATIC HELPER FUNCTIONS
168///
169/// /// Allocate a maximally-aligned memory block of the specified `size`
170/// /// (in bytes) from the specified `buffer` having the specified
171/// /// `bufferSize` (in bytes) at the specified `cursor` position. Return
172/// /// the address of the allocated memory block if `buffer` contains
173/// /// sufficient available memory, and 0 otherwise. The `cursor` is set
174/// /// to the first byte position immediately after the allocated memory if
175/// /// there is sufficient memory, and not modified otherwise. The
176/// /// behavior is undefined unless `0 < size`, `0 <= *cursor`, and
177/// /// `*cursor <= bufferSize`.
178/// static
179/// void *allocateFromBufferImp(bsls::Types::IntPtr *cursor,
180/// char *buffer,
181/// bsls::Types::size_type bufferSize,
182/// bsls::Types::size_type size)
183/// {
184/// const int offset = bsls::AlignmentUtil::calculateAlignmentOffset(
185/// buffer + *cursor,
186/// bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT);
187///
188/// if (*cursor + offset + size > bufferSize) { // insufficient space
189/// return 0; // RETURN
190/// }
191///
192/// void *result = &buffer[*cursor + offset];
193/// *cursor += offset + size;
194///
195/// return result;
196/// }
197///
198/// // CREATORS
199/// my_BufferAllocator::~my_BufferAllocator()
200/// {
201/// }
202///
203/// // MANIPULATORS
204/// void *my_BufferAllocator::allocate(bsls::Types::size_type size)
205/// {
206/// return 0 == size ? 0 : allocateFromBufferImp(&d_cursor,
207/// d_buffer_p,
208/// d_bufferSize,
209/// static_cast<int>(size));
210/// }
211/// @endcode
212///
213/// ### Example 2: Using the bdlma::ManagedAllocator Protocol {#bdlma_managedallocator-example-2-using-the-bdlma-managedallocator-protocol}
214///
215///
216/// In this second usage example, we illustrate how the managed allocator that
217/// was defined in Example 1, `my_BufferAllocator`, may be used. Note that
218/// substantial portions of the sample implementation are elided as they would
219/// only add unnecessary complications to the usage example. The portions shown
220/// are sufficient to illustrate the use of `bdlma::ManagedAllocator`.
221///
222/// The domain of our example is financial markets. Suppose that we are given a
223/// list of market indices (e.g., Dow Jones Industrial Average, S&P 500, etc.),
224/// and we want to perform some computation on each index, in turn. In this
225/// example, the essential attributes of an index are held in a `bsl::pair`
226/// consisting of the name of the index (e.g., "DJIA") and the number of
227/// securities that comprise the index (e.g., 30 in the case of the DJIA). The
228/// collection of market indices that we wish to process is given by a vector of
229/// such pairs. Thus, we make use of these types related to indices:
230/// @code
231/// typedef bsl::pair<const char *, int> IndexAttributes;
232/// typedef bsl::vector<IndexAttributes> IndexCollection;
233/// @endcode
234/// In our example, a security is defined by the unconstrained attribute type
235/// `my_SecurityAttributes`, the interface and implementation of which is elided
236/// except we note that it uses `bslma` allocators:
237/// @code
238/// class my_SecurityAttributes {
239/// // ...
240///
241/// public:
242/// // TRAITS
243/// BSLMF_NESTED_TRAIT_DECLARATION(my_SecurityAttributes,
244/// bslma::UsesBslmaAllocator);
245///
246/// // ...
247/// };
248/// @endcode
249/// For the collection of securities comprising an index we use a vector of
250/// `my_SecurityAttributes`:
251/// @code
252/// typedef bsl::vector<my_SecurityAttributes> SecurityCollection;
253/// @endcode
254/// Since some indices are quite large (e.g., Russell 3000, Wilshire 5000), for
255/// performance reasons it is advantageous for a `SecurityCollection` to use an
256/// efficient memory allocation strategy. This is where `my_BufferAllocator`
257/// comes into play, which we will see shortly.
258///
259/// The top-level function in our example takes a `bdlma::ManagedAllocator *`
260/// and the collection of market indices that we wish to process:
261/// @code
262/// /// Process the specified market `indices` using the specified
263/// /// `managedAllocator` to supply memory.
264/// static
265/// void processIndices(bdlma::ManagedAllocator *managedAllocator,
266/// const IndexCollection& indices);
267/// @endcode
268/// `processIndices` makes use of two helper functions to process each index:
269/// @code
270/// /// Load into the specified collection of `securities` the attributes of
271/// /// the securities comprising the specified market `index` using the
272/// /// specified `managedAllocator` to supply memory.
273/// static
274/// void loadIndex(SecurityCollection *securities,
275/// bdlma::ManagedAllocator *managedAllocator,
276/// const IndexAttributes& index);
277///
278/// /// Process the specified collection of `securities` that comprise the
279/// /// specified market `index`.
280/// static
281/// void processIndex(const SecurityCollection& securities,
282/// const IndexAttributes& index);
283/// @endcode
284/// Since we plan to use `my_BufferAllocator` as our managed allocator, we need
285/// to supply it with an external buffer. The `calculateMaxBufferSize` function
286/// computes the size of the buffer required to store the `SecurityCollection`
287/// corresponding to the largest index to be processed by a given call to
288/// `processIndices`:
289/// @code
290/// /// Return the maximum buffer size (in bytes) required to process the
291/// /// specified collection of market `indices`.
292/// int calculateMaxBufferSize(const IndexCollection& indices);
293/// @endcode
294/// Before showing the implementation of `processIndices`, where the most
295/// interesting use of our managed allocator takes place, we show the site of
296/// the call to `processIndices`.
297///
298/// First, assume that we have been given an `IndexCollection` that has been
299/// populated with one or more `IndexAttributes`:
300/// @code
301/// IndexCollection indices; // assume populated
302/// @endcode
303/// Next, we calculate the size of the buffer that is needed, allocate the
304/// memory for the buffer from the default allocator, create our concrete
305/// managed allocator (namely, an instance of `my_BufferAllocator`), and call
306/// `processIndices`:
307/// @code
308/// const int bufferSize = calculateMaxBufferSize(indices);
309///
310/// bslma::Allocator *allocator = bslma::Default::defaultAllocator();
311/// char *buffer = static_cast<char *>(allocator->allocate(bufferSize));
312///
313/// my_BufferAllocator bufferAllocator(buffer, bufferSize);
314///
315/// processIndices(&bufferAllocator, indices);
316/// @endcode
317/// Next, we show the implementation of `processIndices`, within which we
318/// iterate over the market `indices` that are passed to it:
319/// @code
320/// /// Process the specified market `indices` using the specified
321/// /// `managedAllocator` to supply memory.
322/// static
323/// void processIndices(bdlma::ManagedAllocator *managedAllocator,
324/// const IndexCollection& indices)
325/// {
326/// for (IndexCollection::const_iterator citer = indices.begin();
327/// citer != indices.end(); ++citer) {
328///
329/// @endcode
330/// For each index, the `SecurityCollection` comprising that index is created.
331/// All of the memory needs of the `SecurityCollection` are provided by the
332/// `managedAllocator`. Note that even the memory for the footprint of the
333/// collection comes from the `managedAllocator`:
334/// @code
335/// SecurityCollection *securities =
336/// new (managedAllocator->allocate(sizeof(SecurityCollection)))
337/// SecurityCollection(managedAllocator);
338///
339/// @endcode
340/// Next, we call `loadIndex` to populate `securities`, followed by the call to
341/// `processIndex`. `loadIndex` also uses the `managedAllocator`, the details
342/// of which are not shown here:
343/// @code
344/// loadIndex(securities, managedAllocator, *citer);
345///
346/// processIndex(*securities, *citer);
347/// @endcode
348/// After the index is processed, `release` is called on the managed allocator
349/// making all of the buffer supplied to the allocator at construction available
350/// for reuse:
351/// @code
352/// managedAllocator->release();
353/// }
354/// @endcode
355/// Finally, we let the `SecurityCollection` used to process the index go out of
356/// scope intentionally without deleting `securities`. The call to `release`
357/// renders superfluous the need to call the `SecurityCollection` destructor as
358/// well as the destructor of the contained `my_SecurityAttributes` elements.
359/// @code
360/// }
361/// @endcode
362/// @}
363/** @} */
364/** @} */
365
366/** @addtogroup bdl
367 * @{
368 */
369/** @addtogroup bdlma
370 * @{
371 */
372/** @addtogroup bdlma_managedallocator
373 * @{
374 */
375
376#include <bdlscm_version.h>
377
378#include <bslma_allocator.h>
379
380
381namespace bdlma {
382
383 // ======================
384 // class ManagedAllocator
385 // ======================
386
387/// This protocol class extends `bslma::Allocator` for allocators with the
388/// ability to `release` all memory currently allocated through the protocol
389/// back to the memory supplier of the derived concrete allocator object.
390///
391/// See @ref bdlma_managedallocator
393
394 public:
395 // MANIPULATORS
396
397 /// Release all memory currently allocated through this allocator. The
398 /// effect of using a pointer after this call that was obtained from
399 /// this allocator before this call is undefined.
400 virtual void release() = 0;
401};
402
403} // close package namespace
404
405
406#endif
407
408// ----------------------------------------------------------------------------
409// Copyright 2016 Bloomberg Finance L.P.
410//
411// Licensed under the Apache License, Version 2.0 (the "License");
412// you may not use this file except in compliance with the License.
413// You may obtain a copy of the License at
414//
415// http://www.apache.org/licenses/LICENSE-2.0
416//
417// Unless required by applicable law or agreed to in writing, software
418// distributed under the License is distributed on an "AS IS" BASIS,
419// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
420// See the License for the specific language governing permissions and
421// limitations under the License.
422// ----------------------------- END-OF-FILE ----------------------------------
423
424/** @} */
425/** @} */
426/** @} */
Definition bdlma_managedallocator.h:392
virtual void release()=0
Definition bslma_allocator.h:545
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlma_alignedallocator.h:278