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