LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / include / rtl / stringconcat.hxx
blob51605d0731e991bb3ccfc279986f4e3d825ba124
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 // This file is only included from LIBO_INTERNAL_ONLY
15 #include "rtl/stringutils.hxx"
16 #include "rtl/string.h"
17 #include "rtl/ustring.h"
19 #include <cassert>
20 #include <cstddef>
21 #include <memory>
22 #include <string>
23 #include <string_view>
24 #include <type_traits>
25 #include <utility>
27 #include <string.h>
29 #if defined RTL_STRING_UNITTEST_CONCAT
30 extern bool rtl_string_unittest_invalid_concat;
31 #endif
33 #ifdef RTL_STRING_UNITTEST
34 #define rtl rtlunittest
35 #endif
36 namespace rtl
38 #ifdef RTL_STRING_UNITTEST
39 #undef rtl
40 #endif
43 Implementation of efficient string concatenation.
45 The whole system is built around two basic template classes:
46 - ToStringHelper< T > - for each T it can give the length of the resulting string representation and can write
47 this string representation to a buffer
48 - O(U)StringConcat< T1, T2 > - operator+ now, instead of creating O(U)String object, returns only this helper object,
49 that keeps a reference to both operator+ operands; only when converted to O(U)String it will actually create
50 the resulting string object using ToStringHelper, creating directly the resulting object without any string
51 intermediate objects
52 As all the code is inline methods, it allows for extensive optimization and will usually result in very effective code
53 (even surpassing strlen/strcat and equalling handwritten), while allowing for very easy and intuitive syntax.
56 /**
57 @internal
59 Helper class for converting a given type to a string representation.
61 template< typename T >
62 struct ToStringHelper
64 /// Return length of the string representation of the given object.
65 static std::size_t length( const T& );
66 /// Add 8-bit representation of the given object to the given buffer and return position right after the added data.
67 static char* addData( char* buffer, const T& ) SAL_RETURNS_NONNULL;
68 /// Add Unicode representation of the given object to the given buffer and return position right after the added data.
69 static sal_Unicode* addData( sal_Unicode* buffer, const T& ) SAL_RETURNS_NONNULL;
70 /// If true, T can be used in concatenation resulting in OString.
71 static const bool allowOStringConcat = false;
72 /// If true, T can be used in concatenation resulting in OUString.
73 static const bool allowOUStringConcat = false;
76 inline
77 char* addDataHelper( char* buffer, const char* data, std::size_t length )
79 if (length != 0) {
80 memcpy( buffer, data, length );
82 return buffer + length;
85 inline
86 sal_Unicode* addDataHelper( sal_Unicode* buffer, const sal_Unicode* data, std::size_t length )
88 if (length != 0) {
89 memcpy( buffer, data, length * sizeof( sal_Unicode ));
91 return buffer + length;
94 inline
95 sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, std::size_t length )
97 for( std::size_t i = 0; i != length; ++i )
98 *buffer++ = *data++;
99 return buffer;
102 inline
103 char* addDataCString( char* buffer, const char* str )
105 while( *str != '\0' )
106 *buffer++ = *str++;
107 return buffer;
110 inline
111 sal_Unicode* addDataUString( sal_Unicode* buffer, const sal_Unicode* str )
113 while( *str != '\0' )
114 *buffer++ = *str++;
115 return buffer;
118 template<>
119 struct ToStringHelper< const char* >
121 static std::size_t length( const char* str ) {
122 return str ? strlen( str ) : 0;
124 static char* addData( char* buffer, const char* str ) {
125 return str ? addDataCString( buffer, str ) : buffer;
127 static const bool allowOStringConcat = true;
128 static const bool allowOUStringConcat = false;
131 template<>
132 struct ToStringHelper< char* > : public ToStringHelper< const char* > {};
134 template< std::size_t N >
135 struct ToStringHelper< char[ N ] >
137 static std::size_t length( const char str[ N ] ) {
138 return strlen( str );
140 static char* addData( char* buffer, const char str[ N ] ) { return addDataCString( buffer, str ); }
141 static const bool allowOStringConcat = true;
142 static const bool allowOUStringConcat = false;
145 template< std::size_t N >
146 struct ToStringHelper< const char[ N ] >
148 static std::size_t length( const char str[ N ] ) { (void)str; assert( strlen( str ) == N - 1 ); return N - 1; }
149 static char* addData( char* buffer, const char str[ N ] ) { return addDataHelper( buffer, str, N - 1 ); }
150 static sal_Unicode* addData( sal_Unicode* buffer, const char str[ N ] ) { return addDataLiteral( buffer, str, N - 1 ); }
151 static const bool allowOStringConcat = true;
152 static const bool allowOUStringConcat = true;
155 template<>
156 struct ToStringHelper<OStringChar>
158 static std::size_t length(OStringChar) { return 1; }
159 static char* addData(char* buffer, OStringChar data)
160 { return addDataHelper(buffer, &data.c, 1); }
161 static bool const allowOStringConcat = true;
162 static bool const allowOUStringConcat = false;
165 template<>
166 struct ToStringHelper< const sal_Unicode* >
168 static std::size_t length( const sal_Unicode* str ) {
169 return str ? std::char_traits<char16_t>::length( str ) : 0;
171 static sal_Unicode* addData( sal_Unicode* buffer, const sal_Unicode* str ) {
172 return str ? addDataUString( buffer, str ) : buffer;
174 static const bool allowOStringConcat = false;
175 static const bool allowOUStringConcat = true;
178 template<>
179 struct ToStringHelper< sal_Unicode* > : public ToStringHelper< const sal_Unicode* > {};
181 template<std::size_t N>
182 struct ToStringHelper<sal_Unicode[ N ]>
184 static std::size_t length( const sal_Unicode str[ N ] ) {
185 return std::char_traits<char16_t>::length( str );
187 static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const str[N])
188 { return addDataHelper(buffer, str, N - 1); }
189 static bool const allowOStringConcat = false;
190 static bool const allowOUStringConcat = true;
193 template<std::size_t N>
194 struct ToStringHelper<sal_Unicode const[N]>
196 static std::size_t length( const sal_Unicode str[ N ] ) { (void)str; assert( std::char_traits<char16_t>::length( str ) == N - 1 ); return N - 1; }
197 static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const str[N])
198 { return addDataHelper(buffer, str, N - 1); }
199 static bool const allowOStringConcat = false;
200 static bool const allowOUStringConcat = true;
203 template<>
204 struct ToStringHelper<OUStringChar_>
206 static std::size_t length(OUStringChar_) { return 1; }
207 static sal_Unicode * addData(sal_Unicode * buffer, OUStringChar_ literal)
208 { return addDataHelper(buffer, &literal.c, 1); }
209 static bool const allowOStringConcat = false;
210 static bool const allowOUStringConcat = true;
214 @internal
216 Objects returned by operator+, instead of OString. These objects (possibly recursively) keep a representation of the whole
217 concatenation operation.
219 If you get a build error related to this class, you most probably need to explicitly convert the result of a string
220 concatenation to OString.
222 template< typename T1, typename T2 >
223 struct OStringConcat
225 public:
226 OStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
227 std::size_t length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
228 char* addData( char* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
229 // NOTE here could be functions that would forward to the "real" temporary OString. Note however that e.g. getStr()
230 // is not so simple, as the OString temporary must live long enough (i.e. can't be created here in a function, a wrapper
231 // temporary object containing it must be returned instead).
232 private:
233 const T1& left;
234 const T2& right;
238 @internal
240 Objects returned by operator+, instead of OUString. These objects (possibly recursively) keep a representation of the whole
241 concatenation operation.
243 If you get a build error related to this class, you most probably need to explicitly convert the result of a string
244 concatenation to OUString.
246 template< typename T1, typename T2 >
247 struct OUStringConcat
249 public:
250 OUStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
251 std::size_t length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
252 sal_Unicode* addData( sal_Unicode* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
253 private:
254 const T1& left;
255 const T2& right;
258 template< typename T1, typename T2 >
259 struct ToStringHelper< OStringConcat< T1, T2 > >
261 static std::size_t length( const OStringConcat< T1, T2 >& c ) { return c.length(); }
262 static char* addData( char* buffer, const OStringConcat< T1, T2 >& c ) SAL_RETURNS_NONNULL { return c.addData( buffer ); }
263 static const bool allowOStringConcat = ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat;
264 static const bool allowOUStringConcat = false;
267 template< typename T1, typename T2 >
268 struct ToStringHelper< OUStringConcat< T1, T2 > >
270 static std::size_t length( const OUStringConcat< T1, T2 >& c ) { return c.length(); }
271 static sal_Unicode* addData( sal_Unicode* buffer, const OUStringConcat< T1, T2 >& c ) SAL_RETURNS_NONNULL { return c.addData( buffer ); }
272 static const bool allowOStringConcat = false;
273 static const bool allowOUStringConcat = ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat;
276 template< typename T1, typename T2 >
277 [[nodiscard]]
278 inline
279 typename std::enable_if_t< ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat, OStringConcat< T1, T2 > > operator+( const T1& left, const T2& right )
281 return OStringConcat< T1, T2 >( left, right );
284 // char[N] and const char[N] need to be done explicitly, otherwise the compiler likes to treat them the same way for some reason
285 template< typename T, std::size_t N >
286 [[nodiscard]]
287 inline
288 typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< T, const char[ N ] > > operator+( const T& left, const char (&right)[ N ] )
290 return OStringConcat< T, const char[ N ] >( left, right );
293 template< typename T, std::size_t N >
294 [[nodiscard]]
295 inline
296 typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< const char[ N ], T > > operator+( const char (&left)[ N ], const T& right )
298 return OStringConcat< const char[ N ], T >( left, right );
301 template< typename T, std::size_t N >
302 [[nodiscard]]
303 inline
304 typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< T, char[ N ] > > operator+( const T& left, char (&right)[ N ] )
306 return OStringConcat< T, char[ N ] >( left, right );
309 template< typename T, std::size_t N >
310 [[nodiscard]]
311 inline
312 typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< char[ N ], T > > operator+( char (&left)[ N ], const T& right )
314 return OStringConcat< char[ N ], T >( left, right );
317 template< typename T1, typename T2 >
318 [[nodiscard]]
319 inline
320 typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat, OUStringConcat< T1, T2 > > operator+( const T1& left, const T2& right )
322 return OUStringConcat< T1, T2 >( left, right );
325 template< typename T1, typename T2 >
326 [[nodiscard]]
327 inline
328 typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && libreoffice_internal::ConstCharArrayDetector< T1, void >::ok, OUStringConcat< T1, T2 > > operator+( T1& left, const T2& right )
330 return OUStringConcat< T1, T2 >( left, right );
333 template< typename T1, typename T2 >
334 [[nodiscard]]
335 inline
336 typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && libreoffice_internal::ConstCharArrayDetector< T2, void >::ok, OUStringConcat< T1, T2 > > operator+( const T1& left, T2& right )
338 return OUStringConcat< T1, T2 >( left, right );
341 #ifdef RTL_STRING_UNITTEST_CONCAT
342 // Special overload to catch the remaining invalid combinations. The helper struct must
343 // be used to make this operator+ overload a worse choice than all the existing overloads above.
344 struct StringConcatInvalid
346 template< typename T >
347 StringConcatInvalid( const T& ) {}
349 template< typename T >
350 inline
351 int operator+( const StringConcatInvalid&, const T& )
353 rtl_string_unittest_invalid_concat = true;
354 return 0; // doesn't matter
356 #endif
358 // Lightweight alternative to OString when a (temporary) object is needed to hold an OStringConcat
359 // result that can then be used as a std::string_view:
360 class OStringConcatenation {
361 public:
362 template<typename T1, typename T2>
363 explicit OStringConcatenation(OStringConcat<T1, T2> const & c):
364 length_(c.length()),
365 buffer_(new char[length_])
367 auto const end = c.addData(buffer_.get());
368 assert(end == buffer_.get() + length_); (void)end;
371 operator std::string_view() const { return {buffer_.get(), length_}; }
373 private:
374 std::size_t length_;
375 std::unique_ptr<char[]> buffer_;
378 // Lightweight alternative to OUString when a (temporary) object is needed to hold an
379 // OUStringConcat result that can then be used as a std::u16string_view:
380 class OUStringConcatenation {
381 public:
382 template<typename T1, typename T2>
383 explicit OUStringConcatenation(OUStringConcat<T1, T2> const & c):
384 length_(c.length()),
385 buffer_(new char16_t[length_])
387 auto const end = c.addData(buffer_.get());
388 assert(end == buffer_.get() + length_); (void)end;
391 operator std::u16string_view() const { return {buffer_.get(), length_}; }
393 private:
394 std::size_t length_;
395 std::unique_ptr<char16_t[]> buffer_;
399 @internal
401 Objects returned by OString::number(), instead of OString. These objects keep a representation of the number() operation.
403 If you get a build error related to this class, you most probably need to explicitly convert the result of calling
404 OString::number() to OString.
406 template< typename T >
407 struct OStringNumber;
409 template <typename Number, std::size_t nBufSize> struct OStringNumberBase
411 using number_t = Number;
412 // OString::number(value).getStr() is very common (writing xml code, ...),
413 // so implement that one also here, to avoid having to explicitly to convert
414 // to OString in all such places
415 const char * getStr() const SAL_RETURNS_NONNULL { return buf; }
416 OStringNumber<number_t>&& toAsciiUpperCase()
418 rtl_str_toAsciiUpperCase_WithLength(buf, length);
419 return std::move(*static_cast<OStringNumber<number_t>*>(this));
421 operator std::string_view() const { return std::string_view(buf, length); }
422 char buf[nBufSize];
423 sal_Int32 length;
426 template<>
427 struct OStringNumber< int >
428 : public OStringNumberBase<int, RTL_STR_MAX_VALUEOFINT32>
430 OStringNumber(number_t i, sal_Int16 radix) { length = rtl_str_valueOfInt32(buf, i, radix); }
433 template<>
434 struct OStringNumber< long long >
435 : public OStringNumberBase<long long, RTL_STR_MAX_VALUEOFINT64>
437 OStringNumber(number_t i, sal_Int16 radix) { length = rtl_str_valueOfInt64(buf, i, radix); }
440 template<>
441 struct OStringNumber< unsigned long long >
442 : public OStringNumberBase<unsigned long long, RTL_STR_MAX_VALUEOFUINT64>
444 OStringNumber(number_t i, sal_Int16 radix) { length = rtl_str_valueOfUInt64(buf, i, radix); }
447 template<>
448 struct OStringNumber< float >
449 : public OStringNumberBase<float, RTL_STR_MAX_VALUEOFFLOAT>
451 OStringNumber(number_t f) { length = rtl_str_valueOfFloat(buf, f); }
454 template<>
455 struct OStringNumber< double >
456 : public OStringNumberBase<double, RTL_STR_MAX_VALUEOFDOUBLE>
458 OStringNumber(number_t d) { length = rtl_str_valueOfDouble(buf, d); }
461 template< typename T >
462 struct ToStringHelper< OStringNumber< T > >
464 static std::size_t length( const OStringNumber< T >& n ) { return n.length; }
465 static char* addData( char* buffer, const OStringNumber< T >& n ) SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
466 static const bool allowOStringConcat = true;
467 static const bool allowOUStringConcat = false;
472 @internal
474 Objects returned by OUString::number(), instead of OUString. These objects keep a representation of the number() operation.
476 If you get a build error related to this class, you most probably need to explicitly convert the result of calling
477 OUString::number() to OUString.
479 template< typename T >
480 struct OUStringNumber;
482 template <typename Number, std::size_t nBufSize> struct OUStringNumberBase
484 using number_t = Number;
485 OUStringNumber<number_t>&& toAsciiUpperCase()
487 rtl_ustr_toAsciiUpperCase_WithLength(buf, length);
488 return std::move(*static_cast<OUStringNumber<number_t>*>(this));
490 operator std::u16string_view() const { return std::u16string_view(buf, length); }
491 sal_Unicode buf[nBufSize];
492 sal_Int32 length;
495 template<>
496 struct OUStringNumber< int >
497 : public OUStringNumberBase<int, RTL_USTR_MAX_VALUEOFINT32>
499 OUStringNumber(number_t i, sal_Int16 radix) { length = rtl_ustr_valueOfInt32(buf, i, radix); }
502 template<>
503 struct OUStringNumber< long long >
504 : public OUStringNumberBase<long long, RTL_USTR_MAX_VALUEOFINT64>
506 OUStringNumber(number_t i, sal_Int16 radix) { length = rtl_ustr_valueOfInt64(buf, i, radix); }
509 template<>
510 struct OUStringNumber< unsigned long long >
511 : public OUStringNumberBase<unsigned long long, RTL_USTR_MAX_VALUEOFUINT64>
513 OUStringNumber(number_t i, sal_Int16 radix) { length = rtl_ustr_valueOfUInt64(buf, i, radix); }
516 template<>
517 struct OUStringNumber< float >
518 : public OUStringNumberBase<float, RTL_USTR_MAX_VALUEOFFLOAT>
520 OUStringNumber(number_t f) { length = rtl_ustr_valueOfFloat(buf, f); }
523 template<>
524 struct OUStringNumber< double >
525 : public OUStringNumberBase<double, RTL_USTR_MAX_VALUEOFDOUBLE>
527 OUStringNumber(number_t d) { length = rtl_ustr_valueOfDouble(buf, d); }
530 template< typename T >
531 struct ToStringHelper< OUStringNumber< T > >
533 static std::size_t length( const OUStringNumber< T >& n ) { return n.length; }
534 static sal_Unicode* addData( sal_Unicode* buffer, const OUStringNumber< T >& n ) SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
535 static const bool allowOStringConcat = false;
536 static const bool allowOUStringConcat = true;
539 template<> struct ToStringHelper<std::string_view> {
540 static constexpr std::size_t length(std::string_view s) { return s.size(); }
542 static char * addData(char * buffer, std::string_view s) SAL_RETURNS_NONNULL
543 { return addDataHelper(buffer, s.data(), s.size()); }
545 static constexpr bool allowOStringConcat = true;
546 static constexpr bool allowOUStringConcat = false;
549 template<> struct ToStringHelper<std::u16string_view> {
550 static constexpr std::size_t length(std::u16string_view s) { return s.size(); }
552 static sal_Unicode * addData(sal_Unicode * buffer, std::u16string_view s) SAL_RETURNS_NONNULL
553 { return addDataHelper(buffer, s.data(), s.size()); }
555 static constexpr bool allowOStringConcat = false;
556 static constexpr bool allowOUStringConcat = true;
559 // An internal marker class used by OString::Concat:
560 struct OStringConcatMarker {};
562 template<> struct ToStringHelper<OStringConcatMarker> {
563 static constexpr std::size_t length(OStringConcatMarker) { return 0; }
565 static constexpr char * addData(char * buffer, OStringConcatMarker) SAL_RETURNS_NONNULL
566 { return buffer; }
568 static constexpr bool allowOStringConcat = true;
569 static constexpr bool allowOUStringConcat = false;
572 // An internal marker class used by OUString::Concat:
573 struct OUStringConcatMarker {};
575 template<> struct ToStringHelper<OUStringConcatMarker> {
576 static constexpr std::size_t length(OUStringConcatMarker) { return 0; }
578 static constexpr sal_Unicode * addData(sal_Unicode * buffer, OUStringConcatMarker)
579 SAL_RETURNS_NONNULL
580 { return buffer; }
582 static constexpr bool allowOStringConcat = false;
583 static constexpr bool allowOUStringConcat = true;
586 } // namespace
588 #endif