From 4df2d9d3c15ef142e30bb0bada584cf6689ef7c1 Mon Sep 17 00:00:00 2001 From: Gennadiy Rozental Date: Sat, 5 Jun 2004 11:03:12 +0000 Subject: [PATCH] input_iterator_adaptor simplified token_iterator added [SVN r23028] --- .../iterator/ifstream_line_iterator.hpp | 10 +- .../detail/iterator/input_iterator_facade.hpp | 110 ++-- .../detail/iterator/istream_line_iterator.hpp | 65 +- .../test/detail/iterator/token_iterator.hpp | 559 ++++++++++++++++++ 4 files changed, 645 insertions(+), 99 deletions(-) create mode 100644 include/boost/test/detail/iterator/token_iterator.hpp diff --git a/include/boost/test/detail/iterator/ifstream_line_iterator.hpp b/include/boost/test/detail/iterator/ifstream_line_iterator.hpp index f6d501fc..8a2ff7ba 100644 --- a/include/boost/test/detail/iterator/ifstream_line_iterator.hpp +++ b/include/boost/test/detail/iterator/ifstream_line_iterator.hpp @@ -35,7 +35,7 @@ template class ifstream_holder { public: // Constructor - explicit ifstream_holder( basic_cstring file_name ) + explicit ifstream_holder( basic_cstring file_name ) { if( file_name.is_empty() ) return; @@ -60,10 +60,10 @@ template class basic_ifstream_line_iterator : detail::ifstream_holder, public basic_istream_line_iterator { public: - basic_ifstream_line_iterator( basic_cstring file_name, CharT delimeter ) + basic_ifstream_line_iterator( basic_cstring file_name, CharT delimeter ) : detail::ifstream_holder( file_name ), basic_istream_line_iterator( this->m_stream, delimeter ) {} - explicit basic_ifstream_line_iterator( basic_cstring file_name = basic_cstring() ) + explicit basic_ifstream_line_iterator( basic_cstring file_name = basic_cstring() ) : detail::ifstream_holder( file_name ), basic_istream_line_iterator( this->m_stream ) {} }; @@ -78,6 +78,10 @@ typedef basic_ifstream_line_iterator wifstream_line_iterator; // Revision History : // // $Log$ +// Revision 1.4 2004/06/05 11:03:12 rogeeff +// input_iterator_adaptor simplified +// token_iterator added +// // Revision 1.3 2004/05/27 07:01:49 rogeeff // portability workarounds // diff --git a/include/boost/test/detail/iterator/input_iterator_facade.hpp b/include/boost/test/detail/iterator/input_iterator_facade.hpp index 3ea0867e..fa9aac4a 100644 --- a/include/boost/test/detail/iterator/input_iterator_facade.hpp +++ b/include/boost/test/detail/iterator/input_iterator_facade.hpp @@ -17,79 +17,49 @@ // Boost #include -#include -#include namespace boost { namespace unit_test { -namespace detail { +// ************************************************************************** // +// ************** input_iterator_core_access ************** // +// ************************************************************************** // -template -struct value_type_ident +class input_iterator_core_access { - typedef T value_type; -}; +#if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) +public: +#else + template friend class input_iterator_facade; +#endif -template -struct ref_type_ident -{ - typedef T reference; -}; + template + static bool get( Facade& f ) + { + return f.get(); + } -} // namespace detail +private: + // objects of this class are useless + input_iterator_core_access(); //undefined +}; // ************************************************************************** // // ************** input_iterator_facade ************** // // ************************************************************************** // -template -class input_iterator_facade : public iterator_facade< - typename mpl::if_,input_iterator_facade,Derived>::type, - typename mpl::if_,ImplPolicy,detail::value_type_ident >::type::value_type, - forward_traversal_tag, - typename mpl::if_,ImplPolicy,detail::ref_type_ident >::type::reference> +template +class input_iterator_facade : public iterator_facade { public: // Constructor - explicit input_iterator_facade( ImplPolicy const& p = ImplPolicy() ) - : m_policy( p ) - { - increment(); - } - - //!! copy constructor/assigment - should we make rhs invalid after copy?? - // input_iterator_facade( input_iterator_facade const& rhs ) - // : m_policy( rhs.m_policy ), m_valid( rhs.m_valid ) - // { - // const_cast( rhs ).m_valid = false; - // } - // - // void operator=( input_iterator_facade const& rhs ) - // { - // m_policies = rhs.p_policies; - // m_valid = rhs.m_valid; - // - // const_cast( rhs ).m_valid = false; - // } - - //!! do we need reset method? - // void reset() - // { - // m_valid = m_policy.intialize(); - // - // increment(); - // } - -protected: // provide access to the derived - // Data members - ImplPolicy m_policy; - -private: - typedef typename mpl::if_,detail::value_type_ident,ImplPolicy>::type::value_type value_type; - typedef typename mpl::if_,ImplPolicy,detail::ref_type_ident >::type::reference reference; + input_iterator_facade() : m_valid( false ), m_value() {} +protected: friend class iterator_core_access; // iterator facade interface implementation @@ -97,23 +67,31 @@ private: { // we make post-end incrementation indefinetly safe if( m_valid ) - m_valid = m_policy.get(); + m_valid = input_iterator_core_access::get( *static_cast(this) ); } - bool equal( input_iterator_facade const& rhs ) const + Reference dereference() const { - // two invalid iterator equals, two valid need to be compared, invalid never equal to valid - return !m_valid && !rhs.m_valid || m_valid && rhs.m_valid && m_policy.equal( rhs.m_policy ); + return m_value; } - reference dereference() const - { - //!! should we call some kind of assert( m_valid ) here instead or do nothing??? - // we pass m_valid inside the policy to decide what to do on attempt to dereference invalid iterator - return m_policy.dereference( m_valid ); +protected: // provide access to the Derived + void init() + { + m_valid = true; + increment(); } // Data members bool m_valid; + ValueType m_value; + +private: + // iterator facade interface implementation + bool equal( input_iterator_facade const& rhs ) const + { + // two invalid iterator equals, inequal otherwise + return !m_valid && !rhs.m_valid; + } }; } // namespace unit_test @@ -124,6 +102,10 @@ private: // Revision History : // // $Log$ +// Revision 1.3 2004/06/05 11:03:12 rogeeff +// input_iterator_adaptor simplified +// token_iterator added +// // Revision 1.2 2004/05/25 10:29:09 rogeeff // use standard getline // eliminate initialize diff --git a/include/boost/test/detail/iterator/istream_line_iterator.hpp b/include/boost/test/detail/iterator/istream_line_iterator.hpp index f9bd35d5..a8c977cf 100644 --- a/include/boost/test/detail/iterator/istream_line_iterator.hpp +++ b/include/boost/test/detail/iterator/istream_line_iterator.hpp @@ -18,7 +18,6 @@ // Boost #include #include -#include // STL #include @@ -31,44 +30,42 @@ namespace unit_test { // ************** basic_istream_line_iterator ************** // // ************************************************************************** // -namespace detail { - -template -class istream_line_iterator_impl { -public: - typedef basic_cstring value_type; - typedef basic_cstring reference; - - istream_line_iterator_impl( std::basic_istream& input, CharT delimeter ) - : m_input_stream( &input ), m_delimeter( delimeter ) {} - - bool get() { return std::getline( *m_input_stream, m_buffer, m_delimeter ); } - reference dereference( bool valid ) const { return m_buffer; } - bool equal( istream_line_iterator_impl const& ) const { return false; } - -private: - // Data members - std::basic_istream* m_input_stream; - std::basic_string m_buffer; - CharT m_delimeter; -}; - -} // namespace detail - //!! Should we support policy based delimitation template class basic_istream_line_iterator -: public input_iterator_facade,basic_istream_line_iterator > { - typedef detail::istream_line_iterator_impl impl; - typedef input_iterator_facade > base; +: public input_iterator_facade, + std::basic_string, + basic_cstring > { + typedef input_iterator_facade, + std::basic_string, + basic_cstring > base; public: - // Constructor + // Constructors + basic_istream_line_iterator() {} basic_istream_line_iterator( std::basic_istream& input, CharT delimeter ) - : base( impl( input, delimeter ) ) {} - + : m_input_stream( &input ), m_delimeter( delimeter ) + { + init(); + } explicit basic_istream_line_iterator( std::basic_istream& input ) - : base( impl( input, input.widen( '\n' ) ) ) {} + : m_input_stream( &input ), m_delimeter( input.widen( '\n' ) ) + { + init(); + } + +private: + friend class input_iterator_core_access; + + // increment implementation + bool get() + { + return std::getline( *m_input_stream, m_value, m_delimeter ); + } + + // Data members + std::basic_istream* m_input_stream; + CharT m_delimeter; }; typedef basic_istream_line_iterator istream_line_iterator; @@ -82,6 +79,10 @@ typedef basic_istream_line_iterator wistream_line_iterator; // Revision History : // // $Log$ +// Revision 1.4 2004/06/05 11:03:12 rogeeff +// input_iterator_adaptor simplified +// token_iterator added +// // Revision 1.3 2004/05/27 07:01:49 rogeeff // portability workarounds // diff --git a/include/boost/test/detail/iterator/token_iterator.hpp b/include/boost/test/detail/iterator/token_iterator.hpp new file mode 100644 index 00000000..681a8f05 --- /dev/null +++ b/include/boost/test/detail/iterator/token_iterator.hpp @@ -0,0 +1,559 @@ +// (C) Copyright Gennadiy Rozental 2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision$ +// +// Description : +// *************************************************************************** + +#ifndef BOOST_TOKEN_ITERATOR_HPP +#define BOOST_TOKEN_ITERATOR_HPP + +// Boost +#include +#include + +#include +#include + +// STL +#include +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std{ using ::ispunct; using ::isspace; } +#endif + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** ti_delimeter_type ************** // +// ************************************************************************** // + +enum ti_delimeter_type { use_delim, use_ispunct, use_isspace }; + +namespace detail { + +// ************************************************************************** // +// ************** delim_policy ************** // +// ************************************************************************** // + +template +class delim_policy { + typedef basic_cstring cstring; +public: + // Constructor + explicit delim_policy( ti_delimeter_type t = use_delim ) : m_type( t ) {} + explicit delim_policy( cstring d, ti_delimeter_type t ) + { + use_delimeters( d, t ); + } + + void use_delimeters( cstring d, ti_delimeter_type t ) + { + m_delimeters = d; + m_type = d.is_empty() ? t : use_delim; + } + + bool operator()( CharT c ) + { + switch( m_type ) { + case use_delim: { + typename cstring::iterator it = m_delimeters.begin(); + for( ; it != m_delimeters.end(); ++it ) + if( CharCompare()( *it, c ) ) + break; + return it != m_delimeters.end(); + } + case use_ispunct: return (std::ispunct)( c ) != 0; + case use_isspace: return (std::isspace)( c ) != 0; + } + + return false; + } + + // Data members + cstring m_delimeters; + ti_delimeter_type m_type; +}; + +// ************************************************************************** // +// ************** token_assigner ************** // +// ************************************************************************** // + +template +struct token_assigner { + template + static void assign( Iterator b, Iterator e, Token& t ) { t.assign( b, e ); } + + template + static void append_move( Iterator& b, Token& t ) { ++b; } + + template + static void clear( Token& t ) {} +}; + +template<> +struct token_assigner { + template + static void assign( Iterator b, Iterator e, Token& t ) {} + + template + static void append_move( Iterator& b, Token& t ) { t += *b; ++b; } + + template + static void clear( Token& t ) { t.clear(); } +}; + +// ************************************************************************** // +// ************** default_char_compare ************** // +// ************************************************************************** // + +template +class default_char_compare { +public: + bool operator()( CharT c1, CharT c2 ) + { +#if BOOST_WORKAROUND(__GNUC__, < 3) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) + return std::string_char_traits::eq( c1, c2 ); +#else + return std::char_traits::eq( c1, c2 ); +#endif + } +}; + +// ************************************************************************** // +// ************** dropped_delimeters_m ************** // +// ************************************************************************** // + +template +struct dropped_delimeters_m +{ + explicit dropped_delimeters_m( basic_cstring delims ) + : m_delims( delims ) {} + + template + void apply( delim_policy& is_drop, delim_policy&, bool ) const + { + is_drop.use_delimeters( m_delims, use_isspace ); + } + + basic_cstring m_delims; +}; + +//____________________________________________________________________________// + +template<> +struct dropped_delimeters_m +{ + explicit dropped_delimeters_m( ti_delimeter_type type ) + : m_type( type ) {} + + template + void apply( delim_policy& is_drop, delim_policy&, bool ) const + { + is_drop.use_delimeters( "", m_type ); + } + + ti_delimeter_type m_type; +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** kept_delimeters_m ************** // +// ************************************************************************** // + +template +struct kept_delimeters_m +{ + explicit kept_delimeters_m( basic_cstring delims, ti_delimeter_type type = use_ispunct ) + : m_delims( delims ), m_type( type ) {} + + template + void apply( delim_policy&, delim_policy& is_kept, bool ) const + { + is_kept.use_delimeters( m_delims, m_type ); + } + + basic_cstring m_delims; + ti_delimeter_type m_type; +}; + +//____________________________________________________________________________// + +template<> +struct kept_delimeters_m +{ + explicit kept_delimeters_m( ti_delimeter_type type ) + : m_type( type ) {} + + template + void apply( delim_policy&, delim_policy& is_kept, bool ) const + { + is_kept.use_delimeters( "", m_type ); + } + + ti_delimeter_type m_type; +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** keep_empty_tokens_m ************** // +// ************************************************************************** // + +struct keep_empty_tokens_m +{ + explicit keep_empty_tokens_m( bool v ) + : m_keep_empty_tokens( v ) {} + + template + void apply( delim_policy&, delim_policy&, bool& keep_empty_tokens ) const + { + keep_empty_tokens = m_keep_empty_tokens; + } + + bool m_keep_empty_tokens; +}; + +} // namespace detail + +// ************************************************************************** // +// ************** modifiers generators ************** // +// ************************************************************************** // + +static struct dropped_delimeters_generator { + template + detail::dropped_delimeters_m + operator=( basic_cstring d ) { return detail::dropped_delimeters_m( d ); } + template + detail::dropped_delimeters_m + operator=( CharT const* d ) { return detail::dropped_delimeters_m( basic_cstring( d ) ); } + + detail::dropped_delimeters_m + operator=( ti_delimeter_type t ) { return detail::dropped_delimeters_m( t ); } +} dropped_delimeters; + +//____________________________________________________________________________// + +static struct kept_delimeters_generator { + template + detail::kept_delimeters_m + operator=( basic_cstring d ) { return detail::kept_delimeters_m( d ); } + template + detail::kept_delimeters_m + operator=( CharT const* d ) { return detail::kept_delimeters_m( basic_cstring( d ) ); } + + detail::kept_delimeters_m + operator=( ti_delimeter_type t ) { return detail::kept_delimeters_m( t ); } +} kept_delimeters; + +//____________________________________________________________________________// + +static struct keep_empty_tokens_generator : detail::keep_empty_tokens_m { + keep_empty_tokens_generator() : detail::keep_empty_tokens_m( true ) {} + + detail::keep_empty_tokens_m + operator=( bool v ) { return detail::keep_empty_tokens_m( v ); } +} keep_empty_tokens; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** token_iterator_base ************** // +// ************************************************************************** // + +template, + typename ValueType = basic_cstring, + typename Reference = basic_cstring, + typename Traversal = forward_traversal_tag> +class token_iterator_base +: public input_iterator_facade { + typedef basic_cstring cstring; + typedef detail::delim_policy delim_policy; + typedef input_iterator_facade base; +public: + // Constructor + explicit token_iterator_base() + : m_is_dropped( use_isspace ), + m_is_kept( use_ispunct ), + m_keep_empty_tokens( false ), + m_token_produced( false ) + { + } + +protected: + template + token_iterator_base& + use( Modifier const& m ) + { + m.apply( m_is_dropped, m_is_kept, m_keep_empty_tokens ); + return *this; + } + + template + bool get( Iter& begin, Iter end ) + { + typedef detail::token_assigner::type> Assigner; + Iter checkpoint; + + Assigner::clear( m_value ); + + if( !m_keep_empty_tokens ) { + while( begin != end && m_is_dropped( *begin ) ) + ++begin; + + if( begin == end ) + return false; + + checkpoint = begin; + + if( m_is_kept( *begin ) ) + Assigner::append_move( begin, m_value ); + else + while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) ) + Assigner::append_move( begin, m_value ); + } + else { // m_keep_empty_tokens ia true + checkpoint = begin; + + if( begin == end ) { + if( m_token_produced ) + return false; + + m_token_produced = true; + } + else if( m_is_kept( *begin ) ) { + if( m_token_produced ) + Assigner::append_move( begin, m_value ); + + m_token_produced = !m_token_produced; + } + else if( !m_token_produced && m_is_dropped( *begin ) ) + m_token_produced = true; + else { + if( m_is_dropped( *begin ) ) + checkpoint = ++begin; + + while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) ) + Assigner::append_move( begin, m_value ); + + m_token_produced = true; + } + } + + Assigner::assign( checkpoint, begin, m_value ); + + return true; + } + +private: + // Data members + delim_policy m_is_dropped; + delim_policy m_is_kept; + bool m_keep_empty_tokens; + bool m_token_produced; +}; + +// ************************************************************************** // +// ************** basic_string_token_iterator ************** // +// ************************************************************************** // + +template > +class basic_string_token_iterator +: public token_iterator_base,CharT,CharCompare> { + typedef basic_cstring cstring; + typedef token_iterator_base,CharT,CharCompare> base; +public: + explicit basic_string_token_iterator() {} + explicit basic_string_token_iterator( cstring src ) + : m_src( src ) + { + this->init(); + } + + template + basic_string_token_iterator( Src src, M1 const& m1 ) + : m_src( src ) + { + this->use( m1 ); + + this->init(); + } + + template + basic_string_token_iterator( Src src, M1 const& m1, M2 const& m2 ) + : m_src( src ) + { + this->use( m1 ); + this->use( m2 ); + + this->init(); + } + + template + basic_string_token_iterator( Src src, M1 const& m1, M2 const& m2, M3 const& m3 ) + : m_src( src ) + { + this->use( m1 ); + this->use( m2 ); + this->use( m3 ); + + this->init(); + } + +private: + friend class input_iterator_core_access; + + // input iterator implementation + bool get() + { + typename cstring::iterator begin = m_src.begin(); + bool res = base::get( begin, m_src.end() ); + + m_src.assign( begin, m_src.end() ); + + return res; + } + + // Data members + cstring m_src; +}; + +typedef basic_string_token_iterator string_token_iterator; +typedef basic_string_token_iterator wstring_token_iterator; + +// ************************************************************************** // +// ************** range_token_iterator ************** // +// ************************************************************************** // + +template::type>, + typename ValueType = std::basic_string::type>, + typename Reference = ValueType const&> +class range_token_iterator +: public token_iterator_base, + typename iterator_value::type,CharCompare,ValueType,Reference> { + typedef basic_cstring cstring; + typedef token_iterator_base, + typename iterator_value::type,CharCompare,ValueType,Reference> base; +public: + explicit range_token_iterator() {} + explicit range_token_iterator( Iter begin, Iter end = Iter() ) + : m_begin( begin ), m_end( end ) + { + this->init(); + } + + template + range_token_iterator( Iter begin, Iter end, M1 const& m1 ) + : m_begin( begin ), m_end( end ) + { + this->use( m1 ); + + this->init(); + } + + template + range_token_iterator( Iter begin, Iter end, M1 const& m1, M2 const& m2 ) + : m_begin( begin ), m_end( end ) + { + this->use( m1 ); + this->use( m2 ); + + this->init(); + } + + template + range_token_iterator( Iter begin, Iter end, M1 const& m1, M2 const& m2, M3 const& m3 ) + : m_begin( begin ), m_end( end ) + { + this->use( m1 ); + this->use( m2 ); + this->use( m3 ); + + this->init(); + } + +private: + friend class input_iterator_core_access; + + // input iterator implementation + bool get() + { + return base::get( m_begin, m_end ); + } + + // Data members + Iter m_begin; + Iter m_end; +}; + +// ************************************************************************** // +// ************** make_range_token_iterator ************** // +// ************************************************************************** // + +template +inline range_token_iterator +make_range_token_iterator( Iter begin, Iter end = Iter() ) +{ + return range_token_iterator( begin, end ); +} + +//____________________________________________________________________________// + +template +inline range_token_iterator +make_range_token_iterator( Iter begin, Iter end, M1 const& m1 ) +{ + return range_token_iterator( begin, end, m1 ); +} + +//____________________________________________________________________________// + +template +inline range_token_iterator +make_range_token_iterator( Iter begin, Iter end, M1 const& m1, M2 const& m2 ) +{ + return range_token_iterator( begin, end, m1, m2 ); +} + +//____________________________________________________________________________// + +template +inline range_token_iterator +make_range_token_iterator( Iter begin, Iter end, M1 const& m1, M2 const& m2, M3 const& m3 ) +{ + return range_token_iterator( begin, end, m1, m2, m3 ); +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +// *************************************************************************** +// Revision History : +// +// $Log$ +// Revision 1.1 2004/06/05 11:03:12 rogeeff +// input_iterator_adaptor simplified +// token_iterator added +// +// *************************************************************************** + +#endif // BOOST_TOKEN_ITERATOR_HPP +