Home | History | Annotate | Download | only in iterator
      1 //  (C) Copyright Gennadiy Rozental 2004-2008.
      2 //  Distributed under the Boost Software License, Version 1.0.
      3 //  (See accompanying file LICENSE_1_0.txt or copy at
      4 //  http://www.boost.org/LICENSE_1_0.txt)
      5 
      6 //  See http://www.boost.org/libs/test for the library home page.
      7 //
      8 //  File        : $RCSfile$
      9 //
     10 //  Version     : $Revision: 54633 $
     11 //
     12 //  Description : token iterator for string and range tokenization
     13 // ***************************************************************************
     14 
     15 #ifndef BOOST_TOKEN_ITERATOR_HPP_071894GER
     16 #define BOOST_TOKEN_ITERATOR_HPP_071894GER
     17 
     18 // Boost
     19 #include <boost/config.hpp>
     20 #include <boost/detail/workaround.hpp>
     21 
     22 #include <boost/iterator/iterator_categories.hpp>
     23 #include <boost/iterator/iterator_traits.hpp>
     24 
     25 #include <boost/test/utils/iterator/input_iterator_facade.hpp>
     26 #include <boost/test/utils/basic_cstring/basic_cstring.hpp>
     27 #include <boost/test/utils/named_params.hpp>
     28 #include <boost/test/utils/foreach.hpp>
     29 
     30 // STL
     31 #include <iosfwd>
     32 #include <cctype>
     33 
     34 #include <boost/test/detail/suppress_warnings.hpp>
     35 
     36 //____________________________________________________________________________//
     37 
     38 #ifdef BOOST_NO_STDC_NAMESPACE
     39 namespace std{ using ::ispunct; using ::isspace; }
     40 #endif
     41 
     42 namespace boost {
     43 
     44 namespace unit_test {
     45 
     46 // ************************************************************************** //
     47 // **************               ti_delimeter_type              ************** //
     48 // ************************************************************************** //
     49 
     50 enum ti_delimeter_type {
     51     dt_char,        // character is delimeter if it among explicit list of some characters
     52     dt_ispunct,     // character is delimeter if it satisfies ispunct functor
     53     dt_isspace,     // character is delimeter if it satisfies isspace functor
     54     dt_none         // no character is delimeter
     55 };
     56 
     57 namespace ut_detail {
     58 
     59 // ************************************************************************** //
     60 // **************             default_char_compare             ************** //
     61 // ************************************************************************** //
     62 
     63 template<typename CharT>
     64 class default_char_compare {
     65 public:
     66     bool operator()( CharT c1, CharT c2 )
     67     {
     68 #ifdef BOOST_CLASSIC_IOSTREAMS
     69         return std::string_char_traits<CharT>::eq( c1, c2 );
     70 #else
     71         return std::char_traits<CharT>::eq( c1, c2 );
     72 #endif
     73     }
     74 };
     75 
     76 // ************************************************************************** //
     77 // **************                 delim_policy                 ************** //
     78 // ************************************************************************** //
     79 
     80 template<typename CharT,typename CharCompare>
     81 class delim_policy {
     82     typedef basic_cstring<CharT const> cstring;
     83 public:
     84     // Constructor
     85     explicit    delim_policy( ti_delimeter_type t = dt_char, cstring d = cstring() )
     86     : m_type( t )
     87     {
     88         set_delimeters( d );
     89     }
     90 
     91     void        set_delimeters( ti_delimeter_type t ) { m_type = t; }
     92     template<typename Src>
     93     void        set_delimeters( Src d )
     94     {
     95         nfp::optionally_assign( m_delimeters, d );
     96 
     97         if( !m_delimeters.is_empty() )
     98             m_type = dt_char;
     99     }
    100 
    101     bool        operator()( CharT c )
    102     {
    103         switch( m_type ) {
    104         case dt_char: {
    105             BOOST_TEST_FOREACH( CharT, delim, m_delimeters )
    106                 if( CharCompare()( delim, c ) )
    107                     return true;
    108 
    109             return false;
    110         }
    111         case dt_ispunct:
    112             return (std::ispunct)( c ) != 0;
    113         case dt_isspace:
    114             return (std::isspace)( c ) != 0;
    115         case dt_none:
    116             return false;
    117         }
    118 
    119         return false;
    120     }
    121 
    122 private:
    123     // Data members
    124     cstring             m_delimeters;
    125     ti_delimeter_type   m_type;
    126 };
    127 
    128 // ************************************************************************** //
    129 // **************                 token_assigner               ************** //
    130 // ************************************************************************** //
    131 
    132 template<typename TraversalTag>
    133 struct token_assigner {
    134 #if BOOST_WORKAROUND( BOOST_DINKUMWARE_STDLIB, < 306 )
    135     template<typename Iterator, typename C, typename T>
    136     static void assign( Iterator b, Iterator e, std::basic_string<C,T>& t )
    137     { for( ; b != e; ++b ) t += *b; }
    138 
    139     template<typename Iterator, typename C>
    140     static void assign( Iterator b, Iterator e, basic_cstring<C>& t )  { t.assign( b, e ); }
    141 #else
    142     template<typename Iterator, typename Token>
    143     static void assign( Iterator b, Iterator e, Token& t )  { t.assign( b, e ); }
    144 #endif
    145     template<typename Iterator, typename Token>
    146     static void append_move( Iterator& b, Token& )          { ++b; }
    147 };
    148 
    149 //____________________________________________________________________________//
    150 
    151 template<>
    152 struct token_assigner<single_pass_traversal_tag> {
    153     template<typename Iterator, typename Token>
    154     static void assign( Iterator b, Iterator e, Token& t )  {}
    155 
    156     template<typename Iterator, typename Token>
    157     static void append_move( Iterator& b, Token& t )        { t += *b; ++b; }
    158 };
    159 
    160 } // namespace ut_detail
    161 
    162 // ************************************************************************** //
    163 // **************                  modifiers                   ************** //
    164 // ************************************************************************** //
    165 
    166 namespace {
    167 nfp::keyword<struct dropped_delimeters_t >           dropped_delimeters;
    168 nfp::keyword<struct kept_delimeters_t >              kept_delimeters;
    169 nfp::typed_keyword<bool,struct keep_empty_tokens_t > keep_empty_tokens;
    170 nfp::typed_keyword<std::size_t,struct max_tokens_t > max_tokens;
    171 }
    172 
    173 // ************************************************************************** //
    174 // **************             token_iterator_base              ************** //
    175 // ************************************************************************** //
    176 
    177 template<typename Derived,
    178          typename CharT,
    179          typename CharCompare   = ut_detail::default_char_compare<CharT>,
    180          typename ValueType     = basic_cstring<CharT const>,
    181          typename Reference     = basic_cstring<CharT const>,
    182          typename Traversal     = forward_traversal_tag>
    183 class token_iterator_base
    184 : public input_iterator_facade<Derived,ValueType,Reference,Traversal> {
    185     typedef basic_cstring<CharT const>                                      cstring;
    186     typedef ut_detail::delim_policy<CharT,CharCompare>                      delim_policy;
    187     typedef input_iterator_facade<Derived,ValueType,Reference,Traversal>    base;
    188 
    189 protected:
    190     // Constructor
    191     explicit    token_iterator_base()
    192     : m_is_dropped( dt_isspace )
    193     , m_is_kept( dt_ispunct )
    194     , m_keep_empty_tokens( false )
    195     , m_tokens_left( static_cast<std::size_t>(-1) )
    196     , m_token_produced( false )
    197     {
    198     }
    199 
    200     template<typename Modifier>
    201     void
    202     apply_modifier( Modifier const& m )
    203     {
    204         if( m.has( dropped_delimeters ) )
    205             m_is_dropped.set_delimeters( m[dropped_delimeters] );
    206 
    207         if( m.has( kept_delimeters ) )
    208             m_is_kept.set_delimeters( m[kept_delimeters] );
    209 
    210         if( m.has( keep_empty_tokens ) )
    211             m_keep_empty_tokens = true;
    212 
    213         nfp::optionally_assign( m_tokens_left, m, max_tokens );
    214     }
    215 
    216     template<typename Iter>
    217     bool                    get( Iter& begin, Iter end )
    218     {
    219         typedef ut_detail::token_assigner<BOOST_DEDUCED_TYPENAME iterator_traversal<Iter>::type> Assigner;
    220         Iter check_point;
    221 
    222         this->m_value.clear();
    223 
    224         if( !m_keep_empty_tokens ) {
    225             while( begin != end && m_is_dropped( *begin ) )
    226                 ++begin;
    227 
    228             if( begin == end )
    229                 return false;
    230 
    231             check_point = begin;
    232 
    233             if( m_tokens_left == 1 )
    234                 while( begin != end )
    235                     Assigner::append_move( begin, this->m_value );
    236             else if( m_is_kept( *begin ) )
    237                 Assigner::append_move( begin, this->m_value );
    238             else
    239                 while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) )
    240                     Assigner::append_move( begin, this->m_value );
    241 
    242             --m_tokens_left;
    243         }
    244         else { // m_keep_empty_tokens is true
    245             check_point = begin;
    246 
    247             if( begin == end ) {
    248                 if( m_token_produced )
    249                     return false;
    250 
    251                 m_token_produced = true;
    252             }
    253             if( m_is_kept( *begin ) ) {
    254                 if( m_token_produced )
    255                     Assigner::append_move( begin, this->m_value );
    256 
    257                 m_token_produced = !m_token_produced;
    258             }
    259             else if( !m_token_produced && m_is_dropped( *begin ) )
    260                 m_token_produced = true;
    261             else {
    262                 if( m_is_dropped( *begin ) )
    263                     check_point = ++begin;
    264 
    265                 while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) )
    266                     Assigner::append_move( begin, this->m_value );
    267 
    268                 m_token_produced = true;
    269             }
    270         }
    271 
    272         Assigner::assign( check_point, begin, this->m_value );
    273 
    274         return true;
    275     }
    276 
    277 private:
    278     // Data members
    279     delim_policy            m_is_dropped;
    280     delim_policy            m_is_kept;
    281     bool                    m_keep_empty_tokens;
    282     std::size_t             m_tokens_left;
    283     bool                    m_token_produced;
    284 };
    285 
    286 // ************************************************************************** //
    287 // **************          basic_string_token_iterator         ************** //
    288 // ************************************************************************** //
    289 
    290 template<typename CharT,
    291          typename CharCompare = ut_detail::default_char_compare<CharT> >
    292 class basic_string_token_iterator
    293 : public token_iterator_base<basic_string_token_iterator<CharT,CharCompare>,CharT,CharCompare> {
    294     typedef basic_cstring<CharT const> cstring;
    295     typedef token_iterator_base<basic_string_token_iterator<CharT,CharCompare>,CharT,CharCompare> base;
    296 public:
    297     explicit    basic_string_token_iterator() {}
    298     explicit    basic_string_token_iterator( cstring src )
    299     : m_src( src )
    300     {
    301         this->init();
    302     }
    303 
    304     template<typename Src, typename Modifier>
    305     basic_string_token_iterator( Src src, Modifier const& m )
    306     : m_src( src )
    307     {
    308         this->apply_modifier( m );
    309 
    310         this->init();
    311     }
    312 
    313 private:
    314     friend class input_iterator_core_access;
    315 
    316     // input iterator implementation
    317     bool        get()
    318     {
    319         typename cstring::iterator begin = m_src.begin();
    320         bool res = base::get( begin, m_src.end() );
    321 
    322         m_src.assign( begin, m_src.end() );
    323 
    324         return res;
    325     }
    326 
    327     // Data members
    328     cstring     m_src;
    329 };
    330 
    331 typedef basic_string_token_iterator<char>       string_token_iterator;
    332 typedef basic_string_token_iterator<wchar_t>    wstring_token_iterator;
    333 
    334 // ************************************************************************** //
    335 // **************              range_token_iterator            ************** //
    336 // ************************************************************************** //
    337 
    338 template<typename Iter,
    339          typename CharCompare = ut_detail::default_char_compare<BOOST_DEDUCED_TYPENAME iterator_value<Iter>::type>,
    340          typename ValueType   = std::basic_string<BOOST_DEDUCED_TYPENAME iterator_value<Iter>::type>,
    341          typename Reference   = ValueType const&>
    342 class range_token_iterator
    343 : public token_iterator_base<range_token_iterator<Iter,CharCompare,ValueType,Reference>,
    344                              typename iterator_value<Iter>::type,CharCompare,ValueType,Reference> {
    345     typedef basic_cstring<typename ValueType::value_type> cstring;
    346     typedef token_iterator_base<range_token_iterator<Iter,CharCompare,ValueType,Reference>,
    347                                 typename iterator_value<Iter>::type,CharCompare,ValueType,Reference> base;
    348 public:
    349     explicit    range_token_iterator() {}
    350     explicit    range_token_iterator( Iter begin, Iter end = Iter() )
    351     : m_begin( begin ), m_end( end )
    352     {
    353         this->init();
    354     }
    355     range_token_iterator( range_token_iterator const& rhs )
    356     : base( rhs )
    357     {
    358         if( this->m_valid ) {
    359             m_begin = rhs.m_begin;
    360             m_end   = rhs.m_end;
    361         }
    362     }
    363 
    364     template<typename Modifier>
    365     range_token_iterator( Iter begin, Iter end, Modifier const& m )
    366     : m_begin( begin ), m_end( end )
    367     {
    368         this->apply_modifier( m );
    369 
    370         this->init();
    371     }
    372 
    373 private:
    374     friend class input_iterator_core_access;
    375 
    376     // input iterator implementation
    377     bool        get()
    378     {
    379         return base::get( m_begin, m_end );
    380     }
    381 
    382     // Data members
    383     Iter m_begin;
    384     Iter m_end;
    385 };
    386 
    387 // ************************************************************************** //
    388 // **************            make_range_token_iterator         ************** //
    389 // ************************************************************************** //
    390 
    391 template<typename Iter>
    392 inline range_token_iterator<Iter>
    393 make_range_token_iterator( Iter begin, Iter end = Iter() )
    394 {
    395     return range_token_iterator<Iter>( begin, end );
    396 }
    397 
    398 //____________________________________________________________________________//
    399 
    400 template<typename Iter,typename Modifier>
    401 inline range_token_iterator<Iter>
    402 make_range_token_iterator( Iter begin, Iter end, Modifier const& m )
    403 {
    404     return range_token_iterator<Iter>( begin, end, m );
    405 }
    406 
    407 //____________________________________________________________________________//
    408 
    409 } // namespace unit_test
    410 
    411 } // namespace boost
    412 
    413 //____________________________________________________________________________//
    414 
    415 #include <boost/test/detail/enable_warnings.hpp>
    416 
    417 #endif // BOOST_TOKEN_ITERATOR_HPP_071894GER
    418 
    419