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_STRINGUTILS_HXX
11 #define INCLUDED_RTL_STRINGUTILS_HXX
13 #include "sal/config.h"
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
32 #ifdef RTL_STRING_UNITTEST
36 #if defined LIBO_INTERNAL_ONLY
39 // A simple wrapper around a single char. Can be useful in string concatenation contexts, like in
43 // s += OStringChar(c);
45 struct SAL_WARN_UNUSED OStringChar
{
46 constexpr OStringChar(char theC
): c(theC
) {}
47 template<typename T
> OStringChar(T
&&) = delete;
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,
57 sal_Unicode const WILDCARD = '%';
59 if (s[i] == WILDCARD) ...
61 if (s.endsWith(OUString(WILDCARD))) ...
65 sal_Unicode const WILDCARD = '%';
67 if (s[i] == WILDCARD) ...
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
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
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 = ...;
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}; }
100 using OUStringChar
= OUStringChar_
const;
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[].
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.
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
>
141 static const bool ok
= true;
143 template< typename T
>
144 struct CharPtrDetector
< char*, T
>
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
; };
156 template< typename T1
, typename T2
>
157 struct NonConstCharArrayDetector
160 template< typename T
, int N
>
161 struct NonConstCharArrayDetector
< char[ N
], T
>
165 #ifdef RTL_STRING_UNITTEST
166 // never use, until all compilers handle this
167 template< typename T
>
168 struct NonConstCharArrayDetector
< char[], T
>
172 template< typename T
>
173 struct NonConstCharArrayDetector
< const char[], T
>
178 #if defined LIBO_INTERNAL_ONLY
179 template<typename T
, std::size_t N
> struct NonConstCharArrayDetector
<sal_Unicode
[N
], T
> {
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
>
193 static const std::size_t length
= N
- 1;
194 static const bool ok
= true;
195 #if defined LIBO_INTERNAL_ONLY
198 static bool isValid(char const (& literal
)[N
]) {
199 for (std::size_t i
= 0; i
!= N
- 1; ++i
) {
200 if (literal
[i
] == '\0') {
204 return literal
[N
- 1] == '\0';
206 #if defined LIBO_INTERNAL_ONLY
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
>
219 static const std::size_t length
= 0;
220 static const bool ok
= true;
221 #if defined LIBO_INTERNAL_ONLY
224 static bool isValid(char const (& literal
)[1]) {
225 return literal
[0] == '\0';
227 #if defined LIBO_INTERNAL_ONLY
230 static char const * toPointer(char const (& literal
)[1]) { return literal
; }
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
> {
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') {
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
); }
253 #if defined LIBO_INTERNAL_ONLY
254 template<std::size_t N
, typename T
>
255 struct ConstCharArrayDetector
<sal_Unicode
const [N
], 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') {
265 return literal
[N
- 1] == '\0';
267 static constexpr sal_Unicode
const * toPointer(
268 sal_Unicode
const (& literal
)[N
])
272 #if defined(__COVERITY__)
273 //to silence over zealous warnings that the loop is logically dead
274 //for the single char case
276 struct ConstCharArrayDetector
<sal_Unicode
const [1], 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])
289 template<typename T
> struct ConstCharArrayDetector
<
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
; }
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
312 struct ExceptConstCharArrayDetector
< const char[ N
] >
315 template<std::size_t N
>
316 struct ExceptConstCharArrayDetector
<sal_Unicode
const[N
]> {};
317 template<> struct ExceptConstCharArrayDetector
<
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
332 struct ExceptCharArrayDetector
< char[ 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_
> {};
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
>
354 static const bool ok
= true;
356 template< typename T
>
357 struct SalUnicodePtrDetector
< sal_Unicode
*, T
>
360 static const bool ok
= true;
363 // SFINAE helper class
364 template< typename T
, bool >
369 template< typename T
>
370 struct Enable
< T
, true >
380 #endif // INCLUDED_RTL_STRINGUTILS_HXX
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */