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 sal_Unicode character literal.
41 Can be useful to pass a sal_Unicode constant into an OUString-related
42 function that is optimized for UTF-16 string literal arguments. That is,
45 sal_Unicode const WILDCARD = '%';
47 if (s[i] == WILDCARD) ...
49 if (s.endsWith(OUString(WILDCARD))) ...
53 sal_Unicode const WILDCARD = '%';
55 if (s[i] == WILDCARD) ...
57 if (s.endsWith(OUStringLiteral1(WILDCARD))) ...
59 to avoid creating a temporary OUString instance, and instead pick the
60 endsWith overload actually designed to take an argument of type
63 Instances of OUStringLiteral1 need to be const, as those literal-optimized
64 functions take the literal argument by non-const lvalue reference, for
65 technical reasons. Except with MSVC, at least up to Visual Studio 2013:
66 For one, it fails to take that const-ness into account when trying to match
67 "OUStringLiteral1_ const" against T in a "T & literal" parameter of a
68 function template. But for another, as a language extension, it allows to
69 bind non-const temporary OUStringLiteral1_ instances to non-const lvalue
70 references, but also with a warning that thus needs to be disabled.
72 @since LibreOffice 5.0
74 struct SAL_WARN_UNUSED OUStringLiteral1_
{
75 constexpr OUStringLiteral1_(sal_Unicode theC
): c(theC
) {}
78 #if defined _MSC_VER && _MSC_VER <= 1900 && !defined __clang__
80 using OUStringLiteral1
= OUStringLiteral1_
;
81 #pragma warning(disable: 4239)
83 using OUStringLiteral1
= OUStringLiteral1_
const;
89 namespace libreoffice_internal
92 These templates use SFINAE (Substitution failure is not an error) to help distinguish the various
93 plain C string types: char*, const char*, char[N], const char[N], char[] and const char[].
95 1) Only string literal (i.e. const char[N]) is wanted, not any of the others.
96 In this case it is necessary to distinguish between const char[N] and char[N], as the latter
97 would be automatically converted to the const variant, which is not wanted (not a string literal
98 with known size of the content). In this case ConstCharArrayDetector is used to ensure the function
99 is called only with const char[N] arguments. There's no other plain C string type overload.
100 2) All plain C string types are wanted, and const char[N] needs to be handled differently.
101 In this case const char[N] would match const char* argument type (not exactly sure why, but it's
102 consistent in all of gcc, clang and msvc). Using a template with a reference to const of the type
103 avoids this problem, and CharPtrDetector ensures that the function is called only with char pointer
104 arguments. The const in the argument is necessary to handle the case when something is explicitly
105 cast to const char*. Additionally (non-const) char[N] needs to be handled, but with the reference
106 being const, it would also match const char[N], so another overload with a reference to non-const
107 and NonConstCharArrayDetector are used to ensure the function is called only with (non-const) char[N].
108 Additionally, char[] and const char[] (i.e. size unknown) are rather tricky. Their usage with 'T&' would
109 mean it would be 'char(&)[]', which seems to be invalid. But gcc and clang somehow manage when it is
110 a template. while msvc complains about no conversion from char[] to char[1]. And the reference cannot
111 be avoided, because 'const char[]' as argument type would match also 'const char[N]'
112 So char[] and const char[] should always be used with their contents specified (which automatically
113 turns them into char[N] or const char[N]), or char* and const char* should be used.
116 template< typename T1
, typename T2
= void >
117 struct CharPtrDetector
119 static const bool ok
= false;
121 template< typename T
>
122 struct CharPtrDetector
< const char*, T
>
125 static const bool ok
= true;
127 template< typename T
>
128 struct CharPtrDetector
< char*, T
>
131 static const bool ok
= true;
134 template< typename T1
, typename T2
>
135 struct NonConstCharArrayDetector
138 template< typename T
, int N
>
139 struct NonConstCharArrayDetector
< char[ N
], T
>
143 #ifdef RTL_STRING_UNITTEST
144 // never use, until all compilers handle this
145 template< typename T
>
146 struct NonConstCharArrayDetector
< char[], T
>
150 template< typename T
>
151 struct NonConstCharArrayDetector
< const char[], T
>
157 template< typename T1
, typename T2
= void >
158 struct ConstCharArrayDetector
160 static const bool ok
= false;
162 template< std::size_t N
, typename T
>
163 struct ConstCharArrayDetector
< const char[ N
], T
>
166 static const std::size_t length
= N
- 1;
167 static const bool ok
= true;
168 static bool isValid(char const (& literal
)[N
])
169 { return std::strlen(literal
) == length
; }
170 static char const * toPointer(char const (& literal
)[N
]) { return literal
; }
172 #if defined LIBO_INTERNAL_ONLY
173 template<std::size_t N
, typename T
>
174 struct ConstCharArrayDetector
<sal_Unicode
const [N
], T
> {
176 static constexpr bool const ok
= true;
177 static constexpr std::size_t const length
= N
- 1;
178 static constexpr sal_Unicode
const * toPointer(
179 sal_Unicode
const (& literal
)[N
])
182 template<typename T
> struct ConstCharArrayDetector
<
183 #if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
184 && !defined __clang__
185 OUStringLiteral1_
const,
192 static constexpr bool const ok
= true;
193 static constexpr std::size_t const length
= 1;
194 static constexpr sal_Unicode
const * toPointer(
195 OUStringLiteral1_
const & literal
)
196 { return &literal
.c
; }
200 // this one is used to rule out only const char[N]
201 template< typename T
>
202 struct ExceptConstCharArrayDetector
207 struct ExceptConstCharArrayDetector
< const char[ N
] >
210 #if defined LIBO_INTERNAL_ONLY
211 template<std::size_t N
>
212 struct ExceptConstCharArrayDetector
<sal_Unicode
const[N
]> {};
213 template<> struct ExceptConstCharArrayDetector
<
214 #if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
215 && !defined __clang__
216 OUStringLiteral1_
const
224 // this one is used to rule out only const char[N]
225 // (const will be brought in by 'const T&' in the function call)
226 // msvc needs const char[N] here (not sure whether gcc or msvc
227 // are right, it doesn't matter).
228 template< typename T
>
229 struct ExceptCharArrayDetector
234 struct ExceptCharArrayDetector
< char[ N
] >
238 struct ExceptCharArrayDetector
< const char[ N
] >
241 #if defined LIBO_INTERNAL_ONLY
242 template<std::size_t N
> struct ExceptCharArrayDetector
<sal_Unicode
[N
]> {};
243 template<std::size_t N
> struct ExceptCharArrayDetector
<sal_Unicode
const[N
]> {};
244 template<> struct ExceptCharArrayDetector
<OUStringLiteral1_
> {};
247 template< typename T1
, typename T2
= void >
248 struct SalUnicodePtrDetector
250 static const bool ok
= false;
252 template< typename T
>
253 struct SalUnicodePtrDetector
< const sal_Unicode
*, T
>
256 static const bool ok
= true;
258 template< typename T
>
259 struct SalUnicodePtrDetector
< sal_Unicode
*, T
>
262 static const bool ok
= true;
265 // SFINAE helper class
266 template< typename T
, bool >
271 template< typename T
>
272 struct Enable
< T
, true >
282 #endif // INCLUDED_RTL_STRINGUTILS_HXX
284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */