bump product version to 6.3.0.0.beta1
[LibreOffice.git] / include / rtl / stringconcat.hxx
blob220d0a2cfc9e7ec636b979873c33c3339d2fc079
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #ifndef INCLUDED_RTL_STRINGCONCAT_HXX
11 #define INCLUDED_RTL_STRINGCONCAT_HXX
13 #include "rtl/stringutils.hxx"
15 #include <cstddef>
16 #include <string.h>
18 #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
20 #if defined RTL_STRING_UNITTEST_CONCAT
21 extern bool rtl_string_unittest_invalid_concat;
22 #endif
24 #ifdef RTL_STRING_UNITTEST
25 #define rtl rtlunittest
26 #endif
27 namespace rtl
29 #ifdef RTL_STRING_UNITTEST
30 #undef rtl
31 #endif
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
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.
47 /**
48 @internal
50 Helper class for converting a given type to a string representation.
52 template< typename T >
53 struct ToStringHelper
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;
67 inline
68 char* addDataHelper( char* buffer, const char* data, int length )
70 memcpy( buffer, data, length );
71 return buffer + length;
74 inline
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;
81 inline
82 sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, int length )
84 while( length-- > 0 )
85 *buffer++ = *data++;
86 return buffer;
89 inline
90 char* addDataCString( char* buffer, const char* str )
92 while( *str != '\0' )
93 *buffer++ = *str++;
94 return buffer;
97 inline
98 sal_Unicode* addDataUString( sal_Unicode* buffer, const sal_Unicode* str )
100 while( *str != '\0' )
101 *buffer++ = *str++;
102 return buffer;
105 template<>
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;
116 template<>
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;
127 template< int N >
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;
139 template< int N >
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;
167 @internal
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 >
173 struct OStringConcat
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;
188 @internal
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
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;
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 >
224 [[nodiscard]]
225 inline
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 >
233 [[nodiscard]]
234 inline
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 >
241 [[nodiscard]]
242 inline
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 >
249 [[nodiscard]]
250 inline
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 >
257 [[nodiscard]]
258 inline
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 >
265 [[nodiscard]]
266 inline
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 >
273 [[nodiscard]]
274 inline
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 >
281 [[nodiscard]]
282 inline
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 >
297 inline
298 int operator+( const StringConcatInvalid&, const T& )
300 rtl_string_unittest_invalid_concat = true;
301 return 0; // doesn't matter
303 #endif
305 } // namespace
307 #endif
309 #endif