// Type Vector (tv.hpp) // (C) Copyright Hamish Mackenzie 2000. Permission to copy, use, // modify, sell and distribute this software is granted provided // this copyright notice appears in all copies. This software is // provided "as is" without express or implied warranty, and with // no claim as to its suitability for any porpose. // Revision History // 24 July 2000 Initial version // 25 March 2001 General tidy up with view to submiting to boost // 30 March 2001 Added const version of for_each #ifndef HKM_TV_HPP #define HKM_TV_HPP namespace hkm { // No one seems certain what this should be called if, iif, conditional, select template< bool b, class result_if_true, class result_if_false > class choose; template< class result_if_true, class result_if_false > class choose< true, result_if_true, result_if_false > { public: typedef result_if_true result; }; template< class result_if_true, class result_if_false > class choose< false, result_if_true, result_if_false > { public: typedef result_if_false result; }; template< class TV, int n > class tv_rfind_nth; // Left = tv of all start of the list // Back = the type being appended template< class Left, class Back > class tv { public: // size is the number of type/values static const int size = Left::size + 1; // back_index is the largest valid index static const int back_index = Left::size; // Default constructer // Requirement: All types in the vector need a default constructer tv() {} // Copy constructer // Requirement: All types must have a copy constructer tv( const tv< Left, Back > & x ) : tv_left( x.tv_left ), value_back( x.value_back ) {} explicit tv( const Left & l, const Back & b ) : tv_left( l ), value_back( b ) {} // Constructing each value with a single parameter // Note: Passed by reference to allow values to accept paramters by refence // this must be used carefully but is usefull template< class T > explicit tv( tv< Left, T > & x ) : tv_left( x.left() ), value_back( x.back() ) {} // type is the last type the list typedef Back type; // left_type is the tv of the all previous types typedef Left left_type; // back gets and sets the last value in the list const type & back() const { return value_back; } type & back() { return value_back; } // Accesses the tv of items left of back const Left & left() const { return tv_left; } Left & left() { return tv_left; } // Append a value/type to the vector and return the result template< class New > tv< tv< Left, Back >, New > operator |( New n ) { return tv< tv< Left, Back >, New >( *this, n ); } // Append a type to the vector template< class New > class append { public: typedef tv< tv< Left, Back >, New > result; }; // Enumerate values/types template< class Func > void for_each( Func f ) { tv_left.for_each( f ); f( value_back ); } template< class Func > void for_each( Func f ) const { tv_left.for_each( f ); f( value_back ); } // Enumerate just types template< class Func > static void for_each_static( Func f ) { Left::for_each_static( f ); f( (Back *) 0 ); // Should probably call a template member } // Run time index template< class Func > void for_nth( int n, Func f ) { tv_left.for_nth( n, f ); if( n == back_index ) f( value_back ); } template< class Func > void for_nth( int n, Func f ) const { tv_left.for_nth( n, f ); if( n == back_index ) f( value_back ); } template< class Func > static void for_nth_static( int n, Func f ) { Left::for_nth_static( n, f ); if( n == back_index ) f( (Back *) 0 ); // Should probably call a template member } // Transform one tv into another tv (types only) template< class transform_type > class transform { public: typedef tv< typename Left::transform< transform_type >::result, typename transform_type::transform< Back >::result > result; }; template< class filter_type > class filter { typedef typename filter_type::filter< Back > temp_type; typedef typename Left::filter< filter_type >::result left_filtered; public: typedef typename choose< temp_type::result, tv< left_filtered, Back >, left_filtered >::result result; }; // Find the nth value from the back template< int n > const typename tv_rfind_nth< tv< Left, Back >, n + 1 >::type &rval() const { tv_rfind_nth< tv< Left, Back >, n + 1 > temp; return temp( *this ); } template< int n > typename tv_rfind_nth< tv< Left, Back >, n + 1 >::type &rval() { tv_rfind_nth< tv< Left, Back >, n + 1 > temp; return temp( *this ); } // Find the nth value from the left template< int n > const typename tv_rfind_nth< tv< Left, Back >, back_index - n + 1 >::type &val() const { tv_rfind_nth< tv< Left, Back >, back_index - n + 1 > temp; return temp( *this ); } template< int n > typename tv_rfind_nth< tv< Left, Back >, back_index - n + 1 >::type &val() { tv_rfind_nth< tv< Left, Back >, back_index - n + 1 > temp; return temp( *this ); } private: Left tv_left; Back value_back; }; // Special type to expresz the empty tv // all other tv will have this as the left parameter // for the first item in the list // eg. tv< tv0, Fred > is a tv with one type called Fred class tv0 { public: static const int size = 0; template< class New > tv< tv0, New > operator |( New n ) { return tv< tv0, New >( *this, n ); } template< class New > class append { public: typedef tv< tv0, New > result; }; template< class Func > void for_each( Func f ) const { } template< class Func > static void for_each_static( Func f ) { } template< class Func > void for_nth( int n, Func f ) const { } template< class Func > static void for_nth_static( int n, Func f ) { } template< class transform_type > class transform { public: typedef tv0 result; }; template< class filter_type > class filter { public: typedef tv0 result; }; }; // Finds the nth type/value from the back // Uses parameter of n_plus_one to avoid a // compilere error distinguishing between 0 and -0 // in the terminating case template< class TV, int n_plus_one > class tv_rfind_nth { public: typedef tv_rfind_nth< typename TV::left_type, n_plus_one - 1 > next; typedef typename next::type type; const type &operator()( const TV &tv ) { next temp; return temp( tv.left() ); } type &operator()( TV &tv ) { next temp; return temp( tv.left() ); } }; template< class TV > class tv_rfind_nth< TV, 1 > { public: typedef typename TV::type type; const type &operator()( const TV &tv ) { return tv.back(); } type &operator()( TV &tv ) { return tv.back(); } }; class make_tv_null_type { }; template< class TV, class TYPE > class tv_add { public: typedef tv< TV, TYPE > result; }; template< class TV > class tv_add< TV, make_tv_null_type > { public: typedef TV result; }; template< class Type0 = make_tv_null_type, class Type1 = make_tv_null_type, class Type2 = make_tv_null_type, class Type3 = make_tv_null_type, class Type4 = make_tv_null_type, class Type5 = make_tv_null_type, class Type6 = make_tv_null_type, class Type7 = make_tv_null_type, class Type8 = make_tv_null_type, class Type9 = make_tv_null_type > class make_tv { public: typedef tv_add< tv_add< tv_add< tv_add< tv_add< tv_add< tv_add< tv_add< tv_add< tv_add< tv0, Type0 >::result, Type1 >::result, Type2 >::result, Type3 >::result, Type4 >::result, Type5 >::result, Type6 >::result, Type7 >::result, Type8 >::result, Type9 >::result result; }; } #endif //HKM_TV_HPP