// Semantics Consulting's Tyr Library // http://www.semantics.org // // Copyright (c) 2003 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 makes no representations about the suitability of this // software for any purpose. It is provided "as is" without express // or implied warranty. // MultiOut // // Described in Output Iterator Adapters. C/C++ Users Journal 20, 2 (February 2002). // MultiOut is an output iterator adapter that allows an output sequence to be sent to an // unbounded number of output streams simultaneously. // NOTE: This implementation is substantially different from that // described in the article. #ifndef MULTIOUT_H #define MULTIOUT_H #include #include "utils.h" #include "typeof.h" namespace Tyr { // Note that MultiOut requires specification of its value_type. // This is inconvenient, but often necessary (see below). // The helper functions below do a pretty good job of figuring // out what the value_type should be, and should be used in // preference to direct instantiation of MultiOut. template ::value_type> class MultiOut : public std::iterator< std::output_iterator_tag, ValueType, void > { public: typedef ValueType value_type; MultiOut( Out1 a, Out2 b ) : a_(a), b_(b) {} MultiOut &operator ++() { ++a_; ++b_; return *this; } MultiOut operator ++(int) { MultiOut tmp( *this ); ++*this; return tmp; } MultiOut &operator =( const value_type &v ) { *a_ = v; *b_ = v; return *this; } bool operator ==( const MultiOut &that ) const { return a_ == that.a_ && b_ == that.b_; } bool operator !=( const MultiOut &that ) const { return !(*this == that); } MultiOut &operator *() { return *this; } private: Out1 a_; Out2 b_; }; // Note that inserters, ostream_iterators, etc. often do not define // a value type. This is legal but unfortunate. // All this mess below is simply a mechanism to choose the "best" // value type for the MultiOut given the individual value types of // each output iterator. // // 1) collect in a typelist the value_type of each output iterator // 2) get rid of any void value_types // 3) sort the resultant type list based on the criteria in VTComp // 4) choose the "smallest" type as the value_type for the MultiOut // 5) if there is no smallest type, die horribly template struct VTComp { // A < B if A converts to B and B doesn't convert to A // if A and B are mutually convertible, then the larger of the // two is <. // Therefore double < char, for instance. enum { atob = !CanConvert::r, btoa = !CanConvert::r, r = (atob && !btoa) || (atob && btoa && sizeof(A)>sizeof(B)) }; }; template struct SelectValueType { struct VoidValueTypeInMultiOut {}; typedef typename EraseIf::template Adapted>::R Vnovoid; typedef typename Sort::R Vsorted; typedef typename Append::R Vfinal; typedef typename Vfinal::head R; }; template struct MultiOutHelper2 { typedef typename std::iterator_traits::value_type V1; typedef typename std::iterator_traits::value_type V2; typedef MakeTypelist2(V1,V2) Vs; typedef typename SelectValueType::R VT; typedef MultiOut R; }; template struct MultiOutHelper3 { typedef typename std::iterator_traits::value_type V1; typedef typename std::iterator_traits::value_type V2; typedef typename std::iterator_traits::value_type V3; typedef MakeTypelist3(V1,V2,V3) Vs; typedef typename SelectValueType::R VT; typedef MultiOut MO23; typedef MultiOut R; }; template struct MultiOutHelper4 { typedef typename std::iterator_traits::value_type V1; typedef typename std::iterator_traits::value_type V2; typedef typename std::iterator_traits::value_type V3; typedef typename std::iterator_traits::value_type V4; typedef MakeTypelist4(V1,V2,V3,V4) Vs; typedef typename SelectValueType::R VT; typedef MultiOut MO34; typedef MultiOut MO234; typedef MultiOut R; }; // These helpers deduce the value_type of the MultiOut by // examination of the value_types of each component. // This requires that at least one of the output iterators // define an acceptable value type. template typename MultiOutHelper2::R multiOut( Out1 a, Out2 b ) { return typename MultiOutHelper2::R( a, b ); } // Alternatively, you can specify the value_type explicitly. template MultiOut multiOutV( Out1 a, Out2 b ) { return MultiOut( a, b ); } template typename MultiOutHelper3::R multiOut( Out1 a, Out2 b, Out3 c ) { typedef MultiOutHelper3 MOH; typedef typename MOH::MO23 MO23; return typename MOH::R( a, MO23(b,c) ); } template MultiOut,ValueType> multiOutV( Out1 a, Out2 b, Out3 c ) { typedef MultiOut MO23; return MultiOut( a, MO23(b,c) ); } template typename MultiOutHelper4::R multiOut( Out1 a, Out2 b, Out3 c, Out4 d ) { typedef MultiOutHelper4 MOH; typedef typename MOH::MO34 MO34; typedef typename MOH::MO234 MO234; return typename MOH::R( a, MO234( b, MO34(c,d) ) ); } template MultiOut,ValueType>,ValueType> multiOutV( Out1 a, Out2 b, Out3 c, Out4 d ) { typedef MultiOut MO34; typedef MultiOut MO234; return MultiOut( a, MO234(b,MO34(c,d)) ); } } // namespace Tyr #endif