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