nss: upgrade to release 3.73
[LibreOffice.git] / include / rtl / stringutils.hxx
blob7a1bc606ff5b0ad6379f170745bf0d757d76e135
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_STRINGUTILS_HXX
11 #define INCLUDED_RTL_STRINGUTILS_HXX
13 #include "sal/config.h"
15 #include <cassert>
16 #include <cstddef>
18 #include "sal/types.h"
20 // The unittest uses slightly different code to help check that the proper
21 // calls are made. The class is put into a different namespace to make
22 // sure the compiler generates a different (if generating also non-inline)
23 // copy of the function and does not merge them together. The class
24 // is "brought" into the proper rtl namespace by a typedef below.
25 #ifdef RTL_STRING_UNITTEST
26 #define rtl rtlunittest
27 #endif
29 namespace rtl
32 #ifdef RTL_STRING_UNITTEST
33 #undef rtl
34 #endif
36 #if defined LIBO_INTERNAL_ONLY
37 /// @cond INTERNAL
39 // A simple wrapper around a single char. Can be useful in string concatenation contexts, like in
41 // OString s = ...;
42 // char c = ...;
43 // s += OStringChar(c);
45 struct SAL_WARN_UNUSED OStringChar {
46 constexpr OStringChar(char theC): c(theC) {}
47 template<typename T> OStringChar(T &&) = delete;
48 char const c;
51 /** A simple wrapper around a single sal_Unicode character.
53 Can be useful to pass a sal_Unicode constant into an OUString-related
54 function that is optimized for UTF-16 string literal arguments. That is,
55 instead of
57 sal_Unicode const WILDCARD = '%';
58 ...
59 if (s[i] == WILDCARD) ...
60 ...
61 if (s.endsWith(OUString(WILDCARD))) ...
63 use
65 sal_Unicode const WILDCARD = '%';
66 ...
67 if (s[i] == WILDCARD) ...
68 ...
69 if (s.endsWith(OUStringChar(WILDCARD))) ...
71 to avoid creating a temporary OUString instance, and instead pick the
72 endsWith overload actually designed to take an argument of type
73 sal_Unicode const[N].
75 (Because of the above use case,
76 instances of OUStringChar need to be const, as those literal-optimized
77 functions take the literal argument by non-const lvalue reference, for
78 technical reasons.
80 For actual arrays, it is important to distinguish string literals from other char or sal_Unicode
81 arrays, which may contain junk after the first NUL character or may be non-ASCII in the case of
82 char arrays. This is not so much a concern for single char and sal_Unicode values, where NUL is
83 assumed to always be meant as an actual character.)
85 Can also be useful in string concatenation contexts, like in
87 sal_Unicode const * s = ...;
88 sal_Unicode c = ...;
89 OUString t = s + OUStringChar(c);
91 @since LibreOffice 5.0
93 struct SAL_WARN_UNUSED OUStringChar_ {
94 constexpr OUStringChar_(sal_Unicode theC): c(theC) {}
95 constexpr OUStringChar_(char theC): c(theC) { assert(c <= 0x7F); }
96 template<typename T> OUStringChar_(T &&) = delete;
97 constexpr operator std::u16string_view() const { return {&c, 1}; }
98 sal_Unicode const c;
100 using OUStringChar = OUStringChar_ const;
102 /// @endcond
103 #endif
105 namespace libreoffice_internal
108 These templates use SFINAE (Substitution failure is not an error) to help distinguish the various
109 plain C string types: char*, const char*, char[N], const char[N], char[] and const char[].
110 There are 2 cases:
111 1) Only string literal (i.e. const char[N]) is wanted, not any of the others.
112 In this case it is necessary to distinguish between const char[N] and char[N], as the latter
113 would be automatically converted to the const variant, which is not wanted (not a string literal
114 with known size of the content). In this case ConstCharArrayDetector is used to ensure the function
115 is called only with const char[N] arguments. There's no other plain C string type overload.
116 2) All plain C string types are wanted, and const char[N] needs to be handled differently.
117 In this case const char[N] would match const char* argument type (not exactly sure why, but it's
118 consistent in all of gcc, clang and msvc). Using a template with a reference to const of the type
119 avoids this problem, and CharPtrDetector ensures that the function is called only with char pointer
120 arguments. The const in the argument is necessary to handle the case when something is explicitly
121 cast to const char*. Additionally (non-const) char[N] needs to be handled, but with the reference
122 being const, it would also match const char[N], so another overload with a reference to non-const
123 and NonConstCharArrayDetector are used to ensure the function is called only with (non-const) char[N].
124 Additionally, char[] and const char[] (i.e. size unknown) are rather tricky. Their usage with 'T&' would
125 mean it would be 'char(&)[]', which seems to be invalid. But gcc and clang somehow manage when it is
126 a template. while msvc complains about no conversion from char[] to char[1]. And the reference cannot
127 be avoided, because 'const char[]' as argument type would match also 'const char[N]'
128 So char[] and const char[] should always be used with their contents specified (which automatically
129 turns them into char[N] or const char[N]), or char* and const char* should be used.
131 struct Dummy {};
132 template< typename T1, typename T2 = void >
133 struct CharPtrDetector
135 static const bool ok = false;
137 template< typename T >
138 struct CharPtrDetector< const char*, T >
140 typedef T Type;
141 static const bool ok = true;
143 template< typename T >
144 struct CharPtrDetector< char*, T >
146 typedef T Type;
147 static const bool ok = true;
149 #if defined LIBO_INTERNAL_ONLY
150 template<typename T> struct CharPtrDetector<sal_Unicode *, T> { using TypeUtf16 = T; };
151 template<typename T> struct CharPtrDetector<sal_Unicode const *, T> { using TypeUtf16 = T; };
152 template<typename T> struct CharPtrDetector<sal_Unicode[], T> { using TypeUtf16 = T; };
153 template<typename T> struct CharPtrDetector<sal_Unicode const[], T> { using TypeUtf16 = T; };
154 #endif
156 template< typename T1, typename T2 >
157 struct NonConstCharArrayDetector
160 template< typename T, int N >
161 struct NonConstCharArrayDetector< char[ N ], T >
163 typedef T Type;
165 #ifdef RTL_STRING_UNITTEST
166 // never use, until all compilers handle this
167 template< typename T >
168 struct NonConstCharArrayDetector< char[], T >
170 typedef T Type;
172 template< typename T >
173 struct NonConstCharArrayDetector< const char[], T >
175 typedef T Type;
177 #endif
178 #if defined LIBO_INTERNAL_ONLY
179 template<typename T, std::size_t N> struct NonConstCharArrayDetector<sal_Unicode[N], T> {
180 using TypeUtf16 = T;
182 #endif
184 template< typename T1, typename T2 = void >
185 struct ConstCharArrayDetector
187 static const bool ok = false;
189 template< std::size_t N, typename T >
190 struct ConstCharArrayDetector< const char[ N ], T >
192 typedef T Type;
193 static const std::size_t length = N - 1;
194 static const bool ok = true;
195 #if defined LIBO_INTERNAL_ONLY
196 constexpr
197 #endif
198 static bool isValid(char const (& literal)[N]) {
199 for (std::size_t i = 0; i != N - 1; ++i) {
200 if (literal[i] == '\0') {
201 return false;
204 return literal[N - 1] == '\0';
206 #if defined LIBO_INTERNAL_ONLY
207 constexpr
208 #endif
209 static char const * toPointer(char const (& literal)[N]) { return literal; }
212 #if defined(__COVERITY__)
213 //to silence over zealous warnings that the loop is logically dead
214 //for the single char case
215 template< typename T >
216 struct ConstCharArrayDetector< const char[ 1 ], T >
218 typedef T Type;
219 static const std::size_t length = 0;
220 static const bool ok = true;
221 #if defined LIBO_INTERNAL_ONLY
222 constexpr
223 #endif
224 static bool isValid(char const (& literal)[1]) {
225 return literal[0] == '\0';
227 #if defined LIBO_INTERNAL_ONLY
228 constexpr
229 #endif
230 static char const * toPointer(char const (& literal)[1]) { return literal; }
232 #endif
234 #if defined LIBO_INTERNAL_ONLY && defined __cpp_char8_t
235 template<std::size_t N, typename T>
236 struct ConstCharArrayDetector<char8_t const [N], T> {
237 using Type = T;
238 static constexpr bool const ok = true;
239 static constexpr std::size_t const length = N - 1;
240 static constexpr bool isValid(char8_t const (& literal)[N]) {
241 for (std::size_t i = 0; i != N - 1; ++i) {
242 if (literal[i] == u8'\0') {
243 return false;
246 return literal[N - 1] == u8'\0';
248 static constexpr char const * toPointer(char8_t const (& literal)[N])
249 { return reinterpret_cast<char const *>(literal); }
251 #endif
253 #if defined LIBO_INTERNAL_ONLY
254 template<std::size_t N, typename T>
255 struct ConstCharArrayDetector<sal_Unicode const [N], T> {
256 using TypeUtf16 = T;
257 static constexpr bool const ok = true;
258 static constexpr std::size_t const length = N - 1;
259 static constexpr bool isValid(sal_Unicode const (& literal)[N]) {
260 for (std::size_t i = 0; i != N - 1; ++i) {
261 if (literal[i] == '\0') {
262 return false;
265 return literal[N - 1] == '\0';
267 static constexpr sal_Unicode const * toPointer(
268 sal_Unicode const (& literal)[N])
269 { return literal; }
272 #if defined(__COVERITY__)
273 //to silence over zealous warnings that the loop is logically dead
274 //for the single char case
275 template<typename T>
276 struct ConstCharArrayDetector<sal_Unicode const [1], T> {
277 using TypeUtf16 = T;
278 static constexpr bool const ok = true;
279 static constexpr std::size_t const length = 0;
280 static constexpr bool isValid(sal_Unicode const (& literal)[1]) {
281 return literal[0] == '\0';
283 static constexpr sal_Unicode const * toPointer(
284 sal_Unicode const (& literal)[1])
285 { return literal; }
287 #endif
289 template<typename T> struct ConstCharArrayDetector<
290 OUStringChar,
293 using TypeUtf16 = T;
294 static constexpr bool const ok = true;
295 static constexpr std::size_t const length = 1;
296 static constexpr bool isValid(OUStringChar) { return true; }
297 static constexpr sal_Unicode const * toPointer(
298 OUStringChar_ const & literal)
299 { return &literal.c; }
301 #endif
303 #if defined LIBO_INTERNAL_ONLY && defined RTL_STRING_UNITTEST
305 // this one is used to rule out only const char[N]
306 template< typename T >
307 struct ExceptConstCharArrayDetector
309 typedef Dummy Type;
311 template< int N >
312 struct ExceptConstCharArrayDetector< const char[ N ] >
315 template<std::size_t N>
316 struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
317 template<> struct ExceptConstCharArrayDetector<
318 OUStringChar
322 // this one is used to rule out only const char[N]
323 // (const will be brought in by 'const T&' in the function call)
324 // msvc needs const char[N] here (not sure whether gcc or msvc
325 // are right, it doesn't matter).
326 template< typename T >
327 struct ExceptCharArrayDetector
329 typedef Dummy Type;
331 template< int N >
332 struct ExceptCharArrayDetector< char[ N ] >
335 template< int N >
336 struct ExceptCharArrayDetector< const char[ N ] >
339 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
340 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
341 template<> struct ExceptCharArrayDetector<OUStringChar_> {};
343 #endif
345 template< typename T1, typename T2 = void >
346 struct SalUnicodePtrDetector
348 static const bool ok = false;
350 template< typename T >
351 struct SalUnicodePtrDetector< const sal_Unicode*, T >
353 typedef T Type;
354 static const bool ok = true;
356 template< typename T >
357 struct SalUnicodePtrDetector< sal_Unicode*, T >
359 typedef T Type;
360 static const bool ok = true;
363 // SFINAE helper class
364 template< typename T, bool >
365 struct Enable
369 template< typename T >
370 struct Enable< T, true >
372 typedef T Type;
376 } /* Namespace */
378 } /* Namespace */
380 #endif // INCLUDED_RTL_STRINGUTILS_HXX
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */