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