/* * * Copyright (C) 2014-2015, 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: Implementing generic tuples similar to C++11's std::tuple. * */ #ifndef OFTUPLE_H #define OFTUPLE_H #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/ofstd/ofutil.h" #include "dcmtk/ofstd/ofdefine.h" // use native classes if C++11 is supported #ifdef DCMTK_USE_CXX11_STL #include #define OFignore std::ignore #define OFmake_tuple std::make_tuple #define OFtie std::tie template using OFtuple = std::tuple; #elif !defined(DOXYGEN) // fallback implementations #include // Implementation of OFignore: struct OFignore_t // that can be constructed and assigned to anything // which it then simply ignores. struct DCMTK_OFSTD_EXPORT OFignore_t { inline OFignore_t() {} template inline OFignore_t(const X&) {} template inline OFignore_t& operator=(const X&) { return *this; } template inline const OFignore_t& operator=(const X&) const { return *this; } }; // OFignore is a reference to an object of type OFignore_t, to // fix some external linkage problems in MinGW extern DCMTK_OFSTD_EXPORT const OFignore_t& OFignore; // Helper metatemplate for OFget for OFtuple. The first // parameter is the return type. This way OFtuple_element // has to be instantiated only once instead of at every // (template-recursive) instantiation of OFget_tuple_element. // This should increase compiletime performance. // Unspecialized version implements recursion step: // N -> OFget_tuple_element( tail ) template struct OFget_tuple_element { template static T& from( Seq& seq ) { return OFget_tuple_element::from( seq.tail() ); } template static const T& from( const Seq& seq ) { return OFget_tuple_element::from( seq.tail() ); } }; // Specialization to implement recursion base: // 0 -> head template struct OFget_tuple_element { template static T& from( Seq& seq ) { return seq.head; } template static const T& from( const Seq& seq ) { return seq.head; } }; // Helper template for resolving recursive definition // of content tail. template struct OFtuple_content_tail { typedef Tail type; }; // Metafunction to determine appropriate parameter types // for constructing a tuple from a sequence of arguments. template struct OFtuple_param { typedef const T& type; }; // Specialization for pointers that allows passing // pointers by value instead of by reference. template struct OFtuple_param { typedef const T* type; }; // Specialization for compilers that can't ignore // "double references" themselves. template struct OFtuple_param { typedef const T& type; }; // The actual implementation of OFtuple's content // OFtuple_content is used as a sequence of nested instances // of OFtuple_content. The argument 'Head' declares the element // type of the current instance, where 'Tail' is used to // pass the next instance. The last sequence element is always // OFtuple_content<> ~ OFtuple_content, // so the end of the sequence can be 'detected' when using // OFtuple_content in template-recursion. template class OFtuple_content : OFtuple_content_tail::type { public: // Helper typedef to resolve the matching OFtuple_content // type on compilers that don't support accessing this // directly (older versions of GCC). // Needs to be accessible in global scope, therefore public. typedef OFtuple_content content_type; private: // Friend declarations. OFtuple_content only has private // members, since these are accessed via free standing // functions (OFget, ...) only. Therefore this API // has to be declared OFtuple_contents friend. #include "dcmtk/ofstd/variadic/tuplefrd.h" template friend class OFtuple_content; template friend class OFget_tuple_element; // Helper class that wraps 'va_list' in a portable way. // This is for example necessary on platforms where // va_list is implemented as an array-type and therefore // can't be used as a function argument directly. // This is also used for ensuring the correct overload // of the constructor gets picked. struct va_args{ va_args() {} mutable va_list args; }; // Determine real Tailtype, see specialization of // OFtuple_content_tail for details. typedef typename OFtuple_content_tail::type tail_type; // Default constructor, default constructs all the elements. OFtuple_content() : tail_type() , head() {} // Copy constructor, copy elements from any other tuple, // as long ans the elements themselves are fine with that. template OFtuple_content( const OFtuple_content& rhs ) : tail_type( rhs.tail() ) , head( rhs.head ) {} // Construct from OFPair. // Note: Ensuring only sequences with two elements are // constructed from OFPair is done in OFtuple itself. // It's not verified in this constructor (again) to // improve compiletime performance. template OFtuple_content( const OFPair& p ) : tail_type( p ) , head( OFget<2-OFtuple_size::value>( p ) ) {} // Construct a tuple element sequence via C-style variadic // arguments. This overload initializes the va_list and // passes a pointer to it to the tail's constructor. // Note: Since 'tail_type' is a base class, it has to // be initialized before 'head'. Therefore the arguments // need to be given to this method in the reversed order! OFtuple_content( va_args args, ... ) : tail_type( ( va_start( args.args, args ), &args.args ) ) , head( *va_arg( args.args, typename OFadd_pointer::type ) ) { va_end( args.args ); } // Overload that takes a 'va_list' pointer and passes it to // its tail. Then takes its 'head' from the va_list. OFtuple_content( va_list* args ) : tail_type( args ) , head( *va_arg( *args, typename OFadd_pointer::type ) ) {} // Implementation of tuple assignment. // Effectively: head -> rhs.head // tail().head -> rhs.tail().head // tail().tail() ... template void assign( const OFtuple_content& rhs ) { head = rhs.head; tail().assign( rhs.tail() ); } // Assign an OFPair. No recursion required since // a pair always has just two arguments. // Note: Ensuring only sequences with two elements are // assigned an OFPair to is done in OFtuple itself. // It's not verified in this method (again) to // improve compiletime performance. template void assign( const OFPair& p ) { head = p.first; tail().head = p.second; } // Check if two tuple element sequences are equal. // Effectively: OFget<0>( a ) == OFget<0>( b ) && // OFget<1>( a ) == OFget<1>( b ) && // ... // OFget( a ) == OFget( b ) template OFBool equal( const OFtuple_content& rhs ) const { return head == rhs.head && tail().equal( rhs.tail() ); } // Check if two tuple element sequences are not equal. // Effectively: OFget<0>( a ) != OFget<0>( b ) || // OFget<1>( a ) != OFget<1>( b ) || // ... // OFget( a ) != OFget( b ) template OFBool not_equal( const OFtuple_content& rhs ) const { return head != rhs.head || tail().not_equal( rhs.tail() ); } // Check if one tuple element sequences is less then another. template OFBool less( const OFtuple_content& rhs ) const { return head < rhs.head || ( !( rhs.head < head ) && tail().less( rhs.tail() ) ); } // Check if one tuple element sequences is less then or equal to another. template OFBool less_equal( const OFtuple_content& rhs ) const { return head < rhs.head || ( !( rhs.head < head ) && tail().less_equal( rhs.tail() ) ); } // Implementation of swap. // Swaps 'head' and recurses to 'tail()' void swap_content( OFtuple_content& rhs ) { OFswap( head, rhs.head ); tail().swap_content( rhs.tail() ); } // Helper methods to access the base class (tail_type) // without the need to specify its type. tail_type& tail() { return *this; } const tail_type& tail() const { return *this; } // The actual content of the current sequence element. Head head; }; // Specialization that resolves passing // 'void' for OFtuple_content's 'Tail' argument // to OFtuple_content<>. template<> struct OFtuple_content_tail { typedef OFtuple_content<> type; }; // Specialization of OFtuple_content's sentinel // element 'OFtuple_content<>'. This class // supplies the recursion base for all the required // methods, ignoring any given arguments and returning // the appropriate values. // This is especially important for the comparison // methods, where two instances of OFtuple_content<> // are considered 'equal' and 'less_equal' but not // 'less' or 'not_equal'. template<> struct OFtuple_content<> { OFtuple_content() {} template OFtuple_content(const X&) {} template void assign(const X&) {} template OFBool equal(const X&) const { return OFTrue; } template OFBool not_equal(const X&) const { return OFFalse; } template OFBool less(const X&) const { return OFFalse; } template OFBool less_equal(const X&) const { return OFTrue; } template void swap_content(const X&) {} }; // Specialization of OFtuple_element for OFtuple. // This implements the recursion base: 0 -> Head. template struct OFtuple_element<0,OFtuple_content > { typedef Head type; }; // Specialization of OFtuple_element for OFtuple. // This implements the recursion step: Index -> OFtuple_element. template struct OFtuple_element > { typedef typename OFtuple_element::type type; }; // Specialization of OFtuple_size for OFtuple. // This implements the recursion base: OFtuple_content<> -> 0. template<> struct OFtuple_size > : OFintegral_constant {}; // Specialization of OFtuple_size for OFtuple. // This implements the recursion step: X -> OFtuple_size. template struct OFtuple_size > : OFintegral_constant::type>::value + 1> {}; // Specialization of OFtuple to implement empty tuples. // This is not generated, since it's so different to the // other specializations. template<> struct OFtuple<> : OFtuple_content<> { }; OFtuple<> OFmake_tuple(); OFtuple<> OFtie(); // Include the generated implementation of OFtuple. // This contains the implementation of the general case // and specializations for different element numbers. // Each provide appropriate constructors and assignment // operators as well as the 'swap' method. // The specialization for two elements also provides // constructors and assignment operators for OFPair. // This file also contains the implementations of the // comparators, OFmake_tuple, OFtie and OFswap for // OFtuple. // Note that for OFmake_tuple and OFtie an overload // is required for every different number of elements. // The comparators and OFswap instead only need an // implementation / overload for the maximum number // of elements currently supported. #include "dcmtk/ofstd/variadic/tuple.h" #else // NOT C++11 && NOT DOXYGEN /** A class template that implements generic tuples. * @headerfile dcmtk/ofstd/oftuple.h "dcmtk/ofstd/oftuple.h" * @tparam Types a sequence of element types that * shall be contained in the tuple. An empty sequence * is allowed. *
Note * When C++11 support is not available, the number * of elements OFtuple may contain is limited, * currently up to 50 elements are supported. *
* @details *

@anchor tuple_types Tuple Types

* The term tuple type refers to the generic concept * of tuples of elements, to be described as follows: *
    *
  • * A tuple type may contain a specific number of elements of * arbitrary types. *
  • *
  • * The metafunction OFtuple_size is specialized in an * appropriate way to determine the number of elements a tuple * type may contain. *
  • *
  • * The metafunction OFtuple_element is specialized in * an appropriate way to determine the type of one of the * tuple's elements at the provided index. *
  • *
  • * The function-template OFget is overloaded in * appropriate ways to enable access to one of the tuple's * elements at the provided index. *
  • *
* The following types provided by the DCMTK currently fulfill * all the above requirements and may therefore be regarded * as tuple types: *
    *
  • any instance of OFtuple
  • *
  • any instance of OFPair
  • *
* When C++11 support is enabled, OFtuple_size, OFtuple_element * and OFget refer to the respective STL declarations and * therefore std::array may then be regarded as a * tuple type as well. *

Defining own tuple types

* It is possible to define one's own tuple types, which * may then be modified by all operations that are defined on * tuple types as well. To define a custom tuple type, you * need to implement the above accession methods, which means * to specialize OFtuple_size and OFtuple_element and overload * OFget in appropriate ways. * @note When C++11 support is enabled, you need to specialize * and overload the respective STL definitions (e.g. std::get) * instead! * @details *

@anchor oftuple_syntax %OFtuple Syntax

* As described in the @ref tuple_types "previous section" * tuple types are queried and modified by the freestanding * metafunctions and function templates OFtuple_size, * OFtuple_element and OFget. Regarding OFtuple, * two additional function templates are provided: * OFmake_tuple and OFtie. Take a look at the * Related Definitions section for their * description.
* However, some operations are defined on OFtuple objects * themselves, these are described in this section. But first * we need to declare the following symbols, which are used in * that description: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
SymbolDefinition
* T0, T1, ..., Tn
* U0, U1, ..., Un *
The elements' types of two (possibly) different tuples
* t0, t1, ..., tn *
Objects of types T0, T1, ..., Tn respectively
* u0, u1, ..., un *
Objects of types U0, U1, ..., Un respectively
t, rhs
* An object of type OFtuple0,T1,...,Tn> *
u
* An object of type OFtuple0,U1,...,Un> *
t2
An object of type OFtuple0,T1>, a tuple with exactly two elements
p
An object of type OFPair0,U1>
* The allowed syntax on OFtuple objects is described in the following table: * * * * * * * * * * * * * * * * * * * * * * *
ExpressionMeaning
t == u, u == t
t != u, u != t
* Compares the tuples t and u for equality / inequality.
* You may compare tuples with different element types, as long as both elements at the same * index are comparable (overload operator== rsp. operator!=). * - Both tuples are considered equal IFF all pairs of elements that share the same index compare equal to one and another. * - Both tuples are considered inequal IFF at least a pair of elements that share the same index compare inequal to one and another. *
t < u, u > t
t > u, u < t
t <= u, u >= t
t >= u, u <= t
* Tests if the tuples t and u are less / less or equal to each other.
* You may compare tuples with different element types, as long as both elements at the same * index are comparable (overload operator< rsp. operator<=). * - Both tuples are considered less IFF for at least a pair of elements that share the same index the left hand side's tuple's * element compares less to the other and all previously compared pairs of elements (elements with smaller indices) compared equal * to one and another. * - Both tuples are considered less or equal IFF for at least a pair of elements that share the same index the left hand * side's tuple's element compares less to the other and all previously compared pairs of elements (elements with smaller indices) * compared equal to one and another or all pairs of elements compare equal to one and another. *
* OFtuple0,T1,...,Tn> t
* OFtuple0,T1,...,Tn> t( t0, t1, ..., tn )
* OFtuple0,T1,...,Tn> t( u0, u1, ..., un )C++11
* OFtuple0,T1> t2( p )
* OFmake_tuple( t0, t1, ..., tn ) *
* Constructs a tuple containing the supplied arguments as its elements (if any). The elements' types * T0, T1, ..., Tn * must be specified explicitly unless OFmake_tuple is used, which deduces appropriate types from the given parameters * t0, t1, ..., tn.
* If C++11 support is available, t may be move constructed from whatever arguments were supplied, possibly increasing * the performance. * @note You may still supply objects of different types than the respective elements even if C++11 support is not available. * The arguments will then be copy constructed from the supplied objects first (and be copied again to initialized the elements * inside the tuple). *
t = rhs
t = u
t2 = p
* Assigns the elements from another tuple type to the elements in the left hand side OFtuple object.
* If C++11 support is available, the elements may be move assigned instead of being copied, possibly increasing the performance. * @note You may directly assign an object of type OFPair to an OFtuple, but only if the tuple has exactly two elements. *
t.swap( rhs )
OFswap( t, rhs )
* Swaps the elements of two OFtuple objects with identical element types.
* Effectively calls OFswap() on each pair of elements that share the same index. Note however that this is done * sequentially, at no time requiring a whole copy of one the tuples to reside in the memory. *
*

Usage Example:

* @code{.cpp} * // Include this file to use OFtuple * #include "dcmtk/ofstd/oftuple.h" * * // A metatemplate for printing all elements of a tuple * // Note: This works on any tuple type, not just OFtuple * // based ones. * template * struct printer * { * // First template-recurse to print the previous elements * // Then append the current one. * template * static void print( std::ostream& out, const Tuple& tuple ) * { * printer::print( out, tuple ); * out << ", " << OFget( tuple ); * } * }; * * // Specialization to print the first element without a * // preceding ','. * template<> * struct printer<1> * { * template * static void print( std::ostream& out, const Tuple& tuple ) * { * out << OFget<0>( tuple ); * } * }; * * // Specialization so that printing empty tuples does * // not lead to an error. * template<> * struct printer<0> * { * static void print( ... ) {} * }; * * // A wrapper function template that applies * // OFtuple_size automatically, to ease printing tuples. * template * void printTuple( std::ostream& out, const Tuple& tuple ) * { * printer::value>::print( out, tuple ); * out << OFendl; * } * * // Construct some tuples. Two OFtuple based ones and one * // OFPair based tuple. * OFtuple t0( "Hello World", 42 ), t1; * OFPair p( "Hello World", 42 ); * * // Compare the tuples and print them * if( t0 != t1 ) * { * COUT << "The following tuples are inequal:" << OFendl; * COUT << " "; * printTuple( COUT, t0 ); * COUT << " "; * printTuple( COUT, t1 ); * } * * // Assign the pair to the tuple * // Note: const char* gets auto-converted to OFString * // and int gets converted to size_t * // (probably with a warning, depending on your * // compiler and settings). * t1 = p; * * // Compare the tuples and the pair * // Note: The pair needs to be converted to a tuple * // first, but comparing tuples with different element * // types goes well. * if( t0 == t1 && t0 == OFtuple( p ) ) * { * COUT << "The following tuples are equal:" << OFendl; * COUT << " "; * printTuple( COUT, t0 ); * COUT << " "; * printTuple( COUT, t1 ); * COUT << " "; * printTuple( COUT, p ); * } * * // Construct a tuple with some more elements and template-recursively print it * // Note: You don't need to declare the element types explicitly when using tuples this way. * printTuple( COUT, OFmake_tuple( "This", "is", "a", "tuple", "with", 7, "elements" ) ); * @endcode * Output: * @verbatim The following tuples are inequal: Hello World, 42 , 0 The following tuples are equal: Hello World, 42 Hello World, 42 Hello World, 42 This, is, a, tuple, with, 7, elements @endverbatim */ template class OFtuple {}; /** A literal used in conjunction with OFtie to ignore specific elements. * @relates OFtuple * @details * OFignore is a global constant that "tags" a specific tuple element * which should be ignored. This means anything can be assigned to this * element without any effect. *

Usage Example:

* @code{.cpp} * typedef OFMap,OFString> PhoneBook; * PhoneBook pb; * PhoneBook::iterator it; * ... * // We don't care if this was a new entry or an old one existed, we just want to update it * OFtie( it, OFignore ) = pb.insert( PhoneBook::value_type( OFmake_tuple( "Ringo", "John" ), "" ); * updatePhonebookEntry( it ); * ... * @endcode */ const OFignore; /** Creates a tuple, automatically deducing the element types from the given arguments. * @relates OFtuple * @param args a sequence of arguments. When no arguments are supplied, an object of type * OFtuple<> is created. *
Note * When C++11 support is not available, the number * of elements OFtuple may contain is limited, * currently up to 50 elements are supported. *
* @details * OFcreate_tuple deduces the element types from the arguments by applying OFdecay * to each parameter type. *

Usage Example:

* @code{.cpp} * OFVector > personIndex; * personIndex.push_back( OFmake_tuple( "Alexander", "Emily", 17 ) ); * personIndex.push_back( OFmake_tuple( "Henke", "Michelle", 0 ) ); * @endcode */ template OFtuple::type...> OFmake_tuple( Types&&... args ); /** Creates a tuple of references to the given arguments. * @relates OFtuple * @param args a sequence of arguments. When no arguments are supplied, an object of type * OFtuple<> is created. *
Note * When C++11 support is not available, the number * of elements OFtuple may contain is limited, * currently up to 50 elements are supported. *
* @details * OFtie is meant to link its arguments to an OFtuple object, to ease extracting the * elements from a tuple. *

Usage Example:

* @code{.cpp} * OFtuple getAccount( const size_t accountId ) * { * ... * } * * ... * * OFString name; * OFBool sex; * unsigned age; * OFString data; * * OFtie( name, sex, age, data ) = getAccount( currentId ); * @endcode * @see OFignore */ template OFtuple OFtie( Types&... args ); #endif // DOXYGEN #endif // OFTUPLE_H