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)
5
6// See http://www.boost.org/libs/test for the library home page.
7//
8// File : $RCSfile$
9//
10// Version : $Revision$
11//
12// Description : class basic_cstring wraps C string and provide std_string like
13// interface
14// ***************************************************************************
15
16#ifndef BOOST_TEST_UTILS_BASIC_CSTRING_HPP
17#define BOOST_TEST_UTILS_BASIC_CSTRING_HPP
18
19// Boost.Test
20#include <boost/test/utils/basic_cstring/basic_cstring_fwd.hpp>
21#include <boost/test/utils/basic_cstring/bcs_char_traits.hpp>
22
23// Boost
24#include <boost/type_traits/remove_cv.hpp>
25
26// STL
27#include <string>
28
29#include <boost/test/detail/suppress_warnings.hpp>
30
31//____________________________________________________________________________//
32
33namespace boost {
34
35namespace unit_test {
36
37// ************************************************************************** //
38// ************** basic_cstring ************** //
39// ************************************************************************** //
40
41template<typename CharT>
42class basic_cstring {
43 typedef basic_cstring<CharT> self_type;
44public:
45 // Subtypes
46 typedef ut_detail::bcs_char_traits<CharT> traits_type;
47 typedef typename ut_detail::bcs_char_traits<CharT>::std_string std_string;
48
49 typedef CharT value_type;
50 typedef typename remove_cv<value_type>::type value_ret_type;
51 typedef value_type* pointer;
52 typedef value_type const* const_pointer;
53 typedef value_type& reference;
54 typedef const value_type& const_reference;
55 typedef std::size_t size_type;
56 typedef std::ptrdiff_t difference_type;
57
58 typedef value_type const* const_iterator;
59 typedef value_type* iterator;
60
61 // !! should also present reverse_iterator, const_reverse_iterator
62
63#if !BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
64 enum npos_type { npos = static_cast<size_type>(-1) };
65#else
66 // IBM/VisualAge version 6 is not able to handle enums larger than 4 bytes.
67 // But size_type is 8 bytes in 64bit mode.
68 static const size_type npos = -1 ;
69#endif
70
71 static pointer null_str();
72
73 // Constructors; default copy constructor is generated by compiler
74 basic_cstring();
75 basic_cstring( std_string const& s );
76 basic_cstring( pointer s );
77 template<typename LenType>
78 basic_cstring( pointer s, LenType len ) : m_begin( s ), m_end( m_begin + len ) {}
79 basic_cstring( pointer first, pointer last );
80
81 // data access methods
82 value_ret_type operator[]( size_type index ) const;
83 value_ret_type at( size_type index ) const;
84
85 // size operators
86 size_type size() const;
87 bool is_empty() const;
88 void clear();
89 void resize( size_type new_len );
90
91 // !! only for STL container conformance use is_empty instead
92 bool empty() const;
93
94 // Trimming
95 self_type& trim_right( size_type trim_size );
96 self_type& trim_left( size_type trim_size );
97 self_type& trim_right( iterator it );
98 self_type& trim_left( iterator it );
99#if !BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(800))
100 self_type& trim_left( self_type exclusions = self_type() ) ;
101 self_type& trim_right( self_type exclusions = self_type() ) ;
102 self_type& trim( self_type exclusions = self_type() ) ;
103#else
104 // VA C++/XL C++ v6 and v8 has in this case a problem with the default arguments.
105 self_type& trim_left( self_type exclusions );
106 self_type& trim_right( self_type exclusions );
107 self_type& trim( self_type exclusions );
108 self_type& trim_left() { return trim_left( self_type() ); }
109 self_type& trim_right() { return trim_right( self_type() ); }
110 self_type& trim() { return trim( self_type() ); }
111#endif
112
113 // Assignment operators
114 basic_cstring& operator=( self_type const& s );
115 basic_cstring& operator=( std_string const& s );
116 basic_cstring& operator=( pointer s );
117
118 template<typename CharT2>
119 basic_cstring& assign( basic_cstring<CharT2> const& s )
120 {
121 return *this = basic_cstring<CharT>( s.begin(), s.end() );
122 }
123 template<typename PosType, typename LenType>
124 basic_cstring& assign( self_type const& s, PosType pos, LenType len )
125 {
126 return *this = self_type( s.m_begin + pos, len );
127 }
128
129 basic_cstring& assign( std_string const& s );
130 template<typename PosType, typename LenType>
131 basic_cstring& assign( std_string const& s, PosType pos, LenType len )
132 {
133 return *this = self_type( s.c_str() + pos, len );
134 }
135 basic_cstring& assign( pointer s );
136 template<typename LenType>
137 basic_cstring& assign( pointer s, LenType len )
138 {
139 return *this = self_type( s, len );
140 }
141 basic_cstring& assign( pointer f, pointer l );
142
143 // swapping
144 void swap( self_type& s );
145
146 // Iterators
147 iterator begin();
148 const_iterator begin() const;
149 iterator end();
150 const_iterator end() const;
151
152 // !! should have rbegin, rend
153
154 // substring search operation
155 size_type find( basic_cstring ) const;
156 size_type rfind( basic_cstring ) const;
157 self_type substr( size_type beg_index, size_type end_index = npos ) const;
158
159private:
160 static self_type default_trim_ex();
161
162 // Data members
163 iterator m_begin;
164 iterator m_end;
165};
166
167//____________________________________________________________________________//
168
169template<typename CharT>
170inline typename basic_cstring<CharT>::pointer
171basic_cstring<CharT>::null_str()
172{
173 static CharT null = 0;
174 return &null;
175}
176
177//____________________________________________________________________________//
178
179template<typename CharT>
180inline
181basic_cstring<CharT>::basic_cstring()
182: m_begin( null_str() )
183, m_end( m_begin )
184{
185}
186
187//____________________________________________________________________________//
188
189template<typename CharT>
190inline
191basic_cstring<CharT>::basic_cstring( std_string const& s )
192: m_begin( s.c_str() )
193, m_end( m_begin + s.size() )
194{
195}
196
197//____________________________________________________________________________//
198
199template<typename CharT>
200inline
201basic_cstring<CharT>::basic_cstring( pointer s )
202: m_begin( s ? s : null_str() )
203, m_end ( m_begin + (s ? traits_type::length( s ) : 0 ) )
204{
205}
206
207//____________________________________________________________________________//
208
209template<typename CharT>
210inline
211basic_cstring<CharT>::basic_cstring( pointer first, pointer last )
212: m_begin( first )
213, m_end( last )
214{
215}
216
217//____________________________________________________________________________//
218
219template<typename CharT>
220inline typename basic_cstring<CharT>::value_ret_type
221basic_cstring<CharT>::operator[]( size_type index ) const
222{
223 return m_begin[index];
224}
225
226//____________________________________________________________________________//
227
228template<typename CharT>
229inline typename basic_cstring<CharT>::value_ret_type
230basic_cstring<CharT>::at( size_type index ) const
231{
232 if( m_begin + index >= m_end )
233 return static_cast<value_type>(0);
234
235 return m_begin[index];
236}
237
238//____________________________________________________________________________//
239
240template<typename CharT>
241inline typename basic_cstring<CharT>::size_type
242basic_cstring<CharT>::size() const
243{
244 return static_cast<size_type>(m_end - m_begin);
245}
246
247//____________________________________________________________________________//
248
249template<typename CharT>
250inline bool
251basic_cstring<CharT>::is_empty() const
252{
253 return m_end == m_begin;
254}
255
256//____________________________________________________________________________//
257
258template<typename CharT>
259inline bool
260basic_cstring<CharT>::empty() const
261{
262 return is_empty();
263}
264
265//____________________________________________________________________________//
266
267template<typename CharT>
268inline void
269basic_cstring<CharT>::clear()
270{
271 m_begin = m_end;
272}
273
274//____________________________________________________________________________//
275
276template<typename CharT>
277inline void
278basic_cstring<CharT>::resize( size_type new_len )
279{
280 if( m_begin + new_len < m_end )
281 m_end = m_begin + new_len;
282}
283
284//____________________________________________________________________________//
285
286template<typename CharT>
287inline basic_cstring<CharT>&
288basic_cstring<CharT>::trim_left( size_type trim_size )
289{
290 m_begin += trim_size;
291 if( m_end <= m_begin )
292 clear();
293
294 return *this;
295}
296
297//____________________________________________________________________________//
298
299template<typename CharT>
300inline basic_cstring<CharT>&
301basic_cstring<CharT>::trim_left( iterator it )
302{
303 m_begin = it;
304 if( m_end <= m_begin )
305 clear();
306
307 return *this;
308}
309
310//____________________________________________________________________________//
311
312template<typename CharT>
313inline basic_cstring<CharT>&
314basic_cstring<CharT>::trim_left( basic_cstring exclusions )
315{
316 if( exclusions.is_empty() )
317 exclusions = default_trim_ex();
318
319 iterator it;
320 for( it = begin(); it != end(); ++it ) {
321 if( traits_type::find( exclusions.begin(), exclusions.size(), *it ) == reinterpret_cast<pointer>(0) )
322 break;
323 }
324
325 return trim_left( it );
326}
327
328//____________________________________________________________________________//
329
330template<typename CharT>
331inline basic_cstring<CharT>&
332basic_cstring<CharT>::trim_right( size_type trim_size )
333{
334 m_end -= trim_size;
335 if( m_end <= m_begin )
336 clear();
337
338 return *this;
339}
340
341//____________________________________________________________________________//
342
343template<typename CharT>
344inline basic_cstring<CharT>&
345basic_cstring<CharT>::trim_right( iterator it )
346{
347 m_end = it;
348 if( m_end <= m_begin )
349 clear();
350
351 return *this;
352}
353
354//____________________________________________________________________________//
355
356template<typename CharT>
357inline basic_cstring<CharT>&
358basic_cstring<CharT>::trim_right( basic_cstring exclusions )
359{
360 if( exclusions.is_empty() )
361 exclusions = default_trim_ex();
362
363 iterator it;
364
365 for( it = end()-1; it != begin()-1; --it ) {
366 if( self_type::traits_type::find( exclusions.begin(), exclusions.size(), *it ) == reinterpret_cast<pointer>(0) )
367 break;
368 }
369
370 return trim_right( it+1 );
371}
372
373//____________________________________________________________________________//
374
375template<typename CharT>
376inline basic_cstring<CharT>&
377basic_cstring<CharT>::trim( basic_cstring exclusions )
378{
379 trim_left( exclusions );
380 trim_right( exclusions );
381
382 return *this;
383}
384
385//____________________________________________________________________________//
386
387template<typename CharT>
388inline basic_cstring<CharT>&
389basic_cstring<CharT>::operator=( basic_cstring<CharT> const& s )
390{
391 m_begin = s.m_begin;
392 m_end = s.m_end;
393
394 return *this;
395}
396
397//____________________________________________________________________________//
398
399template<typename CharT>
400inline basic_cstring<CharT>&
401basic_cstring<CharT>::operator=( std_string const& s )
402{
403 return *this = self_type( s );
404}
405
406//____________________________________________________________________________//
407
408template<typename CharT>
409inline basic_cstring<CharT>&
410basic_cstring<CharT>::operator=( pointer s )
411{
412 return *this = self_type( s );
413}
414
415//____________________________________________________________________________//
416
417template<typename CharT>
418inline basic_cstring<CharT>&
419basic_cstring<CharT>::assign( std_string const& s )
420{
421 return *this = self_type( s );
422}
423
424//____________________________________________________________________________//
425
426template<typename CharT>
427inline basic_cstring<CharT>&
428basic_cstring<CharT>::assign( pointer s )
429{
430 return *this = self_type( s );
431}
432
433//____________________________________________________________________________//
434
435template<typename CharT>
436inline basic_cstring<CharT>&
437basic_cstring<CharT>::assign( pointer f, pointer l )
438{
439 return *this = self_type( f, l );
440}
441
442//____________________________________________________________________________//
443
444template<typename CharT>
445inline void
446basic_cstring<CharT>::swap( basic_cstring<CharT>& s )
447{
448 // do not want to include alogrithm
449 pointer tmp1 = m_begin;
450 pointer tmp2 = m_end;
451
452 m_begin = s.m_begin;
453 m_end = s.m_end;
454
455 s.m_begin = tmp1;
456 s.m_end = tmp2;
457}
458
459//____________________________________________________________________________//
460
461template<typename CharT>
462inline typename basic_cstring<CharT>::iterator
463basic_cstring<CharT>::begin()
464{
465 return m_begin;
466}
467
468//____________________________________________________________________________//
469
470template<typename CharT>
471inline typename basic_cstring<CharT>::const_iterator
472basic_cstring<CharT>::begin() const
473{
474 return m_begin;
475}
476
477//____________________________________________________________________________//
478
479template<typename CharT>
480inline typename basic_cstring<CharT>::iterator
481basic_cstring<CharT>::end()
482{
483 return m_end;
484}
485
486//____________________________________________________________________________//
487
488template<typename CharT>
489inline typename basic_cstring<CharT>::const_iterator
490basic_cstring<CharT>::end() const
491{
492 return m_end;
493}
494
495//____________________________________________________________________________//
496
497template<typename CharT>
498inline typename basic_cstring<CharT>::size_type
499basic_cstring<CharT>::find( basic_cstring<CharT> str ) const
500{
501 if( str.is_empty() || str.size() > size() )
502 return static_cast<size_type>(npos);
503
504 const_iterator it = begin();
505 const_iterator last = end() - str.size() + 1;
506
507 while( it != last ) {
508 if( traits_type::compare( it, str.begin(), str.size() ) == 0 )
509 break;
510
511 ++it;
512 }
513
514 return it == last ? npos : static_cast<size_type>(it - begin());
515}
516
517//____________________________________________________________________________//
518
519template<typename CharT>
520inline typename basic_cstring<CharT>::size_type
521basic_cstring<CharT>::rfind( basic_cstring<CharT> str ) const
522{
523 if( str.is_empty() || str.size() > size() )
524 return static_cast<size_type>(npos);
525
526 const_iterator it = end() - str.size();
527 const_iterator last = begin()-1;
528
529 while( it != last ) {
530 if( traits_type::compare( it, str.begin(), str.size() ) == 0 )
531 break;
532
533 --it;
534 }
535
536 return it == last ? static_cast<size_type>(npos) : static_cast<size_type>(it - begin());
537}
538
539//____________________________________________________________________________//
540
541template<typename CharT>
542inline basic_cstring<CharT>
543basic_cstring<CharT>::substr( size_type beg_index, size_type end_index ) const
544{
545 return beg_index > size()
546 ? self_type()
547 : end_index > size()
548 ? self_type( m_begin + beg_index, m_end )
549 : self_type( m_begin + beg_index, m_begin + end_index );
550}
551
552//____________________________________________________________________________//
553
554template<typename CharT>
555inline basic_cstring<CharT>
556basic_cstring<CharT>::default_trim_ex()
557{
558 static CharT ws[3] = { CharT(' '), CharT('\t'), CharT('\n') }; // !! wide case
559
560 return self_type( ws, 3 );
561}
562
563//____________________________________________________________________________//
564
565// ************************************************************************** //
566// ************** comparison operators ************** //
567// ************************************************************************** //
568
569template<typename CharT1,typename CharT2>
570inline bool
571operator==( basic_cstring<CharT1> const& s1, basic_cstring<CharT2> const& s2 )
572{
573 typedef typename basic_cstring<CharT1>::traits_type traits_type;
574 return s1.size() == s2.size() &&
575 traits_type::compare( s1.begin(), s2.begin(), s1.size() ) == 0;
576}
577
578//____________________________________________________________________________//
579
580template<typename CharT1,typename CharT2>
581inline bool
582operator==( basic_cstring<CharT1> const& s1, CharT2* s2 )
583{
584#if !defined(__DMC__)
585 return s1 == basic_cstring<CharT2>( s2 );
586#else
587 return s1 == basic_cstring<CharT2 const>( s2 );
588#endif
589}
590
591//____________________________________________________________________________//
592
593template<typename CharT>
594inline bool
595operator==( basic_cstring<CharT> const& s1, typename basic_cstring<CharT>::std_string const& s2 )
596{
597 return s1 == basic_cstring<CharT>( s2 );
598}
599
600//____________________________________________________________________________//
601
602template<typename CharT1,typename CharT2>
603inline bool
604operator==( CharT1* s2, basic_cstring<CharT2> const& s1 )
605{
606 return s1 == s2;
607}
608
609//____________________________________________________________________________//
610
611template<typename CharT>
612inline bool
613operator==( typename basic_cstring<CharT>::std_string const& s2, basic_cstring<CharT> const& s1 )
614{
615 return s1 == s2;
616}
617
618//____________________________________________________________________________//
619
620template<typename CharT>
621inline bool
622operator!=( basic_cstring<CharT> const& s1, CharT* s2 )
623{
624 return !(s1 == s2);
625}
626
627//____________________________________________________________________________//
628
629template<typename CharT>
630inline bool
631operator!=( CharT* s2, basic_cstring<CharT> const& s1 )
632{
633 return !(s1 == s2);
634}
635
636//____________________________________________________________________________//
637
638template<typename CharT>
639inline bool
640operator!=( basic_cstring<CharT> const& s1, basic_cstring<CharT> const& s2 )
641{
642 return !(s1 == s2);
643}
644
645//____________________________________________________________________________//
646
647template<typename CharT>
648inline bool
649operator!=( basic_cstring<CharT> const& s1, typename basic_cstring<CharT>::std_string const& s2 )
650{
651 return !(s1 == s2);
652}
653
654//____________________________________________________________________________//
655
656template<typename CharT>
657inline bool
658operator!=( typename basic_cstring<CharT>::std_string const& s2, basic_cstring<CharT> const& s1 )
659{
660 return !(s1 == s2);
661}
662
663//____________________________________________________________________________//
664
665// ************************************************************************** //
666// ************** first_char ************** //
667// ************************************************************************** //
668
669template<typename CharT>
670inline typename basic_cstring<CharT>::value_ret_type
671first_char( basic_cstring<CharT> source )
672{
673 typedef typename basic_cstring<CharT>::value_ret_type res_type;
674
675 return source.is_empty() ? static_cast<res_type>(0) : *source.begin();
676}
677
678//____________________________________________________________________________//
679
680// ************************************************************************** //
681// ************** last_char ************** //
682// ************************************************************************** //
683
684template<typename CharT>
685inline typename basic_cstring<CharT>::value_ret_type
686last_char( basic_cstring<CharT> source )
687{
688 typedef typename basic_cstring<CharT>::value_ret_type res_type;
689
690 return source.is_empty() ? static_cast<res_type>(0) : *(source.end()-1);
691}
692
693//____________________________________________________________________________//
694
695// ************************************************************************** //
696// ************** assign_op ************** //
697// ************************************************************************** //
698
699template<typename CharT1, typename CharT2>
700inline void
701assign_op( std::basic_string<CharT1>& target, basic_cstring<CharT2> src, int )
702{
703 target.assign( src.begin(), src.size() );
704}
705
706//____________________________________________________________________________//
707
708template<typename CharT1, typename CharT2>
709inline std::basic_string<CharT1>&
710operator+=( std::basic_string<CharT1>& target, basic_cstring<CharT2> const& str )
711{
712 target.append( str.begin(), str.end() );
713 return target;
714}
715
716//____________________________________________________________________________//
717
718template<typename CharT1, typename CharT2>
719inline std::basic_string<CharT1>
720operator+( std::basic_string<CharT1> const& lhs, basic_cstring<CharT2> const& rhs )
721{
722 std::basic_string<CharT1> res( lhs );
723
724 res.append( rhs.begin(), rhs.end() );
725 return res;
726}
727
728//____________________________________________________________________________//
729
730} // namespace unit_test
731
732} // namespace boost
733
734//____________________________________________________________________________//
735
736#include <boost/test/detail/enable_warnings.hpp>
737
738#endif // BOOST_TEST_UTILS_BASIC_CSTRING_HPP
739