BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslma_constructionutil.h
Go to the documentation of this file.
1/// @file bslma_constructionutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslma_constructionutil.h -*-C++-*-
8#ifndef INCLUDED_BSLMA_CONSTRUCTIONUTIL
9#define INCLUDED_BSLMA_CONSTRUCTIONUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslma_constructionutil bslma_constructionutil
15/// @brief Provide methods to construct arbitrarily-typed objects uniformly.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslma
19/// @{
20/// @addtogroup bslma_constructionutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslma_constructionutil-purpose"> Purpose</a>
25/// * <a href="#bslma_constructionutil-classes"> Classes </a>
26/// * <a href="#bslma_constructionutil-description"> Description </a>
27/// * <a href="#bslma_constructionutil-type-traits"> Type Traits </a>
28/// * <a href="#bslma_constructionutil-usage"> Usage </a>
29/// * <a href="#bslma_constructionutil-example-1-using-bslma-constructionutil-to-implement-a-container"> Example 1: Using bslma::ConstructionUtil to Implement a Container </a>
30/// * <a href="#bslma_constructionutil-example-2-bslma-allocator-propagation"> Example 2: bslma Allocator Propagation </a>
31/// * <a href="#bslma_constructionutil-example-3-constructing-into-non-heap-memory"> Example 3: Constructing into Non-heap Memory </a>
32///
33/// # Purpose {#bslma_constructionutil-purpose}
34/// Provide methods to construct arbitrarily-typed objects uniformly.
35///
36/// # Classes {#bslma_constructionutil-classes}
37///
38/// - bslma::ConstructionUtil: namespace for methods to construct objects
39///
40/// @see bslma_allocator, bslma_bslallocator, bslma_destructionutil
41///
42/// # Description {#bslma_constructionutil-description}
43/// This component provides a `struct`, `bslma::ConstructionUtil`,
44/// that serves as a namespace for utility functions to construct objects of an
45/// arbitrary (template parameter) type, given an allocator and an arbitrary
46/// number of arguments. These functions are useful for uniformly constructing
47/// an object without concern for whether the object's type is allocator-aware
48/// (AA) and, if so, whether the allocator is passed at the end of the argument
49/// list (trailing allocator-argument convention) or at the start of the
50/// argument list, preceeded by `bsl::allocator_arg` (leading allocator-argument
51/// convention). If the type being constructed is not AA or if a non-allocator
52/// scalar such as an `int` or `void *` is passed to these methods, the
53/// allocator argument is discarded and a non-allocator constructor is invoked.
54///
55/// An additional `destructiveMove` method moves an object to a new address and
56/// destroys the object at the original address, often doing so as an efficient
57/// `memcpy` rather than separate move-destroy operations.
58///
59/// *Legacy-AA* (types with constructors having a parameter of type
60/// `bslma::Allocator *`) and *bsl-AA* types (types with constructors having a
61/// parameter of type `bsl::allocator<>`) are handled interchangeably by the
62/// functions in this component, accepting either a `bslma::Allocator*` or a
63/// `bsl::allocator` argument and then passing the appropriate type to the
64/// constructed type. Thus *bsl-AA* code can work seamlessly with *legacy-AA*
65/// code, allowing for a smooth transition from the old model to the new one.
66/// Note that this component does not directly use `bsl::allocator` or
67/// `bsl::polymorphic_allocator` because such use would cause a circular
68/// dependancy; an allocator is considered bsl-like if it is implicitly
69/// convertible from `bslma::Allocator *` and has a `mechanism` method that
70/// returns a `bslma::Allocator *` and an allocator is considered pmr-like if it
71/// is convertible from `bsl::memory_resource *` (and therefore also convertible
72/// from `bslma::Allocator *`.
73///
74/// The `construct` method provided here has roughly the same functionality as
75/// the C++20 library function `std::uninitialized_construct_using_allocator`
76/// and the `make` method has roughly the same functionality as
77/// `std::make_obj_using_allocator`, with the following differences:
78///
79/// * As described above, *Legacy-AA* types are treated as interchangle with
80/// *bsl-AA* types and `bslma::Allocator *` is treated as interchangeable
81/// with `bsl::allocator`.
82/// * The methods in this component accept a non-allocator scalar (e.g., `int`
83/// or `void *`) instead of an allocator to indicate that no allocator should
84/// be supplied to the object constructor, even if it is AA.
85/// * The `std` functions will ignore the allocator if it is incompatible with
86/// the object type being constructed. The methods in this component,
87/// conversely, will ignore the allocator only for *non-AA* and *stl-AA*
88/// types. For *legacy-AA*, *bsl-AA*, and *pmr-AA* types, an incompatible
89/// allocator will result in a compilation failure. This special case exists
90/// to avoid subtle errors in the Bloomberg code base where a bad allocator
91/// argument is used in a situation where allocator propagation is expected.
92/// * This component does not provide special handling for `std::pair`.
93///
94/// ## Type Traits {#bslma_constructionutil-type-traits}
95///
96///
97/// The facilities in this component query several type traits of the `TYPE`
98/// being constructed, using that information as follows:
99/// @code
100/// Trait How Used
101/// --------------------------- -----------------------------------------------
102/// bslma::UsesBslmaAllocator If true, the allocator being passed in must be
103/// either convertible to `bslma::Allocator *` or
104/// else have a `mechanism` accessor. If false,
105/// the allocator argument must be convertible to
106/// the `TYPE::allocator_type`.
107///
108/// bslma::HasAllocatorType If true, `TYPE::allocator_type` is assumed to
109/// the type of allocator accepted by `TYPE`'s
110/// constructors.
111///
112/// bsl::uses_allocator<TYPE,A> If true, then `A` can be used as an allocator
113/// to construct `TYPE`.
114///
115/// bslmf::UsesAllocatorArgT If true, an allocator argument is passed as the
116/// second argument to the constructor, preceeded
117/// by a `bsl::allocator_arg` tag; otherwise the
118/// allocator is passed as the last argument to the
119/// constructor.
120///
121/// bslmf::IsBitwiseMoveable If true, `destructiveMove` is implemented as a
122/// simple `memcpy`, rather than as a move-destroy
123/// sequence.
124/// @endcode
125///
126/// ## Usage {#bslma_constructionutil-usage}
127///
128///
129/// This section illustrates intended use of this component.
130///
131/// ### Example 1: Using bslma::ConstructionUtil to Implement a Container {#bslma_constructionutil-example-1-using-bslma-constructionutil-to-implement-a-container}
132///
133///
134/// This example demonstrates the intended use of `bslma::ConstructionUtil` to
135/// implement a simple container class that uses an instance of `bsl::allocator`
136/// for memory management.
137///
138/// First, because allocation and construction are done in two separate steps,
139/// we need to define a proctor type that will deallocate the allocated memory
140/// in case the constructor throws an exception:
141/// @code
142/// #include <bslma_bslallocator.h>
143///
144/// /// This class implements a proctor to release memory allocated during
145/// /// the construction of a `MyContainer` object if the constructor for
146/// /// the container's data element throws an exception. Such a proctor
147/// /// should be `release`d once the element is safely constructed.
148/// template <class TYPE>
149/// class MyContainerProctor {
150///
151/// // DATA
152/// bsl::allocator<TYPE> d_allocator;
153/// TYPE *d_address_p; // proctored memory
154///
155/// private:
156/// // NOT IMPLEMENTED
157/// MyContainerProctor(const MyContainerProctor&); // = delete
158/// MyContainerProctor& operator=(const MyContainerProctor&); // = delete
159///
160/// public:
161/// // CREATORS
162///
163/// /// Create a proctor that conditionally manages the memory at the
164/// /// specified `address`, and that uses the specified `allocator` to
165/// /// deallocate the block of memory (if not released -- see
166/// /// `release`) upon destruction. The behavior is undefined unless
167/// /// `allocator` is non-zero and supplied the memory at `address`.
168/// MyContainerProctor(const bsl::allocator<TYPE> allocator, TYPE *address)
169/// : d_allocator(allocator)
170/// , d_address_p(address)
171/// {
172/// }
173///
174/// /// Destroy this proctor, and deallocate the block of memory it
175/// /// manages (if any) by invoking the `deallocate` method of the
176/// /// allocator that was supplied at construction of this proctor. If
177/// /// no memory is currently being managed, this method has no effect.
178/// ~MyContainerProctor()
179/// {
180/// if (d_address_p) {
181/// d_allocator.deallocate(d_address_p, 1);
182/// }
183/// }
184///
185/// // MANIPULATORS
186///
187/// /// Release from management the block of memory currently managed by
188/// /// this proctor. If no memory is currently being managed, this
189/// /// method has no effect.
190/// void release()
191/// {
192/// d_address_p = 0;
193/// }
194/// };
195/// @endcode
196/// Then, we create a container class that holds a single element and uses
197/// `bsl::allocator` to supply memory:
198/// @code
199/// #include <bslma_constructionutil.h>
200///
201/// /// This class provides a container that always holds exactly one
202/// /// element, dynamically allocated using the specified `bslma`
203/// /// allocator.
204/// template <class TYPE>
205/// class MyContainer {
206///
207/// // DATA
208/// bsl::allocator<TYPE> d_allocator;
209/// TYPE *d_value_p;
210///
211/// /// Return the address of a new element that was allocated from this
212/// /// container's allocator and initialized with the optionally
213/// /// specified `value`, or default-initialized if `value` is not
214/// /// specified. If `TYPE` is AA, this container's allocator is used
215/// /// to construct the new element.
216/// TYPE *createElement();
217/// TYPE *createElement(const TYPE& value);
218///
219/// public:
220/// typedef bsl::allocator<TYPE> allocator_type;
221///
222/// // CREATORS
223///
224/// /// Create a container with a default-constructed element.
225/// /// Optionally specify a `allocator` used to supply memory.
226/// explicit
227/// MyContainer(const allocator_type& allocator = allocator_type())
228/// : d_allocator(allocator), d_value_p(createElement()) { }
229///
230/// /// Create a container having an element constructed from the
231/// /// specified `value`. Optionally specify an `allocator` to supply
232/// /// memory both for the container and for the contained element.
233/// explicit
234/// MyContainer(const TYPE& value,
235/// const allocator_type& allocator = allocator_type())
236/// : d_allocator(allocator), d_value_p(createElement(value)) { }
237///
238/// /// Create a container having the same value as the specified
239/// /// `original` object. Optionally specify a `allocator` used
240/// /// to supply memory. If `allocator` is 0, the currently
241/// /// installed default allocator is used.
242/// MyContainer(const MyContainer& original,
243/// const allocator_type& allocator = allocator_type())
244/// : d_allocator(allocator)
245/// , d_value_p(createElement(*original.d_value_p)) { }
246///
247/// /// Destroy this object.
248/// ~MyContainer();
249///
250/// // MANIPULATORS
251///
252/// /// Assign to this object the value of the specified `rhs` object,
253/// /// and return a reference providing modifiable access to this
254/// /// object.
255/// MyContainer& operator=(const TYPE& rhs);
256/// MyContainer& operator=(const MyContainer& rhs);
257///
258/// /// Return a non-`const` reference to the element contained in this
259/// /// object.
260/// TYPE& front()
261/// {
262/// return *d_value_p;
263/// }
264///
265/// // ACCESSORS
266///
267/// /// Return a `const` reference to the element contained in this
268/// /// object.
269/// const TYPE& front() const
270/// {
271/// return *d_value_p;
272/// }
273///
274/// /// Return the allocator used by this object to supply memory.
275/// allocator_type get_allocator() const
276/// {
277/// return d_allocator;
278/// }
279///
280/// // etc.
281/// };
282/// @endcode
283/// Next, we implement the private `createElement` members that allocate memory
284/// and construct a `TYPE` object in the allocated memory. We perform the
285/// allocation using the `allocate` method of `bsl::allocator` and the
286/// construction using the `construct` method of `ConstructionUtil` that
287/// provides the correct semantics for passing the allocator to the constructed
288/// object when appropriate:
289/// @code
290/// template <class TYPE>
291/// TYPE *MyContainer<TYPE>::createElement()
292/// {
293/// TYPE *value_p = d_allocator.allocate(1);
294/// MyContainerProctor<TYPE> proctor(d_allocator, value_p);
295///
296/// // Call 'construct' passing the allocator but no constructor
297/// // arguments.
298///
299/// bslma::ConstructionUtil::construct(value_p, d_allocator);
300/// proctor.release();
301///
302/// return value_p;
303/// }
304///
305/// template <class TYPE>
306/// TYPE *MyContainer<TYPE>::createElement(const TYPE& value)
307/// {
308/// TYPE *value_p = d_allocator.allocate(1);
309/// MyContainerProctor<TYPE> proctor(d_allocator, value_p);
310///
311/// // Call 'construct' passing the allocator and 'value' arguments.
312///
313/// bslma::ConstructionUtil::construct(value_p, d_allocator, value);
314/// proctor.release();
315///
316/// return value_p;
317/// }
318/// @endcode
319/// Now, the destructor destroys the object and deallocates the memory used to
320/// hold the element using the allocator:
321/// @code
322/// template <class TYPE>
323/// MyContainer<TYPE>::~MyContainer()
324/// {
325/// d_value_p->~TYPE();
326/// d_allocator.deallocate(d_value_p, 1);
327/// }
328/// @endcode
329/// Next, the assignment operator needs to assign the value without modifying
330/// the allocator.
331/// @code
332/// template <class TYPE>
333/// MyContainer<TYPE>& MyContainer<TYPE>::operator=(const TYPE& rhs)
334/// {
335/// if (&rhs != d_value_p) {
336/// *d_value_p = rhs;
337/// }
338/// return *this;
339/// }
340///
341/// template <class TYPE>
342/// MyContainer<TYPE>& MyContainer<TYPE>::operator=(const MyContainer& rhs)
343/// {
344/// return operator=(*rhs.d_value_p);
345/// }
346/// @endcode
347/// Finally, we perform a simple test of `MyContainer`, instantiating it with
348/// element type `int`:
349/// @code
350/// int main()
351/// {
352/// bslma::TestAllocator testAlloc;
353/// MyContainer<int> C1(123, &testAlloc);
354/// assert(C1.get_allocator() == &testAlloc);
355/// assert(C1.front() == 123);
356///
357/// MyContainer<int> C2(C1);
358/// assert(C2.get_allocator() == bslma::Default::defaultAllocator());
359/// assert(C2.front() == 123);
360///
361/// return 0;
362/// }
363/// @endcode
364///
365/// ### Example 2: bslma Allocator Propagation {#bslma_constructionutil-example-2-bslma-allocator-propagation}
366///
367///
368/// This example demonstrates that `MyContainer` does indeed propagate the
369/// allocator to its contained element.
370///
371/// First, we create a representative element class, `MyType`. Unlike the
372/// `MyContainer` template, `MyType` allocates memory using the
373/// `bslma::Allocator *` (legacy) allocator model instead of the
374/// `bsl::allocator` (bsl) allocator model:
375/// @code
376/// #include <bslma_default.h>
377///
378/// class MyType {
379///
380/// // DATA
381/// bslma::Allocator *d_allocator_p;
382/// int d_value;
383/// // ...
384///
385/// public:
386/// // TRAITS
387/// BSLMF_NESTED_TRAIT_DECLARATION(MyType, bslma::UsesBslmaAllocator);
388///
389/// // CREATORS
390///
391/// /// Create a `MyType` object having the default value. Optionally
392/// /// specify a `basicAllocator` used to supply memory. If
393/// /// `basicAllocator` is 0, the currently installed default allocator
394/// /// is used.
395/// explicit MyType(bslma::Allocator *basicAllocator = 0)
396/// : d_allocator_p(bslma::Default::allocator(basicAllocator))
397/// , d_value()
398/// {
399/// // ...
400/// }
401///
402/// /// Create a `MyType` object having the specified `value`.
403/// /// Optionally specify a `basicAllocator` used to supply memory. If
404/// /// `basicAllocator` is 0, the currently installed default allocator
405/// /// is used.
406/// explicit MyType(int value,
407/// bslma::Allocator *basicAllocator = 0)
408/// : d_allocator_p(bslma::Default::allocator(basicAllocator))
409/// , d_value(value)
410/// {
411/// // ...
412/// }
413///
414/// /// Create a `MyType` object having the same value as the specified
415/// /// `original` object. Optionally specify a `basicAllocator` used
416/// /// to supply memory. If `basicAllocator` is 0, the currently
417/// /// installed default allocator is used.
418/// MyType(const MyType& original, bslma::Allocator *basicAllocator = 0)
419/// : d_allocator_p(bslma::Default::allocator(basicAllocator))
420/// , d_value(original.value())
421/// {
422/// // ...
423/// }
424///
425/// // ...
426///
427/// // ACCESSORS
428///
429/// /// Return the allocator used by this object to supply memory.
430/// bslma::Allocator *allocator() const
431/// {
432/// return d_allocator_p;
433/// }
434///
435/// /// Return the value of this object.
436/// int value() const
437/// {
438/// return d_value;
439/// }
440///
441/// // ...
442/// };
443/// @endcode
444/// Finally, we instantiate `MyContainer` using `MyType` and verify that, when
445/// we provide an allocator to the constructor of the container, the same
446/// allocator is passed to the constructor of the contained element. Because
447/// the container and the element implement different allocator models, the
448/// invocation of `bslma::ConstructionUtil::construct` automatically adapts the
449/// `bsl::allocator` held by the container to a `bslma::Allocator` pointer
450/// expected by the element. We also verify that, when the container is
451/// copy-constructed without supplying an allocator, the copy uses the default
452/// allocator, not the allocator from the original object. Moreover, we verify
453/// that the element stored in the copy also uses the default allocator:
454/// @code
455/// int main()
456/// {
457/// bslma::TestAllocator testAlloc;
458/// bslma::TestAllocator testAlloc2;
459///
460/// MyContainer<MyType> C1(&testAlloc); // extended default constructor
461/// assert(C1.get_allocator() == &testAlloc);
462/// assert(C1.front().allocator() == &testAlloc);
463/// assert(C1.front().value() == 0);
464///
465/// MyContainer<MyType> C2(MyType(22), &testAlloc); // value constructor
466/// assert(C2.get_allocator() == &testAlloc);
467/// assert(C2.front().allocator() == &testAlloc);
468/// assert(C2.front().value() == 22);
469///
470/// MyContainer<MyType> C3(C2);
471/// assert(C3.get_allocator() != C2.get_allocator());
472/// assert(C3.get_allocator() == bslma::Default::defaultAllocator());
473/// assert(C3.front().allocator() != C1.front().allocator());
474/// assert(C3.front().allocator() == bslma::Default::defaultAllocator());
475/// assert(C3.front().value() == 22);
476///
477/// MyContainer<MyType> C4(C2, &testAlloc2);
478/// assert(C4.get_allocator() == &testAlloc2);
479/// assert(C4.front().allocator() == &testAlloc2);
480/// assert(C4.front().value() == 22);
481/// }
482/// @endcode
483///
484/// ### Example 3: Constructing into Non-heap Memory {#bslma_constructionutil-example-3-constructing-into-non-heap-memory}
485///
486///
487/// This example demonstrates using `bslma::ConstructionUtil::make` to
488/// implement a simple wrapper class that contains a single item that might or
489/// might not use the `bslma` allocator protocol.
490///
491/// First, we define a wrapper class that holds an object and a functor. The
492/// functor (known as the *listener*) is called each time the wrapped object is
493/// changes. We store the object directly as a member variable, instead of
494/// using an uninitialized buffer, to avoid a separate construction step:
495/// @code
496/// /// This class is a wrapper around an object of the specified `TYPE`
497/// /// that triggers a call to an object, called the "listener", of the
498/// /// specified `FUNC` invocable type whenever the wrapped object is
499/// /// changed.
500/// template <class TYPE, class FUNC>
501/// class MyTriggeredWrapper {
502///
503/// // DATA
504/// TYPE d_value;
505/// FUNC d_listener;
506///
507/// public:
508/// typedef bsl::allocator<> allocator_type;
509///
510/// // CREATORS
511///
512/// /// Create an object with the specified `f` as the listener to be
513/// /// called when a change is triggered. Optionally specify `v` as
514/// /// the wrapped value; otherwise the wrapped value is default
515/// /// constructed. Optionally specify `allocator` to supply
516/// /// memory; otherwise the current default allocator is used. If
517/// /// `TYPE` is not allocator aware, `allocator` is ignored.
518/// explicit
519/// MyTriggeredWrapper(const FUNC& f,
520/// const allocator_type& allocator = allocator_type());
521/// MyTriggeredWrapper(const TYPE& v,
522/// const FUNC& f,
523/// const allocator_type& allocator = allocator_type());
524///
525/// /// Create a copy of the specified `original`. Optionally specify
526/// /// `allocator` to supply memory; otherwise the current
527/// /// default allocator is used.
528/// MyTriggeredWrapper(const MyTriggeredWrapper& original,
529/// const allocator_type& allocator = allocator_type());
530///
531/// /// Destroy the wrapped object and listener.
532/// ~MyTriggeredWrapper()
533/// {
534/// }
535///
536/// // MANIPULATORS
537///
538/// /// Assign to the wrapped value the value of the specified `rhs`,
539/// /// invoke the listener with the new value, and return a reference
540/// /// providing modifiable access to this object. Note that the
541/// /// listener itself is not assigned.
542/// MyTriggeredWrapper& operator=(const TYPE& rhs);
543/// MyTriggeredWrapper& operator=(const MyTriggeredWrapper& rhs);
544///
545/// /// Set the wrapped value to the specified `value` and invoke the
546/// /// listener with the new value.
547/// void setValue(const TYPE& value);
548///
549/// // ACCESSORS
550///
551/// /// Return a reference providing read-only access to the wrapped
552/// /// value.
553/// const TYPE& value() const
554/// {
555/// return d_value;
556/// }
557///
558/// /// Return a reference providing read-only access to the listener.
559/// const FUNC& listener() const
560/// {
561/// return d_listener;
562/// }
563/// };
564/// @endcode
565/// Next, we define the constructors such that they initialize `d_value` using
566/// the specified allocator if and only if `TYPE` accepts an allocator. The
567/// `bslma::ConstructionUtil::make` family of functions encapsulate all of the
568/// metaprogramming that detects whether `TYPE` uses an allocator and, if so,
569/// which construction protocol it uses (allocator at the front or at the back
570/// of the argument list), making all three constructors straightforward:
571/// @code
572/// template <class TYPE, class FUNC>
573/// MyTriggeredWrapper<TYPE, FUNC>::MyTriggeredWrapper(
574/// const FUNC& f,
575/// const allocator_type& allocator)
576/// : d_value(bslma::ConstructionUtil::make<TYPE>(allocator))
577/// , d_listener(f)
578/// {
579/// }
580///
581/// template <class TYPE, class FUNC>
582/// MyTriggeredWrapper<TYPE, FUNC>::MyTriggeredWrapper(
583/// const TYPE& v,
584/// const FUNC& f,
585/// const allocator_type& allocator)
586/// : d_value(bslma::ConstructionUtil::make<TYPE>(allocator, v))
587/// , d_listener(f)
588/// {
589/// }
590///
591/// template <class TYPE, class FUNC>
592/// MyTriggeredWrapper<TYPE, FUNC>::MyTriggeredWrapper(
593/// const MyTriggeredWrapper& other,
594/// const allocator_type& allocator)
595/// : d_value(bslma::ConstructionUtil::make<TYPE>(allocator, other.value()))
596/// , d_listener(other.d_listener)
597/// {
598/// }
599/// @endcode
600/// Note that, for `d_value` to be constructed with the correct allocator, the
601/// compiler must construct the result returned from `make` directly into the
602/// `d_value` variable, an optimization known prior to C++17 as "copy elision".
603/// This optimization is required by the C++17 standard and is optional in
604/// pre-2017 standards, but is implemented in all of the C++11 compilers for
605/// which this component is expected to be used at Bloomberg.
606///
607/// Next, we implement the assignment operators, which simply call `setValue`:
608/// @code
609/// template <class TYPE, class FUNC>
610/// MyTriggeredWrapper<TYPE, FUNC>&
611/// MyTriggeredWrapper<TYPE, FUNC>::operator=(const TYPE& rhs)
612/// {
613/// setValue(rhs);
614/// return *this;
615/// }
616///
617/// template <class TYPE, class FUNC>
618/// MyTriggeredWrapper<TYPE, FUNC>&
619/// MyTriggeredWrapper<TYPE, FUNC>::operator=(const MyTriggeredWrapper& rhs)
620/// {
621/// setValue(rhs.value());
622/// return *this;
623/// }
624/// @endcode
625/// Then, we implement `setValue`, which calls the listener after modifying the
626/// value:
627/// @code
628/// template <class TYPE, class FUNC>
629/// void MyTriggeredWrapper<TYPE, FUNC>::setValue(const TYPE& value)
630/// {
631/// d_value = value;
632/// d_listener(d_value);
633/// }
634/// @endcode
635/// Finally, we check our work by creating a listener for `MyContainer<int>`
636/// that stores its last-seen value in a known location and a wrapper around
637/// `MyContainer<int>` to test it:
638/// @code
639/// int lastSeen = 0;
640/// void myListener(const MyContainer<int>& c)
641/// {
642/// lastSeen = c.front();
643/// }
644///
645/// int main()
646/// {
647/// bslma::TestAllocator testAlloc;
648/// MyTriggeredWrapper<MyContainer<int>,
649/// void (*)(const MyContainer<int>&)>
650/// wrappedContainer(myListener, &testAlloc);
651/// assert(&testAlloc == wrappedContainer.value().get_allocator());
652///
653/// wrappedContainer = MyContainer<int>(99);
654///
655/// assert(99 == lastSeen);
656/// }
657/// @endcode
658/// @}
659/** @} */
660/** @} */
661
662/** @addtogroup bsl
663 * @{
664 */
665/** @addtogroup bslma
666 * @{
667 */
668/** @addtogroup bslma_constructionutil
669 * @{
670 */
671
672#include <bslscm_version.h>
673
674#include <bslma_allocator.h>
677#include <bslma_pointerutil.h>
679
680#include <bslmf_allocatorargt.h>
683#include <bslmf_isclass.h>
684#include <bslmf_isconvertible.h>
685#include <bslmf_isfundamental.h>
686#include <bslmf_ispointer.h>
687#include <bslmf_movableref.h>
688#include <bslmf_usesallocator.h>
690#include <bslmf_util.h> // 'forward(V)' for C++03
691
692#include <bsls_assert.h>
694#include <bsls_util.h> // 'forward<T>(V)' for C++11
695
696#include <new> // placement 'new'
697
698#include <string.h>
699
700#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
701# include <bslmf_ismemberpointer.h>
702# include <bsls_libraryfeatures.h>
703#endif
704
705#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
706// clang-format off
707// Include version that can be compiled with C++03
708// Generated on Mon Jan 13 08:31:27 2025
709// Command line: sim_cpp11_features.pl bslma_constructionutil.h
710
711# define COMPILING_BSLMA_CONSTRUCTIONUTIL_H
713# undef COMPILING_BSLMA_CONSTRUCTIONUTIL_H
714
715// clang-format on
716#else
717
718
719namespace bslma {
720
721struct ConstructionUtil_Imp;
722
723 // =======================
724 // struct ConstructionUtil
725 // =======================
726
727/// This `struct` provides a namespace for utility functions that construct
728/// elements of (a template parameter) `TARGET_TYPE`.
729///
730/// See @ref bslma_constructionutil
732
733 private:
734 // PRIVATE TYPES
735
736 /// This `typedef` is a convenient alias for the implementation-specific
737 /// utility class defined in this component.
739
740 public:
741 // CLASS METHODS
742
743 /// Create a default-constructed object of (template parameter)
744 /// `TARGET_TYPE` at the specified `address`. If `allocator` is a
745 /// `bslma`-compatible allocator and `TARGET_TYPE` supports
746 /// `bslma`-style allocation, `allocator` is passed to the default
747 /// extended constructor; otherwise, `allocator` is ignored. If the
748 /// constructor throws, the memory at `address` is left in an unspecified state.
749 ///
750 /// \pre The behavior is undefined unless `address`
751 /// refers to a block that is of sufficient size and properly aligned
752 /// for objects of `TARGET_TYPE`.
753 template <class TARGET_TYPE, class ALLOCATOR>
754 static void construct(TARGET_TYPE *address, const ALLOCATOR& allocator);
755
756#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13
757# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
758 // 'ARG1' lvalue overloaded unneeded in C++11 and hits bug in gcc < 10.2.
759 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
760 static void construct(TARGET_TYPE *address,
761 const ALLOCATOR& allocator,
762 ARG1& argument1,
763 ARGS&&... arguments);
764# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
765
766 /// Create an object of (template parameter) `TARGET_TYPE` at the
767 /// specified `address`, constructed by forwarding the specified
768 /// `argument1` and the (variable number of) additional specified
769 /// `arguments` to the corresponding constructor of `TARGET_TYPE`. If
770 /// the specified `allocator` is a bslma-compatible allocator and
771 /// `TARGET_TYPE` supports `bslma`-style allocation, the allocator is
772 /// passed to the constructor; otherwise, `allocator` is ignored. If
773 /// the constructor throws, the memory at `address` is left in an unspecified state.
774 ///
775 /// \note Note that, in C++03, perfect forwarding is
776 /// limited such that any lvalue reference in the `arguments` parameter
777 /// pack is const-qualified when forwarded to the `TARGET_TYPE`
778 /// constructor; only `argument1` can be forwarded as an unqualified lvalue.
779 ///
780 /// \pre The behavior is undefined unless `address` refers to a
781 /// block that is of sufficient size and properly aligned for objects of
782 /// `TARGET_TYPE`.
783 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
784 static void construct(TARGET_TYPE *address,
785 const ALLOCATOR& allocator,
786 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
787 ARGS&&... arguments);
788#endif
789
790 /// Create an object of (template parameter) `TARGET_TYPE` at the
791 /// specified `address` by moving from the specified `original` object,
792 /// then destroy `original`. The specified `allocator` is unused
793 /// (except possibly in precondition checks). The constructed object
794 /// will have the same allocator (if any) as `original`. If
795 /// `bslmf::IsBitwiseMoveable<TARGET_TYPE>::value` is `true`, then the
796 /// entire operation is a simple `memcpy` -- no constructors or
797 /// destructors are invoked; otherwise, this method move-constructs an
798 /// object at `address` from the object at `original` then invokes the
799 /// destructor on `original`. If the move constructor throws an
800 /// exception, the memory at `address` is left in an uninitialized state
801 /// and `original` is left in a valid but unspecified state.
802 ///
803 /// \pre The behavior is undefined if `original` uses an allocator other than `allocator` to supply memory.
804 ///
805 /// \note Note that if `original` points to an
806 /// object of a type derived from `TARGET_TYPE` (i.e., a slicing move)
807 /// where `TARGET_TYPE` has a non-`virtual` destructor, then `original`
808 /// will be only partially destroyed.
809 template <class TARGET_TYPE, class ALLOCATOR>
810 static void destructiveMove(TARGET_TYPE *address,
811 const ALLOCATOR& allocator,
812 TARGET_TYPE *original);
813
814#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
815 /// Return, by value, an object of the specified (template parameter)
816 /// `TARGET_TYPE`, having default value. If `allocator` is a
817 /// `bslma`-compatible allocator and `TARGET_TYPE` supports
818 /// `bslma`-style allocation, `allocator` is passed to the extended
819 /// default constructor; otherwise, `allocator` is ignored.
820 ///
821 /// \note Note that this method is available only for compilers that reliably implement
822 /// copy/move elision (i.e., RVO) on the returned object. This
823 /// copy/move elision is required starting with C++17 and is widely
824 /// implemented, though optional, prior to C++17.
825 template <class TARGET_TYPE, class ALLOCATOR>
826 static TARGET_TYPE make(const ALLOCATOR& allocator);
827
828#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
829# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
830 // 'ARG1' lvalue overloaded unneeded in C++11 and hits bug in gcc < 10.2.
831 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
832 static TARGET_TYPE make(const ALLOCATOR& allocator,
833 ARG1& argument1,
834 ARGS&&... arguments);
835# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
836
837 /// Return, by value, an object of the specified (template parameter)
838 /// `TARGET_TYPE`, constructed by forwarding the specified `argument1`
839 /// and the (variable number of) additional specified `arguments` to the
840 /// corresponding constructor of `TARGET_TYPE`. If the specified
841 /// `allocator` is a bslma-compatible allocator and `TARGET_TYPE`
842 /// supports `bslma`-style allocation, the allocator is passed to the constructor; otherwise, `allocator` is ignored.
843 ///
844 /// \note Note that this
845 /// method is available only for compilers that reliably implement
846 /// copy/move elision (i.e., RVO) on the returned object. This
847 /// copy/move elision is required starting with C++17 and is widely implemented, though optional, prior to C++17.
848 ///
849 /// \note Note that, in C++03,
850 /// perfect forwarding is limited such that any lvalue reference in the
851 /// `arguments` parameter pack is const-qualified when forwarded to the
852 /// `TARGET_TYPE` constructor; only `argument1` can be forwarded as an
853 /// unqualified lvalue.
854 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
855 static TARGET_TYPE make(const ALLOCATOR& allocator,
856 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
857 ARGS&&... arguments);
858#endif
859#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
860};
861
862 // ===========================
863 // struct ConstructionUtil_Imp
864 // ===========================
865
866/// This `struct` provides a namespace for a suite of utility functions that
867/// are used to implement functions in `ConstructionUtil`. In particular,
868/// they provide overloads, resolved at compile-time, for various features
869/// (e.g., passing down the allocator to sub-elements of `pair`-like types)
870/// and optimizations (e.g., bypassing the call to the constructor for
871/// classes with trivial default and copy constructors). These functions
872/// should not be used outside this component.
873///
874/// See @ref bslma_constructionutil
876
877 // TYPES
878
879 /// These constants are used in the overloads below, when the last argument
880 /// is of type `bsl::integral_constant<int, N> *`, indicating that
881 /// `TARGET_TYPE` has the traits for which the enumerator equal to `N` is
882 /// named.
883 enum {
884
888 e_USES_ALLOCATOR_ARG_T_TRAITS // Implies USES_ALLOCATOR
889 };
890
891 // CLASS METHODS
892
893 /// Construct a default instance of (template parameter) `TARGET_TYPE`
894 /// at the specified `address`, passing to the constructor the specified
895 /// `allocator` using the leading or trailing allocator convention,
896 /// according to the specified `integral_constant` tag, or ignoring
897 /// `allocator` in the `e_NIL_TRAITS` case. If the constructor throws,
898 /// the memory at `address` is left in an unspecified state.
899 template <class TARGET_TYPE, class ALLOCATOR>
900 static void construct(
901 TARGET_TYPE *address,
902 const ALLOCATOR& allocator,
904 template <class TARGET_TYPE, class ALLOCATOR>
905 static void construct(
906 TARGET_TYPE *address,
907 const ALLOCATOR& allocator,
909 template <class TARGET_TYPE, class ALLOCATOR>
910 static void construct(
911 TARGET_TYPE *address,
912 const ALLOCATOR& allocator,
914
915#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
916# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
917 // 'ARG1' lvalue overloaded unneeded in C++11 and hits bug in gcc < 10.2.
918 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
919 static void construct(
920 TARGET_TYPE *address,
921 const ALLOCATOR& allocator,
923 ARG1& argument1,
924 ARGS&&... arguments);
925 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
926 static void construct(
927 TARGET_TYPE *address,
928 const ALLOCATOR& allocator,
930 ARG1& argument1,
931 ARGS&&... arguments);
932 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
933 static void construct(
934 TARGET_TYPE *address,
935 const ALLOCATOR& allocator,
937 ARG1& argument1,
938 ARGS&&... arguments);
939# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
940
941 /// Construct an instance of (template parameter) `TARGET_TYPE` at the
942 /// specified `address` forwarding to the constructor the specified
943 /// `argument1` and `arguments` arguments and passing the specified
944 /// `allocator` using the leading or trailing allocator convention,
945 /// according to the specified `integral_constant` tag, or ignoring
946 /// `allocator` in the `e_NIL_TRAITS` case. If the constructor throws,
947 /// the memory at `address` is left in an unspecified state.
948 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
949 static void construct(
950 TARGET_TYPE *address,
951 const ALLOCATOR& allocator,
953 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
954 ARGS&&... arguments);
955 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
956 static void construct(
957 TARGET_TYPE *address,
958 const ALLOCATOR& allocator,
960 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
961 ARGS&&... arguments);
962 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
963 static void construct(
964 TARGET_TYPE *address,
965 const ALLOCATOR& allocator,
967 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
968 ARGS&&... arguments);
969#endif
970
971 /// Move the bitwise movable object of (template parameter)
972 /// `TARGET_TYPE` at the specified `original` address to the specified
973 /// `address`, eliding the call to the move constructor and destructor
974 /// in favor of performing a bitwise copy. The specified `allocator`
975 /// argument is ignored (except possibly for precondition checks).
976 ///
977 /// \pre The behavior is undefined if `original` uses an allocator other than
978 /// `allocator` to supply memory.
979 template <class TARGET_TYPE, class ALLOCATOR>
980 static void destructiveMove(
981 TARGET_TYPE *address,
982 const ALLOCATOR& allocator,
984 TARGET_TYPE *original);
985
986 /// Create an object of (template parameter) `TARGET_TYPE` at the
987 /// specified `address` by move construction from the specified
988 /// `original` object, then destroy `original`. The specified
989 /// `allocator` is unused (except possibly in precondition checks). The
990 /// constructed object will have the same allocator (if any) as
991 /// `original`. If the move constructor throws an exception, the memory
992 /// at `address` is left in an uninitialized state and `original` is left in a valid but unspecified state.
993 ///
994 /// \pre The behavior is undefined if
995 /// `original` uses an allocator other than `allocator` to supply memory.
996 ///
997 /// \note Note that, if `original` points to an object of a type
998 /// derived from `TARGET_TYPE` (i.e., a slicing move) where
999 /// `TARGET_TYPE` has a non-`virtual` destructor, then `original` will
1000 /// be only partially destroyed.
1001 template <class TARGET_TYPE, class ALLOCATOR>
1002 static void destructiveMove(
1003 TARGET_TYPE *address,
1004 const ALLOCATOR& allocator,
1006 TARGET_TYPE *original);
1007
1008#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
1009 /// Return, by value, a default-constructed object of (template
1010 /// parameter) `TARGET_TYPE`, passing the specified `allocator` to the
1011 /// constructor using the leading or trailing allocator convention,
1012 /// according to the specified `integral_constant` tag, or ignoring
1013 /// `allocator` in the `e_NIL_TRAITS` case.
1014 template <class TARGET_TYPE, class ALLOCATOR>
1015 static TARGET_TYPE make(
1016 const ALLOCATOR& allocator,
1018 template <class TARGET_TYPE, class ALLOCATOR>
1019 static TARGET_TYPE make(
1020 const ALLOCATOR& allocator,
1022 template <class TARGET_TYPE, class ALLOCATOR>
1023 static TARGET_TYPE make(
1024 const ALLOCATOR& allocator,
1026
1027#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1028# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1029 // 'ARG1' lvalue overloaded unneeded in C++11 and hits bug in gcc < 10.2.
1030 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1031 static TARGET_TYPE make(
1032 const ALLOCATOR& allocator,
1034 ARG1& argument1,
1035 ARGS&&... arguments);
1036 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1037 static TARGET_TYPE make(
1038 const ALLOCATOR& allocator,
1040 ARG1& argument1,
1041 ARGS&&... arguments);
1042 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1043 static TARGET_TYPE make(
1044 const ALLOCATOR& allocator,
1046 ARG1& argument1,
1047 ARGS&&... arguments);
1048# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1049
1050 /// Return, by value, an instance of (template parameter) `TARGET_TYPE`,
1051 /// forwarding to the constructor the specified `argument1` and
1052 /// `arguments` arguments and passing the specified `allocator` using
1053 /// the leading or trailing allocator convention, according to the
1054 /// specified `integral_constant` tag, or ignoring `allocator` in the
1055 /// `e_NIL_TRAITS` case.
1056 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1057 static TARGET_TYPE make(
1058 const ALLOCATOR& allocator,
1060 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1061 ARGS&&... arguments);
1062 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1063 static TARGET_TYPE make(
1064 const ALLOCATOR& allocator,
1066 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1067 ARGS&&... arguments);
1068 template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1069 static TARGET_TYPE make(
1070 const ALLOCATOR& allocator,
1072 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1073 ARGS&&... arguments);
1074
1075#endif
1076#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
1077};
1078
1079// ============================================================================
1080// TEMPLATE IMPLEMENTATIONS
1081// ============================================================================
1082
1083 // -----------------------------------------------
1084 // struct template ConstructionUtil_IsAllocatorPtr
1085 // -----------------------------------------------
1086
1087/// Metafunction that inherits from `true_type` if the `ALLOC` type is a
1088/// pointer to `bslma::Allocator` or a class derived from it and
1089/// `false_type` otherwise.
1090template <class ALLOC>
1091struct ConstructionUtil_IsAllocatorPtr;
1092
1093/// This primary template is instantiated only for non-pointer type `ALLOC`
1094/// and always evaluates false.
1095template <class ALLOC>
1098
1099/// This partial specialization is for pointer type `ALLOC *` and evaulates
1100/// true if and only if `ALLOC` is derived from `bslma::Allocator`.
1101template <class ALLOC>
1105
1106 // ---------------------------------------------------
1107 // struct template ConstructionUtil_ConstructionTraits
1108 // ---------------------------------------------------
1109
1110/// Metafunction yielding one of the following three `value` constants:
1111///
1112///: e_USES_ALLOCATOR_ARG_T_TRAITS `TARGET_TYPE` supports an allocator as
1113///: its second constructor argument, after
1114///: `bsl::allocator_arg`.
1115///:
1116///: e_USES_ALLOCATOR_TRAITS `TARGET_TYPE` supports an allocator as
1117///: its last constructor argument.
1118///:
1119///: e_NIL_TRAITS `TARGET_TYPE` does not support an
1120///: allocator and/or `ALLOCATOR` is `void*`
1121///: `int`, or any other non-allocator
1122///: scalar. The allocator argument to
1123///: `construct` will be ignored.
1124///
1125/// `ALLOCATOR` is compatible with an AA `TARGET_TYPE` if `ALLOCATOR` is
1126/// convertible to the allocator type expected by `TARGET_TYPE`'s
1127/// constructors. There are three special cases of incompatible `ALLOCATOR`
1128/// types:
1129///
1130/// 1. If `TARGET_TYPE` expects an allocator of type `bslma::Allocator *`
1131/// this metafunction yields either `e_USES_ALLOCATOR_ARG_T_TRAITS` or
1132/// `e_USES_ALLOCATOR_TRAITS`, even if `ALLOCATOR` is not compatible with
1133/// `TARGET_TYPE`. The `construct` method will attempt to extract the
1134/// `bslma::Allocator *` from the allocator using its `mechanism`
1135/// accessor. If there is no `mechanism` accessor, compilation will
1136/// fail.
1137/// 2. Otherwise, if `bslma::UsesBslmaAllocator<TARGET_TYPE>::value` is
1138/// `true`, this metafunction yields either
1139/// `e_USES_ALLOCATOR_ARG_T_TRAITS` or `e_USES_ALLOCATOR_TRAITS`, even if
1140/// `ALLOCATOR` is not compatible with `TARGET_TYPE`, resulting in a
1141/// compilation error within `construct`.
1142/// 3. Otherwise, if `ALLOCATOR` is incompatible with `TARGET_TYPE`, then
1143/// `ALLOCATOR` is ignored and this metafunction yields `e_NIL_TRAITS`,
1144/// as though `TARGET_TYPE` were not AA.
1145///
1146/// The first two special cases allow mixing and matching between
1147/// `bsl::allocator` and `bslma::Allocator *` in both directions, but will
1148/// fail for other allocator types. The failure is desirable to prevent
1149/// code accidentally passing an incorrect allocator type.
1150///
1151/// The third special case is inconsistent with the other two so as to allow
1152/// third-party classes that use third-party allocators to be treated as
1153/// non-AA within containers that use BDE allocators.
1154///
1155/// This metafunction also yields a `type` of 'bsl::integral_constant<value,
1156/// int>'.
1157///
1158/// See @ref bslma_constructionutil
1159template <class TARGET_TYPE, class ALLOCATOR>
1181
1182
1183 // -------------------------------------------------
1184 // struct template ConstructionUtil_AllocAdaptorUtil
1185 // -------------------------------------------------
1186
1187template <class TYPE,
1188 bool HAS_ALLOC_TYPE = HasAllocatorType<TYPE>::value,
1189 bool IS_BSLMA_AA = UsesBslmaAllocator<TYPE>::value>
1191
1192/// This utility class template provides a static `adapt` method that adapts
1193/// an allocator object to the type expected by `TYPE`. This primary
1194/// template is instantiated only for a non-AA `TYPE`; such types do not
1195/// expect an allocator, so no `adapt` method is defined.
1196template <class TYPE>
1197struct ConstructionUtil_AllocAdaptorUtil<TYPE, false, false> {
1198};
1199
1200/// This utility class template provides a static `adapt` method that adapts
1201/// an allocator object to the type expected by `TYPE`. This partial
1202/// specialization is instantiated for types that expect an allocator of
1203/// type `bslma::Allocator *`.
1204template <class TYPE>
1205struct ConstructionUtil_AllocAdaptorUtil<TYPE, false, true> {
1206
1207 /// Return the `bslma::Allocator` pointer held by the specified `a`
1208 /// object of non-pointer class. Compilation will fail if type `ALLOC`
1209 /// does not provide a `mechanism()` accessor returning a pointer to
1210 /// type convertible to `bslma::Allocator *`.
1211 template <class ALLOC>
1212 static bslma::Allocator *adapt(const ALLOC& a) { return a.mechanism(); }
1213
1214 /// Return the specified `alloc_p` pointer, implicitly converted to
1215 /// `bslma::Allocator *`. Compilation will fail unless `ALLOC` is
1216 /// derived from `bslma::Allocator`.
1217 template <class ALLOC>
1218 static bslma::Allocator *adapt(ALLOC *const &alloc_p) { return alloc_p; }
1219};
1220
1221/// This utility class template provides a static `adapt` method that adapts
1222/// an allocator object to the type expected by `TYPE`. This partial
1223/// specialization is instantiated for types that expect an allocator of
1224/// type `TYPE::allocator_type`.
1225template <class TYPE, bool IS_BSLMA_AA>
1226struct ConstructionUtil_AllocAdaptorUtil<TYPE, true, IS_BSLMA_AA> {
1227
1228 /// Return the specified `a` allocator, implicitly converted to
1229 /// `TYPE::allocator_type`. Compilation will fail if implicit
1230 /// conversion to the return type is invalid.
1231 template <class ALLOC>
1232 static typename TYPE::allocator_type adapt(const ALLOC& a) { return a; }
1233};
1234
1235
1236 // -----------------------
1237 // struct ConstructionUtil
1238 // -----------------------
1239
1240// CLASS METHODS
1241template <class TARGET_TYPE, class ALLOCATOR>
1242inline
1243void
1244ConstructionUtil::construct(TARGET_TYPE *address,
1245 const ALLOCATOR& allocator)
1246{
1247 typedef typename
1249
1250 Imp::construct(address, allocator, Trait());
1251}
1252
1253#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1254# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1255template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1256inline
1257void
1258ConstructionUtil::construct(TARGET_TYPE *address,
1259 const ALLOCATOR& allocator,
1260 ARG1& argument1,
1261 ARGS&&... arguments)
1262{
1263 typedef typename
1265
1266 Imp::construct(address,
1267 allocator,
1268 Trait(),
1269 argument1,
1270 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1271}
1272# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1273
1274template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1275inline
1276void
1277ConstructionUtil::construct(TARGET_TYPE *address,
1278 const ALLOCATOR& allocator,
1279 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1280 ARGS&&... arguments)
1281{
1282 typedef typename
1284
1285 Imp::construct(address,
1286 allocator,
1287 Trait(),
1288 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1289 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1290}
1291#endif
1292
1293template <class TARGET_TYPE, class ALLOCATOR>
1294inline
1295void
1297 const ALLOCATOR& allocator,
1298 TARGET_TYPE *original)
1299{
1300 BSLS_ASSERT_SAFE(address);
1301 BSLS_ASSERT_SAFE(original);
1302
1303 enum {
1307 };
1308
1309 Imp::destructiveMove(address,
1310 allocator,
1312 original);
1313}
1314
1315#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
1316// Suppress bde_verify warnings about return-by-value in this region.
1317// BDE_VERIFY pragma: push
1318// BDE_VERIFY pragma: -AR01: Type using allocator is returned by value
1319
1320template <class TARGET_TYPE, class ALLOCATOR>
1321inline
1322TARGET_TYPE
1323ConstructionUtil::make(const ALLOCATOR& allocator)
1324{
1325 typedef typename
1327
1328 return Imp::make<TARGET_TYPE>(allocator, Trait());
1329}
1330
1331#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1332# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1333template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1334inline
1335TARGET_TYPE
1336ConstructionUtil::make(const ALLOCATOR& allocator,
1337 ARG1& argument1,
1338 ARGS&&... arguments)
1339{
1340 typedef typename
1342
1343 return Imp::make<TARGET_TYPE>(
1344 allocator,
1345 Trait(),
1346 argument1,
1347 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1348}
1349# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1350
1351template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1352inline
1353TARGET_TYPE
1354ConstructionUtil::make(const ALLOCATOR& allocator,
1355 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1356 ARGS&&... arguments)
1357{
1358 typedef typename
1360
1361 return Imp::make<TARGET_TYPE>(
1362 allocator,
1363 Trait(),
1364 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1365 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1366}
1367#endif
1368
1369// BDE_VERIFY pragma: pop
1370#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
1371
1372 // ---------------------------
1373 // struct ConstructionUtil_Imp
1374 // ---------------------------
1375
1376// CLASS METHODS
1377template <class TARGET_TYPE, class ALLOCATOR>
1378inline
1379void
1381 TARGET_TYPE *address,
1382 const ALLOCATOR& allocator,
1384{
1386 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1387 bsl::allocator_arg,
1388 AllocUtil::adapt(allocator));
1389}
1390
1391template <class TARGET_TYPE, class ALLOCATOR>
1392inline
1393void
1395 TARGET_TYPE *address,
1396 const ALLOCATOR& allocator,
1398{
1400 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1401 AllocUtil::adapt(allocator));
1402}
1403
1404template <class TARGET_TYPE, class ALLOCATOR>
1405inline
1406void
1408 TARGET_TYPE *address,
1409 const ALLOCATOR& ,
1411{
1412 ::new (PointerUtil::voidify(address)) TARGET_TYPE();
1413}
1414
1415#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1416# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1417template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1418inline
1419void
1421 TARGET_TYPE *address,
1422 const ALLOCATOR& allocator,
1424 ARG1& argument1,
1425 ARGS&&... arguments)
1426{
1428 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1429 bsl::allocator_arg,
1430 AllocUtil::adapt(allocator),
1431 argument1,
1432 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1433}
1434
1435template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1436inline
1437void
1439 TARGET_TYPE *address,
1440 const ALLOCATOR& allocator,
1442 ARG1& argument1,
1443 ARGS&&... arguments)
1444{
1446 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1447 argument1,
1448 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...,
1449 AllocUtil::adapt(allocator));
1450}
1451
1452template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1453inline
1454void
1456 TARGET_TYPE *address,
1457 const ALLOCATOR& ,
1459 ARG1& argument1,
1460 ARGS&&... arguments)
1461{
1462 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1463 argument1,
1464 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1465}
1466# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1467
1468template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1469inline
1470void
1472 TARGET_TYPE *address,
1473 const ALLOCATOR& allocator,
1475 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1476 ARGS&&... arguments)
1477{
1479 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1480 bsl::allocator_arg,
1481 AllocUtil::adapt(allocator),
1482 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1483 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1484}
1485
1486template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1487inline
1488void
1490 TARGET_TYPE *address,
1491 const ALLOCATOR& allocator,
1493 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1494 ARGS&&... arguments)
1495{
1497 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1498 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1499 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...,
1500 AllocUtil::adapt(allocator));
1501}
1502
1503template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1504inline
1505void
1507 TARGET_TYPE *address,
1508 const ALLOCATOR& ,
1510 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1511 ARGS&&... arguments)
1512{
1513 ::new (PointerUtil::voidify(address)) TARGET_TYPE(
1514 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1515 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1516}
1517#endif
1518
1519template <class TARGET_TYPE, class ALLOCATOR>
1520inline
1521void
1523 TARGET_TYPE *address,
1524 const ALLOCATOR& ,
1526 TARGET_TYPE *original)
1527{
1530 ::new (PointerUtil::voidify(address)) TARGET_TYPE(*original);
1531 }
1532 else {
1533 // `PointerUtil::voidify(address)` is used here to suppress compiler
1534 // warning "-Wclass-memaccess".
1535 memcpy(PointerUtil::voidify(address), original, sizeof *original);
1536 }
1537}
1538
1539template <class TARGET_TYPE, class ALLOCATOR>
1540inline
1541void
1543 TARGET_TYPE *address,
1544 const ALLOCATOR& allocator,
1546 TARGET_TYPE *original)
1547{
1548 // TBD: Eventually, we can add a precondition that 'allocator' matches
1549 // 'original''s allocator, but that is not universally detectable right
1550 // now, as not all allocator-aware types provide an 'allocator()' method.
1551 //..
1552 // BSLS_ASSERT(allocator == original->allocator());
1553
1555 allocator,
1556 bslmf::MovableRefUtil::move(*original));
1557 DestructionUtil::destroy(original);
1558}
1559
1560#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
1561// Suppress bde_verify warnings about return-by-value in this region.
1562// BDE_VERIFY pragma: push
1563// BDE_VERIFY pragma: -AR01: Type using allocator is returned by value
1564
1565template <class TARGET_TYPE, class ALLOCATOR>
1566inline
1567TARGET_TYPE
1568ConstructionUtil_Imp::make(
1569 const ALLOCATOR& allocator,
1571{
1573 return TARGET_TYPE(bsl::allocator_arg, AllocUtil::adapt(allocator));
1574}
1575
1576template <class TARGET_TYPE, class ALLOCATOR>
1577inline
1578TARGET_TYPE
1579ConstructionUtil_Imp::make(
1580 const ALLOCATOR& allocator,
1582{
1583 typedef ConstructionUtil_AllocAdaptorUtil<TARGET_TYPE> AllocUtil;
1584 return TARGET_TYPE(AllocUtil::adapt(allocator));
1585}
1586
1587template <class TARGET_TYPE, class ALLOCATOR>
1588inline
1589TARGET_TYPE
1590ConstructionUtil_Imp::make(
1591 const ALLOCATOR& ,
1593{
1594 return TARGET_TYPE();
1595}
1596
1597#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1598# ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1599template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1600inline
1601TARGET_TYPE
1602ConstructionUtil_Imp::make(
1603 const ALLOCATOR& allocator,
1605 ARG1& argument1,
1606 ARGS&&... arguments)
1607{
1608 typedef ConstructionUtil_AllocAdaptorUtil<TARGET_TYPE> AllocUtil;
1609 return TARGET_TYPE(
1610 bsl::allocator_arg,
1611 AllocUtil::adapt(allocator),
1612 argument1,
1613 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1614}
1615
1616template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1617inline
1618TARGET_TYPE
1619ConstructionUtil_Imp::make(
1620 const ALLOCATOR& allocator,
1622 ARG1& argument1,
1623 ARGS&&... arguments)
1624{
1625 typedef ConstructionUtil_AllocAdaptorUtil<TARGET_TYPE> AllocUtil;
1626 return TARGET_TYPE(
1627 argument1,
1628 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...,
1629 AllocUtil::adapt(allocator));
1630}
1631
1632template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1633inline
1634TARGET_TYPE
1635ConstructionUtil_Imp::make(
1636 const ALLOCATOR& ,
1638 ARG1& argument1,
1639 ARGS&&... arguments)
1640{
1641 return TARGET_TYPE(
1642 argument1,
1643 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1644}
1645# endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
1646
1647template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1648inline
1649TARGET_TYPE
1650ConstructionUtil_Imp::make(
1651 const ALLOCATOR& allocator,
1653 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1654 ARGS&&... arguments)
1655{
1656 typedef ConstructionUtil_AllocAdaptorUtil<TARGET_TYPE> AllocUtil;
1657 return TARGET_TYPE(
1658 bsl::allocator_arg,
1659 AllocUtil::adapt(allocator),
1660 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1661 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1662}
1663
1664template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1665inline
1666TARGET_TYPE
1667ConstructionUtil_Imp::make(
1668 const ALLOCATOR& allocator,
1670 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1671 ARGS&&... arguments)
1672{
1673 typedef ConstructionUtil_AllocAdaptorUtil<TARGET_TYPE> AllocUtil;
1674 return TARGET_TYPE(
1675 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1676 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...,
1677 AllocUtil::adapt(allocator));
1678}
1679
1680template <class TARGET_TYPE, class ALLOCATOR, class ARG1, class... ARGS>
1681inline
1682TARGET_TYPE
1683ConstructionUtil_Imp::make(
1684 const ALLOCATOR& ,
1686 BSLS_COMPILERFEATURES_FORWARD_REF(ARG1) argument1,
1687 ARGS&&... arguments)
1688{
1689 return TARGET_TYPE(
1690 BSLS_COMPILERFEATURES_FORWARD(ARG1, argument1),
1691 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
1692}
1693#endif
1694
1695// BDE_VERIFY pragma: pop
1696#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
1697
1698} // close package namespace
1699
1700
1701#endif // End C++11 code
1702
1703#endif
1704
1705// ----------------------------------------------------------------------------
1706// Copyright 2013 Bloomberg Finance L.P.
1707//
1708// Licensed under the Apache License, Version 2.0 (the "License");
1709// you may not use this file except in compliance with the License.
1710// You may obtain a copy of the License at
1711//
1712// http://www.apache.org/licenses/LICENSE-2.0
1713//
1714// Unless required by applicable law or agreed to in writing, software
1715// distributed under the License is distributed on an "AS IS" BASIS,
1716// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1717// See the License for the specific language governing permissions and
1718// limitations under the License.
1719// ----------------------------- END-OF-FILE ----------------------------------
1720
1721/** @} */
1722/** @} */
1723/** @} */
Definition bslma_allocator.h:545
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2343
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2349
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition baljsn_encoder_testtypes.h:76
Definition bslmf_integralconstant.h:261
Definition bslmf_isclass.h:164
Definition bslmf_isconvertible.h:875
Definition bslmf_isfundamental.h:330
Definition bslmf_ispointer.h:138
Definition bslmf_usesallocator.h:165
static bslma::Allocator * adapt(const ALLOC &a)
Definition bslma_constructionutil.h:1212
static bslma::Allocator * adapt(ALLOC *const &alloc_p)
Definition bslma_constructionutil.h:1218
static TYPE::allocator_type adapt(const ALLOC &a)
Definition bslma_constructionutil.h:1232
Definition bslma_constructionutil.h:1190
Definition bslma_constructionutil.h:1160
@ value
Definition bslma_constructionutil.h:1169
bsl::integral_constant< int, value > type
Definition bslma_constructionutil.h:1179
Definition bslma_constructionutil.h:875
static void destructiveMove(TARGET_TYPE *address, const ALLOCATOR &allocator, bsl::integral_constant< int, e_BITWISE_MOVABLE_TRAITS >, TARGET_TYPE *original)
Definition bslma_constructionutil.h:1522
@ e_NIL_TRAITS
Definition bslma_constructionutil.h:885
@ e_BITWISE_MOVABLE_TRAITS
Definition bslma_constructionutil.h:886
@ e_USES_ALLOCATOR_ARG_T_TRAITS
Definition bslma_constructionutil.h:888
@ e_USES_ALLOCATOR_TRAITS
Definition bslma_constructionutil.h:887
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator, bsl::integral_constant< int, e_USES_ALLOCATOR_ARG_T_TRAITS >)
Definition bslma_constructionutil.h:1380
Definition bslma_constructionutil.h:1096
Definition bslma_constructionutil.h:731
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator)
Definition bslma_constructionutil.h:1244
static void destructiveMove(TARGET_TYPE *address, const ALLOCATOR &allocator, TARGET_TYPE *original)
Definition bslma_constructionutil.h:1296
Definition bslma_hasallocatortype.h:176
static BSLS_KEYWORD_CONSTEXPR void * voidify(TYPE *address) BSLS_KEYWORD_NOEXCEPT
Definition bslma_pointerutil.h:350
Definition bslma_usesbslmaallocator.h:344
Definition bslmf_isbitwisemoveable.h:718
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
Definition bslmf_usesallocatorargt.h:100