1 // (C) Copyright Gennadiy Rozental 2001.
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)
6 // See http://www.boost.org/libs/test for the library home page.
10 // Version : $Revision$
12 // Description : token iterator for string and range tokenization
13 // ***************************************************************************
15 #ifndef BOOST_TEST_UTILS_TOKEN_ITERATOR_HPP
16 #define BOOST_TEST_UTILS_TOKEN_ITERATOR_HPP
19 #include <boost/config.hpp>
20 #include <boost/detail/workaround.hpp>
22 #include <boost/iterator/iterator_categories.hpp>
23 #include <boost/iterator/iterator_traits.hpp>
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>
34 #include <boost/test/detail/suppress_warnings.hpp>
36 //____________________________________________________________________________//
38 #ifdef BOOST_NO_STDC_NAMESPACE
39 namespace std{ using ::ispunct; using ::isspace; }
46 // ************************************************************************** //
47 // ************** ti_delimeter_type ************** //
48 // ************************************************************************** //
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
59 // ************************************************************************** //
60 // ************** default_char_compare ************** //
61 // ************************************************************************** //
63 template<typename CharT>
64 class default_char_compare {
66 bool operator()( CharT c1, CharT c2 )
68 #ifdef BOOST_CLASSIC_IOSTREAMS
69 return std::string_char_traits<CharT>::eq( c1, c2 );
71 return std::char_traits<CharT>::eq( c1, c2 );
76 // ************************************************************************** //
77 // ************** delim_policy ************** //
78 // ************************************************************************** //
80 template<typename CharT,typename CharCompare>
82 typedef basic_cstring<CharT const> cstring;
85 explicit delim_policy( ti_delimeter_type type_ = dt_char, cstring delimeters_ = cstring() )
88 set_delimeters( delimeters_ );
91 void set_delimeters( ti_delimeter_type type_ ) { m_type = type_; }
92 void set_delimeters( cstring delimeters_ )
94 m_delimeters = delimeters_;
96 if( !m_delimeters.is_empty() )
99 void set_delimeters( nfp::nil ) {}
100 bool operator()( CharT c )
104 BOOST_TEST_FOREACH( CharT, delim, m_delimeters )
105 if( CharCompare()( delim, c ) )
111 return (std::ispunct)( c ) != 0;
113 return (std::isspace)( c ) != 0;
123 cstring m_delimeters;
124 ti_delimeter_type m_type;
127 // ************************************************************************** //
128 // ************** token_assigner ************** //
129 // ************************************************************************** //
131 template<typename TraversalTag>
132 struct token_assigner {
133 #if BOOST_WORKAROUND( BOOST_DINKUMWARE_STDLIB, < 306 )
134 template<typename Iterator, typename C, typename T>
135 static void assign( Iterator b, Iterator e, std::basic_string<C,T>& t )
136 { for( ; b != e; ++b ) t += *b; }
138 template<typename Iterator, typename C>
139 static void assign( Iterator b, Iterator e, basic_cstring<C>& t ) { t.assign( b, e ); }
141 template<typename Iterator, typename Token>
142 static void assign( Iterator b, Iterator e, Token& t ) { t.assign( b, e ); }
144 template<typename Iterator, typename Token>
145 static void append_move( Iterator& b, Token& ) { ++b; }
148 //____________________________________________________________________________//
151 struct token_assigner<single_pass_traversal_tag> {
152 template<typename Iterator, typename Token>
153 static void assign( Iterator /*b*/, Iterator /*e*/, Token& /*t*/ ) {}
155 template<typename Iterator, typename Token>
156 static void append_move( Iterator& b, Token& t ) { t += *b; ++b; }
159 } // namespace ut_detail
161 // ************************************************************************** //
162 // ************** modifiers ************** //
163 // ************************************************************************** //
166 nfp::keyword<struct dropped_delimeters_t > dropped_delimeters;
167 nfp::keyword<struct kept_delimeters_t > kept_delimeters;
168 nfp::typed_keyword<bool,struct keep_empty_tokens_t > keep_empty_tokens;
169 nfp::typed_keyword<std::size_t,struct max_tokens_t > max_tokens;
172 // ************************************************************************** //
173 // ************** token_iterator_base ************** //
174 // ************************************************************************** //
176 template<typename Derived,
178 typename CharCompare = ut_detail::default_char_compare<CharT>,
179 typename ValueType = basic_cstring<CharT const>,
180 typename Reference = basic_cstring<CharT const>,
181 typename Traversal = forward_traversal_tag>
182 class token_iterator_base
183 : public input_iterator_facade<Derived,ValueType,Reference,Traversal> {
184 typedef basic_cstring<CharT const> cstring;
185 typedef ut_detail::delim_policy<CharT,CharCompare> delim_policy;
186 typedef input_iterator_facade<Derived,ValueType,Reference,Traversal> base;
190 explicit token_iterator_base()
191 : m_is_dropped( dt_isspace )
192 , m_is_kept( dt_ispunct )
193 , m_keep_empty_tokens( false )
194 , m_tokens_left( static_cast<std::size_t>(-1) )
195 , m_token_produced( false )
199 template<typename Modifier>
201 apply_modifier( Modifier const& m )
203 if( m.has( dropped_delimeters ) )
204 m_is_dropped.set_delimeters( m[dropped_delimeters] );
206 if( m.has( kept_delimeters ) )
207 m_is_kept.set_delimeters( m[kept_delimeters] );
209 if( m.has( keep_empty_tokens ) )
210 m_keep_empty_tokens = true;
212 nfp::opt_assign( m_tokens_left, m, max_tokens );
215 template<typename Iter>
216 bool get( Iter& begin, Iter end )
218 typedef ut_detail::token_assigner<BOOST_DEDUCED_TYPENAME iterator_traversal<Iter>::type> Assigner;
221 this->m_value.clear();
223 if( !m_keep_empty_tokens ) {
224 while( begin != end && m_is_dropped( *begin ) )
232 if( m_tokens_left == 1 )
233 while( begin != end )
234 Assigner::append_move( begin, this->m_value );
235 else if( m_is_kept( *begin ) )
236 Assigner::append_move( begin, this->m_value );
238 while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) )
239 Assigner::append_move( begin, this->m_value );
243 else { // m_keep_empty_tokens is true
247 if( m_token_produced )
250 m_token_produced = true;
252 if( m_is_kept( *begin ) ) {
253 if( m_token_produced )
254 Assigner::append_move( begin, this->m_value );
256 m_token_produced = !m_token_produced;
258 else if( !m_token_produced && m_is_dropped( *begin ) )
259 m_token_produced = true;
261 if( m_is_dropped( *begin ) )
262 check_point = ++begin;
264 while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) )
265 Assigner::append_move( begin, this->m_value );
267 m_token_produced = true;
271 Assigner::assign( check_point, begin, this->m_value );
278 delim_policy m_is_dropped;
279 delim_policy m_is_kept;
280 bool m_keep_empty_tokens;
281 std::size_t m_tokens_left;
282 bool m_token_produced;
285 // ************************************************************************** //
286 // ************** basic_string_token_iterator ************** //
287 // ************************************************************************** //
289 template<typename CharT,
290 typename CharCompare = ut_detail::default_char_compare<CharT> >
291 class basic_string_token_iterator
292 : public token_iterator_base<basic_string_token_iterator<CharT,CharCompare>,CharT,CharCompare> {
293 typedef basic_cstring<CharT const> cstring;
294 typedef token_iterator_base<basic_string_token_iterator<CharT,CharCompare>,CharT,CharCompare> base;
296 explicit basic_string_token_iterator() {}
297 explicit basic_string_token_iterator( cstring src )
303 // warning: making the constructor accept anything else than a cstring should
304 // ensure that no temporary object is created during string creation (previous
305 // definition was "template<typename Src, typename Modifier> basic_string_token_iterator( Src src ..."
306 // which may create a temporary string copy when called with an std::string.
307 template<typename Modifier>
308 basic_string_token_iterator( cstring src, Modifier const& m )
311 this->apply_modifier( m );
317 friend class input_iterator_core_access;
319 // input iterator implementation
322 typename cstring::iterator begin = m_src.begin();
323 bool res = base::get( begin, m_src.end() );
325 m_src.assign( begin, m_src.end() );
334 typedef basic_string_token_iterator<char> string_token_iterator;
335 typedef basic_string_token_iterator<wchar_t> wstring_token_iterator;
337 // ************************************************************************** //
338 // ************** range_token_iterator ************** //
339 // ************************************************************************** //
341 template<typename Iter,
342 typename CharCompare = ut_detail::default_char_compare<BOOST_DEDUCED_TYPENAME iterator_value<Iter>::type>,
343 typename ValueType = std::basic_string<BOOST_DEDUCED_TYPENAME iterator_value<Iter>::type>,
344 typename Reference = ValueType const&>
345 class range_token_iterator
346 : public token_iterator_base<range_token_iterator<Iter,CharCompare,ValueType,Reference>,
347 typename iterator_value<Iter>::type,CharCompare,ValueType,Reference> {
348 typedef basic_cstring<typename ValueType::value_type> cstring;
349 typedef token_iterator_base<range_token_iterator<Iter,CharCompare,ValueType,Reference>,
350 typename iterator_value<Iter>::type,CharCompare,ValueType,Reference> base;
352 explicit range_token_iterator() {}
353 explicit range_token_iterator( Iter begin, Iter end = Iter() )
354 : m_begin( begin ), m_end( end )
358 range_token_iterator( range_token_iterator const& rhs )
361 if( this->m_valid ) {
362 m_begin = rhs.m_begin;
367 template<typename Modifier>
368 range_token_iterator( Iter begin, Iter end, Modifier const& m )
369 : m_begin( begin ), m_end( end )
371 this->apply_modifier( m );
377 friend class input_iterator_core_access;
379 // input iterator implementation
382 return base::get( m_begin, m_end );
390 // ************************************************************************** //
391 // ************** make_range_token_iterator ************** //
392 // ************************************************************************** //
394 template<typename Iter>
395 inline range_token_iterator<Iter>
396 make_range_token_iterator( Iter begin, Iter end = Iter() )
398 return range_token_iterator<Iter>( begin, end );
401 //____________________________________________________________________________//
403 template<typename Iter,typename Modifier>
404 inline range_token_iterator<Iter>
405 make_range_token_iterator( Iter begin, Iter end, Modifier const& m )
407 return range_token_iterator<Iter>( begin, end, m );
410 //____________________________________________________________________________//
413 } // namespace unit_test
416 //____________________________________________________________________________//
418 #include <boost/test/detail/enable_warnings.hpp>
420 #endif // BOOST_TEST_UTILS_TOKEN_ITERATOR_HPP