BDE 4.39.x 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 at construction.
261///
262/// \note Note that in no case will the buffered sequential
263/// allocator attempt to deallocate the external buffer.
264///
265/// See @ref bdlma_bufferedsequentialallocator
267
268 // DATA
269 BufferedSequentialPool d_pool; // manager for allocated memory blocks
270
271 private:
272 // NOT IMPLEMENTED
275
276 public:
277 // CREATORS
278
279 /// Create a buffered sequential allocator for allocating memory blocks
280 /// from the specified external `buffer` having the specified `size` (in
281 /// bytes). Optionally specify a `growthStrategy` used to control
282 /// buffer growth. If a `growthStrategy` is not specified, geometric
283 /// growth is used. Optionally specify an `alignmentStrategy` used to
284 /// align allocated memory blocks. If an `alignmentStrategy` is not
285 /// specified, natural alignment is used. Optionally specify a
286 /// `basicAllocator` used to supply memory should the capacity of
287 /// `buffer` be exhausted. If `basicAllocator` is 0, the currently
288 /// installed default allocator is used.
289 ///
290 /// \pre The behavior is undefined unless `0 < size`, and `buffer` has at least `size` bytes.
291 ///
292 /// \note Note that, due to alignment effects, it is possible that not all `size`
293 /// bytes of memory in `buffer` can be used for allocation. Also note
294 /// that no limit is imposed on the size of the internal buffers when
295 /// geometric growth is used. Also note that when constant growth is
296 /// used, the size of the internal buffers will always be the same as
297 /// `size`.
298 BufferedSequentialAllocator(char *buffer,
300 bslma::Allocator *basicAllocator = 0);
302 char *buffer,
304 bsls::BlockGrowth::Strategy growthStrategy,
305 bslma::Allocator *basicAllocator = 0);
306 BufferedSequentialAllocator(char *buffer,
308 bsls::Alignment::Strategy alignmentStrategy,
309 bslma::Allocator *basicAllocator = 0);
311 char *buffer,
313 bsls::BlockGrowth::Strategy growthStrategy,
314 bsls::Alignment::Strategy alignmentStrategy,
315 bslma::Allocator *basicAllocator = 0);
316
317 /// Create a buffered sequential allocator for allocating memory blocks
318 /// from the specified external `buffer` having the specified `size` (in
319 /// bytes), or from an internal buffer (after the external `buffer` is
320 /// exhausted) where the buffer growth is limited to the specified
321 /// `maxBufferSize` (in bytes). Optionally specify a `growthStrategy`
322 /// used to control buffer growth. If a `growthStrategy` is not
323 /// specified, geometric growth is used. Optionally specify an
324 /// `alignmentStrategy` used to align allocated memory blocks. If an
325 /// `alignmentStrategy` is not specified, natural alignment is used.
326 /// Optionally specify a `basicAllocator` used to supply memory should
327 /// the capacity of `buffer` be exhausted. If `basicAllocator` is 0,
328 /// the currently installed default allocator is used.
329 ///
330 /// \pre The behavior is undefined unless `0 < size`, `size <= maxBufferSize`, and `buffer` has at least `size` bytes.
331 ///
332 /// \note Note that, due to alignment effects, it
333 /// is possible that not all `size` bytes of memory in `buffer` can be
334 /// used for allocation. Also note that when constant growth is used,
335 /// the size of the internal buffers will always be the same as `size`.
336 BufferedSequentialAllocator(char *buffer,
338 bsls::Types::size_type maxBufferSize,
339 bslma::Allocator *basicAllocator = 0);
341 char *buffer,
343 bsls::Types::size_type maxBufferSize,
344 bsls::BlockGrowth::Strategy growthStrategy,
345 bslma::Allocator *basicAllocator = 0);
346 BufferedSequentialAllocator(char *buffer,
348 bsls::Types::size_type maxBufferSize,
349 bsls::Alignment::Strategy alignmentStrategy,
350 bslma::Allocator *basicAllocator = 0);
352 char *buffer,
354 bsls::Types::size_type maxBufferSize,
355 bsls::BlockGrowth::Strategy growthStrategy,
356 bsls::Alignment::Strategy alignmentStrategy,
357 bslma::Allocator *basicAllocator = 0);
358
359 /// Destroy this buffered sequential allocator. All memory allocated
360 /// from this allocator is released.
362
363 // MANIPULATORS
364
365 /// Return the address of a contiguous block of memory of the specified
366 /// `size` (in bytes) according to the alignment strategy specified at
367 /// construction. If `size` is 0, no memory is allocated and 0 is
368 /// returned. If the allocation request exceeds the remaining free
369 /// memory space in the external buffer supplied at construction, use
370 /// memory obtained from the allocator supplied at construction.
372
373 /// This method has no effect on the memory block at the specified
374 /// `address` as all memory allocated by this allocator is managed.
375 ///
376 /// \pre The behavior is undefined unless `address` is 0, or was allocated by
377 /// this allocator and has not already been deallocated. The effect of
378 /// using `address` after this call is undefined.
379 void deallocate(void *address) BSLS_KEYWORD_OVERRIDE;
380
381 /// Release all memory allocated through this allocator and return to
382 /// the underlying allocator *all* memory except the external buffer
383 /// supplied at construction. The allocator is reset to its
384 /// default-constructed state, making the memory from the entire
385 /// external buffer supplied at construction available for subsequent
386 /// allocations, retaining the alignment and growth strategies, and the
387 /// initial and maximum buffer sizes in effect following construction.
388 /// The effect of subsequently - to this invokation of `release` - using
389 /// a pointer obtained from this object prior to this call to `release`
390 /// is undefined.
392
393 /// Release all memory allocated through this allocator and return to
394 /// the underlying allocator *only* memory that was allocated outside of
395 /// the typical internal buffer growth of this allocator (i.e., large
396 /// blocks). All retained memory will be used to satisfy subsequent
397 /// allocations. The effect of subsequently - to this invokation of
398 /// `rewind` - using a pointer obtained from this object prior to this
399 /// call to `rewind` is undefined.
400 virtual void rewind();
401
402 // ACCESSORS
403
404 /// Return the allocator passed at construction.
405 bslma::Allocator *allocator() const;
406};
407
408// ============================================================================
409// INLINE DEFINITIONS
410// ============================================================================
411
412 // ---------------------------------
413 // class BufferedSequentialAllocator
414 // ---------------------------------
415
416// CREATORS
417inline
419 char *buffer,
420 bsls::Types::size_type size,
421 bslma::Allocator *basicAllocator)
422: d_pool(buffer, size, basicAllocator)
423{
424}
425
426inline
427BufferedSequentialAllocator::BufferedSequentialAllocator(
428 char *buffer,
430 bsls::BlockGrowth::Strategy growthStrategy,
431 bslma::Allocator *basicAllocator)
432: d_pool(buffer, size, growthStrategy, basicAllocator)
433{
434}
435
436inline
437BufferedSequentialAllocator::BufferedSequentialAllocator(
438 char *buffer,
440 bsls::Alignment::Strategy alignmentStrategy,
441 bslma::Allocator *basicAllocator)
442: d_pool(buffer, size, alignmentStrategy, basicAllocator)
443{
444}
445
446inline
447BufferedSequentialAllocator::BufferedSequentialAllocator(
448 char *buffer,
450 bsls::BlockGrowth::Strategy growthStrategy,
451 bsls::Alignment::Strategy alignmentStrategy,
452 bslma::Allocator *basicAllocator)
453: d_pool(buffer, size, growthStrategy, alignmentStrategy, basicAllocator)
454{
455}
456
457inline
458BufferedSequentialAllocator::BufferedSequentialAllocator(
459 char *buffer,
461 bsls::Types::size_type maxBufferSize,
462 bslma::Allocator *basicAllocator)
463: d_pool(buffer, size, maxBufferSize, basicAllocator)
464{
465}
466
467inline
468BufferedSequentialAllocator::BufferedSequentialAllocator(
469 char *buffer,
471 bsls::Types::size_type maxBufferSize,
472 bsls::BlockGrowth::Strategy growthStrategy,
473 bslma::Allocator *basicAllocator)
474: d_pool(buffer, size, maxBufferSize, growthStrategy, basicAllocator)
475{
476}
477
478inline
479BufferedSequentialAllocator::BufferedSequentialAllocator(
480 char *buffer,
482 bsls::Types::size_type maxBufferSize,
483 bsls::Alignment::Strategy alignmentStrategy,
484 bslma::Allocator *basicAllocator)
485: d_pool(buffer, size, maxBufferSize, alignmentStrategy, basicAllocator)
486{
487}
488
489inline
490BufferedSequentialAllocator::BufferedSequentialAllocator(
491 char *buffer,
493 bsls::Types::size_type maxBufferSize,
494 bsls::BlockGrowth::Strategy growthStrategy,
495 bsls::Alignment::Strategy alignmentStrategy,
496 bslma::Allocator *basicAllocator)
497: d_pool(buffer,
498 size,
499 maxBufferSize,
500 growthStrategy,
501 alignmentStrategy,
502 basicAllocator)
503{
504}
505
506// MANIPULATORS
507inline
509{
512 return 0; // RETURN
513 }
514
515 return d_pool.allocate(size);
516}
517
518inline
522
523inline
525{
526 d_pool.release();
527}
528
529inline
531{
532 d_pool.rewind();
533}
534
535// ACCESSORS
536inline
541
542} // close package namespace
543
544
545#endif
546
547// ----------------------------------------------------------------------------
548// Copyright 2016 Bloomberg Finance L.P.
549//
550// Licensed under the Apache License, Version 2.0 (the "License");
551// you may not use this file except in compliance with the License.
552// You may obtain a copy of the License at
553//
554// http://www.apache.org/licenses/LICENSE-2.0
555//
556// Unless required by applicable law or agreed to in writing, software
557// distributed under the License is distributed on an "AS IS" BASIS,
558// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
559// See the License for the specific language governing permissions and
560// limitations under the License.
561// ----------------------------- END-OF-FILE ----------------------------------
562
563/** @} */
564/** @} */
565/** @} */
Definition bdlma_bufferedsequentialallocator.h:266
~BufferedSequentialAllocator() BSLS_KEYWORD_OVERRIDE
bslma::Allocator * allocator() const
Return the allocator passed at construction.
Definition bdlma_bufferedsequentialallocator.h:537
void * allocate(size_type size) BSLS_KEYWORD_OVERRIDE
Definition bdlma_bufferedsequentialallocator.h:508
virtual void rewind()
Definition bdlma_bufferedsequentialallocator.h:530
void release() BSLS_KEYWORD_OVERRIDE
Definition bdlma_bufferedsequentialallocator.h:524
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE
Definition bdlma_bufferedsequentialallocator.h:519
Definition bdlma_bufferedsequentialpool.h:394
bslma::Allocator * allocator() const
Definition bdlma_bufferedsequentialpool.h:761
void release()
Definition bdlma_bufferedsequentialpool.h:730
void rewind()
Definition bdlma_bufferedsequentialpool.h:748
void * allocate(bsls::Types::size_type size)
Definition bdlma_bufferedsequentialpool.h:690
Definition bdlma_managedallocator.h:392
Definition bslma_allocator.h:545
std::size_t size_type
Definition bslma_allocator.h:593
#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
#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:278
Definition baljsn_encoder_testtypes.h:76
Definition bdlt_iso8601util.h:707
Strategy
Types of alignment strategy.
Definition bsls_alignment.h:241
Strategy
Definition bsls_blockgrowth.h:172
std::size_t size_type
Definition bsls_types.h:126