LibreOffice
LibreOffice 4.2 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 <string.h>
16 
17 #ifdef 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 
47 template< typename T >
48 struct ToStringHelper
49  {
51  static int length( const T& );
53  static char* addData( char* buffer, const T& );
55  static sal_Unicode* addData( sal_Unicode* buffer, const T& );
57  static const bool allowOStringConcat = false;
59  static const bool allowOUStringConcat = false;
60  };
61 
62 inline
63 char* addDataHelper( char* buffer, const char* data, int length )
64  {
65  memcpy( buffer, data, length );
66  return buffer + length;
67  }
68 
69 inline
70 sal_Unicode* addDataHelper( sal_Unicode* buffer, const sal_Unicode* data, int length )
71  {
72  memcpy( buffer, data, length * sizeof( sal_Unicode ));
73  return buffer + length;
74  }
75 
76 inline
77 sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, int length )
78  {
79  while( length-- > 0 )
80  *buffer++ = *data++;
81  return buffer;
82  }
83 
84 inline
85 char* addDataCString( char* buffer, const char* str )
86  {
87  while( *str != '\0' )
88  *buffer++ = *str++;
89  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  static int length( const char* str ) {
104  return sal::static_int_cast<int>(strlen( str ));
105  }
106  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  static int length( const char* str ) {
115  return sal::static_int_cast<int>(strlen( str ));
116  }
117  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  static int length( const char str[ N ] ) {
126  return sal::static_int_cast<int>(strlen( str ));
127  }
128  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  static int length( const char str[ N ] ) { (void)str; assert( strlen( str ) == N - 1 ); return N - 1; }
138  static char* addData( char* buffer, const char str[ N ] ) { return addDataHelper( buffer, str, N - 1 ); }
139  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 
150 template< typename T1, typename T2 >
151 struct OStringConcat
152  {
153  public:
154  OStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
155  int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
156  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 
171 template< typename T1, typename T2 >
172 struct OUStringConcat
173  {
174  public:
175  OUStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
176  int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
177  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  static int length( const OStringConcat< T1, T2 >& c ) { return c.length(); }
187  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  static int length( const OUStringConcat< T1, T2 >& c ) { return c.length(); }
196  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
204 typename internal::Enable< OStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat >::Type operator+( const T1& left, const T2& right )
205  {
206  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
213 typename internal::Enable< OStringConcat< T, const char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, const char (&right)[ N ] )
214  {
215  return OStringConcat< T, const char[ N ] >( left, right );
216  }
217 
218 template< typename T, int N >
219 inline
221 typename internal::Enable< OStringConcat< const char[ N ], T >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const char (&left)[ N ], const T& right )
222  {
223  return OStringConcat< const char[ N ], T >( left, right );
224  }
225 
226 template< typename T, int N >
227 inline
229 typename internal::Enable< OStringConcat< T, char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, char (&right)[ N ] )
230  {
231  return OStringConcat< T, char[ N ] >( left, right );
232  }
233 
234 template< typename T, int N >
235 inline
237 typename 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 typename internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat >::Type operator+( const T1& left, const T2& right )
245  {
246  return OUStringConcat< T1, T2 >( left, right );
247  }
248 
249 template< typename T1, typename T2 >
250 inline
251 typename internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && internal::ConstCharArrayDetector< T1, void >::ok >::Type operator+( T1& left, const T2& right )
252  {
253  return OUStringConcat< T1, T2 >( left, right );
254  }
255 
256 template< typename T1, typename T2 >
257 inline
258 typename internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && internal::ConstCharArrayDetector< T2, void >::ok >::Type operator+( const T1& left, T2& right )
259  {
260  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  StringConcatInvalid( const T& ) {}
270  };
271 template< typename T >
272 inline
273 int operator+( const StringConcatInvalid&, const T& )
274  {
275  rtl_string_unittest_invalid_concat = true;
276  return 0; // doesn't matter
277  }
278 #endif
279 
280 } // namespace
281 
282 #endif
283 
284 #endif
sal_uInt16 sal_Unicode
Definition: types.h:136
T1 static_int_cast(T2 n)
A static_cast between integral types, to avoid C++ compiler warnings.
Definition: types.h:443
#define SAL_WARN_UNUSED_RESULT
Use this as markup for functions and methods whose return value must be checked.
Definition: types.h:305