BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmf_isbitwisemoveable.h
Go to the documentation of this file.
1/// @file bslmf_isbitwisemoveable.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmf_isbitwisemoveable.h -*-C++-*-
8#ifndef INCLUDED_BSLMF_ISBITWISEMOVEABLE
9#define INCLUDED_BSLMF_ISBITWISEMOVEABLE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmf_isbitwisemoveable bslmf_isbitwisemoveable
15/// @brief Provide a primitive type trait for bitwise moveable classes.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmf
19/// @{
20/// @addtogroup bslmf_isbitwisemoveable
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmf_isbitwisemoveable-purpose"> Purpose</a>
25/// * <a href="#bslmf_isbitwisemoveable-classes"> Classes </a>
26/// * <a href="#bslmf_isbitwisemoveable-description"> Description </a>
27/// * <a href="#bslmf_isbitwisemoveable-what-classes-are-not-bitwise-moveable"> What Classes are Not Bitwise Moveable? </a>
28/// * <a href="#bslmf_isbitwisemoveable-one-byte-objects"> One-Byte Objects </a>
29/// * <a href="#bslmf_isbitwisemoveable-usage"> Usage </a>
30/// * <a href="#bslmf_isbitwisemoveable-example-1-using-the-trait-to-implement-destructivemovearray"> Example 1: Using the Trait to Implement destructiveMoveArray </a>
31/// * <a href="#bslmf_isbitwisemoveable-example-2-associating-a-trait-with-a-class-template"> Example 2: Associating a Trait with a Class Template </a>
32/// * <a href="#bslmf_isbitwisemoveable-example-3-avoiding-false-positives-on-one-byte-classes"> Example 3: Avoiding False Positives on One-Byte Classes </a>
33///
34/// # Purpose {#bslmf_isbitwisemoveable-purpose}
35/// Provide a primitive type trait for bitwise moveable classes.
36///
37/// # Classes {#bslmf_isbitwisemoveable-classes}
38///
39/// - bslmf::IsBitwiseMoveable: bitwise moveable trait metafunction
40///
41/// @see
42///
43/// # Description {#bslmf_isbitwisemoveable-description}
44/// This component provides a single trait metafunction,
45/// `bslmf::IsBitwiseMoveable`, which allows generic code to determine whether
46/// `t_TYPE` can be destructively moved using `memcpy`. Given a pointer, `p1`,
47/// to an object of `t_TYPE`, and a pointer `p2` of the same type pointing to
48/// allocated but uninitialized storage, a destructive move from `p1` to `p2`
49/// comprises the following pair of operations:
50/// @code
51/// new ((void*) p2) t_TYPE(*p1);// Or new ((void*) p2) t_TYPE(std::move(*p1));
52/// p1->~t_TYPE();
53/// @endcode
54/// An object of a `t_TYPE` is *bitwise* *moveable*, if the above operation can
55/// be replaced by the following operation without affecting correctness:
56/// @code
57/// std::memcpy(p2, p1, sizeof(t_TYPE));
58/// @endcode
59/// If `IsBitwiseMoveable<t_TYPE>::value` inherits from `true_type` for a given
60/// `t_TYPE`, then a generic algorithm can infer that `t_TYPE` is bitwise
61/// moveable.
62///
63/// This trait is used by various components for providing optimizations for
64/// types that can be bitwise moved. The major benefit of this trait is not for
65/// a single object but for an array of such types, as a loop of copy/destroy
66/// operations can be replaced by a single call to `memcpy`. This replacement
67/// is not only faster, but is guaranteed not to throw an exception.
68///
69/// `IsBitwiseMoveable<t_TYPE>` will inherit from `true_type` if `t_TYPE` is a
70/// fundamental object type, enumeration type, or pointer type. Most
71/// user-defined classes are bitwise moveable, but generic code must assume that
72/// an arbitrary `t_TYPE` is not bitwise-moveable, as bitwise moving a type that
73/// is not bitwise moveable is likely to result in a dangling pointer. Thus, it
74/// is necessary to explicitly associate the bitwise moveable trait with a class
75/// (via template specialization or by use of the `BSLMF_DECLARE_NESTED_TRAIT`
76/// macro) in order for generic algorithms to recognize that class as bitwise
77/// moveable. As a special case, one-byte objects are deduced as bitwise
78/// moveable unless explicitly annotated otherwise (see-below).
79///
80/// ## What Classes are Not Bitwise Moveable? {#bslmf_isbitwisemoveable-what-classes-are-not-bitwise-moveable}
81///
82///
83/// A class that has any of the following attributes is **not** bitwise moveable:
84///
85/// * Its address is one of the salient attributes that comprise its value.
86/// * It contains a pointer that might (directly or indirectly) point to
87/// itself or to one of its own members or which stores an encoding of its
88/// own address or the address of one of its members. For example, a list
89/// implementation that includes an embedded sentinel node such that the
90/// last node in the list points back to the sentinel node within the list
91/// class object is not bitwise moveable.
92/// * Its constructor registers a pointer to itself in some static registry.
93/// * Its constructor or destructor have some side effect that, if omitted
94/// during destructive move, would render the program incorrect.
95/// * It contains a data member or base class that is not bitwise moveable.
96///
97/// Because of the destructive nature of a bitwise move (the original object
98/// must be treated as uninitialized storage after the move), a class can be
99/// bitwise moveable but not also bitwise copyable. For example, a class that
100/// contains a pointer to heap-allocated storage is generally bitwise moveable.
101/// The moved object simply refers to the same storage as the (defunct)
102/// original. However a bitwise copy of the same object would incorrectly cause
103/// the original and the copy to share the same heap-allocated storage.
104///
105/// ### One-Byte Objects {#bslmf_isbitwisemoveable-one-byte-objects}
106///
107///
108/// An object whose size does not exceed one byte are deduced to be bitwise
109/// moveable. The validity of this heuristic can be deduced by examining the
110/// criteria for non-bitwise moveable classes above:
111///
112/// * Very few types have their own address as a salient attribute.
113/// * It is not possible for an object to store a pointer to itself in only one
114/// byte. It is difficult to conceive of why an object would store a
115/// (compressed) encoding of own address in one byte.
116/// * Static registries of objects of any size are rare and are almost never a
117/// good design.
118/// * Constructors and destructors with side effects are also rare, and appear
119/// almost entirely within test code (i.e., counting constructions and
120/// destructions). Even in those cases, it is often acceptable or even
121/// preferable to skip the balanced side effects of the constructor and
122/// destructor during a destructive move.
123/// * Any data member or base class of a one-byte class must also be either an
124/// empty base class or a one-byte object, so the above rationale applies
125/// recursively to them.
126///
127/// The purpose of this heuristic is to deduce bitwise moveability for an
128/// important category of empty classes that are not explicitly annotated as
129/// being bitwise moveable: standard predicate classes such as `std::less<T>`.
130/// Being able to treat these classes as bitwise moveable means that `bsl::set`
131/// and `bsl::map` objects can be deduced as bitwise moveable and that
132/// `bsl::function` objects wrapping these classes can use the small-object
133/// optimization. It can be argued that any type with size less than the size
134/// of a pointer should be deduced as bitwise moveable by the logic above.
135/// However, it is primarily the common case of empty classes that we are trying
136/// to handle. By limiting ourselves to the smallest-possible type, we reduce
137/// the chance of false positives (see next paragraph).
138///
139/// Note that the word "rare" appears several times in the list above. Rare
140/// implies non-zero, so we must provide a way to annotate non-bitwise moveable
141/// one-byte classes so that the `IsBitwiseMoveable` trait is not deduced for
142/// them. This annotation is accomplished simply by specializing
143/// `IsBitwiseMoveable` to inherit from `false_type` for these rare classes.
144///
145/// In C++11 and later, it is possible to accurately deduce a class is bitwise
146/// moveable without relying on the one-byte heuristic. If the deduction with
147/// the one-byte heuristic yields true and the deduction without the one-byte
148/// heuristic yields false, then a static assert fires and the program is
149/// ill-formed. This error can be corrected by specializing the trait to false
150/// for the type in question.
151///
152/// ## Usage {#bslmf_isbitwisemoveable-usage}
153///
154///
155/// This section illustrates intended use of this component.
156///
157/// ### Example 1: Using the Trait to Implement destructiveMoveArray {#bslmf_isbitwisemoveable-example-1-using-the-trait-to-implement-destructivemovearray}
158///
159///
160/// Here, we use this trait in a simple algorithm called `destructiveMoveArray`,
161/// which moves elements from one array to another. The algorithm is
162/// implemented using two implementation functions, one for types that are known
163/// to be bit-wise moveable, and one for other types. The first takes an extra
164/// function argument of type `true_type`, the second takes and extra function
165/// argument of type `false_type`:
166/// @code
167/// namespace BloombergLP {
168///
169/// template <class t_TYPE>
170/// void destructiveMoveArrayImp(t_TYPE *to,
171/// t_TYPE *from,
172/// int size,
173/// bsl::true_type)
174/// {
175/// // Bitwise moveable types can be moved using memcpy
176/// memcpy(static_cast<void *>(to), from, size * sizeof(t_TYPE));
177/// }
178///
179/// template <class t_TYPE>
180/// void destructiveMoveArrayImp(t_TYPE *to,
181/// t_TYPE *from,
182/// int size,
183/// bsl::false_type)
184/// {
185/// for (int i = 0; i < size; ++i) {
186/// ::new(to + i) t_TYPE(from[i]);
187/// from[i].~t_TYPE();
188/// }
189/// }
190/// @endcode
191/// Now we can dispatch between the two Imp functions, using the
192/// `IsBitwiseMoveable` trait metafunction to determine at compile time which of
193/// the implementations should be used:
194/// @code
195/// template <class t_TYPE>
196/// void destructiveMoveArray(t_TYPE *to, t_TYPE *from, int size)
197/// {
198/// destructiveMoveArrayImp(to, from, size,
199/// bslmf::IsBitwiseMoveable<t_TYPE>());
200/// }
201/// @endcode
202/// Next, to check our work, we create three classes that we will use to
203/// instantiate `destructiveMoveArray`. All of the classes will log the number
204/// of constructor and destructor calls. The first class will not be decorated
205/// with the `IsBitwiseMoveable` trait:
206/// @code
207/// class NonMoveableClass
208/// {
209/// private:
210/// int d_value;
211///
212/// static int d_ctorCount;
213/// static int d_dtorCount;
214///
215/// public:
216/// static int ctorCount() { return d_ctorCount; }
217/// static int dtorCount() { return d_dtorCount; }
218///
219/// NonMoveableClass(int val = 0) : d_value(val) { ++d_ctorCount; }
220/// NonMoveableClass(const NonMoveableClass& other)
221/// : d_value(other.d_value) { ++d_ctorCount; }
222/// ~NonMoveableClass() { d_dtorCount++; }
223///
224/// int value() const { return d_value; }
225/// };
226///
227/// int NonMoveableClass::d_ctorCount = 0;
228/// int NonMoveableClass::d_dtorCount = 0;
229/// @endcode
230/// The second class is similar except that we declare it to be bit-wise
231/// moveable by specializing `IsBitwiseMoveable`:
232/// @code
233/// class MoveableClass1
234/// {
235/// private:
236/// int d_value;
237///
238/// static int d_ctorCount;
239/// static int d_dtorCount;
240///
241/// public:
242/// static int ctorCount() { return d_ctorCount; }
243/// static int dtorCount() { return d_dtorCount; }
244///
245/// MoveableClass1(int val = 0) : d_value(val) { ++d_ctorCount; }
246/// MoveableClass1(const MoveableClass1& other)
247/// : d_value(other.d_value) { ++d_ctorCount; }
248/// ~MoveableClass1() { d_dtorCount++; }
249///
250/// int value() const { return d_value; }
251/// };
252///
253/// int MoveableClass1::d_ctorCount = 0;
254/// int MoveableClass1::d_dtorCount = 0;
255///
256/// namespace bslmf {
257/// template <> struct IsBitwiseMoveable<MoveableClass1> : bsl::true_type {
258/// };
259/// } // close namespace bslmf
260/// @endcode
261/// The third class is also declared to be bitwise moveable, but this time we do
262/// it using the `BSLMF_NESTED_TRAIT_DECLARATION` macro:
263/// @code
264/// class MoveableClass2
265/// {
266/// private:
267/// int d_value;
268///
269/// static int d_ctorCount;
270/// static int d_dtorCount;
271///
272/// public:
273/// BSLMF_NESTED_TRAIT_DECLARATION(MoveableClass2,
274/// bslmf::IsBitwiseMoveable);
275///
276/// static int ctorCount() { return d_ctorCount; }
277/// static int dtorCount() { return d_dtorCount; }
278///
279/// MoveableClass2(int val = 0) : d_value(val) { ++d_ctorCount; }
280/// MoveableClass2(const MoveableClass2& other)
281/// : d_value(other.d_value) { ++d_ctorCount; }
282/// ~MoveableClass2() { d_dtorCount++; }
283///
284/// int value() const { return d_value; }
285/// };
286///
287/// int MoveableClass2::d_ctorCount = 0;
288/// int MoveableClass2::d_dtorCount = 0;
289/// @endcode
290/// Finally, invoke `destructiveMoveArray` on arrays of all three classes:
291/// @code
292/// enum MoveableEnum { A_VALUE };
293///
294/// int usageExample1()
295/// {
296/// using namespace bslmf;
297///
298/// // First, check the basic operation of 'IsBitwiseMoveable':
299/// assert( IsBitwiseMoveable<int>::value);
300/// assert( IsBitwiseMoveable<int*>::value);
301/// assert( IsBitwiseMoveable<const int*>::value);
302/// assert( IsBitwiseMoveable<MoveableEnum>::value);
303/// assert(! IsBitwiseMoveable<int&>::value);
304/// assert(! IsBitwiseMoveable<const int&>::value);
305/// assert( IsBitwiseMoveable<MoveableClass1>::value);
306/// assert( IsBitwiseMoveable<const MoveableClass1>::value);
307/// assert( IsBitwiseMoveable<MoveableClass2>::value);
308/// assert( IsBitwiseMoveable<volatile MoveableClass2>::value);
309/// assert(! IsBitwiseMoveable<NonMoveableClass>::value);
310/// assert(! IsBitwiseMoveable<const NonMoveableClass>::value);
311///
312/// // For each of our test classes, allocate an array, construct three
313/// // objects into it, then move it into another array.
314/// const int nObj = 3;
315///
316/// {
317/// NonMoveableClass *p1 = (NonMoveableClass*)
318/// ::operator new(nObj * sizeof(NonMoveableClass));
319/// NonMoveableClass *p2 = (NonMoveableClass*)
320/// ::operator new(nObj * sizeof(NonMoveableClass));
321///
322/// for (int i = 0; i < nObj; ++i) {
323/// new(p1 + i) NonMoveableClass(i);
324/// }
325///
326/// assert(nObj == NonMoveableClass::ctorCount());
327/// assert(0 == NonMoveableClass::dtorCount());
328///
329/// assert(! IsBitwiseMoveable<NonMoveableClass>::value);
330/// destructiveMoveArray(p2, p1, nObj);
331///
332/// // Verify that constructor and destructor were called on each move
333/// assert(2 * nObj == NonMoveableClass::ctorCount());
334/// assert(nObj == NonMoveableClass::dtorCount());
335///
336/// // Verify contents
337/// for (int i = 0; i < nObj; ++i) {
338/// assert(i == p2[i].value());
339/// }
340///
341/// // Destroy and deallocate
342/// for (int i = 0; i < nObj; ++i) {
343/// p2[i].~NonMoveableClass();
344/// }
345/// ::operator delete(p1);
346/// ::operator delete(p2);
347/// }
348///
349/// {
350/// MoveableClass1 *p1 = (MoveableClass1*)
351/// ::operator new(nObj * sizeof(MoveableClass1));
352/// MoveableClass1 *p2 = (MoveableClass1*)
353/// ::operator new(nObj * sizeof(MoveableClass1));
354///
355/// for (int i = 0; i < nObj; ++i) {
356/// ::new(p1 + i) MoveableClass1(i);
357/// }
358///
359/// assert(nObj == MoveableClass1::ctorCount());
360/// assert(0 == MoveableClass1::dtorCount());
361///
362/// assert(IsBitwiseMoveable<MoveableClass1>::value);
363/// destructiveMoveArray(p2, p1, nObj);
364///
365/// // Verify that constructor and destructor were NOT called on each
366/// // move
367/// assert(nObj == MoveableClass1::ctorCount());
368/// assert(0 == MoveableClass1::dtorCount());
369///
370/// // Verify contents
371/// for (int i = 0; i < nObj; ++i) {
372/// assert(i == p2[i].value());
373/// }
374///
375/// // Destroy and deallocate
376/// for (int i = 0; i < nObj; ++i) {
377/// p2[i].~MoveableClass1();
378/// }
379/// ::operator delete(p1);
380/// ::operator delete(p2);
381/// }
382///
383/// {
384/// MoveableClass2 *p1 = (MoveableClass2*)
385/// ::operator new(nObj * sizeof(MoveableClass2));
386/// MoveableClass2 *p2 = (MoveableClass2*)
387/// ::operator new(nObj * sizeof(MoveableClass2));
388///
389/// for (int i = 0; i < nObj; ++i) {
390/// ::new(p1 + i) MoveableClass2(i);
391/// }
392///
393/// assert(nObj == MoveableClass2::ctorCount());
394/// assert(0 == MoveableClass2::dtorCount());
395///
396/// assert(IsBitwiseMoveable<MoveableClass2>::value);
397/// destructiveMoveArray(p2, p1, nObj);
398///
399/// // Verify that constructor and destructor were NOT called on each
400/// // move
401/// assert(nObj == MoveableClass2::ctorCount());
402/// assert(0 == MoveableClass2::dtorCount());
403///
404/// // Verify contents
405/// for (int i = 0; i < nObj; ++i) {
406/// assert(i == p2[i].value());
407/// }
408///
409/// // Destroy and deallocate
410/// for (int i = 0; i < nObj; ++i) {
411/// p2[i].~MoveableClass2();
412/// }
413/// ::operator delete(p1);
414/// ::operator delete(p2);
415/// }
416///
417/// return 0;
418/// }
419///
420/// } // close enterprise namespace
421/// @endcode
422///
423/// ### Example 2: Associating a Trait with a Class Template {#bslmf_isbitwisemoveable-example-2-associating-a-trait-with-a-class-template}
424///
425///
426/// In this example, we associate a trait not with a class, but with a class
427/// *template*. We create three class templates, each of which uses a different
428/// mechanisms for being associated with the `IsBitwiseMoveable` trait, plus a
429/// "control" template that is not bit-wise moveable. First, we define the
430/// non-bit-wise-moveable template, `NonMoveableTemplate`:
431/// @code
432/// namespace BloombergLP {
433///
434/// template <class t_TYPE>
435/// struct NonMoveableTemplate
436/// {
437/// t_TYPE d_p;
438/// };
439/// @endcode
440/// Second, we define a `MoveableTemplate1`, which uses partial template
441/// specialization to associate the `IsBitwiseMoveable` trait with each
442/// instantiation:
443/// @code
444/// template <class t_TYPE>
445/// struct MoveableTemplate1
446/// {
447/// t_TYPE *d_p;
448/// };
449///
450/// namespace bslmf {
451/// template <class t_TYPE>
452/// struct IsBitwiseMoveable<MoveableTemplate1<t_TYPE> > : bsl::true_type {
453/// };
454/// } // close namespace bslmf
455/// @endcode
456/// Third, we define `MoveableTemplate2`, which uses the
457/// `BSLMF_NESTED_TRAIT_DECLARATION` macro to associate the `IsBitwiseMoveable`
458/// trait with each instantiation:
459/// @code
460/// template <class t_TYPE>
461/// struct MoveableTemplate2
462/// {
463/// t_TYPE *d_p;
464///
465/// BSLMF_NESTED_TRAIT_DECLARATION(MoveableTemplate2,
466/// bslmf::IsBitwiseMoveable);
467/// };
468/// @endcode
469/// Fourth, we define `MoveableTemplate3`, which is bit-wise moveable iff its
470/// `t_TYPE` template parameter is bit-wise moveable. There is no way to get
471/// this effect using `BSLMF_NESTED_TRAIT_DECLARATION`, so we use partial
472/// specialization combined with inheritance to "inherit" the trait from
473/// `t_TYPE`:
474/// @code
475/// template <class t_TYPE>
476/// struct MoveableTemplate3
477/// {
478/// t_TYPE d_p;
479/// };
480///
481/// namespace bslmf {
482/// template <class t_TYPE>
483/// struct IsBitwiseMoveable<MoveableTemplate3<t_TYPE> > :
484/// IsBitwiseMoveable<t_TYPE>::type { };
485/// } // close namespace bslmf
486/// @endcode
487/// Now, we check that the traits are correctly associated by instantiating each
488/// class with both bit-wise moveable and non-moveable types and verifying the
489/// value of `IsBitwiseMoveable<T>::value`:
490/// @code
491/// int usageExample2()
492/// {
493/// using namespace bslmf;
494///
495/// assert(! IsBitwiseMoveable<
496/// NonMoveableTemplate<NonMoveableClass> >::value);
497/// assert(! IsBitwiseMoveable<
498/// NonMoveableTemplate<MoveableClass1> >::value);
499///
500/// assert( IsBitwiseMoveable<
501/// MoveableTemplate1<NonMoveableClass> >::value);
502/// assert( IsBitwiseMoveable<
503/// MoveableTemplate1<MoveableClass1> >::value);
504///
505/// assert( IsBitwiseMoveable<
506/// MoveableTemplate2<NonMoveableClass> >::value);
507/// assert( IsBitwiseMoveable<
508/// MoveableTemplate2<MoveableClass1> >::value);
509///
510/// assert(! IsBitwiseMoveable<
511/// MoveableTemplate3<NonMoveableClass> >::value);
512/// assert( IsBitwiseMoveable<
513/// MoveableTemplate3<MoveableClass1> >::value);
514///
515/// return 0;
516/// }
517///
518/// } // close enterprise namespace
519/// @endcode
520///
521/// ### Example 3: Avoiding False Positives on One-Byte Classes {#bslmf_isbitwisemoveable-example-3-avoiding-false-positives-on-one-byte-classes}
522///
523///
524/// In this example, we define an empty class that has a non-trivial copy
525/// constructor that has a global side effect. The side effect should not be
526/// omitted, even in a destructive-move situation, so `IsBitwiseMoveable` should
527/// be false. However, the heuristic described above would deduce any one-byte
528/// class (including an empty class) as bitwise-moveable by default, so we must
529/// take specific action to set the trait to false in this (rare) case.
530///
531/// First, we declare a normal empty class that *is* bitwise moveable:
532/// @code
533/// namespace BloombergLP {
534/// namespace xyza {
535///
536/// class MoveableEmptyClass
537/// {
538/// // This class is implicitly moveable by virtue of being only one byte
539/// // in size.
540/// };
541/// @endcode
542/// The class above requires no special treatment. Next, we define an empty
543/// class that is not bitwise moveable:
544/// @code
545/// class NonMoveableEmptyClass
546/// {
547/// // This class is empty, which normally would imply bitwise moveability.
548/// // However, because it has a non-trivial move/copy constructor, it
549/// // should not be bitwise moved.
550///
551/// static int d_count;
552///
553/// public:
554/// NonMoveableEmptyClass() { ++d_count; }
555/// NonMoveableEmptyClass(const NonMoveableEmptyClass&) { ++d_count; }
556/// };
557///
558/// int NonMoveableEmptyClass::d_count = 0;
559///
560/// } // close package namespace
561/// @endcode
562/// Next, we specialize the `IsBitwiseMoveable` trait so that
563/// `NonMoveableEmptyClass` is not incorrectly flagged by trait deduction as
564/// having the `IsBitwiseMoveable` trait:
565/// @code
566/// namespace bslmf {
567///
568/// template <>
569/// struct IsBitwiseMoveable<xyza::NonMoveableEmptyClass> : bsl::false_type
570/// {
571/// };
572///
573/// } // close namespace bslmf
574/// @endcode
575/// Finally, we show that the first class has the `IsBitwiseMoveable` trait and
576/// the second class does not:
577/// @code
578/// int main()
579/// {
580/// using namespace bslmf;
581///
582/// assert( IsBitwiseMoveable<xyza::MoveableEmptyClass>::value);
583/// assert(! IsBitwiseMoveable<xyza::NonMoveableEmptyClass>::value);
584/// }
585///
586/// } // close enterprise namespace
587/// @endcode
588/// @}
589/** @} */
590/** @} */
591
592/** @addtogroup bsl
593 * @{
594 */
595/** @addtogroup bslmf
596 * @{
597 */
598/** @addtogroup bslmf_isbitwisemoveable
599 * @{
600 */
601
602#include <bslscm_version.h>
603
604#include <bslmf_conditional.h>
607#include <bslmf_isempty.h>
609#include <bslmf_isfunction.h>
610#include <bslmf_isreference.h>
611
613#include <bsls_platform.h>
614
615#include <stddef.h>
616
617#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
618# include <type_traits>
619#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
620
621#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
622#include <bsls_nativestd.h>
623#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
624
625#if !defined(BSLS_PLATFORM_CMP_IBM)
626// Last checked with the xlC 12.1 compiler. The IBM xlC compiler has problems
627// correctly handling arrays of unknown bound as template parameters.
628# define BSLMF_ISBITWISEMOVEABLE_NO_SUPPORT_FOR_ARRAY_OF_UNKNOWN_BOUND 1
629#endif
630
631
632
633namespace bslmf {
634
635template <class t_TYPE>
636struct IsBitwiseMoveable;
637
638#ifdef BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES
639/// This template variable represents the result value of the
640/// `bslmf::IsBitwiseMoveable` meta-function.
641template <class t_TYPE>
642BSLS_KEYWORD_INLINE_VARIABLE constexpr bool IsBitwiseMoveable_v =
643 IsBitwiseMoveable<t_TYPE>::value;
644#endif
645
646/// Function types and reference types are not object types, and so are not
647/// bitwise-movable. Both categories of types must be explicitly handled by
648/// a distinct template specialization to avoid attempting to instantiate
649/// invalid code, such as `sizeof(FUNCTION_TYPE)`, when computing the trait
650/// result for other (object) types.
651template <class t_TYPE,
656
657/// Core implementation of the `IsBitwiseMoveable` trait. A class is
658/// detected as being bitwise moveable iff it is trivially copyable or it
659/// has a nested trait declaration for the `IsBitwiseMoveable` trait. In
660/// C++03 however, detection of trivially copyable classes is imperfect and
661/// depends on programmer intervention. As many empty classes (including
662/// standard classes like `std::less<T>` would not be detected as being
663/// trivially copyable and, therefore, bitwise moveable, a heuristic is put
664/// in place whereby any type of one byte size is assumed to be bitwise
665/// moveable. See component-level documentation for this component for more
666/// details on this heuristic and how to avoid false positives.
667template <class t_TYPE>
668struct IsBitwiseMoveable_Imp<t_TYPE, false> {
669
670 private:
671 static const bool k_NestedBitwiseMoveableTrait =
673
674 public:
676 || k_NestedBitwiseMoveableTrait
677 || sizeof(t_TYPE) == 1;
678
680
681#if defined(BSLS_COMPILERFEATURES_SUPPORT_STATIC_ASSERT) && \
682 defined(BSLMF_ISTRIVIALLYCOPYABLE_NATIVE_IMPLEMENTATION)
683 // In C++11 and beyond, we can accurately detect trivial-copiable types
684 // which would allow us to remove the one-byte heuristic used above.
685 // Testing with gcc-5 on Bloomberg production software indicates that there
686 // are many 1-byte types, which are conceptually bitwise moveable, that are
687 // not correctly marked bitwise moveable (for example, any 1-byte
688 // code-generated type). For the moment we have decided not to enable more
689 // conservative logic for automatically deducing the
690 // 'IsBitwiseMoveableTrait'. The more conservative logic is shown below
691 // for future reference:
692
694 "This imp-detail instantiation should not be selected for "
695 "reference types");
696 static_assert(!bsl::is_function<t_TYPE>::value,
697 "This imp-detail instantiation should not be selected for "
698 "function types");
699
700 static const bool k_ValueWithoutOnebyteHeuristic =
702 std::is_empty<t_TYPE>::value // required for gcc < 5.0
703 || k_NestedBitwiseMoveableTrait;
704#endif
705};
706
707 // ========================
708 // struct IsBitwiseMoveable
709 // ========================
710
711/// Trait metafunction that determines whether the specified parameter
712/// `t_TYPE` is bitwise moveable. If `IsBitwiseMoveable<t_TYPE>` is derived
713/// from `bsl::true_type` then `t_TYPE` is bitwise moveable. Otherwise,
714/// bitwise moveability cannot be inferred for `t_TYPE`. This trait can be
715/// associated with a bitwise moveable user-defined class by specializing
716/// this class or by using the `BSLMF_NESTED_TRAIT_DECLARATION` macro.
717template <class t_TYPE>
719};
720
721/// Traits metafunction explicit specialization to indicate that the type
722/// `void` is not bitwise movable. Note that this specialization is used
723/// as a simpler option than making the compile-time logic of the
724/// `IsBitwiseMoveable_Imp` template robust for `void` types.
725template <>
727};
728
729/// Trait metafunction that determines whether the specified parameter
730/// `t_TYPE` is bitwise moveable by stripping off the `const` qualifier and
731/// forwarding to the base-case of `IsBitwiseMoveable`.
732template <class t_TYPE>
733struct IsBitwiseMoveable<const t_TYPE> : IsBitwiseMoveable<t_TYPE>::type {
734};
735
736/// Trait metafunction that determines whether the specified parameter
737/// `t_TYPE` is bitwise moveable by stripping off the `volatile` qualifier
738/// and forwarding to the base-case of `IsBitwiseMoveable`.
739template <class t_TYPE>
740struct IsBitwiseMoveable<volatile t_TYPE> : IsBitwiseMoveable<t_TYPE>::type {
741};
742
743/// Trait metafunction that determines whether the specified parameter
744/// `t_TYPE` is bitwise moveable by stripping off the `const` and `volatile`
745/// qualifiers and forwarding to the base-case of `IsBitwiseMoveable`.
746template <class t_TYPE>
747struct IsBitwiseMoveable<const volatile t_TYPE>
748: IsBitwiseMoveable<t_TYPE>::type {
749};
750
751template <class t_TYPE, size_t t_LEN>
752struct IsBitwiseMoveable<t_TYPE[t_LEN]> : IsBitwiseMoveable<t_TYPE>::type {
753};
754
755template <class t_TYPE, size_t t_LEN>
756struct IsBitwiseMoveable<const t_TYPE[t_LEN]>
757: IsBitwiseMoveable<t_TYPE>::type {
758};
759
760template <class t_TYPE, size_t t_LEN>
761struct IsBitwiseMoveable<volatile t_TYPE[t_LEN]>
762: IsBitwiseMoveable<t_TYPE>::type {
763};
764
765template <class t_TYPE, size_t t_LEN>
766struct IsBitwiseMoveable<const volatile t_TYPE[t_LEN]>
767: IsBitwiseMoveable<t_TYPE>::type {
768};
769
770#if !defined(BSLMF_ISBITWISEMOVEABLE_NO_SUPPORT_FOR_ARRAY_OF_UNKNOWN_BOUND)
771template <class t_TYPE>
772struct IsBitwiseMoveable<t_TYPE[]> : IsBitwiseMoveable<t_TYPE>::type {
773};
774
775template <class t_TYPE>
776struct IsBitwiseMoveable<const t_TYPE[]> : IsBitwiseMoveable<t_TYPE>::type {
777};
778
779template <class t_TYPE>
780struct IsBitwiseMoveable<volatile t_TYPE[]> : IsBitwiseMoveable<t_TYPE>::type {
781};
782
783template <class t_TYPE>
784struct IsBitwiseMoveable<const volatile t_TYPE[]>
785: IsBitwiseMoveable<t_TYPE>::type {
786};
787#endif // BSLMF_ISBITWISEMOVEABLE_NO_SUPPORT_FOR_ARRAY_OF_UNKNOWN_BOUND
788
789} // close package namespace
790
791
792
793#endif // ! defined(INCLUDED_BSLMF_ISBITWISEMOVEABLE)
794
795// ----------------------------------------------------------------------------
796// Copyright 2013 Bloomberg Finance L.P.
797//
798// Licensed under the Apache License, Version 2.0 (the "License");
799// you may not use this file except in compliance with the License.
800// You may obtain a copy of the License at
801//
802// http://www.apache.org/licenses/LICENSE-2.0
803//
804// Unless required by applicable law or agreed to in writing, software
805// distributed under the License is distributed on an "AS IS" BASIS,
806// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
807// See the License for the specific language governing permissions and
808// limitations under the License.
809// ----------------------------- END-OF-FILE ----------------------------------
810
811/** @} */
812/** @} */
813/** @} */
static const t_TYPE value
Definition bslmf_integralconstant.h:258
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_INLINE_VARIABLE
Definition bsls_keyword.h:623
Definition bdlbb_blob.h:576
Definition bslmf_integralconstant.h:244
Definition bslmf_isfunction.h:232
Definition bslmf_isreference.h:137
Definition bslmf_istriviallycopyable.h:329
Definition bslmf_detectnestedtrait.h:464
Definition bslmf_isbitwisecopyable.h:298
bsl::integral_constant< bool, value > type
Definition bslmf_isbitwisemoveable.h:679
Definition bslmf_isbitwisemoveable.h:654
Definition bslmf_isbitwisemoveable.h:718