LibreOffice: rtl/stringconcat.hxx Source File

LibreOffice LibreOffice 5.1 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 <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
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
144 template<char C> struct ToStringHelper<OUStringLiteral1_<C>> {
145 static int length(OUStringLiteral1_<C>) { return 1; }
146 static char * addData(char * buffer, OUStringLiteral1_<C> literal)
147 { return addDataHelper(buffer, &literal.c, 1); }
148 static sal_Unicode * addData(
149 sal_Unicode * buffer, OUStringLiteral1_<C> literal)
150 { return addDataLiteral(buffer, &literal.c, 1); }
151 static bool const allowOStringConcat = false;
152 static bool const allowOUStringConcat = true;
153 };
154
161 template< typename T1, typename T2 >
162 struct OStringConcat
163 {
164 public:
165 OStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
166 int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
167 char* addData( char* buffer ) const { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
168 // NOTE here could be functions that would forward to the "real" temporary OString. Note however that e.g. getStr()
169 // is not so simple, as the OString temporary must live long enough (i.e. can't be created here in a function, a wrapper
170 // temporary object containing it must be returned instead).
171 private:
172 const T1& left;
173 const T2& right;
174 };
175
182 template< typename T1, typename T2 >
183 struct OUStringConcat
184 {
185 public:
186 OUStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
187 int length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
188 sal_Unicode* addData( sal_Unicode* buffer ) const { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
189 private:
190 const T1& left;
191 const T2& right;
192 };
193
194 template< typename T1, typename T2 >
195 struct ToStringHelper< OStringConcat< T1, T2 > >
196 {
197 static int length( const OStringConcat< T1, T2 >& c ) { return c.length(); }
198 static char* addData( char* buffer, const OStringConcat< T1, T2 >& c ) { return c.addData( buffer ); }
199 static const bool allowOStringConcat = ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat;
200 static const bool allowOUStringConcat = false;
201 };
202
203 template< typename T1, typename T2 >
204 struct ToStringHelper< OUStringConcat< T1, T2 > >
205 {
206 static int length( const OUStringConcat< T1, T2 >& c ) { return c.length(); }
207 static sal_Unicode* addData( sal_Unicode* buffer, const OUStringConcat< T1, T2 >& c ) { return c.addData( buffer ); }
208 static const bool allowOStringConcat = false;
209 static const bool allowOUStringConcat = ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat;
210 };
211
212 template< typename T1, typename T2 >
213 inline
214 SAL_WARN_UNUSED_RESULT
215 typename libreoffice_internal::Enable< OStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat >::Type operator+( const T1& left, const T2& right )
216 {
217 return OStringConcat< T1, T2 >( left, right );
218 }
219
220 // char[N] and const char[N] need to be done explicitly, otherwise the compiler likes to treat them the same way for some reason
221 template< typename T, int N >
222 inline
223 SAL_WARN_UNUSED_RESULT
224 typename libreoffice_internal::Enable< OStringConcat< T, const char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, const char (&right)[ N ] )
225 {
226 return OStringConcat< T, const char[ N ] >( left, right );
227 }
228
229 template< typename T, int N >
230 inline
231 SAL_WARN_UNUSED_RESULT
232 typename libreoffice_internal::Enable< OStringConcat< const char[ N ], T >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const char (&left)[ N ], const T& right )
233 {
234 return OStringConcat< const char[ N ], T >( left, right );
235 }
236
237 template< typename T, int N >
238 inline
239 SAL_WARN_UNUSED_RESULT
240 typename libreoffice_internal::Enable< OStringConcat< T, char[ N ] >, ToStringHelper< T >::allowOStringConcat >::Type operator+( const T& left, char (&right)[ N ] )
241 {
242 return OStringConcat< T, char[ N ] >( left, right );
243 }
244
245 template< typename T, int N >
246 inline
247 SAL_WARN_UNUSED_RESULT
248 typename libreoffice_internal::Enable< OStringConcat< char[ N ], T >, ToStringHelper< T >::allowOStringConcat >::Type operator+( char (&left)[ N ], const T& right )
249 {
250 return OStringConcat< char[ N ], T >( left, right );
251 }
252
253 template< typename T1, typename T2 >
254 inline
255 SAL_WARN_UNUSED_RESULT
256 typename libreoffice_internal::Enable< OUStringConcat< T1, T2 >, ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat >::Type operator+( const T1& left, const T2& right )
257 {
258 return OUStringConcat< T1, T2 >( left, right );
259 }
260
261 template< typename T1, typename T2 >
262 inline
263 SAL_WARN_UNUSED_RESULT
264 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 )
265 {
266 return OUStringConcat< T1, T2 >( left, right );
267 }
268
269 template< typename T1, typename T2 >
270 inline
271 SAL_WARN_UNUSED_RESULT
272 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 )
273 {
274 return OUStringConcat< T1, T2 >( left, right );
275 }
276
277 #ifdef RTL_STRING_UNITTEST_CONCAT
278 // Special overload to catch the remaining invalid combinations. The helper struct must
279 // be used to make this operator+ overload a worse choice than all the existing overloads above.
280 struct StringConcatInvalid
281 {
282 template< typename T >
283 StringConcatInvalid( const T& ) {}
284 };
285 template< typename T >
286 inline
287 int operator+( const StringConcatInvalid&, const T& )
288 {
289 rtl_string_unittest_invalid_concat = true;
290 return 0; // doesn't matter
291 }
292 #endif
293
294 } // namespace
295
296 #endif
297
298 #endif
string.h
sal_Unicode
sal_uInt16 sal_Unicode
Definition: types.h:155
rtl::libreoffice_internal::ConstCharArrayDetector::ok
static const bool ok
Definition: stringutils.hxx:162
sal::static_int_cast
T1 static_int_cast(T2 n)
A static_cast between integral types, to avoid C++ compiler warnings.
Definition: types.h:463
SAL_WARN_UNUSED_RESULT
#define SAL_WARN_UNUSED_RESULT
Use this as markup for functions and methods whose return value must be checked.
Definition: types.h:323
stringutils.hxx
rtl
Definition: bootstrap.hxx:29