// // Copyright (c) 2002 by Stephen C. Dewhurst // Permission to use, copy, modify, distribute and sell this software for any purpose is // hereby granted without fee, provided that the above copyright notice appears in all copies // and that both that copyright notice and this permission notice appear in supporting documentation. // The author or makes no representations about the suitability of this software for any purpose. // It is provided "as is" without express or implied warranty. // // MultiIn // // Described in CUJ 20(4), April 2002: "Metaprogrammed Adapters" // MultiIn is an input/forward iterator adapter that allows an unbounded number of differently-typed // input/forward sequences to be treated as a single "supersequence," without copying the values from // the constituent sequences. namespace org_semantics { // There are two implementations. One specializes some MultiIn functions for the case where the two // component iterators are of the same type (PARTSPEC), one specializes the entire implementation // (FULLSPEC). //#define PARTSPEC #define FULLSPEC #include // // Some background utilities. // // Select is filched from Alexandrescu's Loki library. template struct Select { typedef A R; }; template struct Select { typedef B R; }; struct Yes {}; struct No {}; // Are A and B the same type? template struct IsSame { enum { result = false }; typedef No R; }; template struct IsSame { enum { result = true }; typedef Yes R; }; // Is In a forward iterator? template struct IsFor { enum { result = !IsSame::iterator_category, std::input_iterator_tag>::result }; typedef Select< result, std::forward_iterator_tag, std::input_iterator_tag>::R R; }; // Are In1 and In2 both forward iterators? template struct BothFor { enum { result = IsFor::result && IsFor::result }; typedef Select< result, std::forward_iterator_tag, std::input_iterator_tag>::R R; }; #ifdef FULLSPEC template class MultiIn : public std::iterator< typename BothFor::R, // category depends typename std::iterator_traits::value_type, std::ptrdiff_t> { public: MultiIn( In1 b1, In1 e1, In2 b2 ) : c1_(b1), e1_(e1), c2_(b2), first_(b1!=e1) {} MultiIn( In1 e1, In2 e2 ) : c1_(e1), e1_(e1), c2_(e2), first_(false) {} MultiIn() {} MultiIn &operator ++(); MultiIn operator ++( int ) { MultiIn tmp( *this ); ++*this; return tmp; } typedef typename std::iterator_traits ::value_type value_type; typedef typename Select< BothFor::result, value_type &, const value_type & >::R RefRet; RefRet operator *() const; typedef typename Select< BothFor::result, value_type *, const value_type * >::R PtrRet; PtrRet operator ->() const { return &operator *(); } bool operator ==( const MultiIn &that ) const; bool operator !=( const MultiIn &that ) const { return !(*this == that); } private: In1 c1_; // first In1 e1_; // end of first In2 c2_; // second bool first_; // in first sequence? }; template MultiIn &MultiIn::operator ++() { if( first_ ) { if( ++c1_ == e1_ ) first_ = false; } else ++c2_; return *this; } template typename MultiIn::RefRet MultiIn::operator *() const { if( first_ ) return *c1_; else return *c2_; } template bool MultiIn::operator ==( const MultiIn &that ) const { if( first_ ) if( that.first_ ) return c1_ == that.c1_; else return false; else if( that.first_ ) return false; else return c2_ == that.c2_; } template class MultiIn : public std::iterator< typename IsFor::R, typename std::iterator_traits::value_type, std::ptrdiff_t> { public: typedef typename std::iterator_traits ::value_type value_type; MultiIn( In b1, In e1, In b2 ) : c_(b1), e1_(e1), b2_(b2), first_(b1 != e1) { if( !first_ ) c_ = b2; } MultiIn( In e1, In e2 ) : c_(e2), e1_(e1), b2_(e2), first_(false) {} MultiIn() {} typedef typename Select< IsFor::result, value_type &, const value_type & >::R RefRet; RefRet operator *() const { return *c_; } typedef typename Select< IsFor::result, value_type *, const value_type * >::R PtrRet; PtrRet operator ->() const { return &operator *(); } MultiIn &operator ++(); MultiIn operator ++(int) { MultiIn tmp( *this ); ++*this; return tmp; } bool operator ==( const MultiIn &that ) const { return c_ == that.c_; } bool operator !=( const MultiIn &that ) const { return c_ != that.c_; } private: In c_, e1_, b2_; bool first_; }; template MultiIn &MultiIn::operator ++() { ++c_; if( first_ && c_ == e1_ ) { c_ = b2_; first_ = false; } return *this; } #endif #ifdef PARTSPEC template class MultiIn : public std::iterator< typename BothFor::R, // category depends typename std::iterator_traits::value_type, std::ptrdiff_t> { public: MultiIn( In1 b1, In1 e1, In2 b2 ) : c1_(b1), e1_(e1), c2_(b2), first_(b1!=e1) {} MultiIn( In1 e1, In2 e2 ) : c1_(e1), e1_(e1), c2_(e2), first_(false) {} MultiIn() {} MultiIn &operator ++(); MultiIn operator ++( int ) { MultiIn tmp( *this ); ++*this; return tmp; } typedef typename std::iterator_traits ::value_type value_type; typedef typename Select< BothFor::result, value_type &, const value_type & >::R RefRet; RefRet operator *() const; typedef typename Select< BothFor::result, value_type *, const value_type * >::R PtrRet; PtrRet operator ->() const { return &operator *(); } bool operator ==( const MultiIn &that ) const; bool operator !=( const MultiIn &that ) const { return !(*this == that); } private: In1 c1_; // first In1 e1_; // end of first In2 c2_; // second bool first_; // in first sequence? bool compare( const MultiIn &, No ) const; bool compare( const MultiIn &, Yes ) const; }; template MultiIn &MultiIn::operator ++() { if( first_ ) { if( ++c1_ == e1_ ) first_ = false; } else ++c2_; return *this; } template typename MultiIn::RefRet MultiIn::operator *() const { if( first_ ) return *c1_; else return *c2_; } template bool MultiIn::compare( const MultiIn &that, No ) const { if( first_ ) if( that.first_ ) return c1_ == that.c1_; else return false; else if( that.first_ ) return false; else return c2_ == that.c2_; } template bool MultiIn::compare( const MultiIn &that, Yes ) const { In1 i1( first_?c1_:c2_); In1 i2( that.first_?that.c1_:that.c2_); return i1==i2; } template bool MultiIn::operator ==( const MultiIn &that ) const { return compare( that, IsSame::R() ); } #endif // // Some helper functions that make it a little easier to generate // beginning and end values for MultiIns from standard containers. // template MultiIn multiIn( C1 &c1, C2 &c2 ) { typedef typename C1::iterator I1; typedef typename C2::iterator I2; return MultiIn( c1.begin(), c1.end(), c2.begin() ); } template MultiIn multiInEnd( C1 &c1, C2 &c2 ) { typedef typename C1::iterator I1; typedef typename C2::iterator I2; return MultiIn( c1.end(), c2.end() ); } template MultiIn< typename C1::iterator, MultiIn< typename C2::iterator, typename C3::iterator> > multiIn( C1 &c1, C2 &c2, C3 &c3 ) { typedef typename C1::iterator I1; typedef typename C2::iterator I2; typedef typename C3::iterator I3; return MultiIn< I1, MultiIn > ( c1.begin(), c1.end(), multiIn( c2, c3 ) ); } template MultiIn< typename C1::iterator, MultiIn< typename C2::iterator, typename C3::iterator> > multiInEnd( C1 &c1, C2 &c2, C3 &c3 ) { typedef typename C1::iterator I1; typedef typename C2::iterator I2; typedef typename C3::iterator I3; return MultiIn< I1, MultiIn > ( c1.end(), multiInEnd( c2, c3 ) ); } } // namespace org_semantics