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