LCOV - code coverage report
Current view: top level - include/rtl - stringconcat.hxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 54 54 100.0 %
Date: 2015-06-13 12:38:46 Functions: 2843 8376 33.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #ifndef INCLUDED_RTL_STRINGCONCAT_HXX
      11             : #define INCLUDED_RTL_STRINGCONCAT_HXX
      12             : 
      13             : #include <rtl/stringutils.hxx>
      14             : 
      15             : #include <string.h>
      16             : 
      17             : #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
      18             : 
      19             : #ifdef RTL_STRING_UNITTEST
      20             : #define rtl rtlunittest
      21             : #endif
      22             : namespace rtl
      23             : {
      24             : #ifdef RTL_STRING_UNITTEST
      25             : #undef rtl
      26             : #endif
      27             : 
      28             : /*
      29             : Implementation of efficient string concatenation.
      30             : 
      31             : The whole system is built around two basic template classes:
      32             : - ToStringHelper< T > - for each T it can give the length of the resulting string representation and can write
      33             :     this string representation to a buffer
      34             : - O(U)StringConcat< T1, T2 > - operator+ now, instead of creating O(U)String object, returns only this helper object,
      35             :     that keeps a reference to both operator+ operands; only when converted to O(U)String it will actually create
      36             :     the resulting string object using ToStringHelper, creating directly the resulting object without any string
      37             :     intermediate objects
      38             : As all the code is inline methods, it allows for extensive optimization and will usually result in very effective code
      39             : (even surpassing strlen/strcat and equalling handwritten), while allowing for very easy and intuitive syntax.
      40             : */
      41             : 
      42             : /**
      43             : @internal
      44             : 
      45             : Helper class for converting a given type to a string representation.
      46             : */
      47             : template< typename T >
      48             : struct ToStringHelper
      49             :     {
      50             :     /// Return length of the string representation of the given object (if not known exactly, it needs to be the maximum).
      51             :     static int length( const T& );
      52             :     /// Add 8-bit representation of the given object to the given buffer and return position right after the added data.
      53             :     static char* addData( char* buffer, const T& );
      54             :     /// Add Unicode representation of the given object to the given buffer and return position right after the added data.
      55             :     static sal_Unicode* addData( sal_Unicode* buffer, const T& );
      56             :     /// If true, T can be used in concatenation resulting in OString.
      57             :     static const bool allowOStringConcat = false;
      58             :     /// If true, T can be used in concatenation resulting in OUString.
      59             :     static const bool allowOUStringConcat = false;
      60             :     };
      61             : 
      62             : inline
      63     1388728 : char* addDataHelper( char* buffer, const char* data, int length )
      64             :     {
      65     1388728 :     memcpy( buffer, data, length );
      66     1388728 :     return buffer + length;
      67             :     }
      68             : 
      69             : inline
      70  1868913766 : sal_Unicode* addDataHelper( sal_Unicode* buffer, const sal_Unicode* data, int length )
      71             :     {
      72  1868913766 :     memcpy( buffer, data, length * sizeof( sal_Unicode ));
      73  1868913766 :     return buffer + length;
      74             :     }
      75             : 
      76             : inline
      77   942489046 : sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, int length )
      78             :     {
      79  2842313881 :     while( length-- > 0 )
      80   957335789 :         *buffer++ = *data++;
      81   942489046 :     return buffer;
      82             :     }
      83             : 
      84             : inline
      85          49 : char* addDataCString( char* buffer, const char* str )
      86             :     {
      87         806 :     while( *str != '\0' )
      88         708 :         *buffer++ = *str++;
      89          49 :     return buffer;
      90             :     }
      91             : 
      92             : inline
      93             : sal_Unicode* addDataUString( sal_Unicode* buffer, const sal_Unicode* str )
      94             :     {
      95             :     while( *str != '\0' )
      96             :         *buffer++ = *str++;
      97             :     return buffer;
      98             :     }
      99             : 
     100             : template<>
     101             : struct ToStringHelper< const char* >
     102             :     {
     103          47 :     static int length( const char* str ) {
     104          47 :         return sal::static_int_cast<int>(strlen( str ));
     105             :     }
     106          47 :     static char* addData( char* buffer, const char* str ) { return addDataCString( buffer, str ); }
     107             :     static const bool allowOStringConcat = true;
     108             :     static const bool allowOUStringConcat = false;
     109             :     };
     110             : 
     111             : template<>
     112             : struct ToStringHelper< char* >
     113             :     {
     114           1 :     static int length( const char* str ) {
     115           1 :         return sal::static_int_cast<int>(strlen( str ));
     116             :     }
     117           1 :     static char* addData( char* buffer, const char* str ) { return addDataCString( buffer, str ); }
     118             :     static const bool allowOStringConcat = true;
     119             :     static const bool allowOUStringConcat = false;
     120             :     };
     121             : 
     122             : template< int N >
     123             : struct ToStringHelper< char[ N ] >
     124             :     {
     125           1 :     static int length( const char str[ N ] ) {
     126           1 :         return sal::static_int_cast<int>(strlen( str ));
     127             :     }
     128           1 :     static char* addData( char* buffer, const char str[ N ] ) { return addDataCString( buffer, str ); }
     129             :     static sal_Unicode* addData( sal_Unicode* buffer, const char str[ N ] ) { return addDataLiteral( buffer, str, N - 1 ); }
     130             :     static const bool allowOStringConcat = true;
     131             :     static const bool allowOUStringConcat = false;
     132             :     };
     133             : 
     134             : template< int N >
     135             : struct ToStringHelper< const char[ N ] >
     136             :     {
     137   943073208 :     static int length( const char str[ N ] ) { (void)str; assert( strlen( str ) == N - 1 ); return N - 1; }
     138      584170 :     static char* addData( char* buffer, const char str[ N ] ) { return addDataHelper( buffer, str, N - 1 ); }
     139   942489038 :     static sal_Unicode* addData( sal_Unicode* buffer, const char str[ N ] ) { return addDataLiteral( buffer, str, N - 1 ); }
     140             :     static const bool allowOStringConcat = true;
     141             :     static const bool allowOUStringConcat = true;
     142             :     };
     143             : 
     144             : /**
     145             : @internal
     146             : 
     147             : Objects returned by operator+, instead of OString. These objects (possibly recursively) keep a representation of the whole
     148             : concatenation operation.
     149             : */
     150             : template< typename T1, typename T2 >
     151             : struct OStringConcat
     152             :     {
     153             :     public:
     154      721627 :         OStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
     155      721627 :         int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
     156      721625 :         char* addData( char* buffer ) const { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
     157             :         // NOTE here could be functions that would forward to the "real" temporary OString. Note however that e.g. getStr()
     158             :         // is not so simple, as the OString temporary must live long enough (i.e. can't be created here in a function, a wrapper
     159             :         // temporary object containing it must be returned instead).
     160             :     private:
     161             :         const T1& left;
     162             :         const T2& right;
     163             :     };
     164             : 
     165             : /**
     166             : @internal
     167             : 
     168             : Objects returned by operator+, instead of OUString. These objects (possibly recursively) keep a representation of the whole
     169             : concatenation operation.
     170             : */
     171             : template< typename T1, typename T2 >
     172             : struct OUStringConcat
     173             :     {
     174             :     public:
     175  1862933668 :         OUStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
     176  1862933668 :         int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
     177  1862932204 :         sal_Unicode* addData( sal_Unicode* buffer ) const { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
     178             :     private:
     179             :         const T1& left;
     180             :         const T2& right;
     181             :     };
     182             : 
     183             : template< typename T1, typename T2 >
     184             : struct ToStringHelper< OStringConcat< T1, T2 > >
     185             :     {
     186       54473 :     static int length( const OStringConcat< T1, T2 >& c ) { return c.length(); }
     187       54473 :     static char* addData( char* buffer, const OStringConcat< T1, T2 >& c ) { return c.addData( buffer ); }
     188             :     static const bool allowOStringConcat = ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat;
     189             :     static const bool allowOUStringConcat = false;
     190             :     };
     191             : 
     192             : template< typename T1, typename T2 >
     193             : struct ToStringHelper< OUStringConcat< T1, T2 > >
     194             :     {
     195   914461897 :     static int length( const OUStringConcat< T1, T2 >& c ) { return c.length(); }
     196   914461172 :     static sal_Unicode* addData( sal_Unicode* buffer, const OUStringConcat< T1, T2 >& c ) { return c.addData( buffer ); }
     197             :     static const bool allowOStringConcat = false;
     198             :     static const bool allowOUStringConcat = ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat;
     199             :     };
     200             : 
     201             : template< typename T1, typename T2 >
     202             : inline
     203             : SAL_WARN_UNUSED_RESULT
     204      137456 : typename libreoffice_internal::Enable< OStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat >::Type operator+( const T1& left, const T2& right )
     205             :     {
     206      137456 :     return OStringConcat< T1, T2 >( left, right );
     207             :     }
     208             : 
     209             : // char[N] and const char[N] need to be done explicitly, otherwise the compiler likes to treat them the same way for some reason
     210             : template< typename T, int N >
     211             : inline
     212             : SAL_WARN_UNUSED_RESULT
     213       44568 : typename libreoffice_internal::Enable< OStringConcat< T, const char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, const char (&right)[ N ] )
     214             :     {
     215       44568 :     return OStringConcat< T, const char[ N ] >( left, right );
     216             :     }
     217             : 
     218             : template< typename T, int N >
     219             : inline
     220             : SAL_WARN_UNUSED_RESULT
     221      539602 : typename libreoffice_internal::Enable< OStringConcat< const char[ N ], T >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const char (&left)[ N ], const T& right )
     222             :     {
     223      539602 :     return OStringConcat< const char[ N ], T >( left, right );
     224             :     }
     225             : 
     226             : template< typename T, int N >
     227             : inline
     228             : SAL_WARN_UNUSED_RESULT
     229           1 : typename libreoffice_internal::Enable< OStringConcat< T, char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, char (&right)[ N ] )
     230             :     {
     231           1 :     return OStringConcat< T, char[ N ] >( left, right );
     232             :     }
     233             : 
     234             : template< typename T, int N >
     235             : inline
     236             : SAL_WARN_UNUSED_RESULT
     237             : typename libreoffice_internal::Enable< OStringConcat< char[ N ], T >, ToStringHelper< T >::allowOStringConcat >::Type operator+( char (&left)[ N ], const T& right )
     238             :     {
     239             :     return OStringConcat< char[ N ], T >( left, right );
     240             :     }
     241             : 
     242             : template< typename T1, typename T2 >
     243             : inline
     244   920444630 : typename libreoffice_internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat >::Type operator+( const T1& left, const T2& right )
     245             :     {
     246   920444630 :     return OUStringConcat< T1, T2 >( left, right );
     247             :     }
     248             : 
     249             : template< typename T1, typename T2 >
     250             : inline
     251    28048853 : typename libreoffice_internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && libreoffice_internal::ConstCharArrayDetector< T1, void >::ok >::Type operator+( T1& left, const T2& right )
     252             :     {
     253    28048853 :     return OUStringConcat< T1, T2 >( left, right );
     254             :     }
     255             : 
     256             : template< typename T1, typename T2 >
     257             : inline
     258   914440185 : typename libreoffice_internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && libreoffice_internal::ConstCharArrayDetector< T2, void >::ok >::Type operator+( const T1& left, T2& right )
     259             :     {
     260   914440185 :     return OUStringConcat< T1, T2 >( left, right );
     261             :     }
     262             : 
     263             : #ifdef RTL_STRING_UNITTEST_CONCAT
     264             : // Special overload to catch the remaining invalid combinations. The helper struct must
     265             : // be used to make this operator+ overload a worse choice than all the existing overloads above.
     266             : struct StringConcatInvalid
     267             :     {
     268             :     template< typename T >
     269          15 :     StringConcatInvalid( const T& ) {}
     270             :     };
     271             : template< typename T >
     272             : inline
     273          15 : int operator+( const StringConcatInvalid&, const T& )
     274             :     {
     275          15 :     rtl_string_unittest_invalid_concat = true;
     276          15 :     return 0; // doesn't matter
     277             :     }
     278             : #endif
     279             : 
     280             : } // namespace
     281             : 
     282             : #endif
     283             : 
     284             : #endif

Generated by: LCOV version 1.11