LibreOffice: rtl/stringconcat.hxx Source File

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
225 SAL_WARN_UNUSED_RESULT
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
234 SAL_WARN_UNUSED_RESULT
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
242 SAL_WARN_UNUSED_RESULT
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
250 SAL_WARN_UNUSED_RESULT
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
258 SAL_WARN_UNUSED_RESULT
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
266 SAL_WARN_UNUSED_RESULT
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
274 SAL_WARN_UNUSED_RESULT
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
282 SAL_WARN_UNUSED_RESULT
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
string.h
sal_Unicode
sal_uInt16 sal_Unicode
Definition: types.h:142
rtl
Definition: bootstrap.hxx:29
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:457
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:307
stringutils.hxx