1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #ifndef INCLUDED_RTL_STRINGCONCAT_HXX
11 #define INCLUDED_RTL_STRINGCONCAT_HXX
13 #include <rtl/stringutils.hxx>
18 #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
20 #ifdef RTL_STRING_UNITTEST
21 #define rtl rtlunittest
25 #ifdef RTL_STRING_UNITTEST
30 Implementation of efficient string concatenation.
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
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.
46 Helper class for converting a given type to a string representation.
48 template< typename T
>
51 /// Return length of the string representation of the given object (if not known exactly, it needs to be the maximum).
52 static int length( const T
& );
53 /// Add 8-bit representation of the given object to the given buffer and return position right after the added data.
54 static char* addData( char* buffer
, const T
& );
55 /// Add Unicode representation of the given object to the given buffer and return position right after the added data.
56 static sal_Unicode
* addData( sal_Unicode
* buffer
, const T
& );
57 /// If true, T can be used in concatenation resulting in OString.
58 static const bool allowOStringConcat
= false;
59 /// If true, T can be used in concatenation resulting in OUString.
60 static const bool allowOUStringConcat
= false;
64 char* addDataHelper( char* buffer
, const char* data
, int length
)
66 memcpy( buffer
, data
, length
);
67 return buffer
+ length
;
71 sal_Unicode
* addDataHelper( sal_Unicode
* buffer
, const sal_Unicode
* data
, int length
)
73 memcpy( buffer
, data
, length
* sizeof( sal_Unicode
));
74 return buffer
+ length
;
78 sal_Unicode
* addDataLiteral( sal_Unicode
* buffer
, const char* data
, int length
)
86 char* addDataCString( char* buffer
, const char* str
)
94 sal_Unicode
* addDataUString( sal_Unicode
* buffer
, const sal_Unicode
* str
)
102 struct ToStringHelper
< const char* >
104 static int length( const char* str
) {
105 return sal::static_int_cast
<int>(strlen( str
));
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;
113 struct ToStringHelper
< char* >
115 static int length( const char* str
) {
116 return sal::static_int_cast
<int>(strlen( str
));
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;
124 struct ToStringHelper
< char[ N
] >
126 static int length( const char str
[ N
] ) {
127 return sal::static_int_cast
<int>(strlen( str
));
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;
136 struct ToStringHelper
< const char[ N
] >
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;
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;
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;
165 Objects returned by operator+, instead of OString. These objects (possibly recursively) keep a representation of the whole
166 concatenation operation.
168 template< typename T1
, typename T2
>
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).
186 Objects returned by operator+, instead of OUString. These objects (possibly recursively) keep a representation of the whole
187 concatenation operation.
189 template< typename T1
, typename T2
>
190 struct OUStringConcat
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
); }
201 template< typename T1
, typename T2
>
202 struct ToStringHelper
< OStringConcat
< T1
, T2
> >
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;
210 template< typename T1
, typename T2
>
211 struct ToStringHelper
< OUStringConcat
< T1
, T2
> >
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
;
219 template< typename T1
, typename T2
>
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
)
224 return OStringConcat
< T1
, T2
>( left
, right
);
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
>
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
] )
233 return OStringConcat
< T
, const char[ N
] >( left
, right
);
236 template< typename T
, int N
>
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
)
241 return OStringConcat
< const char[ N
], T
>( left
, right
);
244 template< typename T
, int N
>
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
] )
249 return OStringConcat
< T
, char[ N
] >( left
, right
);
252 template< typename T
, int N
>
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
)
257 return OStringConcat
< char[ N
], T
>( left
, right
);
260 template< typename T1
, typename T2
>
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
)
265 return OUStringConcat
< T1
, T2
>( left
, right
);
268 template< typename T1
, typename T2
>
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
)
273 return OUStringConcat
< T1
, T2
>( left
, right
);
276 template< typename T1
, typename T2
>
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
)
281 return OUStringConcat
< T1
, T2
>( left
, right
);
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
289 template< typename T
>
290 StringConcatInvalid( const T
& ) {}
292 template< typename T
>
294 int operator+( const StringConcatInvalid
&, const T
& )
296 rtl_string_unittest_invalid_concat
= true;
297 return 0; // doesn't matter