BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslalg_containerbase.h
Go to the documentation of this file.
1/// @file bslalg_containerbase.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslalg_containerbase.h -*-C++-*-
8#ifndef INCLUDED_BSLALG_CONTAINERBASE
9#define INCLUDED_BSLALG_CONTAINERBASE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslalg_containerbase bslalg_containerbase
15/// @brief Provide a wrapper for STL allocators, for container use.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslalg
19/// @{
20/// @addtogroup bslalg_containerbase
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslalg_containerbase-purpose"> Purpose</a>
25/// * <a href="#bslalg_containerbase-classes"> Classes </a>
26/// * <a href="#bslalg_containerbase-description"> Description </a>
27/// * <a href="#bslalg_containerbase-usage"> Usage </a>
28/// * <a href="#bslalg_containerbase-example-1-creating-a-fixed-size-array-with-bslalg-containerbase"> Example 1: Creating a Fixed-Size Array with bslalg::ContainerBase </a>
29///
30/// # Purpose {#bslalg_containerbase-purpose}
31/// Provide a wrapper for STL allocators, for container use.
32///
33/// # Classes {#bslalg_containerbase-classes}
34///
35/// - bslalg::ContainerBase: base class for allocator-aware STL-style containers
36///
37/// @see bslma_bslallocator
38///
39/// # Description {#bslalg_containerbase-description}
40/// This component provides a single mechanism class,
41/// `bslalg::ContainerBase`, that can used as a base class by STL-style
42/// containers for storing the container's allocator. If instantiated with an
43/// empty allocator type, `ContainerBase` will itself be an empty class type.
44/// Thus, a container class derived from `ContainerBase` can benefit from the
45/// base-class optimization in that an empty allocator object will not add to
46/// the size of the container's footprint.
47///
48/// ## Usage {#bslalg_containerbase-usage}
49///
50///
51/// This section illustrates intended use of this component.
52///
53/// ### Example 1: Creating a Fixed-Size Array with bslalg::ContainerBase {#bslalg_containerbase-example-1-creating-a-fixed-size-array-with-bslalg-containerbase}
54///
55///
56/// Suppose we would like to implement a fixed-size array that allocates memory
57/// from a user-supplied allocator at construction.
58///
59/// First, we define the interface of the container, `MyFixedSizeArray`. We
60/// privately derive from `ContainerBase` to take advantage of the
61/// empty-base-class optimization (in case `ALLOCATOR` is an empty class) and to
62/// take advantage of implementation conveniences `ContainerBase` provides:
63/// @code
64/// #include <bslalg_containerbase.h>
65/// #include <bslma_allocatorutil.h>
66/// #include <bslma_autodestructor.h>
67/// #include <bslma_constructionutil.h>
68/// #include <bslma_deallocateobjectproctor.h>
69/// #include <bslma_destructionutil.h>
70/// #include <bslma_bslallocator.h>
71/// #include <bslma_testallocator.h>
72/// #include <bslmf_isempty.h>
73///
74/// /// This class implements a container that contains a fixed number of
75/// /// elements of the parameterized type `VALUE` using the parameterized
76/// /// `ALLOCATOR` to allocate memory. The number of elements is specified
77/// /// on construction.
78/// template <class VALUE, class ALLOCATOR>
79/// class MyFixedSizeArray : private bslalg::ContainerBase<ALLOCATOR>
80/// {
81/// // PRIVATE TYPES
82/// typedef bslalg::ContainerBase<ALLOCATOR> Base;
83///
84/// // DATA
85/// VALUE *d_array; // head pointer to the array of elements
86/// const int d_size; // (fixed) number of elements in 'd_array'
87///
88/// public:
89/// // TYPES
90/// typedef ALLOCATOR allocator_type;
91///
92/// // CREATORS
93///
94/// /// Create a `MyFixedSizeArray` object having the specified `size`
95/// /// elements, and using the optionally specified `allocator` to
96/// /// supply memory. Each element of the array is value initialized.
97/// explicit MyFixedSizeArray(int size,
98/// const ALLOCATOR& allocator = ALLOCATOR());
99///
100/// /// Create a `MyFixedSizeArray` object having same number of
101/// /// elements as that of the specified `original`, the same value of
102/// /// each element as that of corresponding element in `original`, and
103/// /// using the optionally specified `allocator` to supply memory.
104/// MyFixedSizeArray(const MyFixedSizeArray& original,
105/// const ALLOCATOR& allocator = ALLOCATOR());
106///
107/// /// Destroy this object.
108/// ~MyFixedSizeArray();
109///
110/// // MANIPULATORS
111///
112/// /// Return a modifiable reference to the specified `i`th element of
113/// /// this object. The behavior is undefined unless `i < size()`.
114/// VALUE& operator[](int i) { return d_array[i]; }
115///
116/// // ACCESSORS
117///
118/// /// Return a const reference to the specified `i`th element of this
119/// /// object. The behavior is undefined unless `i < size()`.
120/// const VALUE& operator[](int i) const { return d_array[i]; }
121///
122/// /// Return the allocator used by this object to allocate memory.
123/// ALLOCATOR get_allocator() const;
124///
125/// /// Return the number of elements contained in this object.
126/// int size() const { return d_size; }
127/// };
128/// @endcode
129/// Next, we define the @ref get_allocator accessor, which extracts the allocator
130/// from the `ContainerBase` base class using its `allocatorRef` method:
131/// @code
132/// template<class VALUE, class ALLOCATOR>
133/// inline
134/// ALLOCATOR
135/// MyFixedSizeArray<VALUE,ALLOCATOR>::get_allocator() const {
136/// return Base::allocatorRef();
137/// }
138/// @endcode
139/// Next, we define the first constructor, beginning with the initialization the
140/// `ContainerBase` base class with the supplied `allocator`:
141/// @code
142/// template<class VALUE, class ALLOCATOR>
143/// MyFixedSizeArray<VALUE,ALLOCATOR>::MyFixedSizeArray(
144/// int size,
145/// const ALLOCATOR& allocator)
146/// : Base(allocator)
147/// , d_size(size)
148/// {
149/// @endcode
150/// Then, we allocate the specified number of array elements using the allocator
151/// returned by the `get_allocator()` method. Once allocated, we protect the
152/// array memory with a `bslma::DeallocateObjectProctor` object:
153/// @code
154/// d_array =
155/// bslma::AllocatorUtil::allocateObject<VALUE>(get_allocator(),
156/// d_size);
157/// bslma::DeallocateObjectProctor<ALLOCATOR, VALUE>
158/// deallocateProctor(get_allocator(), d_array, d_size);
159/// @endcode
160/// Then, we invoke the constructor for each array element using the
161/// `bslma::ConstructionUtil::construct` method. We use a
162/// `bslma::AutoDestuctor` proctor to unwind these constructions if an exception
163/// is thrown:
164/// @code
165/// bslma::AutoDestructor<VALUE> autoDtor(d_array, 0);
166/// // Default construct each element of the array:
167/// for (int i = 0; i < d_size; ++i) {
168/// bslma::ConstructionUtil::construct(&d_array[i], get_allocator());
169/// ++autoDtor;
170/// }
171/// @endcode
172/// Then, when every element has been constructed, we free the proctors:
173/// @code
174/// autoDtor.release();
175/// deallocateProctor.release();
176/// }
177/// @endcode
178/// Next we implement the destructor as the reverse of the constructor, invoking
179/// `bslma::DestructionUtil::destroy` on each element then deallocating them
180/// with `bslma::AllocatorUtil::deallocateObject`:
181/// @code
182/// template<class VALUE, class ALLOCATOR>
183/// MyFixedSizeArray<VALUE,ALLOCATOR>::~MyFixedSizeArray()
184/// {
185/// // Call destructor for each element
186/// for (int i = 0; i < d_size; ++i) {
187/// bslma::DestructionUtil::destroy(&d_array[i]);
188/// }
189///
190/// // Return memory to allocator.
191/// bslma::AllocatorUtil::deallocateObject(get_allocator(),
192/// d_array, d_size);
193/// }
194/// @endcode
195/// Next, for testing purposes, we create a `StatelessAllocator` template that
196/// simply allocates a global test allocator:
197/// @code
198/// bslma::TestAllocator g_testAllocator;
199///
200/// /// Allocator that allocates from the default `bslma::Allocator` resource.
201/// template <class TYPE>
202/// class StatelessAllocator {
203///
204/// public:
205/// typedef TYPE value_type;
206///
207/// value_type *allocate(std::size_t n, void * = 0) {
208/// return bslma::AllocatorUtil::allocateObject<value_type>(
209/// &g_testAllocator, n);
210/// }
211///
212/// void deallocate(value_type *p, std::size_t n) {
213/// bslma::AllocatorUtil::deallocateObject(&g_testAllocator, p, n);
214/// }
215/// };
216/// @endcode
217/// Finally, we create two `MyFixedSizeArray` objects, one using
218/// `StatelessAllocator`, and the other using `bsl::allocator`, and we verify
219/// that memory is allocated from the correct allocator for each. Because
220/// `StatelessAllocator` is an empty class, the first object is smaller than the
221/// second object by at least the size of a `bsl::allocator`.
222/// @code
223/// int main()
224/// {
225/// assert(bsl::is_empty<StatelessAllocator<int> >::value);
226///
227/// MyFixedSizeArray<int, StatelessAllocator<int> > fixedArray1(3);
228/// assert(3 == fixedArray1.size());
229/// assert(1 == g_testAllocator.numBlocksInUse());
230/// assert(3 * sizeof(int) == g_testAllocator.numBytesInUse());
231///
232/// bslma::TestAllocator ta;
233/// MyFixedSizeArray<int, bsl::allocator<int> > fixedArray2(3, &ta);
234/// assert(3 == fixedArray2.size());
235/// assert(&ta == fixedArray2.get_allocator());
236/// assert(1 == ta.numBlocksInUse());
237/// assert(3 * sizeof(int) == ta.numBytesInUse());
238///
239/// assert(sizeof(fixedArray2) - sizeof(fixedArray1) >=
240/// sizeof(bsl::allocator<int>));
241/// }
242/// @endcode
243/// @}
244/** @} */
245/** @} */
246
247/** @addtogroup bsl
248 * @{
249 */
250/** @addtogroup bslalg
251 * @{
252 */
253/** @addtogroup bslalg_containerbase
254 * @{
255 */
256
257#include <bslscm_version.h>
258
259#include <bslmf_assert.h>
260#include <bslmf_conditional.h>
261#include <bslmf_isempty.h>
262
263#include <bsls_keyword.h>
264
265#include <new> // Placement new
266
267
268
269namespace bslalg {
270
271 // ================================
272 // class ContainerBase_NonEmptyBase
273 // ================================
274
275/// One of two possible base classes for `ContainerBase`. This class should
276/// be used only for allocators with size > 0 (Inheritance from this type
277/// can cause ambiguous conversions and should be avoided or insulated.)
278///
279/// See @ref bslalg_containerbase
280template <class ALLOCATOR>
282
283 ALLOCATOR d_allocator;
284
285 private:
286 // NOT IMPLEMENTED
291
292 public:
293 // TYPES
294 typedef ALLOCATOR AllocatorType;
295
296 // CREATORS
297
298 /// Construct this object to hold a copy of the specified
299 /// `basicAllocator` of the (template parameter) type `ALLOCATOR`.
300 explicit ContainerBase_NonEmptyBase(const ALLOCATOR& basicAllocator);
301
302 /// Destroy this object.
304
305 // MANIPULATORS
306
307 /// Return a reference to this object's allocator, which is typically a
308 /// copy of the allocator used to construct this object.
309 ALLOCATOR& allocatorRef();
310
311 // ACCESSORS
312
313 /// Return a non-modifiable reference to this object's allocator, which
314 /// is typically a copy of the allocator used to construct this object.
315 const ALLOCATOR& allocatorRef() const;
316};
317
318 // =============================
319 // class ContainerBase_EmptyBase
320 // =============================
321
322/// One of two possible base classes for `ContainerBase`. This class is for
323/// stateless allocators (i.e., that have size 0), including
324/// `std::allocator` (but not `bsl::allocator`). Provides access to the
325/// allocator.
326///
327/// This class does **not** have a subobject of type `ALLOCATOR`. Instead,
328/// a (zero-sized) `ALLOCATOR` is implicitly sited at the address of the
329/// start of an object of this class. This approach was chosen in
330/// preference to inheriting from `ALLOCATOR` so as to avoid inheriting the
331/// interface for `ALLOCATOR` and thus making this class (and all classes
332/// derived from it) improperly categorized as an allocator when using the
333/// `bslma::IsStdAllocator` metafunction. `ContainerBase_EmptyBase` is an
334/// empty class and will not increase the footprint of a derived class.
335///
336/// See @ref bslalg_containerbase
337template <class ALLOCATOR>
339
340 private:
341 // NOT IMPLEMENTED
346
347 public:
348 // TYPES
349 typedef ALLOCATOR AllocatorType;
350
351 // CREATORS
352
353 /// Construct this object to hold a copy of the specified
354 /// `basicAllocator` of the parameterized `ALLOCATOR` type.
355 explicit ContainerBase_EmptyBase(const ALLOCATOR& basicAllocator);
356
357 /// Destroy this object.
359
360 // MANIPULATORS
361
362 /// Return a reference to the modifiable allocator used to construct
363 /// this object.
364 ALLOCATOR& allocatorRef();
365
366 // ACCESSORS
367
368 /// Return a reference to the non-modifiable allocator used to construct
369 /// this object.
370 const ALLOCATOR& allocatorRef() const;
371};
372
373 // ===================
374 // class ContainerBase
375 // ===================
376
377/// Allocator proxy class for STL-style containers. Provides access to the
378/// allocator. Implements the entire STL allocator interface, redirecting
379/// allocation and deallocation calls to the proxied allocator. One of two
380/// possible base classes is chosen depending on whether `ALLOCATOR` is
381/// an empty class.
382template <class ALLOCATOR>
383class ContainerBase : public
384 bsl::conditional<bsl::is_empty<ALLOCATOR>::value,
385 ContainerBase_EmptyBase<ALLOCATOR>,
386 ContainerBase_NonEmptyBase<ALLOCATOR> >::type {
387
388 // PRIVATE TYPES
389 typedef typename
393
394 // NOT IMPLEMENTED
397
398 public:
399 // PUBLIC TYPES
400 typedef typename Base::AllocatorType AllocatorType;
401
402 // CREATORS
403
404 /// Construct this object using the specified `basicAllocator` of the
405 /// parameterized `ALLOCATOR` type.
406 explicit ContainerBase(const ALLOCATOR& basicAllocator);
407
408 /// Destroy this object.
410
411 // ACCESSORS
412
413 /// Returns true if this object and `rhs` have allocators that compare
414 /// equal.
415 bool equalAllocator(const ContainerBase& rhs) const;
416};
417
418// ============================================================================
419// INLINE FUNCTION DEFINITIONS
420// ============================================================================
421
422 // --------------------------------
423 // class ContainerBase_NonEmptyBase
424 // --------------------------------
425
426// CREATORS
427template <class ALLOCATOR>
428inline
430ContainerBase_NonEmptyBase(const ALLOCATOR& basicAllocator)
431: d_allocator(basicAllocator)
432{
433}
434
435template <class ALLOCATOR>
436inline
440
441// MANIPULATORS
442template <class ALLOCATOR>
443inline
445{
446 return d_allocator;
447}
448
449// ACCESSORS
450template <class ALLOCATOR>
451inline
453{
454 return d_allocator;
455}
456
457 // -----------------------------
458 // class ContainerBase_EmptyBase
459 // -----------------------------
460
461// CREATORS
462template <class ALLOCATOR>
463inline
465ContainerBase_EmptyBase(const ALLOCATOR& basicAllocator)
466{
467 BSLMF_ASSERT(1 == sizeof(ALLOCATOR));
468 BSLMF_ASSERT(1 == sizeof(*this));
469
470 // Construct the allocator at this location. Because `ALLOCATOR` is an
471 // empty class, the constructor is almost certainly a no-op, but it could
472 // have an external side effect such as logging or inserting the allocator
473 // address into a global map.
474 ::new(this) ALLOCATOR(basicAllocator);
475}
476
477template <class ALLOCATOR>
478inline
480{
481 // Destroy the allocator at this location. Because `ALLOCATOR` is an
482 // empty class, the destructor is almost certainly a no-op, but it could
483 // have an external side effect such as logging or removing the allocator
484 // address from a global map.
485 allocatorRef().~ALLOCATOR();
486}
487
488// MANIPULATORS
489template <class ALLOCATOR>
490inline
492{
493 return *reinterpret_cast<ALLOCATOR *>(this);
494}
495
496// ACCESSORS
497template <class ALLOCATOR>
498inline
499const ALLOCATOR&
501{
502 return *reinterpret_cast<const ALLOCATOR *>(this);
503}
504
505 // -------------------
506 // class ContainerBase
507 // -------------------
508
509// CREATORS
510template <class ALLOCATOR>
511inline
512ContainerBase<ALLOCATOR>::ContainerBase(const ALLOCATOR& basicAllocator)
513: Base(basicAllocator)
514{
515}
516
517template <class ALLOCATOR>
518inline
522
523// ACCESSORS
524template <class ALLOCATOR>
525inline
527{
528 return this->allocatorRef() == rhs.allocatorRef();
529}
530
531} // close package namespace
532
533
534#endif
535
536// ----------------------------------------------------------------------------
537// Copyright 2013 Bloomberg Finance L.P.
538//
539// Licensed under the Apache License, Version 2.0 (the "License");
540// you may not use this file except in compliance with the License.
541// You may obtain a copy of the License at
542//
543// http://www.apache.org/licenses/LICENSE-2.0
544//
545// Unless required by applicable law or agreed to in writing, software
546// distributed under the License is distributed on an "AS IS" BASIS,
547// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
548// See the License for the specific language governing permissions and
549// limitations under the License.
550// ----------------------------- END-OF-FILE ----------------------------------
551
552/** @} */
553/** @} */
554/** @} */
Definition bslalg_containerbase.h:338
~ContainerBase_EmptyBase()
Destroy this object.
Definition bslalg_containerbase.h:479
ALLOCATOR AllocatorType
Definition bslalg_containerbase.h:349
ALLOCATOR & allocatorRef()
Definition bslalg_containerbase.h:491
Definition bslalg_containerbase.h:281
~ContainerBase_NonEmptyBase()
Destroy this object.
Definition bslalg_containerbase.h:437
ALLOCATOR AllocatorType
Definition bslalg_containerbase.h:294
ALLOCATOR & allocatorRef()
Definition bslalg_containerbase.h:444
Definition bslalg_containerbase.h:386
~ContainerBase()
Destroy this object.
Definition bslalg_containerbase.h:519
Base::AllocatorType AllocatorType
Definition bslalg_containerbase.h:400
bool equalAllocator(const ContainerBase &rhs) const
Definition bslalg_containerbase.h:526
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:609
Definition bdlc_flathashmap.h:1805
Definition bslmf_conditional.h:120
Definition bslmf_integralconstant.h:244
integral_constant type
Definition bslmf_integralconstant.h:255