422 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			422 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | //  (C) Copyright Gennadiy Rozental 2001. | ||
|  | //  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 : token iterator for string and range tokenization | ||
|  | // *************************************************************************** | ||
|  | 
 | ||
|  | #ifndef BOOST_TEST_UTILS_TOKEN_ITERATOR_HPP | ||
|  | #define BOOST_TEST_UTILS_TOKEN_ITERATOR_HPP | ||
|  | 
 | ||
|  | // Boost | ||
|  | #include <boost/config.hpp> | ||
|  | #include <boost/detail/workaround.hpp> | ||
|  | 
 | ||
|  | #include <boost/iterator/iterator_categories.hpp> | ||
|  | #include <boost/iterator/iterator_traits.hpp> | ||
|  | 
 | ||
|  | #include <boost/test/utils/iterator/input_iterator_facade.hpp> | ||
|  | #include <boost/test/utils/basic_cstring/basic_cstring.hpp> | ||
|  | #include <boost/test/utils/named_params.hpp> | ||
|  | #include <boost/test/utils/foreach.hpp> | ||
|  | 
 | ||
|  | // STL | ||
|  | #include <iosfwd> | ||
|  | #include <cctype> | ||
|  | 
 | ||
|  | #include <boost/test/detail/suppress_warnings.hpp> | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #ifdef BOOST_NO_STDC_NAMESPACE | ||
|  | namespace std{ using ::ispunct; using ::isspace; } | ||
|  | #endif | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | namespace unit_test { | ||
|  | namespace utils { | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************               ti_delimeter_type              ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | enum ti_delimeter_type { | ||
|  |     dt_char,        // character is delimeter if it among explicit list of some characters | ||
|  |     dt_ispunct,     // character is delimeter if it satisfies ispunct functor | ||
|  |     dt_isspace,     // character is delimeter if it satisfies isspace functor | ||
|  |     dt_none         // no character is delimeter | ||
|  | }; | ||
|  | 
 | ||
|  | namespace ut_detail { | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************             default_char_compare             ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | template<typename CharT> | ||
|  | class default_char_compare { | ||
|  | public: | ||
|  |     bool operator()( CharT c1, CharT c2 ) | ||
|  |     { | ||
|  | #ifdef BOOST_CLASSIC_IOSTREAMS | ||
|  |         return std::string_char_traits<CharT>::eq( c1, c2 ); | ||
|  | #else | ||
|  |         return std::char_traits<CharT>::eq( c1, c2 ); | ||
|  | #endif | ||
|  |     } | ||
|  | }; | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************                 delim_policy                 ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | template<typename CharT,typename CharCompare> | ||
|  | class delim_policy { | ||
|  |     typedef basic_cstring<CharT const> cstring; | ||
|  | public: | ||
|  |     // Constructor | ||
|  |     explicit    delim_policy( ti_delimeter_type type_ = dt_char, cstring delimeters_ = cstring() ) | ||
|  |     : m_type( type_ ) | ||
|  |     { | ||
|  |         set_delimeters( delimeters_ ); | ||
|  |     } | ||
|  | 
 | ||
|  |     void        set_delimeters( ti_delimeter_type type_ ) { m_type = type_; } | ||
|  |     void        set_delimeters( cstring delimeters_ ) | ||
|  |     { | ||
|  |         m_delimeters = delimeters_; | ||
|  | 
 | ||
|  |         if( !m_delimeters.is_empty() ) | ||
|  |             m_type = dt_char; | ||
|  |     } | ||
|  |     void        set_delimeters( nfp::nil ) {} | ||
|  |     bool        operator()( CharT c ) | ||
|  |     { | ||
|  |         switch( m_type ) { | ||
|  |         case dt_char: { | ||
|  |             BOOST_TEST_FOREACH( CharT, delim, m_delimeters ) | ||
|  |                 if( CharCompare()( delim, c ) ) | ||
|  |                     return true; | ||
|  | 
 | ||
|  |             return false; | ||
|  |         } | ||
|  |         case dt_ispunct: | ||
|  |             return (std::ispunct)( c ) != 0; | ||
|  |         case dt_isspace: | ||
|  |             return (std::isspace)( c ) != 0; | ||
|  |         case dt_none: | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  | private: | ||
|  |     // Data members | ||
|  |     cstring             m_delimeters; | ||
|  |     ti_delimeter_type   m_type; | ||
|  | }; | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************                 token_assigner               ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | template<typename TraversalTag> | ||
|  | struct token_assigner { | ||
|  | #if BOOST_WORKAROUND( BOOST_DINKUMWARE_STDLIB, < 306 ) | ||
|  |     template<typename Iterator, typename C, typename T> | ||
|  |     static void assign( Iterator b, Iterator e, std::basic_string<C,T>& t ) | ||
|  |     { for( ; b != e; ++b ) t += *b; } | ||
|  | 
 | ||
|  |     template<typename Iterator, typename C> | ||
|  |     static void assign( Iterator b, Iterator e, basic_cstring<C>& t )  { t.assign( b, e ); } | ||
|  | #else | ||
|  |     template<typename Iterator, typename Token> | ||
|  |     static void assign( Iterator b, Iterator e, Token& t )  { t.assign( b, e ); } | ||
|  | #endif | ||
|  |     template<typename Iterator, typename Token> | ||
|  |     static void append_move( Iterator& b, Token& )          { ++b; } | ||
|  | }; | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | template<> | ||
|  | struct token_assigner<single_pass_traversal_tag> { | ||
|  |     template<typename Iterator, typename Token> | ||
|  |     static void assign( Iterator /*b*/, Iterator /*e*/, Token& /*t*/ )  {} | ||
|  | 
 | ||
|  |     template<typename Iterator, typename Token> | ||
|  |     static void append_move( Iterator& b, Token& t )        { t += *b; ++b; } | ||
|  | }; | ||
|  | 
 | ||
|  | } // namespace ut_detail | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************                  modifiers                   ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | namespace { | ||
|  | nfp::keyword<struct dropped_delimeters_t >           dropped_delimeters; | ||
|  | nfp::keyword<struct kept_delimeters_t >              kept_delimeters; | ||
|  | nfp::typed_keyword<bool,struct keep_empty_tokens_t > keep_empty_tokens; | ||
|  | nfp::typed_keyword<std::size_t,struct max_tokens_t > max_tokens; | ||
|  | } | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************             token_iterator_base              ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | template<typename Derived, | ||
|  |          typename CharT, | ||
|  |          typename CharCompare   = ut_detail::default_char_compare<CharT>, | ||
|  |          typename ValueType     = basic_cstring<CharT const>, | ||
|  |          typename Reference     = basic_cstring<CharT const>, | ||
|  |          typename Traversal     = forward_traversal_tag> | ||
|  | class token_iterator_base | ||
|  | : public input_iterator_facade<Derived,ValueType,Reference,Traversal> { | ||
|  |     typedef basic_cstring<CharT const>                                      cstring; | ||
|  |     typedef ut_detail::delim_policy<CharT,CharCompare>                      delim_policy; | ||
|  |     typedef input_iterator_facade<Derived,ValueType,Reference,Traversal>    base; | ||
|  | 
 | ||
|  | protected: | ||
|  |     // Constructor | ||
|  |     explicit    token_iterator_base() | ||
|  |     : m_is_dropped( dt_isspace ) | ||
|  |     , m_is_kept( dt_ispunct ) | ||
|  |     , m_keep_empty_tokens( false ) | ||
|  |     , m_tokens_left( static_cast<std::size_t>(-1) ) | ||
|  |     , m_token_produced( false ) | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     template<typename Modifier> | ||
|  |     void | ||
|  |     apply_modifier( Modifier const& m ) | ||
|  |     { | ||
|  |         if( m.has( dropped_delimeters ) ) | ||
|  |             m_is_dropped.set_delimeters( m[dropped_delimeters] ); | ||
|  | 
 | ||
|  |         if( m.has( kept_delimeters ) ) | ||
|  |             m_is_kept.set_delimeters( m[kept_delimeters] ); | ||
|  | 
 | ||
|  |         if( m.has( keep_empty_tokens ) ) | ||
|  |             m_keep_empty_tokens = true; | ||
|  | 
 | ||
|  |         nfp::opt_assign( m_tokens_left, m, max_tokens ); | ||
|  |     } | ||
|  | 
 | ||
|  |     template<typename Iter> | ||
|  |     bool                    get( Iter& begin, Iter end ) | ||
|  |     { | ||
|  |         typedef ut_detail::token_assigner<BOOST_DEDUCED_TYPENAME iterator_traversal<Iter>::type> Assigner; | ||
|  |         Iter check_point; | ||
|  | 
 | ||
|  |         this->m_value.clear(); | ||
|  | 
 | ||
|  |         if( !m_keep_empty_tokens ) { | ||
|  |             while( begin != end && m_is_dropped( *begin ) ) | ||
|  |                 ++begin; | ||
|  | 
 | ||
|  |             if( begin == end ) | ||
|  |                 return false; | ||
|  | 
 | ||
|  |             check_point = begin; | ||
|  | 
 | ||
|  |             if( m_tokens_left == 1 ) | ||
|  |                 while( begin != end ) | ||
|  |                     Assigner::append_move( begin, this->m_value ); | ||
|  |             else if( m_is_kept( *begin ) ) | ||
|  |                 Assigner::append_move( begin, this->m_value ); | ||
|  |             else | ||
|  |                 while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) ) | ||
|  |                     Assigner::append_move( begin, this->m_value ); | ||
|  | 
 | ||
|  |             --m_tokens_left; | ||
|  |         } | ||
|  |         else { // m_keep_empty_tokens is true | ||
|  |             check_point = begin; | ||
|  | 
 | ||
|  |             if( begin == end ) { | ||
|  |                 if( m_token_produced ) | ||
|  |                     return false; | ||
|  | 
 | ||
|  |                 m_token_produced = true; | ||
|  |             } | ||
|  |             if( m_is_kept( *begin ) ) { | ||
|  |                 if( m_token_produced ) | ||
|  |                     Assigner::append_move( begin, this->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 ) ) | ||
|  |                     check_point = ++begin; | ||
|  | 
 | ||
|  |                 while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) ) | ||
|  |                     Assigner::append_move( begin, this->m_value ); | ||
|  | 
 | ||
|  |                 m_token_produced = true; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         Assigner::assign( check_point, begin, this->m_value ); | ||
|  | 
 | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  | private: | ||
|  |     // Data members | ||
|  |     delim_policy            m_is_dropped; | ||
|  |     delim_policy            m_is_kept; | ||
|  |     bool                    m_keep_empty_tokens; | ||
|  |     std::size_t             m_tokens_left; | ||
|  |     bool                    m_token_produced; | ||
|  | }; | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************          basic_string_token_iterator         ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | template<typename CharT, | ||
|  |          typename CharCompare = ut_detail::default_char_compare<CharT> > | ||
|  | class basic_string_token_iterator | ||
|  | : public token_iterator_base<basic_string_token_iterator<CharT,CharCompare>,CharT,CharCompare> { | ||
|  |     typedef basic_cstring<CharT const> cstring; | ||
|  |     typedef token_iterator_base<basic_string_token_iterator<CharT,CharCompare>,CharT,CharCompare> base; | ||
|  | public: | ||
|  |     explicit    basic_string_token_iterator() {} | ||
|  |     explicit    basic_string_token_iterator( cstring src ) | ||
|  |     : m_src( src ) | ||
|  |     { | ||
|  |         this->init(); | ||
|  |     } | ||
|  | 
 | ||
|  |     // warning: making the constructor accept anything else than a cstring should | ||
|  |     // ensure that no temporary object is created during string creation (previous | ||
|  |     // definition was "template<typename Src, typename Modifier> basic_string_token_iterator( Src src ..." | ||
|  |     // which may create a temporary string copy when called with an std::string. | ||
|  |     template<typename Modifier> | ||
|  |     basic_string_token_iterator( cstring src, Modifier const& m ) | ||
|  |     : m_src( src ) | ||
|  |     { | ||
|  |         this->apply_modifier( m ); | ||
|  | 
 | ||
|  |         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<char>       string_token_iterator; | ||
|  | typedef basic_string_token_iterator<wchar_t>    wstring_token_iterator; | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************              range_token_iterator            ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | template<typename Iter, | ||
|  |          typename CharCompare = ut_detail::default_char_compare<BOOST_DEDUCED_TYPENAME iterator_value<Iter>::type>, | ||
|  |          typename ValueType   = std::basic_string<BOOST_DEDUCED_TYPENAME iterator_value<Iter>::type>, | ||
|  |          typename Reference   = ValueType const&> | ||
|  | class range_token_iterator | ||
|  | : public token_iterator_base<range_token_iterator<Iter,CharCompare,ValueType,Reference>, | ||
|  |                              typename iterator_value<Iter>::type,CharCompare,ValueType,Reference> { | ||
|  |     typedef basic_cstring<typename ValueType::value_type> cstring; | ||
|  |     typedef token_iterator_base<range_token_iterator<Iter,CharCompare,ValueType,Reference>, | ||
|  |                                 typename iterator_value<Iter>::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(); | ||
|  |     } | ||
|  |     range_token_iterator( range_token_iterator const& rhs ) | ||
|  |     : base( rhs ) | ||
|  |     { | ||
|  |         if( this->m_valid ) { | ||
|  |             m_begin = rhs.m_begin; | ||
|  |             m_end   = rhs.m_end; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     template<typename Modifier> | ||
|  |     range_token_iterator( Iter begin, Iter end, Modifier const& m ) | ||
|  |     : m_begin( begin ), m_end( end ) | ||
|  |     { | ||
|  |         this->apply_modifier( m ); | ||
|  | 
 | ||
|  |         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<typename Iter> | ||
|  | inline range_token_iterator<Iter> | ||
|  | make_range_token_iterator( Iter begin, Iter end = Iter() ) | ||
|  | { | ||
|  |     return range_token_iterator<Iter>( begin, end ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | template<typename Iter,typename Modifier> | ||
|  | inline range_token_iterator<Iter> | ||
|  | make_range_token_iterator( Iter begin, Iter end, Modifier const& m ) | ||
|  | { | ||
|  |     return range_token_iterator<Iter>( begin, end, m ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | } // namespace utils | ||
|  | } // namespace unit_test | ||
|  | } // namespace boost | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #include <boost/test/detail/enable_warnings.hpp> | ||
|  | 
 | ||
|  | #endif // BOOST_TEST_UTILS_TOKEN_ITERATOR_HPP | ||
|  | 
 |