LibreOffice: rtl/stringconcat.hxx Source File

LibreOffice LibreOffice 5.3 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 #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
221 SAL_WARN_UNUSED_RESULT
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
230 SAL_WARN_UNUSED_RESULT
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
238 SAL_WARN_UNUSED_RESULT
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
246 SAL_WARN_UNUSED_RESULT
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
254 SAL_WARN_UNUSED_RESULT
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
262 SAL_WARN_UNUSED_RESULT
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
270 SAL_WARN_UNUSED_RESULT
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
278 SAL_WARN_UNUSED_RESULT
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
string.h
sal_Unicode
sal_uInt16 sal_Unicode
Definition: types.h:155
rtl::libreoffice_internal::ConstCharArrayDetector::ok
static const bool ok
Definition: stringutils.hxx:160
sal::static_int_cast
T1 static_int_cast(T2 n)
A static_cast between integral types, to avoid C++ compiler warnings.
Definition: types.h:473
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:325
stringutils.hxx
rtl
Definition: bootstrap.hxx:29