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