LibreOffice
LibreOffice 24.8 SDK C/C++ API Reference
Loading...
Searching...
No Matches
stringutils.hxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10/*
11 * This file is part of LibreOffice published API.
12 */
13
14#ifndef INCLUDED_RTL_STRINGUTILS_HXX
15#define INCLUDED_RTL_STRINGUTILS_HXX
16
17#include "sal/config.h"
18
19#include <cassert>
20#include <cstddef>
21
22#if defined LIBO_INTERNAL_ONLY
23#include <type_traits>
24#endif
25
26#include "sal/types.h"
27
28// The unittest uses slightly different code to help check that the proper
29// calls are made. The class is put into a different namespace to make
30// sure the compiler generates a different (if generating also non-inline)
31// copy of the function and does not merge them together. The class
32// is "brought" into the proper rtl namespace by a typedef below.
33#ifdef RTL_STRING_UNITTEST
34#define rtl rtlunittest
35#endif
36
37namespace rtl
38{
39
40#ifdef RTL_STRING_UNITTEST
41#undef rtl
42#endif
43
44#if defined LIBO_INTERNAL_ONLY
46
47// A simple wrapper around a single char. Can be useful in string concatenation contexts, like in
48//
49// OString s = ...;
50// char c = ...;
51// s += OStringChar(c);
52//
53struct SAL_WARN_UNUSED OStringChar {
54 constexpr OStringChar(char theC): c(theC) {}
55 template<typename T> OStringChar(
56 T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_enum_v<T>, int> = 0) = delete;
57 constexpr operator std::string_view() const { return {&c, 1}; }
58 char const c;
59};
60
103struct SAL_WARN_UNUSED OUStringChar_ {
104 constexpr OUStringChar_(sal_Unicode theC): c(theC) {}
105 constexpr OUStringChar_(char theC): c(theC) { assert(c <= 0x7F); }
106 template<typename T> OUStringChar_(
107 T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_enum_v<T>, int> = 0) = delete;
108 constexpr operator std::u16string_view() const { return {&c, 1}; }
109 sal_Unicode const c;
110};
111using OUStringChar = OUStringChar_ const;
112
114#endif
115
116namespace libreoffice_internal
117{
118/*
119These templates use SFINAE (Substitution failure is not an error) to help distinguish the various
120plain C string types: char*, const char*, char[N], const char[N], char[] and const char[].
121There are 2 cases:
1221) Only string literal (i.e. const char[N]) is wanted, not any of the others.
123 In this case it is necessary to distinguish between const char[N] and char[N], as the latter
124 would be automatically converted to the const variant, which is not wanted (not a string literal
125 with known size of the content). In this case ConstCharArrayDetector is used to ensure the function
126 is called only with const char[N] arguments. There's no other plain C string type overload.
127 (Note that OUStringChar is also covered by ConstCharArrayDetector's TypeUtf16 check, but
128 provides a pointer to a string that is not NUL-terminated, unlike the char16_t const[N] arrays
129 normally covered by that check, and which are assumed to represent NUL-terminated string
130 literals.)
1312) All plain C string types are wanted, and const char[N] needs to be handled differently.
132 In this case const char[N] would match const char* argument type (not exactly sure why, but it's
133 consistent in all of gcc, clang and msvc). Using a template with a reference to const of the type
134 avoids this problem, and CharPtrDetector ensures that the function is called only with char pointer
135 arguments. The const in the argument is necessary to handle the case when something is explicitly
136 cast to const char*. Additionally (non-const) char[N] needs to be handled, but with the reference
137 being const, it would also match const char[N], so another overload with a reference to non-const
138 and NonConstCharArrayDetector are used to ensure the function is called only with (non-const) char[N].
139Additionally, char[] and const char[] (i.e. size unknown) are rather tricky. Their usage with 'T&' would
140mean it would be 'char(&)[]', which seems to be invalid. But gcc and clang somehow manage when it is
141a template. while msvc complains about no conversion from char[] to char[1]. And the reference cannot
142be avoided, because 'const char[]' as argument type would match also 'const char[N]'
143So char[] and const char[] should always be used with their contents specified (which automatically
144turns them into char[N] or const char[N]), or char* and const char* should be used.
145*/
146struct Dummy {};
147template< typename T1, typename T2 = void >
149{
150 static const bool ok = false;
151};
152template< typename T >
153struct CharPtrDetector< const char*, T >
154{
155 typedef T Type;
156 static const bool ok = true;
157};
158template< typename T >
159struct CharPtrDetector< char*, T >
160{
161 typedef T Type;
162 static const bool ok = true;
163};
164#if defined LIBO_INTERNAL_ONLY
165template<typename T> struct CharPtrDetector<sal_Unicode *, T> { using TypeUtf16 = T; };
166template<typename T> struct CharPtrDetector<sal_Unicode const *, T> { using TypeUtf16 = T; };
167template<typename T> struct CharPtrDetector<sal_Unicode[], T> { using TypeUtf16 = T; };
168template<typename T> struct CharPtrDetector<sal_Unicode const[], T> { using TypeUtf16 = T; };
169#endif
170
171template< typename T1, typename T2 >
175template< typename T, int N >
176struct NonConstCharArrayDetector< char[ N ], T >
177{
178 typedef T Type;
179};
180#ifdef RTL_STRING_UNITTEST
181// never use, until all compilers handle this
182template< typename T >
183struct NonConstCharArrayDetector< char[], T >
184{
185 typedef T Type;
186};
187template< typename T >
188struct NonConstCharArrayDetector< const char[], T >
189{
190 typedef T Type;
191};
192#endif
193#if defined LIBO_INTERNAL_ONLY
194template<typename T, std::size_t N> struct NonConstCharArrayDetector<sal_Unicode[N], T> {
195 using TypeUtf16 = T;
196};
197#endif
198
199template< typename T1, typename T2 = void >
201{
202 static const bool ok = false;
203};
204template< std::size_t N, typename T >
205struct ConstCharArrayDetector< const char[ N ], T >
206{
207 typedef T Type;
208 static const std::size_t length = N - 1;
209 static const bool ok = true;
210#if defined LIBO_INTERNAL_ONLY
211 constexpr
212#endif
213 static bool isValid(char const (& literal)[N]) {
214 for (std::size_t i = 0; i != N - 1; ++i) {
215 if (literal[i] == '\0') {
216 return false;
217 }
218 }
219 return literal[N - 1] == '\0';
220 }
221#if defined LIBO_INTERNAL_ONLY
222 constexpr
223#endif
224 static char const * toPointer(char const (& literal)[N]) { return literal; }
225};
226
227#if defined(__COVERITY__)
228//to silence over zealous warnings that the loop is logically dead
229//for the single char case
230template< typename T >
231struct ConstCharArrayDetector< const char[ 1 ], T >
232{
233 typedef T Type;
234 static const std::size_t length = 0;
235 static const bool ok = true;
236#if defined LIBO_INTERNAL_ONLY
237 constexpr
238#endif
239 static bool isValid(char const (& literal)[1]) {
240 return literal[0] == '\0';
241 }
242#if defined LIBO_INTERNAL_ONLY
243 constexpr
244#endif
245 static char const * toPointer(char const (& literal)[1]) { return literal; }
246};
247#endif
248
249#if defined LIBO_INTERNAL_ONLY \
250 && !(defined _MSC_VER && _MSC_VER >= 1930 && _MSC_VER <= 1939 && defined _MANAGED)
251template<std::size_t N, typename T>
252struct ConstCharArrayDetector<char8_t const [N], T> {
253 using Type = T;
254 static constexpr bool const ok = true;
255 static constexpr std::size_t const length = N - 1;
256 static constexpr bool isValid(char8_t const (& literal)[N]) {
257 for (std::size_t i = 0; i != N - 1; ++i) {
258 if (literal[i] == u8'\0') {
259 return false;
260 }
261 }
262 return literal[N - 1] == u8'\0';
263 }
264 static constexpr char const * toPointer(char8_t const (& literal)[N])
265 { return reinterpret_cast<char const *>(literal); }
266};
267#endif
268
269#if defined LIBO_INTERNAL_ONLY
270template<std::size_t N, typename T>
271struct ConstCharArrayDetector<sal_Unicode const [N], T> {
272 using TypeUtf16 = T;
273 static constexpr bool const ok = true;
274 static constexpr std::size_t const length = N - 1;
275 static constexpr bool isValid(sal_Unicode const (& literal)[N]) {
276 for (std::size_t i = 0; i != N - 1; ++i) {
277 if (literal[i] == '\0') {
278 return false;
279 }
280 }
281 return literal[N - 1] == '\0';
282 }
283 static constexpr sal_Unicode const * toPointer(
284 sal_Unicode const (& literal)[N])
285 { return literal; }
286};
287
288#if defined(__COVERITY__)
289//to silence over zealous warnings that the loop is logically dead
290//for the single char case
291template<typename T>
292struct ConstCharArrayDetector<sal_Unicode const [1], T> {
293 using TypeUtf16 = T;
294 static constexpr bool const ok = true;
295 static constexpr std::size_t const length = 0;
296 static constexpr bool isValid(sal_Unicode const (& literal)[1]) {
297 return literal[0] == '\0';
298 }
299 static constexpr sal_Unicode const * toPointer(
300 sal_Unicode const (& literal)[1])
301 { return literal; }
302};
303#endif
304
305template<typename T> struct ConstCharArrayDetector<
306 OUStringChar,
307 T>
308{
309 using TypeUtf16 = T;
310 static constexpr bool const ok = true;
311 static constexpr std::size_t const length = 1;
312 static constexpr bool isValid(OUStringChar) { return true; }
313 static constexpr sal_Unicode const * toPointer(
314 OUStringChar_ const & literal)
315 { return &literal.c; }
316};
317#endif
318
319#if defined LIBO_INTERNAL_ONLY && defined RTL_STRING_UNITTEST
320
321// this one is used to rule out only const char[N]
322template< typename T >
323struct ExceptConstCharArrayDetector
324{
325 typedef Dummy Type;
326};
327template< int N >
328struct ExceptConstCharArrayDetector< const char[ N ] >
329{
330};
331template<std::size_t N>
332struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
333template<> struct ExceptConstCharArrayDetector<
334 OUStringChar
335 >
336{};
337
338// this one is used to rule out only const char[N]
339// (const will be brought in by 'const T&' in the function call)
340// msvc needs const char[N] here (not sure whether gcc or msvc
341// are right, it doesn't matter).
342template< typename T >
343struct ExceptCharArrayDetector
344{
345 typedef Dummy Type;
346};
347template< int N >
348struct ExceptCharArrayDetector< char[ N ] >
349{
350};
351template< int N >
352struct ExceptCharArrayDetector< const char[ N ] >
353{
354};
355template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
356template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
357template<> struct ExceptCharArrayDetector<OUStringChar_> {};
358
359#endif
360
361template< typename T1, typename T2 = void >
363{
364 static const bool ok = false;
365};
366template< typename T >
368{
369 typedef T Type;
370 static const bool ok = true;
371};
372template< typename T >
374{
375 typedef T Type;
376 static const bool ok = true;
377};
378
379// SFINAE helper class
380template< typename T, bool >
381struct Enable
382 {
383 };
384
385template< typename T >
386struct Enable< T, true >
387 {
388 typedef T Type;
389 };
390
391
392} /* Namespace */
393
394} /* Namespace */
395
396#endif // INCLUDED_RTL_STRINGUTILS_HXX
397
398/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 sal_Unicode
Definition types.h:123
#define SAL_WARN_UNUSED
Annotate classes where a compiler should warn if an instance is unused.
Definition types.h:611
Definition bootstrap.hxx:34
Definition stringutils.hxx:146
Definition stringutils.hxx:149
static const bool ok
Definition stringutils.hxx:150
static const bool ok
Definition stringutils.hxx:202
static char const * toPointer(char const (&literal)[N])
Definition stringutils.hxx:224
static bool isValid(char const (&literal)[N])
Definition stringutils.hxx:213
static const bool ok
Definition stringutils.hxx:364
Definition stringutils.hxx:382
T Type
Definition stringutils.hxx:388