LibreOffice
LibreOffice 7.1 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#ifndef INCLUDED_RTL_STRINGUTILS_HXX
11#define INCLUDED_RTL_STRINGUTILS_HXX
12
13#include "sal/config.h"
14
15#include <cassert>
16#include <cstddef>
17
18#include "sal/types.h"
19
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
28
29namespace rtl
30{
31
32#ifdef RTL_STRING_UNITTEST
33#undef rtl
34#endif
35
36#if defined LIBO_INTERNAL_ONLY
38
39// A simple wrapper around a single char. Can be useful in string concatenation contexts, like in
40//
41// OString s = ...;
42// char c = ...;
43// s += OStringChar(c);
44//
45struct SAL_WARN_UNUSED OStringChar {
46 constexpr OStringChar(char theC): c(theC) {}
47 template<typename T> OStringChar(T &&) = delete;
48 char const c;
49};
50
93struct 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;
99};
100using OUStringChar = OUStringChar_ const;
101
103#endif
104
105namespace libreoffice_internal
106{
107/*
108These templates use SFINAE (Substitution failure is not an error) to help distinguish the various
109plain C string types: char*, const char*, char[N], const char[N], char[] and const char[].
110There are 2 cases:
1111) 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.
1162) 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].
124Additionally, char[] and const char[] (i.e. size unknown) are rather tricky. Their usage with 'T&' would
125mean it would be 'char(&)[]', which seems to be invalid. But gcc and clang somehow manage when it is
126a template. while msvc complains about no conversion from char[] to char[1]. And the reference cannot
127be avoided, because 'const char[]' as argument type would match also 'const char[N]'
128So char[] and const char[] should always be used with their contents specified (which automatically
129turns them into char[N] or const char[N]), or char* and const char* should be used.
130*/
131struct Dummy {};
132template< typename T1, typename T2 = void >
134{
135 static const bool ok = false;
136};
137template< typename T >
138struct CharPtrDetector< const char*, T >
139{
140 typedef T Type;
141 static const bool ok = true;
142};
143template< typename T >
144struct CharPtrDetector< char*, T >
145{
146 typedef T Type;
147 static const bool ok = true;
148};
149#if defined LIBO_INTERNAL_ONLY
150template<typename T> struct CharPtrDetector<sal_Unicode *, T> { using TypeUtf16 = T; };
151template<typename T> struct CharPtrDetector<sal_Unicode const *, T> { using TypeUtf16 = T; };
152template<typename T> struct CharPtrDetector<sal_Unicode[], T> { using TypeUtf16 = T; };
153template<typename T> struct CharPtrDetector<sal_Unicode const[], T> { using TypeUtf16 = T; };
154#endif
155
156template< typename T1, typename T2 >
158{
159};
160template< typename T, int N >
161struct NonConstCharArrayDetector< char[ N ], T >
162{
163 typedef T Type;
164};
165#ifdef RTL_STRING_UNITTEST
166// never use, until all compilers handle this
167template< typename T >
168struct NonConstCharArrayDetector< char[], T >
169{
170 typedef T Type;
171};
172template< typename T >
173struct NonConstCharArrayDetector< const char[], T >
174{
175 typedef T Type;
176};
177#endif
178#if defined LIBO_INTERNAL_ONLY
179template<typename T, std::size_t N> struct NonConstCharArrayDetector<sal_Unicode[N], T> {
180 using TypeUtf16 = T;
181};
182#endif
183
184template< typename T1, typename T2 = void >
186{
187 static const bool ok = false;
188};
189template< std::size_t N, typename T >
190struct ConstCharArrayDetector< const char[ N ], T >
191{
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;
202 }
203 }
204 return literal[N - 1] == '\0';
205 }
206#if defined LIBO_INTERNAL_ONLY
207 constexpr
208#endif
209 static char const * toPointer(char const (& literal)[N]) { return literal; }
210};
211
212#if defined(__COVERITY__)
213//to silence over zealous warnings that the loop is logically dead
214//for the single char case
215template< typename T >
216struct ConstCharArrayDetector< const char[ 1 ], T >
217{
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';
226 }
227#if defined LIBO_INTERNAL_ONLY
228 constexpr
229#endif
230 static char const * toPointer(char const (& literal)[1]) { return literal; }
231};
232#endif
233
234#if defined LIBO_INTERNAL_ONLY && defined __cpp_char8_t
235template<std::size_t N, typename T>
236struct 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;
244 }
245 }
246 return literal[N - 1] == u8'\0';
247 }
248 static constexpr char const * toPointer(char8_t const (& literal)[N])
249 { return reinterpret_cast<char const *>(literal); }
250};
251#endif
252
253#if defined LIBO_INTERNAL_ONLY
254template<std::size_t N, typename T>
255struct 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;
263 }
264 }
265 return literal[N - 1] == '\0';
266 }
267 static constexpr sal_Unicode const * toPointer(
268 sal_Unicode const (& literal)[N])
269 { return literal; }
270};
271
272#if defined(__COVERITY__)
273//to silence over zealous warnings that the loop is logically dead
274//for the single char case
275template<typename T>
276struct 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';
282 }
283 static constexpr sal_Unicode const * toPointer(
284 sal_Unicode const (& literal)[1])
285 { return literal; }
286};
287#endif
288
289template<typename T> struct ConstCharArrayDetector<
290 OUStringChar,
291 T>
292{
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; }
300};
301#endif
302
303#if defined LIBO_INTERNAL_ONLY && defined RTL_STRING_UNITTEST
304
305// this one is used to rule out only const char[N]
306template< typename T >
307struct ExceptConstCharArrayDetector
308{
309 typedef Dummy Type;
310};
311template< int N >
312struct ExceptConstCharArrayDetector< const char[ N ] >
313{
314};
315template<std::size_t N>
316struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
317template<> struct ExceptConstCharArrayDetector<
318 OUStringChar
319 >
320{};
321
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).
326template< typename T >
327struct ExceptCharArrayDetector
328{
329 typedef Dummy Type;
330};
331template< int N >
332struct ExceptCharArrayDetector< char[ N ] >
333{
334};
335template< int N >
336struct ExceptCharArrayDetector< const char[ N ] >
337{
338};
339template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
340template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
341template<> struct ExceptCharArrayDetector<OUStringChar_> {};
342
343#endif
344
345template< typename T1, typename T2 = void >
347{
348 static const bool ok = false;
349};
350template< typename T >
352{
353 typedef T Type;
354 static const bool ok = true;
355};
356template< typename T >
358{
359 typedef T Type;
360 static const bool ok = true;
361};
362
363// SFINAE helper class
364template< typename T, bool >
365struct Enable
366 {
367 };
368
369template< typename T >
370struct Enable< T, true >
371 {
372 typedef T Type;
373 };
374
375
376} /* Namespace */
377
378} /* Namespace */
379
380#endif // INCLUDED_RTL_STRINGUTILS_HXX
381
382/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 sal_Unicode
Definition: types.h:119
#define SAL_WARN_UNUSED
Annotate classes where a compiler should warn if an instance is unused.
Definition: types.h:558
Definition: unotype.hxx:43
Definition: stringutils.hxx:131
Definition: stringutils.hxx:134
static const bool ok
Definition: stringutils.hxx:135
static const bool ok
Definition: stringutils.hxx:187
static char const * toPointer(char const (&literal)[N])
Definition: stringutils.hxx:209
static bool isValid(char const (&literal)[N])
Definition: stringutils.hxx:198
static const bool ok
Definition: stringutils.hxx:348
Definition: stringutils.hxx:366
T Type
Definition: stringutils.hxx:372