BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslma_allocatorutil.h
Go to the documentation of this file.
1/// @file bslma_allocatorutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslma_allocatorutil.h -*-C++-*-
8#ifndef INCLUDED_BSLMA_ALLOCATORUTIL
9#define INCLUDED_BSLMA_ALLOCATORUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslma_allocatorutil bslma_allocatorutil
15/// @brief Provide a namespace for utility functions on allocators.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslma
19/// @{
20/// @addtogroup bslma_allocatorutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslma_allocatorutil-purpose"> Purpose</a>
25/// * <a href="#bslma_allocatorutil-classes"> Classes </a>
26/// * <a href="#bslma_allocatorutil-description"> Description </a>
27/// * <a href="#bslma_allocatorutil-usage"> Usage </a>
28/// * <a href="#bslma_allocatorutil-example-1-future-proofing-member-construction"> Example 1: Future-proofing Member Construction </a>
29/// * <a href="#bslma_allocatorutil-example-2-building-an-aa-object-on-the-heap"> Example 2: Building an AA object on the heap </a>
30/// * <a href="#bslma_allocatorutil-example-3-safe-container-swap"> Example 3: Safe container swap </a>
31///
32/// # Purpose {#bslma_allocatorutil-purpose}
33/// Provide a namespace for utility functions on allocators.
34///
35/// # Classes {#bslma_allocatorutil-classes}
36///
37/// - bslma::AllocatorUtil: Namespace for utility functions on allocators
38///
39/// @see bslma_aatypeutil, bslma_allocatortraits
40///
41/// # Description {#bslma_allocatorutil-description}
42/// This component provides a namespace `struct`,
43/// `bslma::AllocatorUtil`, with functions that operate on both raw pointers to
44/// `bslma::Allocator` or derived classes and objects of C++11 compliant
45/// allocator classes. The functions in this utility `struct` also free the
46/// user from worrying about rebinding the allocator and creating copies of
47/// rebound allocators. Operations provided include `allocateBytes` and
48/// `deallocateBytes` to acquire and free raw bytes; `allocateObject` and
49/// `deallocateObject` to aquire and free uninitialized object storages; and
50/// `newObject` and `deleteObject` to allocate+construct and destroy+deallocate
51/// full objects. There are also operations for conditionally assigning or
52/// swapping allocator objects themselves, depending on the allocator's
53/// propagation traits.
54///
55/// ## Usage {#bslma_allocatorutil-usage}
56///
57///
58///
59/// ### Example 1: Future-proofing Member Construction {#bslma_allocatorutil-example-1-future-proofing-member-construction}
60///
61///
62/// This example shows how we construct an AA member variable, using
63/// `bslma::AllocatorUtil::adapt` so that it is both self-documenting and robust
64/// in case the member type is modernized from *legacy-AA* (using
65/// `bslma::Allocator *` directly in its interface) to *bsl-AA* (using
66/// `bsl::allocator` in its interface).
67///
68/// First, we define a class, `Data1`, that has a legacy-AA interface:
69/// @code
70/// /// Legacy-AA data class.
71/// class Data1 {
72///
73/// bslma::Allocator *d_allocator_p;
74/// // ...
75///
76/// public:
77/// explicit Data1(bslma::Allocator *basicAllocator = 0)
78/// : d_allocator_p(basicAllocator) { /* ... */ }
79///
80/// bslma::Allocator *allocator() const { return d_allocator_p; }
81/// };
82/// @endcode
83/// Next, we define a class, `MyClass1`, that has a member of type `Data1`.
84/// `MyClass` uses a modern, bsl-AA interface:
85/// @code
86/// class MyClass1 {
87/// bsl::allocator<char> d_allocator;
88/// Data1 d_data;
89///
90/// public:
91/// typedef bsl::allocator<char> allocator_type;
92///
93/// explicit MyClass1(const allocator_type& allocator = allocator_type());
94///
95/// const Data1& data() const { return d_data; }
96/// allocator_type get_allocator() const { return d_allocator; }
97/// };
98/// @endcode
99/// Next, we define the constructor for `MyClass1`. Since `MyClass1` uses
100/// `bsl::allocator` and the `Data1` uses `bslma::Allocator *`, we employ
101/// `bslma::AllocatorUtil::adapt` to obtain an allocator suitable for passing to
102/// the constructor for `d_data`:
103/// @code
104/// MyClass1::MyClass1(const allocator_type& allocator)
105/// : d_allocator(allocator)
106/// , d_data(bslma::AllocatorUtil::adapt(allocator))
107/// {
108/// }
109/// @endcode
110/// Next, assume that we update our `Data` class from legacy-AA to bsl-AA
111/// (renamed from `Data1` to `Data2` for illustrative purposes):
112/// @code
113/// /// Bsl-AA data class.
114/// class Data2 {
115///
116/// bsl::allocator<int> d_allocator;
117/// // ...
118///
119/// public:
120/// typedef bsl::allocator<int> allocator_type;
121///
122/// explicit Data2(const allocator_type& allocator = allocator_type())
123/// : d_allocator(allocator) { /* ... */ }
124///
125/// allocator_type get_allocator() const { return d_allocator; }
126/// };
127/// @endcode
128/// Now, we notice that **nothing** about `MyClass` needs to change, not even
129/// the way its constructor passes an allocator to `d_data`:
130/// @code
131/// class MyClass2 {
132/// bsl::allocator<char> d_allocator;
133/// Data2 d_data;
134///
135/// public:
136/// typedef bsl::allocator<char> allocator_type;
137///
138/// explicit MyClass2(const allocator_type& allocator = allocator_type());
139///
140/// const Data2& data() const { return d_data; }
141/// allocator_type get_allocator() const { return d_allocator; }
142/// };
143///
144/// MyClass2::MyClass2(const allocator_type& allocator)
145/// : d_allocator(allocator)
146/// , d_data(bslma::AllocatorUtil::adapt(allocator))
147/// {
148/// }
149/// @endcode
150/// Finally, we test both versions of `MyClass` and show that the allocator that
151/// is passed to the `MyClass` constructor gets forwarded to its data member:
152/// @code
153/// int main()
154/// {
155/// bslma::TestAllocator ta;
156/// bsl::allocator<char> alloc(&ta);
157///
158/// MyClass1 obj1(alloc);
159/// assert(&ta == obj1.data().allocator());
160///
161/// MyClass2 obj2(alloc);
162/// assert(alloc == obj2.data().get_allocator());
163/// }
164/// @endcode
165///
166/// ### Example 2: Building an AA object on the heap {#bslma_allocatorutil-example-2-building-an-aa-object-on-the-heap}
167///
168///
169/// This example shows how we can allocate a *bsl-AA* object from an allocator
170/// and construct the object, passing the allocator along, in one step.
171///
172/// First, we define a simple class, `BslAAType`, that uses `bsl::allocator` to
173/// allocate memory (i.e., it is *bsl-AA*):
174/// @code
175/// #include <bslma_bslallocator.h>
176/// class BslAAType {
177/// bsl::allocator<> d_allocator;
178/// int d_value;
179///
180/// public:
181/// typedef bsl::allocator<> allocator_type;
182///
183/// explicit BslAAType(const allocator_type& a = allocator_type())
184/// : d_allocator(a), d_value(0) { }
185/// explicit BslAAType(int v, const allocator_type& a = allocator_type())
186/// : d_allocator(a), d_value(v) { }
187///
188/// allocator_type get_allocator() const { return d_allocator; }
189/// int value() const { return d_value; }
190/// };
191/// @endcode
192/// Now we can use `bslma::AllocatorUtil::newObject` to, in a single operation,
193/// allocate and construct an `BslAAType` object. We can see that the right
194/// allocator and value are passed to the new object:
195/// @code
196/// #include <bslma_testallocator.h>
197/// int main()
198/// {
199/// bslma::TestAllocator ta;
200/// BslAAType *p = bslma::AllocatorUtil::newObject<BslAAType>(&ta, 77);
201/// assert(sizeof(BslAAType) == ta.numBytesInUse());
202/// assert(77 == p->value());
203/// assert(&ta == p->get_allocator().mechanism());
204/// @endcode
205/// Finally, we use `deleteObject` to destroy and return the object to the
206/// allocator:
207/// @code
208/// bslma::AllocatorUtil::deleteObject(&ta, p);
209/// assert(0 == ta.numBytesInUse());
210/// }
211/// @endcode
212///
213/// ### Example 3: Safe container swap {#bslma_allocatorutil-example-3-safe-container-swap}
214///
215///
216/// In this example, we see how `bslma::AllocatorUtil::swap` can be used to swap
217/// allocators without the risk of calling a non-existant swap.
218///
219/// First, we create a class, `StdAAType`, that uses any valid STL-compatible
220/// allocator (i.e., it is *stl-AA*). Note that this class has non-default copy
221/// constructor and assignment operations (whose implementation is not shown)
222/// and a non-default `swap` operation:
223/// @code
224/// template <class t_TYPE, class t_ALLOCATOR = bsl::allocator<t_TYPE> >
225/// class StlAAType {
226/// t_ALLOCATOR d_allocator;
227/// t_TYPE *d_value_p;
228///
229/// public:
230/// typedef t_ALLOCATOR allocator_type;
231///
232/// explicit StlAAType(const allocator_type& a = allocator_type())
233/// : d_allocator(a)
234/// , d_value_p(bslma::AllocatorUtil::newObject<t_TYPE>(a)) { }
235/// explicit StlAAType(const t_TYPE& v,
236/// const allocator_type& a = allocator_type())
237/// : d_allocator(a)
238/// , d_value_p(bslma::AllocatorUtil::newObject<t_TYPE>(a, v)) { }
239///
240/// StlAAType(const StlAAType&);
241///
242/// ~StlAAType() {
243/// bslma::AllocatorUtil::deleteObject(d_allocator, d_value_p);
244/// }
245///
246/// StlAAType operator=(const StlAAType&);
247///
248/// void swap(StlAAType& other);
249///
250/// allocator_type get_allocator() const { return d_allocator; }
251/// const t_TYPE& value() const { return *d_value_p; }
252/// };
253///
254/// template <class t_TYPE, class t_ALLOCATOR>
255/// inline void swap(StlAAType<t_TYPE, t_ALLOCATOR>& a,
256/// StlAAType<t_TYPE, t_ALLOCATOR>& b)
257/// {
258/// a.swap(b);
259/// }
260/// @endcode
261/// Next, we write the `swap` member function. This function should follow our
262/// standard AA rule for member swap: if the allocators compare equal or if the
263/// allocators should propagate on swap, then perform a fast swap, moving only
264/// pointers and (possibly) allocators, rather than copying elements; otherwise
265/// revert to element-by-element swap:
266/// @code
267/// template <class t_TYPE, class t_ALLOCATOR>
268/// void StlAAType<t_TYPE, t_ALLOCATOR>::swap(StlAAType& other)
269/// {
270/// typedef typename
271/// bsl::allocator_traits<allocator_type>::propagate_on_container_swap
272/// Propagate;
273///
274/// using std::swap;
275///
276/// if (Propagate::value || d_allocator == other.d_allocator) {
277/// // Swap allocators and pointers, but not individual elements.
278/// bslma::AllocatorUtil::swap(&d_allocator, &other.d_allocator,
279/// Propagate());
280/// swap(d_value_p, other.d_value_p);
281/// }
282/// else
283/// {
284/// // Swap element values
285/// swap(*d_value_p, *other.d_value_p);
286/// }
287/// }
288/// @endcode
289/// Note that, in the above implementation of `swap`, that we swap the
290/// allocators using `bslma::AllocatorUtil::swap` instead of calling `swap`
291/// directly. If the `t_ALLOCATOR` type does not propagate on container
292/// assignment or swap, the allocator itself is not required to support
293/// assignment or swap. By using this utility, we avoid trying to compile a
294/// call to allocator `swap` when it is not needed.
295///
296/// Next, we'll define an allocator that illustrates this point. Our `MyAlloc`
297/// allocator does not support allocator propogation and deletes the assignment
298/// operators (thus also disabling swap):
299/// @code
300/// #include <bsls_keyword.h>
301///
302/// template <class t_TYPE>
303/// class MyAlloc {
304/// bsl::allocator<t_TYPE> d_imp;
305///
306/// // Disable assignment
307/// MyAlloc operator=(const MyAlloc&) BSLS_KEYWORD_DELETED;
308///
309/// public:
310/// typedef t_TYPE value_type;
311///
312/// MyAlloc() { }
313/// MyAlloc(bslma::Allocator *allocPtr) : d_imp(allocPtr) { } // IMPLICIT
314/// template <class U>
315/// MyAlloc(const MyAlloc<U>& other) : d_imp(other.d_imp) { }
316///
317/// t_TYPE *allocate(std::size_t n) { return d_imp.allocate(n); }
318/// void deallocate(t_TYPE* p, std::size_t n) { d_imp.deallocate(p, n); }
319///
320/// template <class T2>
321/// friend bool operator==(const MyAlloc& a, const MyAlloc<T2>& b)
322/// { return a.d_imp == b.d_imp; }
323/// template <class T2>
324/// friend bool operator!=(const MyAlloc& a, const MyAlloc<T2>& b)
325/// { return a.d_imp != b.d_imp; }
326/// };
327/// @endcode
328/// Finally, we create two `StlAAType` objects with the same allocator and show
329/// that they can be swapped even though the allocator type cannot be swapped:
330/// @code
331/// int main()
332/// {
333/// MyAlloc<int> alloc;
334///
335/// StlAAType<int, MyAlloc<int> > objA(1, alloc), objB(2, alloc);
336/// assert(alloc == objA.get_allocator());
337/// assert(alloc == objB.get_allocator());
338/// assert(1 == objA.value());
339/// assert(2 == objB.value());
340///
341/// objA.swap(objB);
342/// assert(2 == objA.value());
343/// assert(1 == objB.value());
344/// }
345/// @endcode
346/// @}
347/** @} */
348/** @} */
349
350/** @addtogroup bsl
351 * @{
352 */
353/** @addtogroup bslma
354 * @{
355 */
356/** @addtogroup bslma_allocatorutil
357 * @{
358 */
359
360#include <bslscm_version.h>
361
362#include <bslma_allocator.h>
364#include <bslma_memoryresource.h>
366#include <bslma_bslallocator.h>
367
368#include <bslmf_assert.h>
369#include <bslmf_enableif.h>
370#include <bslmf_isconst.h>
371#include <bslmf_isconvertible.h>
373#include <bslmf_isvolatile.h>
374
376#include <bsls_alignmentutil.h>
377#include <bsls_assert.h>
378#include <bsls_exceptionutil.h>
380#include <bsls_util.h>
381
382#include <algorithm> // 'std::swap'
383
384#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
385// Include version that can be compiled with C++03
386// Generated on Sat Jul 23 20:07:37 2022
387// Command line: sim_cpp11_features.pl bslma_allocatorutil.h
388# define COMPILING_BSLMA_ALLOCATORUTIL_H
390# undef COMPILING_BSLMA_ALLOCATORUTIL_H
391#else
392
393
394namespace bslma {
395
396// FORWARD DECLARATIONS
397template <class t_ALLOCATOR, class t_TYPE = char>
398struct AllocatorUtil_Traits;
399
400 // ===================
401 // class AllocatorUtil
402 // ===================
403
404/// Namespace for utility functions on allocators
406
407 private:
408 // PRIVATE CONSTANTS
409 enum { k_MAX_ALIGNMENT = bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT };
410
411 // PRIVATE CLASS METHODS
412 template <class t_TYPE>
413 static char matchBslAlloc(bsl::allocator<t_TYPE> *, int);
414 static long matchBslAlloc(void *, ...);
415 // DECLARED BUT NOT DEFINED
416
417 /// Return the specified `nbytes` raw bytes having the specified
418 /// `alignment` allocated from the specified `allocator`. If
419 /// `alignment` is larger than the largest supported alignment, the
420 /// behavior is determined by the allocator.
421 template <class t_TYPE>
422 static
423 void *allocateBytesImp(
424 const bsl::polymorphic_allocator<t_TYPE>& allocator,
425 std::size_t nbytes,
426 std::size_t alignment);
427 template <class t_TYPE>
428 static
429 void *allocateBytesImp(const bsl::allocator<t_TYPE>& allocator,
430 std::size_t nbytes,
431 std::size_t alignment);
432 template <class t_ALLOCATOR>
433 static
435 allocateBytesImp(const t_ALLOCATOR& allocator,
436 std::size_t nbytes,
437 std::size_t alignment);
438
439 /// Return, to the specified `allocator`, the block of raw memory at the
440 /// specified `p` address having the specified `nbytes` size and the
441 /// specified `alignment`. The behavior is undefined unless `p` refers
442 /// to a block having the same size and alignment allocated from a copy
443 /// of `allocator` and not yet deallocated.
444 template <class t_TYPE>
445 static void
446 deallocateBytesImp(const bsl::polymorphic_allocator<t_TYPE>& allocator,
447 void *p,
448 std::size_t nbytes,
449 std::size_t alignment);
450 template <class t_TYPE>
451 static void
452 deallocateBytesImp(const bsl::allocator<t_TYPE>& allocator,
453 void *p,
454 std::size_t nbytes,
455 std::size_t alignment);
456 template <class t_ALLOCATOR>
457 static void deallocateBytesImp(
458 const t_ALLOCATOR& allocator,
460 std::size_t nbytes,
461 std::size_t alignment);
462
463 template <class t_ALLOCATOR, class t_POINTER, class t_VALUE_TYPE>
464 static void deallocateObjectImp(const t_ALLOCATOR& allocator,
465 t_POINTER p,
466 std::size_t n,
467 const t_VALUE_TYPE& );
468
469 template <class t_ALLOCATOR, class t_POINTER, class t_VALUE_TYPE>
470 static void deleteObjectImp(const t_ALLOCATOR& allocator,
471 t_POINTER p,
472 const t_VALUE_TYPE& );
473
474 /// Return `true` if the specified `alignment` is a (positive) power of
475 /// two; otherwise return false.
476 static bool isPowerOf2(std::size_t alignment);
477
478 // PRIVATE TYPES
479
480 /// Metafunction derives from `true_type` if (template argument)
481 /// `t_ALLOC` is derived from any specialization of `bsl::allocator`;
482 /// else derives from `false_type`.
483 template <class t_ALLOC>
484 struct IsDerivedFromBslAllocator
486 1 == sizeof(matchBslAlloc((t_ALLOC *) 0, 0))>
487 {
488 };
489
490 public:
491 // CLASS METHODS
492
493 /// Return the specified `from` allocator adapted to a type most likely
494 /// to be usable for initializing another AA object. Specifically,
495 /// return `from.mechanism()` if `from` is a specialization of
496 /// `bsl::allocator` (or a class derived from `bsl::allocator`);
497 /// otherwise return `from` unchanged.
498 template <class t_ALLOC>
499 static typename bsl::enable_if<
501 t_ALLOC>::type
502 adapt(const t_ALLOC& from);
503 template <class t_TYPE>
504 static bslma::Allocator *adapt(const bsl::allocator<t_TYPE>& from);
505
506 /// Return a pointer to a block of raw memory allocated from the
507 /// specified `allocator` having the specified `nbytes` size and
508 /// optionally specified `alignment`. If `alignment` is larger than the
509 /// largest supported alignment, either the block will be aligned to the
510 /// maximum supported alignment or an exception will be thrown. The
511 /// specific choice of behavior is determined by the allocator: for
512 /// polymorphic allocators the behavior is determined by the memory
513 /// resource, whereas for non-polymorphic allocators, the alignment is
514 /// always truncated to the maximum non-extended alignment.
515 template <class t_ALLOCATOR>
517 allocateBytes(const t_ALLOCATOR& allocator,
518 std::size_t nbytes,
519 std::size_t alignment = k_MAX_ALIGNMENT);
520
521 /// Return a pointer to a block of raw memory allocated from the
522 /// specified `allocator` having a size and alignment appropriate for an
523 /// object of (templatize parameter) `t_TYPE`. Optionally specify `n`
524 /// for the number of objects; otherwise space for a single object is
525 /// allocated. Since `t_TYPE` cannot be deduced from the function
526 /// parameters, it must be supplied explicitly (in `<>` brackets) by the
527 /// caller.
528 template <class t_TYPE, class t_ALLOCATOR>
530 allocateObject(const t_ALLOCATOR& allocator, std::size_t n = 1);
531
532 /// If the specified `allowed` tag is `bsl::true_type` assign the
533 /// allocator object at the specified `lhs` address the value of the
534 /// specified `rhs`; otherwise, do nothing, and, in both cases, return a
535 /// modifiable reference to `*lhs`. The `t_TYPE` template parameter is
536 /// typically an allocator type and the `allowed` flag is typically a
537 /// propagation trait dependant on the calling context, such as
538 /// `propagate_on_container_copy_assignment` or
539 /// `propagate_on_container_move_assignment`. Instantiation will fail
540 /// if `allowed` is `true_type` and `t_TYPE` lacks a publically
541 /// accessible copy assignment operator. The behavior is undefined
542 /// unless `allowed` is `true_type` or `*lhs == rhs` before the call.
543 template <class t_TYPE>
544 static t_TYPE& assign(t_TYPE *lhs,
545 const t_TYPE& rhs,
546 bsl::true_type allowed);
547 template <class t_TYPE>
548 static t_TYPE& assign(t_TYPE *lhs,
549 const t_TYPE& rhs,
550 bsl::false_type allowed);
551
552 /// Return to the specified allocator the block raw memory at the
553 /// specified `p` address having the specified `nbytes` size and
554 /// optionally specified `alignment`. The behavior is undefined unless
555 /// `p` refers to a block having the same size and alignment previously
556 /// allocated from a copy of `allocator` and not yet deallocated.
557 template <class t_ALLOCATOR>
558 static void deallocateBytes(
559 const t_ALLOCATOR& allocator,
561 std::size_t nbytes,
562 std::size_t alignment
563 = k_MAX_ALIGNMENT);
564
565 /// Return to the specified `allocator` a block of raw memory at the
566 /// specified `p` address that is suitably sized and aligned to hold an
567 /// object of (templatize parameter) `t_TYPE`. Optionally specify `n`
568 /// for the number of objects; otherwise a single object is assumed.
569 /// The behavior is undefined unless `p` refers to a block with the same
570 /// type and number of objects previously allocated from a copy of
571 /// `allocator` and not yet deallocated.
572 template <class t_ALLOCATOR, class t_POINTER>
573 static void deallocateObject(const t_ALLOCATOR& allocator,
574 t_POINTER p,
575 std::size_t n = 1);
576
577 /// Destroy the object at the specified `p` address and return the block
578 /// of memory at `p` to the specified `allocator`. The behavior is
579 /// undefined unless `p` refers to a fully constructed object allocated
580 /// from a copy of `allocator` and not yet destroyed or deallocated.
581 template <class t_ALLOCATOR, class t_POINTER>
582 static void deleteObject(const t_ALLOCATOR& allocator, t_POINTER p);
583
584 /// Return an object of (template parameter) `t_TYPE` allocated from the
585 /// specified `allocator` and constructed with no arguments except that,
586 /// for scoped allocator types such as `bsl::allocator` and
587 /// `bsl::polymorphic_allocator`, `allocator` may be passed to the
588 /// `t_TYPE` constructor (i.e., if `t_TYPE` is AA).
589 template <class t_TYPE, class t_ALLOCATOR>
591 newObject(const t_ALLOCATOR& allocator);
592
593#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13
594# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
595 // 't_ARG1' lvalue overloaded unneeded in C++11 and hits bug in gcc < 10.2.
596 template <class t_TYPE, class t_ALLOCATOR, class t_ARG1, class... t_ARGS>
598 newObject(const t_ALLOCATOR& allocator,
599 t_ARG1& argument1,
600 t_ARGS&&... arguments);
601# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
602
603 /// Return an object of (template parameter) `t_TYPE` allocated from the
604 /// specified `allocator` and constructed from the specified `argument1`
605 /// and other specified `arguments`. For scoped allocator types such as
606 /// `bsl::allocator` and `bsl::polymorphic_allocator`, `allocator` may
607 /// be passed to the `t_TYPE` constructor as an additional argument
608 /// (i.e., if `t_TYPE` is AA). Note that, in C++03, perfect forwarding
609 /// is limited such that any lvalue reference in the `arguments`
610 /// parameter pack is const-qualified when forwarded to the
611 /// `TARGET_TYPE` constructor; only `argument1` can be forwarded as an
612 /// unqualified lvalue.
613 template <class t_TYPE, class t_ALLOCATOR, class t_ARG1, class... t_ARGS>
615 newObject(const t_ALLOCATOR& allocator,
616 BSLS_COMPILERFEATURES_FORWARD_REF(t_ARG1) argument1,
617 t_ARGS&&... arguments);
618#endif
619
620 /// If the specified `allowed` tag is `bsl::true_type`, swap the values
621 /// of allocators at the specified `pa` and `pb` addresses using ADL
622 /// swap (with `std::swap` in scope); otherwise, do nothing. The
623 /// `t_TYPE` template parameter is typically an allocator type and the
624 /// `allowed` flag is typically a propagation trait dependant on the
625 /// calling context, such as `propagate_on_container_swap`.
626 /// Instantiation will fail if `allowed` is `false_type` and `t_TYPE` is
627 /// not swappable (i.e., because it lacks a publically available
628 /// assignment operator). The behavior is undefined unless `allowed` is
629 /// `true_type` or '*pa ==
630 /// *pb' before the call.
631 template <class t_TYPE>
632 static void swap(t_TYPE *pa, t_TYPE *pb, bsl::false_type allowed);
633 template <class t_TYPE>
634 static void swap(t_TYPE *pa, t_TYPE *pb, bsl::true_type allowed);
635};
636
637// ============================================================================
638// TEMPLATE AND INLINE FUNCTION IMPLEMENTATIONS
639// ============================================================================
640
641 // --------------------------
642 // class AllocatorUtil_Traits
643 // --------------------------
644
645/// Extend the notion of `allocator_traits` to apply to both standard
646/// allocator and to pointer-to-memory-resource types. If the (template
647/// parameter) `t_ALLOCATOR` is a non-pointer type (i.e., an allocator
648/// class), then inherits from
649/// `bsl::allocator_traits<t_ALLOCATOR>::rebind_traits<t_TYPE>`. However,
650/// if `t_ALLOCATOR` is a pointer type, then inherits from
651/// `bsl::allocator_traits<bsl::allocator<t_TYPE>>` for pointers to classes
652/// derived from `bslma::Allocator` and from
653/// `bsl::allocator_traits<bsl::polymorphic_allocator<t_TYPE>>` for pointers
654/// to other classes derived from `bsl::memory_resource`. This primary
655/// template is for non-pointer `t_ALLOCATOR` template arguments.
656template <class t_ALLOCATOR, class t_TYPE>
663
664/// This specialization is for allocators expressed as a pointer to class
665/// derived from `bsl::memory_resource`. The base class will be
666/// `bsl::allocator_traits<bsl::allocator<t_TYPE>>` if `t_MEMORY_RSRC` is
667/// derived from `bsl::Allocator`; otherwise the base class will be
668/// `bsl::allocator_traits<bsl::polymorphic_allocator<t_TYPE>>`.
669template <class t_MEMORY_RSRC, class t_TYPE>
684
685 // -------------------
686 // class AllocatorUtil
687 // -------------------
688
689// PRIVATE CLASS METHODS
690template <class t_TYPE>
691inline
692void *AllocatorUtil::allocateBytesImp(
693 const bsl::polymorphic_allocator<t_TYPE>& allocator,
694 std::size_t nbytes,
695 std::size_t alignment)
696{
697 return allocator.resource()->allocate(nbytes, alignment);
698}
699
700template <class t_TYPE>
701inline
702void *AllocatorUtil::allocateBytesImp(const bsl::allocator<t_TYPE>& allocator,
703 std::size_t nbytes,
704 std::size_t alignment)
705{
706 return allocator.resource()->allocate(nbytes, alignment);
707}
708
709template <class t_ALLOCATOR>
710typename AllocatorUtil_Traits<t_ALLOCATOR>::void_pointer
711AllocatorUtil::allocateBytesImp(const t_ALLOCATOR& allocator,
712 std::size_t nbytes,
713 std::size_t alignment)
714{
715 BSLMF_ASSERT(4 <= k_MAX_ALIGNMENT && k_MAX_ALIGNMENT <= 32);
716
717 static const int k_8 = k_MAX_ALIGNMENT < 8 ? k_MAX_ALIGNMENT : 8;
718 static const int k_16 = k_MAX_ALIGNMENT < 16 ? k_MAX_ALIGNMENT : 16;
719
720 typedef typename bsls::AlignmentToType< 1>::Type AlignType1;
721 typedef typename bsls::AlignmentToType< 2>::Type AlignType2;
722 typedef typename bsls::AlignmentToType< 4>::Type AlignType4;
723 typedef typename bsls::AlignmentToType<k_8>::Type AlignType8;
724 typedef typename bsls::AlignmentToType<k_16>::Type AlignType16;
725 typedef typename bsls::AlignmentToType<k_MAX_ALIGNMENT>::Type AlignTypeMax;
726
727 if (alignment > k_MAX_ALIGNMENT) {
728 alignment = k_MAX_ALIGNMENT;
729 }
730
731 std::size_t n = (nbytes + alignment - 1) / alignment;
732
733 switch (alignment) {
734 case 1: return allocateObject<AlignType1 >(allocator, n);
735 case 2: return allocateObject<AlignType2 >(allocator, n);
736 case 4: return allocateObject<AlignType4 >(allocator, n);
737 case 8: return allocateObject<AlignType8 >(allocator, n);
738 case 16: return allocateObject<AlignType16 >(allocator, n);
739 default: return allocateObject<AlignTypeMax>(allocator, n);
740 }
741}
742
743template <class t_TYPE>
744inline
745void AllocatorUtil::deallocateBytesImp(
746 const bsl::polymorphic_allocator<t_TYPE>& allocator,
747 void *p,
748 std::size_t nbytes,
749 std::size_t alignment)
750{
751 return allocator.resource()->deallocate(p, nbytes, alignment);
752}
753
754template <class t_TYPE>
755inline
756void AllocatorUtil::deallocateBytesImp(
757 const bsl::allocator<t_TYPE>& allocator,
758 void *p,
759 std::size_t nbytes,
760 std::size_t alignment)
761{
762 return allocator.resource()->deallocate(p, nbytes, alignment);
763}
764
765template <class t_ALLOCATOR>
766void AllocatorUtil::deallocateBytesImp(
767 const t_ALLOCATOR& allocator,
768 typename AllocatorUtil_Traits<t_ALLOCATOR>::void_pointer p,
769 std::size_t nbytes,
770 std::size_t alignment)
771{
772 BSLMF_ASSERT(4 <= k_MAX_ALIGNMENT && k_MAX_ALIGNMENT <= 32);
773
774 static const int k_8 = k_MAX_ALIGNMENT < 8 ? k_MAX_ALIGNMENT : 8;
775 static const int k_16 = k_MAX_ALIGNMENT < 16 ? k_MAX_ALIGNMENT : 16;
776
777 typedef typename bsls::AlignmentToType< 1>::Type AlignType1;
778 typedef typename bsls::AlignmentToType< 2>::Type AlignType2;
779 typedef typename bsls::AlignmentToType< 4>::Type AlignType4;
780 typedef typename bsls::AlignmentToType<k_8>::Type AlignType8;
781 typedef typename bsls::AlignmentToType<k_16>::Type AlignType16;
782 typedef typename bsls::AlignmentToType<k_MAX_ALIGNMENT>::Type AlignTypeMax;
783
784 typedef typename AllocatorUtil_Traits<t_ALLOCATOR,
785 AlignType1 >::pointer Ptr1;
786 typedef typename AllocatorUtil_Traits<t_ALLOCATOR,
787 AlignType2 >::pointer Ptr2;
788 typedef typename AllocatorUtil_Traits<t_ALLOCATOR,
789 AlignType4 >::pointer Ptr4;
790 typedef typename AllocatorUtil_Traits<t_ALLOCATOR,
791 AlignType8 >::pointer Ptr8;
792 typedef typename AllocatorUtil_Traits<t_ALLOCATOR,
793 AlignType16 >::pointer Ptr16;
794 typedef typename AllocatorUtil_Traits<t_ALLOCATOR,
795 AlignTypeMax>::pointer PtrMax;
796
797 if (alignment > k_MAX_ALIGNMENT) {
798 alignment = k_MAX_ALIGNMENT;
799 }
800
801 std::size_t n = (nbytes + alignment - 1) / alignment;
802
803 switch (alignment) {
804 case 1: deallocateObject(allocator, static_cast<Ptr1 >(p), n); break;
805 case 2: deallocateObject(allocator, static_cast<Ptr2 >(p), n); break;
806 case 4: deallocateObject(allocator, static_cast<Ptr4 >(p), n); break;
807 case 8: deallocateObject(allocator, static_cast<Ptr8 >(p), n); break;
808 case 16: deallocateObject(allocator, static_cast<Ptr16 >(p), n); break;
809 default: deallocateObject(allocator, static_cast<PtrMax>(p), n); break;
810 }
811}
812
813template <class t_ALLOCATOR, class t_POINTER, class t_VALUE_TYPE>
814inline
815void AllocatorUtil::deallocateObjectImp(const t_ALLOCATOR& allocator,
816 t_POINTER p,
817 std::size_t n,
818 const t_VALUE_TYPE& )
819{
820 typedef AllocatorUtil_Traits<t_ALLOCATOR, t_VALUE_TYPE> Traits;
821
823
824 typename Traits::allocator_type reboundAlloc(allocator);
825 reboundAlloc.deallocate(p, n);
826}
827
828template <class t_ALLOCATOR, class t_POINTER, class t_VALUE_TYPE>
829inline
830void AllocatorUtil::deleteObjectImp(const t_ALLOCATOR& allocator,
831 t_POINTER p,
832 const t_VALUE_TYPE& )
833{
834 typedef AllocatorUtil_Traits<t_ALLOCATOR, t_VALUE_TYPE> Traits;
835
837
838 typename Traits::allocator_type reboundAlloc(allocator);
839 Traits::destroy(reboundAlloc, BSLS_UTIL_ADDRESSOF(*p));
840 reboundAlloc.deallocate(p, 1);
841}
842
843inline
844bool AllocatorUtil::isPowerOf2(std::size_t alignment)
845{
846 return (0 < alignment) && (0 == (alignment & (alignment - 1)));
847}
848
849
850// CLASS METHODS
851template <class t_ALLOC>
852inline
853typename bsl::enable_if<
855 t_ALLOC>::type
856AllocatorUtil::adapt(const t_ALLOC& from)
857{
858 return from;
859}
860
861template <class t_TYPE>
862inline
867
868template <class t_ALLOCATOR>
869inline
871AllocatorUtil::allocateBytes(const t_ALLOCATOR& allocator,
872 std::size_t nbytes,
873 std::size_t alignment)
874{
875 BSLS_ASSERT(isPowerOf2(alignment));
876
877 typedef
879 return allocateBytesImp(StdAlloc(allocator), nbytes, alignment);
880}
881
882template <class t_TYPE, class t_ALLOCATOR>
883inline
885AllocatorUtil::allocateObject(const t_ALLOCATOR& allocator, std::size_t n)
886{
888 reboundAlloc(allocator);
889 return reboundAlloc.allocate(n);
890}
891
892template <class t_TYPE>
893inline
894t_TYPE& AllocatorUtil::assign(t_TYPE *lhs, const t_TYPE& rhs, bsl::false_type)
895{
896 BSLS_ASSERT(*lhs == rhs);
897 (void)rhs;
898 return *lhs;
899}
900
901template <class t_TYPE>
902inline
903t_TYPE& AllocatorUtil::assign(t_TYPE *lhs, const t_TYPE& rhs, bsl::true_type)
904{
905 *lhs = rhs;
906 return *lhs;
907}
908
909template <class t_ALLOCATOR>
910inline
912 const t_ALLOCATOR& allocator,
914 std::size_t nbytes,
915 std::size_t alignment)
916{
917 BSLS_ASSERT(isPowerOf2(alignment));
918
919 typedef
921 deallocateBytesImp(StdAlloc(allocator), p, nbytes, alignment);
922}
923
924template <class t_ALLOCATOR, class t_POINTER>
925inline
926void AllocatorUtil::deallocateObject(const t_ALLOCATOR& allocator,
927 t_POINTER p,
928 std::size_t n)
929{
930 BSLS_ASSERT(t_POINTER() != p);
931 deallocateObjectImp(allocator, p, n, *p);
932}
933
934template <class t_ALLOCATOR, class t_POINTER>
935inline void
936AllocatorUtil::deleteObject(const t_ALLOCATOR& allocator, t_POINTER p)
937{
938 BSLS_ASSERT(t_POINTER() != p);
939 deleteObjectImp(allocator, p, *p);
940}
941
942template <class t_TYPE, class t_ALLOCATOR>
943inline
945AllocatorUtil::newObject(const t_ALLOCATOR& allocator)
946{
948
949 typename Traits::allocator_type reboundAlloc(allocator);
950 typename Traits::pointer p = reboundAlloc.allocate(1);
951 // Use a 'try' block because the proctor components are at a higher
952 // dependency level than this component. As there is only one possibly
953 // throwing statement, correctness of the 'try' block is easily verified.
954 BSLS_TRY {
955 Traits::construct(reboundAlloc, BSLS_UTIL_ADDRESSOF(*p));
956 }
957 BSLS_CATCH(...) {
958 reboundAlloc.deallocate(p, 1);
960 }
961 return p;
962}
963
964#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
965# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
966template <class t_TYPE, class t_ALLOCATOR, class t_ARG1, class... t_ARGS>
967inline
969AllocatorUtil::newObject(const t_ALLOCATOR& allocator,
970 t_ARG1& argument1,
971 t_ARGS&&... arguments)
972{
974
975 typename Traits::allocator_type reboundAlloc(allocator);
976 typename Traits::pointer p = reboundAlloc.allocate(1);
977 // Use a 'try' block because the proctor components are at a higher
978 // dependency level than this component. As there is only one possibly
979 // throwing statement, correctness of the 'try' block is easily verified.
980 BSLS_TRY {
981 Traits::construct(reboundAlloc,
983 argument1,
984 BSLS_COMPILERFEATURES_FORWARD(t_ARGS, arguments)...);
985 }
986 BSLS_CATCH(...) {
987 reboundAlloc.deallocate(p, 1);
989 }
990 return p;
991}
992# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
993
994template <class t_TYPE, class t_ALLOCATOR, class t_ARG1, class... t_ARGS>
995inline
997AllocatorUtil::newObject(const t_ALLOCATOR& allocator,
998 BSLS_COMPILERFEATURES_FORWARD_REF(t_ARG1) argument1,
999 t_ARGS&&... arguments)
1000{
1002
1003 typename Traits::allocator_type reboundAlloc(allocator);
1004 typename Traits::pointer p = reboundAlloc.allocate(1);
1005 // Use a 'try' block because the proctor components are at a higher
1006 // dependency level than this component. As there is only one possibly
1007 // throwing statement, correctness of the 'try' block is easily verified.
1008 BSLS_TRY {
1009 Traits::construct(reboundAlloc,
1011 BSLS_COMPILERFEATURES_FORWARD(t_ARG1, argument1),
1012 BSLS_COMPILERFEATURES_FORWARD(t_ARGS, arguments)...);
1013 }
1014 BSLS_CATCH(...) {
1015 reboundAlloc.deallocate(p, 1);
1017 }
1018 return p;
1019}
1020#endif
1021
1022template <class t_TYPE>
1023inline
1024void AllocatorUtil::swap(t_TYPE *pa, t_TYPE *pb, bsl::false_type)
1025{
1026 BSLS_ASSERT(*pa == *pb);
1027 (void)pa; (void)pb;
1028}
1029
1030template <class t_TYPE>
1031inline
1032void AllocatorUtil::swap(t_TYPE *pa, t_TYPE *pb, bsl::true_type)
1033{
1034 using std::swap;
1035 swap(*pa, *pb);
1036}
1037
1038} // close package namespace
1039
1040
1041#endif // End C++11 code
1042
1043#endif // ! defined(INCLUDED_BSLMA_ALLOCATORUTIL)
1044
1045// ----------------------------------------------------------------------------
1046// Copyright 2022 Bloomberg Finance L.P.
1047//
1048// Licensed under the Apache License, Version 2.0 (the "License");
1049// you may not use this file except in compliance with the License.
1050// You may obtain a copy of the License at
1051//
1052// http://www.apache.org/licenses/LICENSE-2.0
1053//
1054// Unless required by applicable law or agreed to in writing, software
1055// distributed under the License is distributed on an "AS IS" BASIS,
1056// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1057// See the License for the specific language governing permissions and
1058// limitations under the License.
1059// ----------------------------- END-OF-FILE ----------------------------------
1060
1061/** @} */
1062/** @} */
1063/** @} */
Definition bslma_bslallocator.h:580
BloombergLP::bslma::Allocator * mechanism() const
Definition bslma_bslallocator.h:1126
Definition bslma_memoryresource.h:441
BSLS_ANNOTATION_NODISCARD void * allocate(size_t bytes, size_t alignment=k_MAX_ALIGN)
Definition bslma_memoryresource.h:541
void deallocate(void *p, size_t bytes, size_t alignment=k_MAX_ALIGN)
Definition bslma_memoryresource.h:547
Definition bslma_polymorphicallocator.h:452
memory_resource * resource() const
Return the address of the memory resource supplied on construction.
Definition bslma_polymorphicallocator.h:1048
Definition bslma_allocator.h:457
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
static const bool value
Definition bslmf_integralconstant.h:258
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2012
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2018
#define BSLS_CATCH(X)
Definition bsls_exceptionutil.h:372
#define BSLS_TRY
Definition bsls_exceptionutil.h:370
#define BSLS_RETHROW
Definition bsls_exceptionutil.h:378
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_UTIL_ADDRESSOF(OBJ)
Definition bsls_util.h:289
Definition balxml_encoderoptions.h:68
void swap(TYPE &a, TYPE &b)
Definition bslma_allocatortraits.h:1061
Definition bslmf_conditional.h:120
Definition bslmf_enableif.h:525
Definition bslmf_integralconstant.h:244
Definition bslmf_isconst.h:144
Definition bslmf_isconvertible.h:867
Definition bslmf_issame.h:146
Definition bslmf_isvolatile.h:144
BSLMF_ASSERT(! bsl::is_volatile< t_TYPE >::value)
BSLMF_ASSERT(! bsl::is_const< t_TYPE >::value)
BSLMF_ASSERT((bsl::is_convertible< t_MEMORY_RSRC *, bsl::memory_resource * >::value))
Definition bslma_allocatorutil.h:658
BSLMF_ASSERT(! bsl::is_volatile< t_TYPE >::value)
BSLMF_ASSERT(! bsl::is_const< t_TYPE >::value)
Namespace for utility functions on allocators.
Definition bslma_allocatorutil.h:405
static bsl::enable_if<!IsDerivedFromBslAllocator< t_ALLOC >::value, t_ALLOC >::type adapt(const t_ALLOC &from)
Definition bslma_allocatorutil.h:856
static AllocatorUtil_Traits< t_ALLOCATOR, t_TYPE >::pointer newObject(const t_ALLOCATOR &allocator)
Definition bslma_allocatorutil.h:945
static AllocatorUtil_Traits< t_ALLOCATOR, t_TYPE >::pointer allocateObject(const t_ALLOCATOR &allocator, std::size_t n=1)
Definition bslma_allocatorutil.h:885
static void swap(t_TYPE *pa, t_TYPE *pb, bsl::false_type allowed)
Definition bslma_allocatorutil.h:1024
static void deallocateBytes(const t_ALLOCATOR &allocator, typename AllocatorUtil_Traits< t_ALLOCATOR >::void_pointer p, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_allocatorutil.h:911
static void deleteObject(const t_ALLOCATOR &allocator, t_POINTER p)
Definition bslma_allocatorutil.h:936
static AllocatorUtil_Traits< t_ALLOCATOR >::void_pointer allocateBytes(const t_ALLOCATOR &allocator, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_allocatorutil.h:871
static t_TYPE & assign(t_TYPE *lhs, const t_TYPE &rhs, bsl::true_type allowed)
Definition bslma_allocatorutil.h:903
static void deallocateObject(const t_ALLOCATOR &allocator, t_POINTER p, std::size_t n=1)
Definition bslma_allocatorutil.h:926
AlignmentImpPriorityToType< PRIORITY >::Type Type
Definition bsls_alignmenttotype.h:394
@ BSLS_MAX_ALIGNMENT
Definition bsls_alignmentutil.h:275