build fix
[LibreOffice.git] / include / rtl / stringconcat.hxx
blobd5bc4e8eb5009f545b60b6c13ba22500fe8fbd3d
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 #ifdef RTL_STRING_UNITTEST
21 #define rtl rtlunittest
22 #endif
23 namespace rtl
25 #ifdef RTL_STRING_UNITTEST
26 #undef rtl
27 #endif
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
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.
43 /**
44 @internal
46 Helper class for converting a given type to a string representation.
48 template< typename T >
49 struct ToStringHelper
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;
63 inline
64 char* addDataHelper( char* buffer, const char* data, int length )
66 memcpy( buffer, data, length );
67 return buffer + length;
70 inline
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;
77 inline
78 sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, int length )
80 while( length-- > 0 )
81 *buffer++ = *data++;
82 return buffer;
85 inline
86 char* addDataCString( char* buffer, const char* str )
88 while( *str != '\0' )
89 *buffer++ = *str++;
90 return buffer;
93 inline
94 sal_Unicode* addDataUString( sal_Unicode* buffer, const sal_Unicode* str )
96 while( *str != '\0' )
97 *buffer++ = *str++;
98 return buffer;
101 template<>
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;
112 template<>
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;
123 template< int N >
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;
135 template< int N >
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;
163 @internal
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 >
169 struct OStringConcat
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;
184 @internal
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
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;
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 >
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 )
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 >
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 ] )
233 return OStringConcat< T, const char[ N ] >( left, right );
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 )
241 return OStringConcat< const char[ N ], T >( left, right );
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 ] )
249 return OStringConcat< T, char[ N ] >( left, right );
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 )
257 return OStringConcat< char[ N ], T >( left, right );
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 )
265 return OUStringConcat< T1, T2 >( left, right );
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 )
273 return OUStringConcat< T1, T2 >( left, right );
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 )
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 >
293 inline
294 int operator+( const StringConcatInvalid&, const T& )
296 rtl_string_unittest_invalid_concat = true;
297 return 0; // doesn't matter
299 #endif
301 } // namespace
303 #endif
305 #endif