BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_bufferedsequentialallocator.h
Go to the documentation of this file.
1/// @file bdlma_bufferedsequentialallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_bufferedsequentialallocator.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_BUFFEREDSEQUENTIALALLOCATOR
9#define INCLUDED_BDLMA_BUFFEREDSEQUENTIALALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_bufferedsequentialallocator bdlma_bufferedsequentialallocator
15/// @brief Provide an efficient managed allocator using an external buffer.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_bufferedsequentialallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_bufferedsequentialallocator-purpose"> Purpose</a>
25/// * <a href="#bdlma_bufferedsequentialallocator-classes"> Classes </a>
26/// * <a href="#bdlma_bufferedsequentialallocator-description"> Description </a>
27/// * <a href="#bdlma_bufferedsequentialallocator-optional-maxbuffersize-parameter"> Optional maxBufferSize Parameter </a>
28/// * <a href="#bdlma_bufferedsequentialallocator-warning"> Warning </a>
29/// * <a href="#bdlma_bufferedsequentialallocator-usage"> Usage </a>
30/// * <a href="#bdlma_bufferedsequentialallocator-example-1-using-bdlma-bufferedsequentialallocator-with-exact-calculation"> Example 1: Using bdlma::BufferedSequentialAllocator with Exact Calculation </a>
31/// * <a href="#bdlma_bufferedsequentialallocator-example-2-using-bdlma-bufferedsequentialallocator-with-fallback"> Example 2: Using bdlma::BufferedSequentialAllocator with Fallback </a>
32///
33/// # Purpose {#bdlma_bufferedsequentialallocator-purpose}
34/// Provide an efficient managed allocator using an external buffer.
35///
36/// # Classes {#bdlma_bufferedsequentialallocator-classes}
37///
38/// - bdlma::BufferedSequentialAllocator: allocator using an external buffer
39///
40/// @see bdlma_bufferedsequentialpool, bdlma_sequentialallocator
41///
42/// # Description {#bdlma_bufferedsequentialallocator-description}
43/// This component provides a concrete mechanism,
44/// `bdlma::BufferedSequentialAllocator`, that implements the
45/// `bdlma::ManagedAllocator` protocol to very efficiently allocate
46/// heterogeneous memory blocks (of varying, user-specified sizes) from an
47/// external buffer supplied at construction:
48/// @code
49/// ,----------------------------------.
50/// ( bdlma::BufferedSequentialAllocator )
51/// `----------------------------------'
52/// | ctor/dtor
53/// | rewind
54/// |
55/// V
56/// ,-----------------------.
57/// ( bdlma::ManagedAllocator )
58/// `-----------------------'
59/// | release
60/// V
61/// ,----------------.
62/// ( bslma::Allocator )
63/// `----------------'
64/// allocate
65/// deallocate
66/// @endcode
67/// If an allocation request exceeds the remaining free memory space in the
68/// external buffer, the allocator will fall back to a sequence of
69/// dynamically-allocated buffers. Users can optionally specify a growth
70/// strategy at construction that governs the growth rate of the
71/// dynamically-allocated buffers. If no growth strategy is specified at
72/// construction, geometric growth is used. Users can also optionally specify
73/// an alignment strategy at construction that governs the alignment of
74/// allocated memory blocks. If no alignment strategy is specified at
75/// construction, natural alignment is used. The `release` method releases all
76/// memory allocated through the allocator, as does the destructor. The
77/// `rewind` method releases all memory allocated through the allocator and
78/// returns to the underlying allocator *only* memory that was allocated outside
79/// of the typical internal buffer growth of the allocator (i.e., large blocks).
80/// Note that individually allocated memory blocks cannot be separately
81/// deallocated.
82///
83/// `bdlma::BufferedSequentialAllocator` is typically used when users have a
84/// reasonable estimation of the amount of memory needed. This amount of memory
85/// would typically be created directly on the program stack, and used as the
86/// initial external buffer of the allocator for very fast memory allocation.
87/// While the buffer has sufficient capacity, memory allocations using the pool
88/// will not trigger *any* dynamic memory allocation, will have optimal locality
89/// of reference, and will not require deallocation upon destruction.
90///
91/// Once the external buffer is exhausted, subsequent allocation requests
92/// require dynamic memory allocation, and the performance of the allocator
93/// degrades.
94///
95/// The main difference between a `bdlma::BufferedSequentialAllocator` and a
96/// `bdlma::BufferedSequentialPool` is that, very often, the allocator is
97/// maintained through a `bslma::Allocator` pointer - hence, every call to
98/// `allocate` is a virtual function call, which is slower than invoking
99/// `allocate` with the pool directly. However, the allocator interface is much
100/// more widely accepted across objects, and hence more general purpose.
101///
102/// ### Optional maxBufferSize Parameter {#bdlma_bufferedsequentialallocator-optional-maxbuffersize-parameter}
103///
104///
105/// An optional `maxBufferSize` parameter can be supplied at construction to
106/// specify the maximum size (in bytes) of the dynamically-allocated buffers for
107/// geometric growth. Once the internal buffer grows up to the `maxBufferSize`,
108/// further requests that exceed this size will be served by a separate memory
109/// block instead of the internal buffer. The behavior is undefined unless
110/// `size <= maxBufferSize`, where `size` is the extent (in bytes) of the
111/// external buffer supplied at construction.
112///
113/// ## Warning {#bdlma_bufferedsequentialallocator-warning}
114///
115///
116/// Note that, even when a buffer having `n` bytes of memory is supplied at
117/// construction, it does *not* mean that `n` bytes of memory are available
118/// before dynamic memory allocation is triggered. This is due to memory
119/// alignment requirements. If the buffer supplied is not aligned, the first
120/// call to the `allocate` method will automatically skip one or more bytes such
121/// that the memory allocated is properly aligned. The number of bytes that are
122/// wasted depends on whether natural alignment, maximum alignment, or 1-byte
123/// alignment is used (see @ref bsls_alignment for more details).
124///
125/// ## Usage {#bdlma_bufferedsequentialallocator-usage}
126///
127///
128/// This section illustrates intended use of this component.
129///
130/// ### Example 1: Using bdlma::BufferedSequentialAllocator with Exact Calculation {#bdlma_bufferedsequentialallocator-example-1-using-bdlma-bufferedsequentialallocator-with-exact-calculation}
131///
132///
133/// Suppose we need to implement a method, `calculate`, that performs
134/// calculations (where the specifics are not important to illustrate the use of
135/// this component), which require three vectors of `double` values.
136/// Furthermore, suppose we know that we need to store at most 100 values for
137/// each vector:
138/// @code
139/// double calculate(const bsl::vector<double>& data)
140/// {
141/// @endcode
142/// Since the amount of memory needed is known in advance, we can optimize the
143/// memory allocation by using a `bdlma::BufferedSequentialAllocator` to supply
144/// memory for the vectors. We can also prevent the vectors from resizing
145/// (which triggers more allocations) by reserving for the specific capacity we
146/// need:
147/// @code
148/// enum { k_SIZE = 3 * 100 * sizeof(double) };
149/// @endcode
150/// In the above calculation, we assume that the only memory allocation
151/// requested by the vector is the allocation for the array that stores the
152/// `double` values. Furthermore, we assume that the `reserve` method allocates
153/// the exact amount of memory for the number of items specified (in this case,
154/// of type `double`). Note that both of these assumptions are true for BDE's
155/// implementation of `bsl::vector`.
156///
157/// To avoid alignment issues described in the "Warning" section (above), we
158/// create a `bsls::AlignedBuffer`:
159/// @code
160/// bsls::AlignedBuffer<k_SIZE> bufferStorage;
161///
162/// bdlma::BufferedSequentialAllocator alloc(bufferStorage.buffer(),
163/// k_SIZE);
164///
165/// bsl::vector<double> v1(&alloc); v1.reserve(100);
166/// bsl::vector<double> v2(&alloc); v2.reserve(100);
167/// bsl::vector<double> v3(&alloc); v3.reserve(100);
168///
169/// return data.empty() ? 0.0 : data.front();
170/// }
171/// @endcode
172/// By making use of a `bdlma::BufferedSequentialAllocator`, *all* dynamic
173/// memory allocation is eliminated in the above example.
174///
175/// ### Example 2: Using bdlma::BufferedSequentialAllocator with Fallback {#bdlma_bufferedsequentialallocator-example-2-using-bdlma-bufferedsequentialallocator-with-fallback}
176///
177///
178/// Suppose we are receiving updates for price quotes for a list of securities
179/// through the following function:
180/// @code
181/// void receivePriceQuotes(bsl::map<bsl::string, double> *updateMap);
182/// // Load into the specified 'updateMap' updates for price quotes for a
183/// // list of securities.
184/// @endcode
185/// Furthermore, suppose the number of securities we are interested in is
186/// limited. We can then use a `bdlma::BufferedSequentialAllocator` to optimize
187/// memory allocation for the `bsl::map`. We first create a buffer on the
188/// stack:
189/// @code
190/// enum {
191/// k_NUM_SECURITIES = 100,
192///
193/// k_TREE_NODE_SIZE = sizeof(bsl::map<bsl::string, double>::value_type)
194/// + sizeof(void *) * 4,
195///
196/// k_AVERAGE_SECURITY_LENGTH = 5,
197///
198/// k_TOTAL_SIZE = k_NUM_SECURITIES *
199/// (k_TREE_NODE_SIZE + k_AVERAGE_SECURITY_LENGTH)
200/// };
201///
202/// bsls::AlignedBuffer<k_TOTAL_SIZE> bufferStorage;
203/// @endcode
204/// The calculation of the amount of memory needed is just an estimate, as we
205/// used the average security size instead of the maximum security size. We
206/// also assume that a `bsl::map`s node size is roughly the size of 4 pointers.
207/// @code
208/// bdlma::BufferedSequentialAllocator bsa(bufferStorage.buffer(),
209/// k_TOTAL_SIZE,
210/// &objectAllocator);
211/// bsl::map<bsl::string, double> updateMap(&bsa);
212///
213/// receivePriceQuotes(&updateMap);
214/// @endcode
215/// With the use of a `bdlma::BufferedSequentialAllocator`, we can be reasonably
216/// assured that the memory allocation performance is optimized (i.e., minimal
217/// use of dynamic allocation).
218/// @}
219/** @} */
220/** @} */
221
222/** @addtogroup bdl
223 * @{
224 */
225/** @addtogroup bdlma
226 * @{
227 */
228/** @addtogroup bdlma_bufferedsequentialallocator
229 * @{
230 */
231
232#include <bdlscm_version.h>
233
236
237#include <bslma_allocator.h>
238
239#include <bsls_alignment.h>
240#include <bsls_blockgrowth.h>
241#include <bsls_keyword.h>
242#include <bsls_performancehint.h>
243#include <bsls_types.h>
244
245
246namespace bdlma {
247
248 // =================================
249 // class BufferedSequentialAllocator
250 // =================================
251
252/// This class implements the `ManagedAllocator` protocol to provide a fast
253/// allocator that dispenses heterogeneous blocks of memory (of varying,
254/// user-specified sizes) from an external buffer whose address and size (in
255/// bytes) are supplied at construction. If an allocation request exceeds
256/// the remaining free memory space in the external buffer, memory will be
257/// supplied by an (optional) allocator also supplied at construction; if no
258/// allocator is supplied, the currently installed default allocator is
259/// used. This class is *exception* *neutral*: If memory cannot be
260/// allocated, the behavior is defined by the (optional) allocator supplied
261/// at construction. Note that in no case will the buffered sequential
262/// allocator attempt to deallocate the external buffer.
263///
264/// See @ref bdlma_bufferedsequentialallocator
266
267 // DATA
268 BufferedSequentialPool d_pool; // manager for allocated memory blocks
269
270 private:
271 // NOT IMPLEMENTED
274
275 public:
276 // CREATORS
277
278 BufferedSequentialAllocator(char *buffer,
280 bslma::Allocator *basicAllocator = 0);
282 char *buffer,
284 bsls::BlockGrowth::Strategy growthStrategy,
285 bslma::Allocator *basicAllocator = 0);
286 BufferedSequentialAllocator(char *buffer,
288 bsls::Alignment::Strategy alignmentStrategy,
289 bslma::Allocator *basicAllocator = 0);
290 /// Create a buffered sequential allocator for allocating memory blocks
291 /// from the specified external `buffer` having the specified `size` (in
292 /// bytes). Optionally specify a `growthStrategy` used to control
293 /// buffer growth. If a `growthStrategy` is not specified, geometric
294 /// growth is used. Optionally specify an `alignmentStrategy` used to
295 /// align allocated memory blocks. If an `alignmentStrategy` is not
296 /// specified, natural alignment is used. Optionally specify a
297 /// `basicAllocator` used to supply memory should the capacity of
298 /// `buffer` be exhausted. If `basicAllocator` is 0, the currently
299 /// installed default allocator is used. The behavior is undefined
300 /// unless `0 < size`, and `buffer` has at least `size` bytes. Note
301 /// that, due to alignment effects, it is possible that not all `size`
302 /// bytes of memory in `buffer` can be used for allocation. Also note
303 /// that no limit is imposed on the size of the internal buffers when
304 /// geometric growth is used. Also note that when constant growth is
305 /// used, the size of the internal buffers will always be the same as
306 /// `size`.
308 char *buffer,
310 bsls::BlockGrowth::Strategy growthStrategy,
311 bsls::Alignment::Strategy alignmentStrategy,
312 bslma::Allocator *basicAllocator = 0);
313
314 BufferedSequentialAllocator(char *buffer,
316 bsls::Types::size_type maxBufferSize,
317 bslma::Allocator *basicAllocator = 0);
319 char *buffer,
321 bsls::Types::size_type maxBufferSize,
322 bsls::BlockGrowth::Strategy growthStrategy,
323 bslma::Allocator *basicAllocator = 0);
324 BufferedSequentialAllocator(char *buffer,
326 bsls::Types::size_type maxBufferSize,
327 bsls::Alignment::Strategy alignmentStrategy,
328 bslma::Allocator *basicAllocator = 0);
329 /// Create a buffered sequential allocator for allocating memory blocks
330 /// from the specified external `buffer` having the specified `size` (in
331 /// bytes), or from an internal buffer (after the external `buffer` is
332 /// exhausted) where the buffer growth is limited to the specified
333 /// `maxBufferSize` (in bytes). Optionally specify a `growthStrategy`
334 /// used to control buffer growth. If a `growthStrategy` is not
335 /// specified, geometric growth is used. Optionally specify an
336 /// `alignmentStrategy` used to align allocated memory blocks. If an
337 /// `alignmentStrategy` is not specified, natural alignment is used.
338 /// Optionally specify a `basicAllocator` used to supply memory should
339 /// the capacity of `buffer` be exhausted. If `basicAllocator` is 0,
340 /// the currently installed default allocator is used. The behavior is
341 /// undefined unless `0 < size`, `size <= maxBufferSize`, and `buffer`
342 /// has at least `size` bytes. Note that, due to alignment effects, it
343 /// is possible that not all `size` bytes of memory in `buffer` can be
344 /// used for allocation. Also note that when constant growth is used,
345 /// the size of the internal buffers will always be the same as `size`.
347 char *buffer,
349 bsls::Types::size_type maxBufferSize,
350 bsls::BlockGrowth::Strategy growthStrategy,
351 bsls::Alignment::Strategy alignmentStrategy,
352 bslma::Allocator *basicAllocator = 0);
353
354 /// Destroy this buffered sequential allocator. All memory allocated
355 /// from this allocator is released.
357
358 // MANIPULATORS
359
360 /// Return the address of a contiguous block of memory of the specified
361 /// `size` (in bytes) according to the alignment strategy specified at
362 /// construction. If `size` is 0, no memory is allocated and 0 is
363 /// returned. If the allocation request exceeds the remaining free
364 /// memory space in the external buffer supplied at construction, use
365 /// memory obtained from the allocator supplied at construction.
367
368 /// This method has no effect on the memory block at the specified
369 /// `address` as all memory allocated by this allocator is managed. The
370 /// behavior is undefined unless `address` is 0, or was allocated by
371 /// this allocator and has not already been deallocated. The effect of
372 /// using `address` after this call is undefined.
373 void deallocate(void *address) BSLS_KEYWORD_OVERRIDE;
374
375 /// Release all memory allocated through this allocator and return to
376 /// the underlying allocator *all* memory except the external buffer
377 /// supplied at construction. The allocator is reset to its
378 /// default-constructed state, making the memory from the entire
379 /// external buffer supplied at construction available for subsequent
380 /// allocations, retaining the alignment and growth strategies, and the
381 /// initial and maximum buffer sizes in effect following construction.
382 /// The effect of subsequently - to this invokation of `release` - using
383 /// a pointer obtained from this object prior to this call to `release`
384 /// is undefined.
386
387 /// Release all memory allocated through this allocator and return to
388 /// the underlying allocator *only* memory that was allocated outside of
389 /// the typical internal buffer growth of this allocator (i.e., large
390 /// blocks). All retained memory will be used to satisfy subsequent
391 /// allocations. The effect of subsequently - to this invokation of
392 /// `rewind` - using a pointer obtained from this object prior to this
393 /// call to `rewind` is undefined.
394 virtual void rewind();
395
396 // ACCESSORS
397
398 /// Return the allocator passed at construction.
399 bslma::Allocator *allocator() const;
400};
401
402// ============================================================================
403// INLINE DEFINITIONS
404// ============================================================================
405
406 // ---------------------------------
407 // class BufferedSequentialAllocator
408 // ---------------------------------
409
410// CREATORS
411inline
413 char *buffer,
414 bsls::Types::size_type size,
415 bslma::Allocator *basicAllocator)
416: d_pool(buffer, size, basicAllocator)
417{
418}
419
420inline
421BufferedSequentialAllocator::BufferedSequentialAllocator(
422 char *buffer,
424 bsls::BlockGrowth::Strategy growthStrategy,
425 bslma::Allocator *basicAllocator)
426: d_pool(buffer, size, growthStrategy, basicAllocator)
427{
428}
429
430inline
431BufferedSequentialAllocator::BufferedSequentialAllocator(
432 char *buffer,
434 bsls::Alignment::Strategy alignmentStrategy,
435 bslma::Allocator *basicAllocator)
436: d_pool(buffer, size, alignmentStrategy, basicAllocator)
437{
438}
439
440inline
441BufferedSequentialAllocator::BufferedSequentialAllocator(
442 char *buffer,
444 bsls::BlockGrowth::Strategy growthStrategy,
445 bsls::Alignment::Strategy alignmentStrategy,
446 bslma::Allocator *basicAllocator)
447: d_pool(buffer, size, growthStrategy, alignmentStrategy, basicAllocator)
448{
449}
450
451inline
452BufferedSequentialAllocator::BufferedSequentialAllocator(
453 char *buffer,
455 bsls::Types::size_type maxBufferSize,
456 bslma::Allocator *basicAllocator)
457: d_pool(buffer, size, maxBufferSize, basicAllocator)
458{
459}
460
461inline
462BufferedSequentialAllocator::BufferedSequentialAllocator(
463 char *buffer,
465 bsls::Types::size_type maxBufferSize,
466 bsls::BlockGrowth::Strategy growthStrategy,
467 bslma::Allocator *basicAllocator)
468: d_pool(buffer, size, maxBufferSize, growthStrategy, basicAllocator)
469{
470}
471
472inline
473BufferedSequentialAllocator::BufferedSequentialAllocator(
474 char *buffer,
476 bsls::Types::size_type maxBufferSize,
477 bsls::Alignment::Strategy alignmentStrategy,
478 bslma::Allocator *basicAllocator)
479: d_pool(buffer, size, maxBufferSize, alignmentStrategy, basicAllocator)
480{
481}
482
483inline
484BufferedSequentialAllocator::BufferedSequentialAllocator(
485 char *buffer,
487 bsls::Types::size_type maxBufferSize,
488 bsls::BlockGrowth::Strategy growthStrategy,
489 bsls::Alignment::Strategy alignmentStrategy,
490 bslma::Allocator *basicAllocator)
491: d_pool(buffer,
492 size,
493 maxBufferSize,
494 growthStrategy,
495 alignmentStrategy,
496 basicAllocator)
497{
498}
499
500// MANIPULATORS
501inline
503{
506 return 0; // RETURN
507 }
508
509 return d_pool.allocate(size);
510}
511
512inline
516
517inline
519{
520 d_pool.release();
521}
522
523inline
525{
526 d_pool.rewind();
527}
528
529// ACCESSORS
530inline
535
536} // close package namespace
537
538
539#endif
540
541// ----------------------------------------------------------------------------
542// Copyright 2016 Bloomberg Finance L.P.
543//
544// Licensed under the Apache License, Version 2.0 (the "License");
545// you may not use this file except in compliance with the License.
546// You may obtain a copy of the License at
547//
548// http://www.apache.org/licenses/LICENSE-2.0
549//
550// Unless required by applicable law or agreed to in writing, software
551// distributed under the License is distributed on an "AS IS" BASIS,
552// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
553// See the License for the specific language governing permissions and
554// limitations under the License.
555// ----------------------------- END-OF-FILE ----------------------------------
556
557/** @} */
558/** @} */
559/** @} */
Definition bdlma_bufferedsequentialallocator.h:265
~BufferedSequentialAllocator() BSLS_KEYWORD_OVERRIDE
bslma::Allocator * allocator() const
Return the allocator passed at construction.
Definition bdlma_bufferedsequentialallocator.h:531
void * allocate(size_type size) BSLS_KEYWORD_OVERRIDE
Definition bdlma_bufferedsequentialallocator.h:502
virtual void rewind()
Definition bdlma_bufferedsequentialallocator.h:524
void release() BSLS_KEYWORD_OVERRIDE
Definition bdlma_bufferedsequentialallocator.h:518
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE
Definition bdlma_bufferedsequentialallocator.h:513
Definition bdlma_bufferedsequentialpool.h:388
bslma::Allocator * allocator() const
Definition bdlma_bufferedsequentialpool.h:746
void release()
Definition bdlma_bufferedsequentialpool.h:715
void rewind()
Definition bdlma_bufferedsequentialpool.h:733
void * allocate(bsls::Types::size_type size)
Definition bdlma_bufferedsequentialpool.h:675
Definition bdlma_managedallocator.h:391
Definition bslma_allocator.h:457
std::size_t size_type
Definition bslma_allocator.h:499
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
#define BSLS_PERFORMANCEHINT_UNLIKELY_HINT
Definition bsls_performancehint.h:484
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition bdlma_alignedallocator.h:276
Definition balxml_encoderoptions.h:68
Definition bdlt_iso8601util.h:691
Strategy
Types of alignment strategy.
Definition bsls_alignment.h:239
Strategy
Definition bsls_blockgrowth.h:169
std::size_t size_type
Definition bsls_types.h:124