/* * * Copyright (C) 2014-2019, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: ofstd * * Author: Jan Schlamelcher * * Purpose: Implement fallback support for modern techniques defined * in the STL's header (e.g. move semantics) * for older compilers. */ #ifndef OFUTIL_H #define OFUTIL_H #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/ofstd/oftraits.h" #include "dcmtk/ofstd/oftypes.h" /** @file ofutil.h * Implement fallback support for modern techniques defined * in the STL's header (e.g.\ move semantics) * for older compilers. */ // -------------------- misc C++11 / non C++11 utils -------------------- // The internet says should always be available, so we include // it here to fix an issue with compilers that support std::tuple but // not all of C++11 and perhaps other stuff. #include #ifdef HAVE_STL_TUPLE #include #endif #ifdef HAVE_CXX11 #define OFmove std::move #define OFswap std::swap // OFrvalue simply equals 'identity', as C++11 natively handles // rvalues / prvalues and so on. template using OFrvalue = T; #define OFrvalue_ref(T) T&& #define OFrvalue_access(RV) RV #define OFrvalue_ref_upcast(T, RV) static_cast(RV) #else // fallback implementations #ifndef DOXYGEN // Meta-template to select the base class for OFrvalue template struct OFrvalue_storage { // Helper template to wrap types that we can't derive from, // e.g. primitive types. class type { public: // copy constructor should be fine for primitive types. inline type(const T& pt) : t( pt ) {} inline type(const OFrvalue_storage& rhs) : t( rhs.pt ) {} // automatic conversion to the underlying type inline operator T&() const { return OFconst_cast( T&, t ); } private: // the actual object T t; }; }; // specialization for compound types template struct OFrvalue_storage { // simply use T itself as base typedef T type; }; // SFINAE to detect if a type is derivable from template class OFrvalue_base { // magic SFINAE stuff stolen from en.cppreference.com struct no_type {}; struct yes_type {double d;}; template static yes_type sfinae(int X::*); template static no_type sfinae(...); public: // employ SFINAE + template specialization to select // the base type typedef OFTypename OFrvalue_storage < T, sizeof(sfinae(OFnullptr)) == sizeof(yes_type) >::type type; }; #endif // NOT DOXYGEN /** A helper class to 'tag' objects as rvalues to help * DCMTK's move emulation employed on pre C++11 compilers. * @tparam T the base type an rvalue should be create of. * @details OFrvalue wraps the type T inside a zero-overhead * object employing T's move constructor when possible. * @note When C++11 support is available, OFrvalue will * simply be a type alias for T, since a C++11 compiler * handles rvalue reference conversions natively. * @details *

Example

* This example describes how to move an object of type * OFunique_ptr out of a function by using OFrvalue. * @code * OFrvalue > getDataset() * { * return OFunique_ptr( new DcmDataset ); * } * . . . * OFunique_ptr pDataset = getDataset(); * @endcode * @warning Some compilers might require you to use the following * code instead, as older versions of the C++ standard allowed * the compiler to use the copy constructor for binding an * rvalue to an lvalue reference. * Use this code template instead to achieve maximum portability: * @code * OFrvalue > getDataset() * { * OFunique_ptr pDataset( new DcmDataset ); * return OFmove( pDataset ); * } * @endcode */ template struct OFrvalue : OFrvalue_base::type { #ifndef DOXYGEN // allow to move construct from lvalue references inline OFrvalue(const T& t) : OFrvalue_base::type( *OFreinterpret_cast( const OFrvalue*, &t ) ) {} // copy-construct from an rvalue reference inline OFrvalue(const OFrvalue& rv) : OFrvalue_base::type( rv ) {} // poor man's in-place construction template inline explicit OFrvalue( X x ) : OFrvalue_base::type( x ) {} template inline explicit OFrvalue( X0 x0, X1 x1 ) : OFrvalue_base::type( x0, x1 ) {} template inline explicit OFrvalue( X0 x0, X1 x1, X2 x2 ) : OFrvalue_base::type( x0, x1, x2 ) {} #endif // NOT DOXYGEN }; #ifdef DOXYGEN /** Determines rvalue reference type for the type T. * @param T the base type to determine the rvalue reference type for. * @note OFrvalue_ref(T) will expand to T&& when * C++11 support is available. Otherwise DCMTK's move emulation will * be used, employing an unspecified type to implement rvalue references. * @details *

Example

* This example shows how to implement the move constructor and * move assignment for a custom class in a portable fashion * (employing C++11's native features when available and using DCMTK's * move emulation otherwise). * @code * class MyMovable * { * public: * MyMovable( OFrvalue_ref(MyMovable) rhs ) * : m_hDatabase( rhs.m_hDatabase ) * { * // You need to use OFrvalue_access to get write access * // to rvalue references when DCMTK's move emulation * // is used. * OFrvalue_access(rhs).m_hDatabase = OFnullptr; * } * * MyMovable& operator=( OFrvalue_ref(MyMovable) rvrhs ) * { * // You may bind the rvalue reference to an lvalue * // reference to ease access. * MyMovable& rhs = OFrvalue_access(rvrhs); * if( this != &rhs ) * { * disconnectDatabase( m_hDatabase ); * m_hDatabase = rhs.m_hDatabase; * rhs.m_hDatabase = OFnullptr; * } * return *this; * } * }; * @endcode */ #define OFrvalue_ref(T) unspecified /** Upcast an rvalue reference to an rvalue reference of one of its bases. * This is a helper macro for being used with DCMTK's fallback implementation * of move semantics. C++11 rvalue references should normally allow implicit * upcasts, therefore, this macro typically has no effect if C++11 is enabled * (it may be used to work around the behavior of older GCC versions). * @param T the base class to upcast to * @param RV the rvalue reference to upcast */ #define OFrvalue_ref_upcast(T, RV) unspecified #else // NOT DOXYGEN #define OFrvalue_ref(T) const OFrvalue& #define OFrvalue_ref_upcast(T, RV) OFmove(RV) #endif /** Obtain an lvalue reference from an rvalue reference. * DCMTK's move emulations does restrict write access to rvalue references * due to compiler limitations. * This method enables you to workaround this restriction by converting * DCMTK's emulated rvalue references to lvalue references. * @note Native rvalue references from C++11 don't need this workaround, * therefore OFrvalue_access has no effect when C++11 support is * available. * @param rv an rvalue reference, e.g. the parameter of a move constructor. */ template T& OFrvalue_access( OFrvalue_ref(T) rv ) { #ifndef DOXYGEN return OFconst_cast( OFrvalue&, rv ); #endif } /** Obtains an rvalue reference to its argument and converts it * to an xvalue. OFmove is meant to 'mark' an object for a * move operation, e.g. to move an OFVector object into another * OFVector instance instead of copying it. * @note OFmove will be an alias for std::move when native * move semantics are supported (C++11 support is available). * Otherwise DCMTK's move emulation will be used. This means * you will have to specify rvalues (e.g. function return values) * employing the OFrvalue class template. * @param t The object to move. * @see OFrvalue * @see OFrvalue_ref */ template #ifndef DOXYGEN OFrvalue& OFmove( T& t ) { return *OFreinterpret_cast( OFrvalue*, &t ); } template OFrvalue& OFmove( OFrvalue& rv ) { return rv; } template OFrvalue& OFmove( const OFrvalue& rv ) { return OFconst_cast( OFrvalue&, rv ); } #else // NOT DOXYGEN OFconstexpr xvalue OFmove( T< unspecified > t ); #endif // DOXYGEN /** Exchanges the given values. * OFswap is an alias for std::swap if C++11 is supported. * Otherwise OFswap simply creates a temporary copy of one * argument to exchange both values. * @note As intended for std::swap, there are some * specializations for OFswap available, e.g. for OFoptional, * which specializes OFswap to exchange optional objects * more efficiently. When creating your own specializations * for OFswap, make sure to specialize std::swap instead * when C++11 support is available. * @param t0 An object to be exchanged. * @param t1 The object to be exchanged with t0. */ template void OFswap( T& t0, T& t1 ) #ifndef DOXYGEN { T temp( OFmove( t0 ) ); t0 = OFmove( t1 ); t1 = OFmove( temp ); } #else // NOT DOXYGEN ; #endif // DOXYGEN #endif // NOT C++11 // -------------------- STL pair -------------------- #ifdef HAVE_STL_MAP // Use native pair class, to be compatible to std::map #define OFPair std::pair #define OFMake_pair std::make_pair #else // fallback implementation of std::pair /** a pair - this implements parts of std::pair's interface. */ template class OFPair { public: /** this is the first value of the pair */ K first; /** this is the second value of the pair */ V second; /** default constructor */ OFPair() : first(), second() { } /** construct a OFPair for the two given values * @param f the value for first. * @param s the value for second. */ OFPair(const K& f, const V& s) : first(f), second(s) { } /** copy constructor * @param p Other OFPair to copy from. */ template OFPair(const OFPair& p) : first(p.first), second(p.second) { } /** copy constructor * @param p Other OFPair to copy from. */ OFPair(const OFPair& p) : first(p.first), second(p.second) { } /** assignment operator */ OFPair& operator=(const OFPair& other) { first = other.first; second = other.second; return *this; } }; /** helper function to create a pair. This is similar to std::make_pair() * @param first the first part of the pair * @param second the second art of the pair * @relates OFPair * @return the pair (first, second) */ template OFPair OFMake_pair(const K& first, const V& second) { return OFPair(first, second); } #endif // HAVE_STL_MAP - fallback implementation of OFPair // -------------------- STL tuple -------------------- #ifdef HAVE_STL_TUPLE #ifdef HAVE_CXX11 template constexpr auto OFget( T&& t ) -> decltype( std::get( std::forward( t ) ) ) { return std::get( std::forward( t ) ); } template constexpr auto OFget( T&& t ) -> decltype( std::get( std::forward( t ) ) ) { return std::get( std::forward( t ) ); } template using OFtuple_size = std::tuple_size; template using OFtuple_element = std::tuple_element; #else // HAVE_CXX11 template struct OFtuple_size : STD_NAMESPACE tuple_size {}; template struct OFtuple_element : STD_NAMESPACE tuple_element {}; template OFTypename OFtuple_element::type OFget( T& t ) { return STD_NAMESPACE get( t ); } template OFTypename OFtuple_element::type OFget( const T& t ) { return STD_NAMESPACE get( t ); } #endif // NOT HAVE_CXX11 #else // HAVE_STL_TUPLE template struct OFtuple_size; template struct OFtuple_element; // specialization of OFtuple_size for OFPair -> 2 template struct OFtuple_size > : OFintegral_constant {}; // specialization of OFtuple_element for OFPair // 0 -> K template struct OFtuple_element<0,OFPair > { typedef K type; }; // specialization of OFtuple_element for OFPair // 1 -> V template struct OFtuple_element<1,OFPair > { typedef V type; }; // metafunction to apply OFget to OFPair template struct OFpair_element; // specialization for 0 -> first template<> struct OFpair_element<0> { template static K& from( OFPair& p ) { return p.first; } template static const K& from( const OFPair& p ) { return p.first; } }; // specialization for 1 -> second template<> struct OFpair_element<1> { template static V& from( OFPair& p ) { return p.second; } template static const V& from( const OFPair& p ) { return p.second; } }; // overload of OFget for OFPair, see above metafunction 'OFpair_element' template typename OFtuple_element >::type& OFget( OFPair& p ) { return OFpair_element::from( p ); } // overload of OFget for const OFPair, see above metafunction 'OFpair_element' template const typename OFtuple_element >::type& OFget( const OFPair& p ) { return OFpair_element::from( p ); } // tag to identify invalid OFtuple elements, needed for emulating // variadic templates. struct OFtuple_nil; // include generated forward declaration for OFtuple. #include "dcmtk/ofstd/variadic/tuplefwd.h" #endif // HAVE_STL_TUPLE #ifdef DOXYGEN // doxygen documentation of OFtuple utils /** A metafunction to determine the size of a tuple. * @tparam Tuple a tuple type, e.g. an instance of OFtuple. * @pre Tuple is a tuple type, see @ref tuple_types "Tuple Types" * for definition. * @return OFtuple_size is derived from an appropriate instance of * OFintegral_constant if the preconditions are met. This means * OFtuple_size declares a static member constant value * set to the tuple's size. * @relates OFPair * @relates OFtuple * @details *

Usage Example:

* @code{.cpp} * typedef OFtuple > MyTuple; * typedef OFPair MyPair; * COUT << "OFtuple_size::value: " << OFtuple_size::value << OFendl; * COUT << "OFtuple_size::value: " << OFtuple_size::value << OFendl; * @endcode * Output: * @verbatim OFtuple_size::value: 3 OFtuple_size::value: 2 @endverbatim * */ template OFtuple_size; /** A metafunction to determine the type of one element of a tuple. * @tparam Index the index of the element its type should be determined. * @tparam Tuple a tuple type, e.g. an instance of OFtuple. * @pre Tuple is a tuple type, see @ref tuple_types "Tuple Types" * for definition. * @pre Index is a valid index , essentially: Index < OFtuple_size::value. * @return if the preconditions are met, OFtuple_element declares a member * type alias type that yields the type of the element at the given index. * @relates OFtuple * @details *

Usage Example:

* @code{.cpp} * typedef OFPair MyPair; * typedef OFtuple::type,OFtuple_element<1,MyPair>::type> MyTuple; * MyPair pair( "Hello World", 42 ); * MyTuple tuple( pair ); // Works, since both elements' types are the same as within MyPair. * @endcode * */ template OFtuple_element; /** A function template to access an element of a tuple. * @tparam Index the index of the element that should be accessed. * @tparam Tuple a tuple type, e.g. an instance of OFtuple. This parameter * is deduced automatically. * @param tuple a reference to the tuple to access an element of. * @pre Tuple is a tuple type, see @ref tuple_types "Tuple Types" * for definition. * @pre Index is a valid index , essentially: Index < OFtuple_size::value. * @return a reference to the tuple's element at the given index. * @relates OFtuple * @details *

Usage Example:

* @code{.cpp} * OFtuple > myTuple; * OFget<0>( myTuple ) = "Hamish Alexander"; * OFget<1>( myTuple ) = 23; * OFget<2>( myTuple ).push_back( 42 ); * @endcode */ template typename OFtuple_element::type& OFget( Tuple& tuple ); /** A function template to access an element of a tuple. * @tparam Index the index of the element that should be accessed. * @tparam Tuple a tuple type, e.g. an instance of OFtuple. This parameter * is deduced automatically. * @param tuple a const reference to the tuple to access an element of. * @pre Tuple is a tuple type, see @ref tuple_types "Tuple Types" * for definition. * @pre Index is a valid index , essentially: Index < OFtuple_size::value. * @return a const reference to the tuple's element at the given index. * @relates OFtuple * @details *

Usage Example:

* @code{.cpp} * const OFtuple myConstTuple( "Homer Simpson", 38, OFTrue ); * if( OFget<0>( myConstTuple ) == "Homer Simpson" ) * { * // OFget<1>( myConstTuple ) = 23; INVALID, myConstTuple is const! * OFBool isMale = OFget<2>( myConstTuple ); * if( isMale ) * COUT << OFget<0>( myConstTuple ) << ", age " * << OFget<1>( myConstTuple ) << " is male." << OFendl; * } * @endcode * Output: * @verbatim Homer Simpson, age 38 is male. @endverbatim */ template const typename OFtuple_element::type& OFget( const Tuple& tuple ); #endif // DOXYGEN // -------------------- misc utils (OFinplace etc.) -------------------- #ifndef DOXYGEN // OFin_place hacks, look at the doxygen documentation instead if // you know what's good for you! class DCMTK_OFSTD_EXPORT OFin_place_tag { OFin_place_tag(); }; typedef OFin_place_tag(&OFin_place_t)(); #define OFin_place_type_t(T) OFin_place_tag(&)(T&) #define OFin_place_index_t(I) OFin_place_tag(&)(OFintegral_constant&) DCMTK_OFSTD_EXPORT OFin_place_tag OFin_place(); template OFin_place_tag OFin_place(T&) { return OFin_place(); } template OFin_place_tag OFin_place(OFintegral_constant&) { return OFin_place(); } #else // NOT DOXYGEN /** @defgroup OFin_place_helpers_brief * @details Tools for in-place construction of objects, e.g. certain OFvariant alternatives. * @defgroup OFin_place_helpers Tools for in-place construction * @details * #include "dcmtk/ofstd/ofutil.h"

* @copydoc OFin_place_helpers_brief * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Type Definitions

typedef unspecifiedOFin_place_t
A type for tagging an in-place constructor as such. More...
template<typename T>
typedef unspecifiedOFin_place_type_t(T)
A type for tagging an in-place constructor for a certain type as such. More...
template<size_t I>
typedef unspecifiedOFin_place_index_t(I)
A type for tagging an in-place constructor based on a certain index as such. More...
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Global Constants

OFin_place_tOFin_place
* A constant of type OFin_place_t that may be used for in-place construction. * More... *
template<typename T>
OFin_place_type_t(T)OFin_place<T>
* A constant of type OFin_place_type_t(T) that may be used for in-place construction. * More... *
template<size_t I>
OFin_place_index_t(I)OFin_place<I>
* A constant of type OFin_place_index_t(I) that may be used for in-place construction. * More... *
*

Type Definition Documentation

* @anchor OFin_place_t *
*
*
* typedef unspecified OFin_place_t *
*
*
*
A type for tagging an in-place constructor as such.
*
* Usage Example:
* @code{.cpp} * template * class Wrapper * { * public: * // Will copy construct the wrapped value from a T. * Wrapper( const T& t ); * * // Will in-place construct the value from the given arguments, * // calling T( arguments... ) internally, without unnecessary * // copies. * template * Wrapper( OFin_place_t, Arguments... arguments ); * * private: * // ... wrapper implementation ... * }; * @endcode *
*
* @anchor OFin_place_type_t *
*
*
template
*
* typedef unspecified OFin_place_type_t(T) *
*
*
*
A type for tagging an in-place constructor for a certain type as such. *
*
*
Template Parameters
*
T the type this in-pace constructor handles, i.e. the type that will be constructed.
*
* @note Pre C++11 compilers do not support alias templates, therefore, OFin_place_type_t is implemented * using preprocessor macros internally. This is why you need to use curved brackets instead of angled ones. * * Usage Example:
* @code{.cpp} * template * class Union * { * public: * // Will copy construct the wrapped value as an A from a. * Union( const A& a ); * * // Will copy construct the wrapped value as a B from b. * Union( const B& b ); * * // Will in-place construct the value as an A from the given * // arguments, calling A( arguments... ) internally, without * // unnecessary copies. * template * Union( OFin_place_type_t(A), Arguments... arguments ); * * // Will in-place construct the value as a B from the given * // arguments, calling B( arguments... ) internally, without * // unnecessary copies. * template * Union( OFin_place_type_t(B), Arguments... arguments ); * * private: * // ... union implementation ... * }; * @endcode *
*
* @anchor OFin_place_index_t *
*
*
template
*
* typedef unspecified OFin_place_index_t(I) *
*
*
*
A type for tagging an in-place constructor for a certain index as such.
*
*
Template Parameters
*
* I the index this in-pace constructor handles, i.e. the zero * based index of the type that will be constructed. *
*
* @note Pre C++11 compilers do not support alias templates, therefore, OFin_place_index_t is implemented * using preprocessor macros internally. This is why you need to use curved brackets instead of angled ones. * * Usage Example:
* @code{.cpp} * template * class Union * { * public: * // Will copy construct the wrapped value as an A from a. * Union( const A& a ); * * // Will copy construct the wrapped value as a B from b. * Union( const B& b ); * * // Will in-place construct the value as an A from the given * // arguments, calling A( arguments... ) internally, without * // unnecessary copies. * // This will even work if A and B refer to the same type. * template * Union( OFin_place_index_t(0), Arguments... arguments ); * * // Will in-place construct the value as a B from the given * // arguments, calling B( arguments... ) internally, without * // unnecessary copies. * // This will even work if A and B refer to the same type. * template * Union( OFin_place_index_t(1), Arguments... arguments ); * * private: * // ... union implementation ... * }; * @endcode *
*
*

Global Constant Documentation

* @anchor OFin_place_generic *
*
*
* OFin_place_t OFin_place *
*
*
*
A constant of type OFin_place_t that may be used for in-place construction.
* @remarks OFin_place is actually an overloaded function, but instead of calling it * (which one should never do), its address is used as a tag, since the type of * its address differs depending on which overload and template parameters are used. * See http://en.cppreference.com/w/cpp/utility/in_place for more information. * * Usage Example:
* @code{.cpp} * template * class Wrapper; // see OFin_place_t example * // ... * // will construct an OFString and then copy construct the value in the wrapper * Wrapper( "Hello World" ); * // will in-place construct the value in the wrapper * Wrapper( OFin_place, "Hello World" ); * // this also works with multiple arguments: * // will take only the fist five characters of the const char* * Wrapper( OFin_place, "Hello World", 5 ); * @endcode *
*
* @anchor OFin_place_type *
*
*
template
*
* OFin_place_type_t(T) OFin_place *
*
*
*
A constant of type OFin_place_type_t(T) that may be used for in-place construction.
*
*
Template Parameters
*
T the type for selecting an in-pace constructor, i.e. the type that will be constructed.
*
* @remarks OFin_place is actually an overloaded function, but instead of calling it * (which one should never do), its address is used as a tag, since the type of * its address differs depending on which overload and template parameters are used. * See http://en.cppreference.com/w/cpp/utility/in_place for more information. * * Usage Example:
* @code{.cpp} * template * class Union; // see OFin_place_type_t example * // ... * // will construct an OFString and then copy construct the value inside the union * Union( OFString( "Hello World" ) ); * // will in-place construct an OFString value inside the union * // with only the fist five characters * Union( OFin_place, "Hello World", 5 ); * // will construct an integer value inside the union by casting * // the address of the character array constant to int * Union( OFin_place, "Hello World" ); * @endcode *
*
* @anchor OFin_place_index *
*
*
template
*
* OFin_place_index_t(I) OFin_place<I> *
*
*
*
A constant of type OFin_place_index_t(I) that may be used for in-place construction.
*
*
Template Parameters
*
* I the index for selecting an in-pace constructor, i.e. the * zero based index of the type that will be constructed. *
*
* @remarks OFin_place is actually an overloaded function, but instead of calling it * (which one should never do), its address is used as a tag, since the type of * its address differs depending on which overload and template parameters are used. * See http://en.cppreference.com/w/cpp/utility/in_place for more information. * * Usage Example:
* @code{.cpp} * template * class Union; // see OFin_place_index_t example * // ... * // error, cannot determine which constructor shall be used, * // since both take an int * Union( 3 ); * // will in-place construct an int value inside the union * // tagging it as an A * Union( OFin_place<0>, 3 ); * // will in-place construct an int value inside the union * // tagging it as a B * Union( OFin_place<1>, 3 ); * @endcode *
*
*/ #endif // DOXYGEN #endif // OFUTIL_H