LibreOffice
LibreOffice 6.0 SDK C/C++ API Reference
stringconcat.hxx
Go to the documentation of this file.
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 <cstddef>
16 #include <string.h>
17 
18 #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
19 
20 #if defined RTL_STRING_UNITTEST_CONCAT
21 extern bool rtl_string_unittest_invalid_concat;
22 #endif
23 
24 #ifdef RTL_STRING_UNITTEST
25 #define rtl rtlunittest
26 #endif
27 namespace rtl
28 {
29 #ifdef RTL_STRING_UNITTEST
30 #undef rtl
31 #endif
32 
33 /*
34 Implementation of efficient string concatenation.
35 
36 The whole system is built around two basic template classes:
37 - ToStringHelper< T > - for each T it can give the length of the resulting string representation and can write
38  this string representation to a buffer
39 - O(U)StringConcat< T1, T2 > - operator+ now, instead of creating O(U)String object, returns only this helper object,
40  that keeps a reference to both operator+ operands; only when converted to O(U)String it will actually create
41  the resulting string object using ToStringHelper, creating directly the resulting object without any string
42  intermediate objects
43 As all the code is inline methods, it allows for extensive optimization and will usually result in very effective code
44 (even surpassing strlen/strcat and equalling handwritten), while allowing for very easy and intuitive syntax.
45 */
46 
52 template< typename T >
53 struct ToStringHelper
54  {
56  static int length( const T& );
58  static char* addData( char* buffer, const T& ) SAL_RETURNS_NONNULL;
60  static sal_Unicode* addData( sal_Unicode* buffer, const T& ) SAL_RETURNS_NONNULL;
62  static const bool allowOStringConcat = false;
64  static const bool allowOUStringConcat = false;
65  };
66 
67 inline
68 char* addDataHelper( char* buffer, const char* data, int length )
69  {
70  memcpy( buffer, data, length );
71  return buffer + length;
72  }
73 
74 inline
75 sal_Unicode* addDataHelper( sal_Unicode* buffer, const sal_Unicode* data, int length )
76  {
77  memcpy( buffer, data, length * sizeof( sal_Unicode ));
78  return buffer + length;
79  }
80 
81 inline
82 sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, int length )
83  {
84  while( length-- > 0 )
85  *buffer++ = *data++;
86  return buffer;
87  }
88 
89 inline
90 char* addDataCString( char* buffer, const char* str )
91  {
92  while( *str != '\0' )
93  *buffer++ = *str++;
94  return buffer;
95  }
96 
97 inline
98 sal_Unicode* addDataUString( sal_Unicode* buffer, const sal_Unicode* str )
99  {
100  while( *str != '\0' )
101  *buffer++ = *str++;
102  return buffer;
103  }
104 
105 template<>
106 struct ToStringHelper< const char* >
107  {
108  static int length( const char* str ) {
109  return sal::static_int_cast<int>(strlen( str ));
110  }
111  static char* addData( char* buffer, const char* str ) { return addDataCString( buffer, str ); }
112  static const bool allowOStringConcat = true;
113  static const bool allowOUStringConcat = false;
114  };
115 
116 template<>
117 struct ToStringHelper< char* >
118  {
119  static int length( const char* str ) {
120  return sal::static_int_cast<int>(strlen( str ));
121  }
122  static char* addData( char* buffer, const char* str ) { return addDataCString( buffer, str ); }
123  static const bool allowOStringConcat = true;
124  static const bool allowOUStringConcat = false;
125  };
126 
127 template< int N >
128 struct ToStringHelper< char[ N ] >
129  {
130  static int length( const char str[ N ] ) {
131  return sal::static_int_cast<int>(strlen( str ));
132  }
133  static char* addData( char* buffer, const char str[ N ] ) { return addDataCString( buffer, str ); }
134  static sal_Unicode* addData( sal_Unicode* buffer, const char str[ N ] ) { return addDataLiteral( buffer, str, N - 1 ); }
135  static const bool allowOStringConcat = true;
136  static const bool allowOUStringConcat = false;
137  };
138 
139 template< int N >
140 struct ToStringHelper< const char[ N ] >
141  {
142  static int length( const char str[ N ] ) { (void)str; assert( strlen( str ) == N - 1 ); return N - 1; }
143  static char* addData( char* buffer, const char str[ N ] ) { return addDataHelper( buffer, str, N - 1 ); }
144  static sal_Unicode* addData( sal_Unicode* buffer, const char str[ N ] ) { return addDataLiteral( buffer, str, N - 1 ); }
145  static const bool allowOStringConcat = true;
146  static const bool allowOUStringConcat = true;
147  };
148 
149 template<std::size_t N> struct ToStringHelper<sal_Unicode const[N]> {
150  static int length(sal_Unicode const[N]) { return N - 1; }
151  static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const str[N])
152  { return addDataHelper(buffer, str, N - 1); }
153  static bool const allowOStringConcat = false;
154  static bool const allowOUStringConcat = true;
155 };
156 
157 template<> struct ToStringHelper<OUStringLiteral1_> {
158  static int length(OUStringLiteral1_) { return 1; }
159  static sal_Unicode * addData(
160  sal_Unicode * buffer, OUStringLiteral1_ literal)
161  { return addDataHelper(buffer, &literal.c, 1); }
162  static bool const allowOStringConcat = false;
163  static bool const allowOUStringConcat = true;
164 };
165 
172 template< typename T1, typename T2 >
173 struct OStringConcat
174  {
175  public:
176  OStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
177  int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
178  char* addData( char* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
179  // NOTE here could be functions that would forward to the "real" temporary OString. Note however that e.g. getStr()
180  // is not so simple, as the OString temporary must live long enough (i.e. can't be created here in a function, a wrapper
181  // temporary object containing it must be returned instead).
182  private:
183  const T1& left;
184  const T2& right;
185  };
186 
193 template< typename T1, typename T2 >
194 struct OUStringConcat
195  {
196  public:
197  OUStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
198  int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
199  sal_Unicode* addData( sal_Unicode* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
200  private:
201  const T1& left;
202  const T2& right;
203  };
204 
205 template< typename T1, typename T2 >
206 struct ToStringHelper< OStringConcat< T1, T2 > >
207  {
208  static int length( const OStringConcat< T1, T2 >& c ) { return c.length(); }
209  static char* addData( char* buffer, const OStringConcat< T1, T2 >& c ) SAL_RETURNS_NONNULL { return c.addData( buffer ); }
210  static const bool allowOStringConcat = ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat;
211  static const bool allowOUStringConcat = false;
212  };
213 
214 template< typename T1, typename T2 >
215 struct ToStringHelper< OUStringConcat< T1, T2 > >
216  {
217  static int length( const OUStringConcat< T1, T2 >& c ) { return c.length(); }
218  static sal_Unicode* addData( sal_Unicode* buffer, const OUStringConcat< T1, T2 >& c ) SAL_RETURNS_NONNULL { return c.addData( buffer ); }
219  static const bool allowOStringConcat = false;
220  static const bool allowOUStringConcat = ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat;
221  };
222 
223 template< typename T1, typename T2 >
224 inline
226 typename libreoffice_internal::Enable< OStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat >::Type operator+( const T1& left, const T2& right )
227  {
228  return OStringConcat< T1, T2 >( left, right );
229  }
230 
231 // char[N] and const char[N] need to be done explicitly, otherwise the compiler likes to treat them the same way for some reason
232 template< typename T, int N >
233 inline
235 typename libreoffice_internal::Enable< OStringConcat< T, const char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, const char (&right)[ N ] )
236  {
237  return OStringConcat< T, const char[ N ] >( left, right );
238  }
239 
240 template< typename T, int N >
241 inline
243 typename libreoffice_internal::Enable< OStringConcat< const char[ N ], T >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const char (&left)[ N ], const T& right )
244  {
245  return OStringConcat< const char[ N ], T >( left, right );
246  }
247 
248 template< typename T, int N >
249 inline
251 typename libreoffice_internal::Enable< OStringConcat< T, char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, char (&right)[ N ] )
252  {
253  return OStringConcat< T, char[ N ] >( left, right );
254  }
255 
256 template< typename T, int N >
257 inline
259 typename libreoffice_internal::Enable< OStringConcat< char[ N ], T >, ToStringHelper< T >::allowOStringConcat >::Type operator+( char (&left)[ N ], const T& right )
260  {
261  return OStringConcat< char[ N ], T >( left, right );
262  }
263 
264 template< typename T1, typename T2 >
265 inline
267 typename libreoffice_internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat >::Type operator+( const T1& left, const T2& right )
268  {
269  return OUStringConcat< T1, T2 >( left, right );
270  }
271 
272 template< typename T1, typename T2 >
273 inline
275 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 )
276  {
277  return OUStringConcat< T1, T2 >( left, right );
278  }
279 
280 template< typename T1, typename T2 >
281 inline
283 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 )
284  {
285  return OUStringConcat< T1, T2 >( left, right );
286  }
287 
288 #ifdef RTL_STRING_UNITTEST_CONCAT
289 // Special overload to catch the remaining invalid combinations. The helper struct must
290 // be used to make this operator+ overload a worse choice than all the existing overloads above.
291 struct StringConcatInvalid
292  {
293  template< typename T >
294  StringConcatInvalid( const T& ) {}
295  };
296 template< typename T >
297 inline
298 int operator+( const StringConcatInvalid&, const T& )
299  {
300  rtl_string_unittest_invalid_concat = true;
301  return 0; // doesn't matter
302  }
303 #endif
304 
305 } // namespace
306 
307 #endif
308 
309 #endif
#define SAL_WARN_UNUSED_RESULT
Use this as markup for functions and methods whose return value must be checked.
Definition: types.h:307
sal_uInt16 sal_Unicode
Definition: types.h:142
Definition: bootstrap.hxx:29
static const bool ok
Definition: stringutils.hxx:160
T1 static_int_cast(T2 n)
A static_cast between integral types, to avoid C++ compiler warnings.
Definition: types.h:457