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 #if defined RTL_STRING_UNITTEST_CONCAT
21 extern bool rtl_string_unittest_invalid_concat
;
24 #ifdef RTL_STRING_UNITTEST
25 #define rtl rtlunittest
29 #ifdef RTL_STRING_UNITTEST
34 Implementation of efficient string concatenation.
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
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.
50 Helper class for converting a given type to a string representation.
52 template< typename T
>
55 /// Return length of the string representation of the given object (if not known exactly, it needs to be the maximum).
56 static int length( const T
& );
57 /// Add 8-bit representation of the given object to the given buffer and return position right after the added data.
58 static char* addData( char* buffer
, const T
& ) SAL_RETURNS_NONNULL
;
59 /// Add Unicode representation of the given object to the given buffer and return position right after the added data.
60 static sal_Unicode
* addData( sal_Unicode
* buffer
, const T
& ) SAL_RETURNS_NONNULL
;
61 /// If true, T can be used in concatenation resulting in OString.
62 static const bool allowOStringConcat
= false;
63 /// If true, T can be used in concatenation resulting in OUString.
64 static const bool allowOUStringConcat
= false;
68 char* addDataHelper( char* buffer
, const char* data
, int length
)
70 memcpy( buffer
, data
, length
);
71 return buffer
+ length
;
75 sal_Unicode
* addDataHelper( sal_Unicode
* buffer
, const sal_Unicode
* data
, int length
)
77 memcpy( buffer
, data
, length
* sizeof( sal_Unicode
));
78 return buffer
+ length
;
82 sal_Unicode
* addDataLiteral( sal_Unicode
* buffer
, const char* data
, int length
)
90 char* addDataCString( char* buffer
, const char* str
)
98 sal_Unicode
* addDataUString( sal_Unicode
* buffer
, const sal_Unicode
* str
)
100 while( *str
!= '\0' )
106 struct ToStringHelper
< const char* >
108 static int length( const char* str
) {
109 return sal::static_int_cast
<int>(strlen( str
));
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;
117 struct ToStringHelper
< char* >
119 static int length( const char* str
) {
120 return sal::static_int_cast
<int>(strlen( str
));
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;
128 struct ToStringHelper
< char[ N
] >
130 static int length( const char str
[ N
] ) {
131 return sal::static_int_cast
<int>(strlen( str
));
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;
140 struct ToStringHelper
< const char[ N
] >
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;
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;
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;
169 Objects returned by operator+, instead of OString. These objects (possibly recursively) keep a representation of the whole
170 concatenation operation.
172 template< typename T1
, typename T2
>
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).
190 Objects returned by operator+, instead of OUString. These objects (possibly recursively) keep a representation of the whole
191 concatenation operation.
193 template< typename T1
, typename T2
>
194 struct OUStringConcat
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
); }
205 template< typename T1
, typename T2
>
206 struct ToStringHelper
< OStringConcat
< T1
, T2
> >
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;
214 template< typename T1
, typename T2
>
215 struct ToStringHelper
< OUStringConcat
< T1
, T2
> >
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
;
223 template< typename T1
, typename T2
>
226 typename
libreoffice_internal::Enable
< OStringConcat
< T1
, T2
>, ToStringHelper
< T1
>::allowOStringConcat
&& ToStringHelper
< T2
>::allowOStringConcat
>::Type
operator+( const T1
& left
, const T2
& right
)
228 return OStringConcat
< T1
, T2
>( left
, right
);
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
>
235 typename
libreoffice_internal::Enable
< OStringConcat
< T
, const char[ N
] >, ToStringHelper
< T
>::allowOStringConcat
>::Type
operator+( const T
& left
, const char (&right
)[ N
] )
237 return OStringConcat
< T
, const char[ N
] >( left
, right
);
240 template< typename T
, int N
>
243 typename
libreoffice_internal::Enable
< OStringConcat
< const char[ N
], T
>, ToStringHelper
< T
>::allowOStringConcat
>::Type
operator+( const char (&left
)[ N
], const T
& right
)
245 return OStringConcat
< const char[ N
], T
>( left
, right
);
248 template< typename T
, int N
>
251 typename
libreoffice_internal::Enable
< OStringConcat
< T
, char[ N
] >, ToStringHelper
< T
>::allowOStringConcat
>::Type
operator+( const T
& left
, char (&right
)[ N
] )
253 return OStringConcat
< T
, char[ N
] >( left
, right
);
256 template< typename T
, int N
>
259 typename
libreoffice_internal::Enable
< OStringConcat
< char[ N
], T
>, ToStringHelper
< T
>::allowOStringConcat
>::Type
operator+( char (&left
)[ N
], const T
& right
)
261 return OStringConcat
< char[ N
], T
>( left
, right
);
264 template< typename T1
, typename T2
>
267 typename
libreoffice_internal::Enable
< OUStringConcat
< T1
, T2
>, ToStringHelper
< T1
>::allowOUStringConcat
&& ToStringHelper
< T2
>::allowOUStringConcat
>::Type
operator+( const T1
& left
, const T2
& right
)
269 return OUStringConcat
< T1
, T2
>( left
, right
);
272 template< typename T1
, typename T2
>
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
)
277 return OUStringConcat
< T1
, T2
>( left
, right
);
280 template< typename T1
, typename T2
>
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
)
285 return OUStringConcat
< T1
, T2
>( left
, right
);
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
293 template< typename T
>
294 StringConcatInvalid( const T
& ) {}
296 template< typename T
>
298 int operator+( const StringConcatInvalid
&, const T
& )
300 rtl_string_unittest_invalid_concat
= true;
301 return 0; // doesn't matter