Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
798 lines (754 sloc) 28.6 KB
// bslmf_isbitwisemoveable.h -*-C++-*-
#ifndef INCLUDED_BSLMF_ISBITWISEMOVEABLE
#define INCLUDED_BSLMF_ISBITWISEMOVEABLE
#ifndef INCLUDED_BSLS_IDENT
#include <bsls_ident.h>
#endif
BSLS_IDENT("$Id: $")
//@PURPOSE: Provide a primitive type trait for bitwise moveable classes.
//
//@CLASSES:
// bslmf::IsBitwiseMoveable: bitwise moveable trait metafunction
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component provides a single trait metafunction,
// 'bslmf::IsBitwiseMoveable', which allows generic code to determine whether
// 'TYPE' can be destructively moved using 'memcpy'. Given a pointer, 'p1', to
// an object of 'TYPE', and a pointer 'p2' of the same type pointing to
// allocated but uninitialized storage, a destructive move from 'p1' to 'p2'
// comprises the following pair of operations:
//..
// new ((void*) p2) TYPE(*p1); // Or new ((void*) p2) TYPE(std::move(*p1));
// p1->~TYPE();
//..
// An object of a 'TYPE' is *bitwise* *moveable*, if the above operation can be
// replaced by the following operation without affecting correctness:
//..
// std::memcpy(p2, p1, sizeof(TYPE));
//..
// If 'IsBitwiseMoveable<TYPE>::value' inherits from 'true_type' for a given
// 'TYPE', then a generic algorithm can infer that 'TYPE' is bitwise moveable.
//
// This trait is used by various components for providing optimizations for
// types that can be bitwise moved. The major benefit of this trait is not for
// a single object but for an array of such types, as a loop of copy/destroy
// operations can be replaced by a single call to 'memcpy'. This replacement
// is not only faster, but is guaranteed not to throw an exception.
//
// 'IsBitwiseMoveable<TYPE>' will inherit from 'true_type' if 'TYPE' is a
// fundamental object type, enumeration type, or pointer type. Most
// user-defined classes are bitwise moveable, but generic code must assume that
// an arbitrary 'TYPE' is not bitwise-moveable, as bitwise moving a type that
// is not bitwise moveable is likely to result in a dangling pointer. Thus, it
// is necessary to explicitly associate the bitwise moveable trait with a class
// (via template specialization or by use of the 'BSLMF_DECLARE_NESTED_TRAIT'
// macro) in order for generic algorithms to recognize that class as bitwise
// moveable. As a special case, one-byte objects are deduced as bitwise
// moveable unless explicitly annotated otherwise (see-below).
//
///What Classes are Not Bitwise Moveable?
///--------------------------------------
// A class that has any of the following attributes is !not! bitwise moveable:
//
//: o Its address is one of the salient attributes that comprise its value.
//:
//: o It contains a pointer that might (directly or indirectly) point to
//: itself or to one of its own members or which stores an encoding of its
//: own address or the address of one of its members. For example, a list
//: implementation that includes an embedded sentinel node such that the
//: last node in the list points back to the sentinel node within the list
//: class object is not bitwise moveable.
//:
//: o Its constructor registers a pointer to itself in some static registry.
//:
//: o Its constructor or destructor have some side effect that, if omitted
//: during destructive move, would render the program incorrect.
//:
//: o It contains a data member or base class that is not bitwise moveable.
//
// Because of the destructive nature of a bitwise move (the original object
// must be treated as uninitialized storage after the move), a class can be
// bitwise moveable but not also bitwise copyable. For example, a class that
// contains a pointer to heap-allocated storage is generally bitwise moveable.
// The moved object simply refers to the same storage as the (defunct)
// original. However a bitwise copy of the same object would incorrectly cause
// the original and the copy to share the same heap-allocated storage.
//
///One-Byte Objects
/// - - - - - - - -
// An object whose size does not exceed one byte are deduced to be bitwise
// moveable. The validity of this heuristic can be deduced by examining the
// criteria for non-bitwise moveable classes above:
//
//: o Very few types have their own address as a salient attribute.
//:
//: o It is not possible for an object to store a pointer to itself in only one
//: byte. It is difficult to conceive of why an object would store a
//: (compressed) encoding of own address in one byte.
//:
//: o Static registries of objects of any size are rare and are almost never a
//: good design.
//:
//: o Constructors and destructors with side effects are also rare, and appear
//: almost entirely within test code (i.e., counting constructions and
//: destructions). Even in those cases, it is often acceptable or even
//: preferable to skip the balanced side effects of the constructor and
//: destructor during a destructive move.
//:
//: o Any data member or base class of a one-byte class must also be either an
//: empty base class or a one-byte object, so the above rationale applies
//: recursively to them.
//
// The purpose of this heuristic is to deduce bitwise moveability for an
// important category of empty classes that are not explicitly annotated as
// being bitwise moveable: standard predicate classes such as 'std::less<T>'.
// Being able to treat these classes as bitwise moveable means that 'bsl::set'
// and 'bsl::map' objects can be deduced as bitwise moveable and that
// 'bsl::function' objects wrapping these classes can use the small-object
// optimization. It can be argued that any type with size less than the size
// of a pointer should be deduced as bitwise moveable by the logic above.
// However, it is primarily the common case of empty classes that we are trying
// to handle. By limiting ourselves to the smallest-possible type, we reduce
// the chance of false positives (see next paragraph).
//
// Note that the word "rare" appears several times in the list above. Rare
// implies non-zero, so we must provide a way to annotate non-bitwise moveable
// one-byte classes so that the 'IsBitwiseMoveable' trait is not deduced for
// them. This annotation is accomplished simply by specializing
// 'IsBitwiseMoveable' to inherit from 'false_type' for these rare classes.
//
// In C++11 and later, it is possible to accurately deduce a class is bitwise
// moveable without relying on the one-byte heuristic. If the deduction with
// the one-byte heuristic yields true and the deduction without the one-byte
// heuristic yields false, then a static assert fires and the program is
// ill-formed. This error can be corrected by specializing the trait to false
// for the type in question.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Using the Trait to Implement 'destructiveMoveArray'
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Here, we use this trait in a simple algorithm called 'destructiveMoveArray',
// which moves elements from one array to another. The algorithm is
// implemented using two implementation functions, one for types that are known
// to be bit-wise moveable, and one for other types. The first takes an extra
// function argument of type 'true_type', the second takes and extra function
// argument of type 'false_type':
//..
// namespace BloombergLP {
//
// template <class TYPE>
// void destructiveMoveArrayImp(TYPE *to,
// TYPE *from,
// int size,
// bsl::true_type)
// {
// // Bitwise moveable types can be moved using memcpy
// memcpy(to, from, size * sizeof(TYPE));
// }
//
// template <class TYPE>
// void destructiveMoveArrayImp(TYPE *to,
// TYPE *from,
// int size,
// bsl::false_type)
// {
// for (int i = 0; i < size; ++i) {
// ::new(to + i) TYPE(from[i]);
// from[i].~TYPE();
// }
// }
//..
// Now we can dispatch between the two Imp functions, using the
// 'IsBitwiseMoveable' trait metafunction to determine at compile time which of
// the implementations should be used:
//..
// template <class TYPE>
// void destructiveMoveArray(TYPE *to, TYPE *from, int size)
// {
// destructiveMoveArrayImp(to, from, size,
// bslmf::IsBitwiseMoveable<TYPE>());
// }
//..
// Next, to check our work, we create three classes that we will use to
// instantiate 'destructiveMoveArray'. All of the classes will log the number
// of constructor and destructor calls. The first class will not be decorated
// with the 'IsBitwiseMoveable' trait:
//..
// class NonMoveableClass
// {
// private:
// int d_value;
//
// static int d_ctorCount;
// static int d_dtorCount;
//
// public:
// static int ctorCount() { return d_ctorCount; }
// static int dtorCount() { return d_dtorCount; }
//
// NonMoveableClass(int val = 0) : d_value(val) { ++d_ctorCount; }
// NonMoveableClass(const NonMoveableClass& other)
// : d_value(other.d_value) { ++d_ctorCount; }
// ~NonMoveableClass() { d_dtorCount++; }
//
// int value() const { return d_value; }
// };
//
// int NonMoveableClass::d_ctorCount = 0;
// int NonMoveableClass::d_dtorCount = 0;
//..
// The second class is similar except that we declare it to be bit-wise
// moveable by specializing 'IsBitwiseMoveable':
//..
// class MoveableClass1
// {
// private:
// int d_value;
//
// static int d_ctorCount;
// static int d_dtorCount;
//
// public:
// static int ctorCount() { return d_ctorCount; }
// static int dtorCount() { return d_dtorCount; }
//
// MoveableClass1(int val = 0) : d_value(val) { ++d_ctorCount; }
// MoveableClass1(const MoveableClass1& other)
// : d_value(other.d_value) { ++d_ctorCount; }
// ~MoveableClass1() { d_dtorCount++; }
//
// int value() const { return d_value; }
// };
//
// int MoveableClass1::d_ctorCount = 0;
// int MoveableClass1::d_dtorCount = 0;
//
// namespace bslmf {
// template <> struct IsBitwiseMoveable<MoveableClass1> : bsl::true_type {
// };
// } // close namespace bslmf
//..
// The third class is also declared to be bitwise moveable, but this time we do
// it using the 'BSLMF_NESTED_TRAIT_DECLARATION' macro:
//..
// class MoveableClass2
// {
// private:
// int d_value;
//
// static int d_ctorCount;
// static int d_dtorCount;
//
// public:
// BSLMF_NESTED_TRAIT_DECLARATION(MoveableClass2,
// bslmf::IsBitwiseMoveable);
//
// static int ctorCount() { return d_ctorCount; }
// static int dtorCount() { return d_dtorCount; }
//
// MoveableClass2(int val = 0) : d_value(val) { ++d_ctorCount; }
// MoveableClass2(const MoveableClass2& other)
// : d_value(other.d_value) { ++d_ctorCount; }
// ~MoveableClass2() { d_dtorCount++; }
//
// int value() const { return d_value; }
// };
//
// int MoveableClass2::d_ctorCount = 0;
// int MoveableClass2::d_dtorCount = 0;
//..
// Finally, invoke 'destructiveMoveArray' on arrays of all three classes:
//..
// enum MoveableEnum { A_VALUE };
//
// int usageExample1()
// {
// using namespace bslmf;
//
// // First, check the basic operation of 'IsBitwiseMoveable':
// assert( IsBitwiseMoveable<int>::value);
// assert( IsBitwiseMoveable<int*>::value);
// assert( IsBitwiseMoveable<const int*>::value);
// assert( IsBitwiseMoveable<MoveableEnum>::value);
// assert(! IsBitwiseMoveable<int&>::value);
// assert(! IsBitwiseMoveable<const int&>::value);
// assert( IsBitwiseMoveable<MoveableClass1>::value);
// assert( IsBitwiseMoveable<const MoveableClass1>::value);
// assert( IsBitwiseMoveable<MoveableClass2>::value);
// assert( IsBitwiseMoveable<volatile MoveableClass2>::value);
// assert(! IsBitwiseMoveable<NonMoveableClass>::value);
// assert(! IsBitwiseMoveable<const NonMoveableClass>::value);
//
// // For each of our test classes, allocate an array, construct three
// // objects into it, then move it into another array.
// const int nObj = 3;
//
// {
// NonMoveableClass *p1 = (NonMoveableClass*)
// ::operator new(nObj * sizeof(NonMoveableClass));
// NonMoveableClass *p2 = (NonMoveableClass*)
// ::operator new(nObj * sizeof(NonMoveableClass));
//
// for (int i = 0; i < nObj; ++i) {
// new(p1 + i) NonMoveableClass(i);
// }
//
// assert(nObj == NonMoveableClass::ctorCount());
// assert(0 == NonMoveableClass::dtorCount());
//
// assert(! IsBitwiseMoveable<NonMoveableClass>::value);
// destructiveMoveArray(p2, p1, nObj);
//
// // Verify that constructor and destructor were called on each move
// assert(2 * nObj == NonMoveableClass::ctorCount());
// assert(nObj == NonMoveableClass::dtorCount());
//
// // Verify contents
// for (int i = 0; i < nObj; ++i) {
// assert(i == p2[i].value());
// }
//
// // Destroy and deallocate
// for (int i = 0; i < nObj; ++i) {
// p2[i].~NonMoveableClass();
// }
// ::operator delete(p1);
// ::operator delete(p2);
// }
//
// {
// MoveableClass1 *p1 = (MoveableClass1*)
// ::operator new(nObj * sizeof(MoveableClass1));
// MoveableClass1 *p2 = (MoveableClass1*)
// ::operator new(nObj * sizeof(MoveableClass1));
//
// for (int i = 0; i < nObj; ++i) {
// ::new(p1 + i) MoveableClass1(i);
// }
//
// assert(nObj == MoveableClass1::ctorCount());
// assert(0 == MoveableClass1::dtorCount());
//
// assert(IsBitwiseMoveable<MoveableClass1>::value);
// destructiveMoveArray(p2, p1, nObj);
//
// // Verify that constructor and destructor were NOT called on each
// // move
// assert(nObj == MoveableClass1::ctorCount());
// assert(0 == MoveableClass1::dtorCount());
//
// // Verify contents
// for (int i = 0; i < nObj; ++i) {
// assert(i == p2[i].value());
// }
//
// // Destroy and deallocate
// for (int i = 0; i < nObj; ++i) {
// p2[i].~MoveableClass1();
// }
// ::operator delete(p1);
// ::operator delete(p2);
// }
//
// {
// MoveableClass2 *p1 = (MoveableClass2*)
// ::operator new(nObj * sizeof(MoveableClass2));
// MoveableClass2 *p2 = (MoveableClass2*)
// ::operator new(nObj * sizeof(MoveableClass2));
//
// for (int i = 0; i < nObj; ++i) {
// ::new(p1 + i) MoveableClass2(i);
// }
//
// assert(nObj == MoveableClass2::ctorCount());
// assert(0 == MoveableClass2::dtorCount());
//
// assert(IsBitwiseMoveable<MoveableClass2>::value);
// destructiveMoveArray(p2, p1, nObj);
//
// // Verify that constructor and destructor were NOT called on each
// // move
// assert(nObj == MoveableClass2::ctorCount());
// assert(0 == MoveableClass2::dtorCount());
//
// // Verify contents
// for (int i = 0; i < nObj; ++i) {
// assert(i == p2[i].value());
// }
//
// // Destroy and deallocate
// for (int i = 0; i < nObj; ++i) {
// p2[i].~MoveableClass2();
// }
// ::operator delete(p1);
// ::operator delete(p2);
// }
//
// return 0;
// }
//
// } // close enterprise namespace
//..
//
///Example 2: Associating a Trait with a Class Template
/// - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we associate a trait not with a class, but with a class
// *template*. We create three class templates, each of which uses a different
// mechanisms for being associated with the 'IsBitwiseMoveable' trait, plus a
// "control" template that is not bit-wise moveable. First, we define the
// non-bit-wise-moveable template, 'NonMoveableTemplate':
//..
// namespace BloombergLP {
//
// template <class TYPE>
// struct NonMoveableTemplate
// {
// TYPE d_p;
// };
//..
// Second, we define a 'MoveableTemplate1', which uses partial template
// specialization to associate the 'IsBitwiseMoveable' trait with each
// instantiation:
//..
// template <class TYPE>
// struct MoveableTemplate1
// {
// TYPE *d_p;
// };
//
// namespace bslmf {
// template <class TYPE>
// struct IsBitwiseMoveable<MoveableTemplate1<TYPE> > : bsl::true_type {
// };
// } // close namespace bslmf
//..
// Third, we define 'MoveableTemplate2', which uses the
// 'BSLMF_NESTED_TRAIT_DECLARATION' macro to associate the 'IsBitwiseMoveable'
// trait with each instantiation:
//..
// template <class TYPE>
// struct MoveableTemplate2
// {
// TYPE *d_p;
//
// BSLMF_NESTED_TRAIT_DECLARATION(MoveableTemplate2,
// bslmf::IsBitwiseMoveable);
// };
//..
// Fourth, we define 'MoveableTemplate3', which is bit-wise moveable iff its
// 'TYPE' template parameter is bit-wise moveable. There is no way to get this
// effect using 'BSLMF_NESTED_TRAIT_DECLARATION', so we use partial
// specialization combined with inheritance to "inherit" the trait from 'TYPE':
//..
// template <class TYPE>
// struct MoveableTemplate3
// {
// TYPE d_p;
// };
//
// namespace bslmf {
// template <class TYPE>
// struct IsBitwiseMoveable<MoveableTemplate3<TYPE> > :
// IsBitwiseMoveable<TYPE>::type { };
// } // close namespace bslmf
//..
// Now, we check that the traits are correctly associated by instantiating each
// class with both bit-wise moveable and non-moveable types and verifying the
// value of 'IsBitwiseMoveable<T>::value':
//..
// int usageExample2()
// {
// using namespace bslmf;
//
// assert(! IsBitwiseMoveable<
// NonMoveableTemplate<NonMoveableClass> >::value);
// assert(! IsBitwiseMoveable<
// NonMoveableTemplate<MoveableClass1> >::value);
//
// assert( IsBitwiseMoveable<
// MoveableTemplate1<NonMoveableClass> >::value);
// assert( IsBitwiseMoveable<
// MoveableTemplate1<MoveableClass1> >::value);
//
// assert( IsBitwiseMoveable<
// MoveableTemplate2<NonMoveableClass> >::value);
// assert( IsBitwiseMoveable<
// MoveableTemplate2<MoveableClass1> >::value);
//
// assert(! IsBitwiseMoveable<
// MoveableTemplate3<NonMoveableClass> >::value);
// assert( IsBitwiseMoveable<
// MoveableTemplate3<MoveableClass1> >::value);
//
// return 0;
// }
//
// } // close enterprise namespace
//..
//
///Example 3: Avoiding False Positives on One-Byte Classes
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we define an empty class that has a non-trivial copy
// constructor that has a global side effect. The side effect should not be
// omitted, even in a destructive-move situation, so 'IsBitwiseMoveable' should
// be false. However, the heuristic described above would deduce any one-byte
// class (including an empty class) as bitwise-moveable by default, so we must
// take specific action to set the trait to false in this (rare) case.
//
// First, we declare a normal empty class that *is* bitwise moveable:
//..
// namespace BloombergLP {
// namespace xyza {
//
// class MoveableEmptyClass
// {
// // This class is implicitly moveable by virtue of being only one byte
// // in size.
// };
//..
// The class above requires no special treatment. Next, we define an empty
// class that is not bitwise moveable:
//..
// class NonMoveableEmptyClass
// {
// // This class is empty, which normally would imply bitwise moveability.
// // However, because it has a non-trivial move/copy constructor, it
// // should not be bitwise moved.
//
// static int d_count;
//
// public:
// NonMoveableEmptyClass() { ++d_count; }
// NonMoveableEmptyClass(const NonMoveableEmptyClass&) { ++d_count; }
// };
//
// int NonMoveableEmptyClass::d_count = 0;
//
// } // close package namespace
//..
// Next, we specialize the 'IsBitwiseMoveable' trait so that
// 'NonMoveableEmptyClass' is not incorrectly flagged by trait deduction as
// having the 'IsBitwiseMoveable' trait:
//..
// namespace bslmf {
//
// template <>
// struct IsBitwiseMoveable<xyza::NonMoveableEmptyClass> : bsl::false_type
// {
// };
//
// } // close namespace bslmf
//..
// Finally, we show that the first class has the 'IsBitwiseMoveable' trait and
// the second class does not:
//..
// int main()
// {
// using namespace bslmf;
//
// assert( IsBitwiseMoveable<xyza::MoveableEmptyClass>::value);
// assert(! IsBitwiseMoveable<xyza::NonMoveableEmptyClass>::value);
// }
//
// } // close enterprise namespace
//..
#ifndef INCLUDED_BSLSCM_VERSION
#include <bslscm_version.h>
#endif
#ifndef INCLUDED_BSLMF_CONDITIONAL
#include <bslmf_conditional.h>
#endif
#ifndef INCLUDED_BSLMF_DETECTNESTEDTRAIT
#include <bslmf_detectnestedtrait.h>
#endif
#ifndef INCLUDED_BSLMF_INTEGRALCONSTANT
#include <bslmf_integralconstant.h>
#endif
#ifndef INCLUDED_BSLMF_ISREFERENCE
#include <bslmf_isreference.h>
#endif
#ifndef INCLUDED_BSLMF_ISTRIVIALLYCOPYABLE
#include <bslmf_istriviallycopyable.h>
#endif
#ifndef INCLUDED_BSLS_COMPILERFEATURES
#include <bsls_compilerfeatures.h>
#endif
#ifndef INCLUDED_BSLS_PLATFORM
#include <bsls_platform.h>
#endif
#ifndef INCLUDED_STDDEF_H
#include <stddef.h>
#define INCLUDED_STDDEF_H
#endif
#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
#ifndef INCLUDED_BSLS_NATIVESTD
#include <bsls_nativestd.h>
#endif
#ifndef INCLUDED_TYPE_TRAITS
# define BSLMF_INCLUDE_ONLY_NATIVE_TRAITS
# include <type_traits>
#endif
#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
#if !defined(BSLS_PLATFORM_CMP_IBM)
// Last checked with the xlC 12.1 compiler. The IBM xlC compiler has problems
// correctly handling arrays of unknown bound as template parameters.
# define BSLMF_ISBITWISEMOVEABLE_NO_SUPPORT_FOR_ARRAY_OF_UNKNOWN_BOUND 1
#endif
namespace BloombergLP {
namespace bslmf {
template <class TYPE>
struct IsBitwiseMoveable;
template <class TYPE, bool = bsl::is_reference<TYPE>::value
|| bsl::is_function<TYPE>::value>
struct IsBitwiseMoveable_Imp : bsl::false_type {
// Function types and reference types are not object types, and so are not
// bitwise-movable. Both categories of types must be explicitly handled by
// a distinct template specialization to avoid attempting to instantiate
// invalid code, such as 'sizeof(FUNCTION_TYPE)', when computing the trait
// result for other (object) types.
};
template <class TYPE>
struct IsBitwiseMoveable_Imp<TYPE, false>
{
// Core implementation of the 'IsBitwiseMoveable' trait. A class is
// detected as being bitwise moveable iff it is trivially copyable or it
// has a nested trait declaration for the 'IsBitwiseMoveable' trait. In
// C++03 however, detection of trivially copyable classes is imperfect and
// depends on programmer intervention. As many empty classes (including
// standard classes like 'std::less<T>' would not be detected as being
// trivially copyable and, therefore, bitwise moveable, a heuristic is put
// in place whereby any type of one byte size is assumed to be bitwise
// moveable. See component-level documentation for this component for more
// details on this heuristic and how to avoid false positives.
private:
static const bool k_NestedBitwiseMoveableTrait =
DetectNestedTrait<TYPE, IsBitwiseMoveable>::value;
public:
static const bool value = bsl::is_trivially_copyable<TYPE>::value
|| k_NestedBitwiseMoveableTrait
|| sizeof(TYPE) == 1;
typedef bsl::integral_constant<bool, value> type;
#if defined(BSLS_COMPILERFEATURES_SUPPORT_STATIC_ASSERT) && \
defined(BSLMF_ISTRIVIALLYCOPYABLE_NATIVE_IMPLEMENTATION)
// In C++11 and beyond, we can accurately detect trivial-copiable types
// which would allow us to remove the one-byte heuristic used above.
// Testing with gcc-5 on Bloomberg production software indicates that
// there are many 1-byte types, which are conceptually bitwise moveable,
// that are not correctly marked bitwise moveable (for example, any 1-byte
// code-generated type). For the moment we have decided not to enable
// more conservative logic for automatically deducing the
// 'IsBitwiseMoveableTrait'. The more conservative logic is shown below
// for future reference:
static const bool k_ValueWithoutOnebyteHeuristic =
!bsl::is_reference<TYPE>::value
&& ( bsl::is_trivially_copyable<TYPE>::value
|| native_std::is_empty<TYPE>::value // required for gcc < 5.0
|| k_NestedBitwiseMoveableTrait);
#endif
};
// ========================
// struct IsBitwiseMoveable
// ========================
template <class TYPE>
struct IsBitwiseMoveable : IsBitwiseMoveable_Imp<TYPE>::type
{
// Trait metafunction that determines whether the specified parameter
// 'TYPE' is bitwise moveable. If 'IsBitwiseMoveable<TYPE>' is derived
// from 'bsl::true_type' then 'TYPE' is bitwise moveable. Otherwise,
// bitwise moveability cannot be inferred for 'TYPE'. This trait can be
// associated with a bitwise moveable user-defined class by specializing
// this class or by using the 'BSLMF_NESTED_TRAIT_DECLARATION' macro.
};
template <>
struct IsBitwiseMoveable<void> : bsl::false_type
{
// Traits metafunction explicit specialization to indicate that the type
// 'void' is not bitwise movable. Note that this specialization is used
// as a simpler option than making the compile-time logic of the
// 'IsBitwiseMoveable_Imp' template robust for 'void' types.
};
template <class TYPE>
struct IsBitwiseMoveable<const TYPE> : IsBitwiseMoveable<TYPE>::type
{
// Trait metafunction that determines whether the specified parameter
// 'TYPE' is bitwise moveable by stripping off the 'const' qualifier and
// forwarding to the base-case of 'IsBitwiseMoveable'.
};
template <class TYPE>
struct IsBitwiseMoveable<volatile TYPE> : IsBitwiseMoveable<TYPE>::type
{
// Trait metafunction that determines whether the specified parameter
// 'TYPE' is bitwise moveable by stripping off the 'volatile' qualifier
// and forwarding to the base-case of 'IsBitwiseMoveable'.
};
template <class TYPE>
struct IsBitwiseMoveable<const volatile TYPE> : IsBitwiseMoveable<TYPE>::type
{
// Trait metafunction that determines whether the specified parameter
// 'TYPE' is bitwise moveable by stripping off the 'const' and 'volatile'
// qualifiers and forwarding to the base-case of 'IsBitwiseMoveable'.
};
template <class TYPE, size_t LEN>
struct IsBitwiseMoveable<TYPE[LEN]>
: IsBitwiseMoveable<TYPE>::type
{
};
template <class TYPE, size_t LEN>
struct IsBitwiseMoveable<const TYPE[LEN]>
: IsBitwiseMoveable<TYPE>::type
{
};
template <class TYPE, size_t LEN>
struct IsBitwiseMoveable<volatile TYPE[LEN]>
: IsBitwiseMoveable<TYPE>::type
{
};
template <class TYPE, size_t LEN>
struct IsBitwiseMoveable<const volatile TYPE[LEN]>
: IsBitwiseMoveable<TYPE>::type
{
};
#if !defined(BSLMF_ISBITWISEMOVEABLE_NO_SUPPORT_FOR_ARRAY_OF_UNKNOWN_BOUND)
template <class TYPE>
struct IsBitwiseMoveable<TYPE[]>
: IsBitwiseMoveable<TYPE>::type
{
};
template <class TYPE>
struct IsBitwiseMoveable<const TYPE[]>
: IsBitwiseMoveable<TYPE>::type
{
};
template <class TYPE>
struct IsBitwiseMoveable<volatile TYPE[]>
: IsBitwiseMoveable<TYPE>::type
{
};
template <class TYPE>
struct IsBitwiseMoveable<const volatile TYPE[]>
: IsBitwiseMoveable<TYPE>::type
{
};
#endif // BSLMF_ISBITWISEMOVEABLE_NO_SUPPORT_FOR_ARRAY_OF_UNKNOWN_BOUND
} // close package namespace
} // close enterprise namespace
#endif // ! defined(INCLUDED_BSLMF_ISBITWISEMOVEABLE)
// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
You can’t perform that action at this time.