LibreOffice LibreOffice 26.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
39 namespace 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//
55 struct 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
105 struct 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};
113 using OUStringChar = OUStringChar_ const;
114
116#endif
117
118 namespace libreoffice_internal
119{
120#if defined LIBO_INTERNAL_ONLY
121 template <typename I, std::enable_if_t<
122 std::is_integral_v<I> && std::is_signed_v<I>,
123 int> = 0>
124 constexpr 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
131 template <typename I, std::enable_if_t<
132 std::is_integral_v<I> && std::is_unsigned_v<I>,
133 int> = 0>
134 constexpr 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
141 template <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/*
151 These templates use SFINAE (Substitution failure is not an error) to help distinguish the various
152 plain C string types: char*, const char*, char[N], const char[N], char[] and const char[].
153 There are 2 cases:
154 1) 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.)
163 2) 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].
171 Additionally, char[] and const char[] (i.e. size unknown) are rather tricky. Their usage with 'T&' would
172 mean it would be 'char(&)[]', which seems to be invalid. But gcc and clang somehow manage when it is
173 a template. while msvc complains about no conversion from char[] to char[1]. And the reference cannot
174 be avoided, because 'const char[]' as argument type would match also 'const char[N]'
175 So char[] and const char[] should always be used with their contents specified (which automatically
176 turns them into char[N] or const char[N]), or char* and const char* should be used.
177*/
178 struct Dummy {};
179 template< typename T1, typename T2 = void >
180 struct CharPtrDetector
181{
182 static const bool ok = false;
183};
184 template< typename T >
185 struct CharPtrDetector< const char*, T >
186{
187 typedef T Type;
188 static const bool ok = true;
189};
190 template< typename T >
191 struct CharPtrDetector< char*, T >
192{
193 typedef T Type;
194 static const bool ok = true;
195};
196#if defined LIBO_INTERNAL_ONLY
197 template<typename T> struct CharPtrDetector<sal_Unicode *, T> { using TypeUtf16 = T; };
198 template<typename T> struct CharPtrDetector<sal_Unicode const *, T> { using TypeUtf16 = T; };
199 template<typename T> struct CharPtrDetector<sal_Unicode[], T> { using TypeUtf16 = T; };
200 template<typename T> struct CharPtrDetector<sal_Unicode const[], T> { using TypeUtf16 = T; };
201#endif
202
203 template< typename T1, typename T2 >
204 struct NonConstCharArrayDetector
205{
206};
207 template< typename T, int N >
208 struct NonConstCharArrayDetector< char[ N ], T >
209{
210 typedef T Type;
211};
212#ifdef RTL_STRING_UNITTEST
213// never use, until all compilers handle this
214 template< typename T >
215 struct NonConstCharArrayDetector< char[], T >
216{
217 typedef T Type;
218};
219 template< typename T >
220 struct NonConstCharArrayDetector< const char[], T >
221{
222 typedef T Type;
223};
224#endif
225#if defined LIBO_INTERNAL_ONLY
226 template<typename T, std::size_t N> struct NonConstCharArrayDetector<sal_Unicode[N], T> {
227 using TypeUtf16 = T;
228};
229#endif
230
231 template< typename T1, typename T2 = void >
232 struct ConstCharArrayDetector
233{
234 static const bool ok = false;
235};
236 template< std::size_t N, typename T >
237 struct 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__ <= 2024
260//to silence over zealous warnings that the loop is logically dead
261//for the single char case
262 template< typename T >
263 struct 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)
283 template<std::size_t N, typename T>
284 struct 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
302 template<std::size_t N, typename T>
303 struct 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 template<typename T> struct ConstCharArrayDetector<
321 OUStringChar,
322 T>
323{
324 using TypeUtf16 = T;
325 static constexpr bool const ok = true;
326 static constexpr std::size_t const length = 1;
327 static constexpr bool isValid(OUStringChar) { return true; }
328 static constexpr sal_Unicode const * toPointer(
329 OUStringChar_ const & literal)
330 { return &literal.c; }
331};
332#endif
333
334#if defined LIBO_INTERNAL_ONLY && defined RTL_STRING_UNITTEST
335
336// this one is used to rule out only const char[N]
337 template< typename T >
338 struct ExceptConstCharArrayDetector
339{
340 typedef Dummy Type;
341};
342 template< int N >
343 struct ExceptConstCharArrayDetector< const char[ N ] >
344{
345};
346 template<std::size_t N>
347 struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
348 template<> struct ExceptConstCharArrayDetector<
349 OUStringChar
350 >
351{};
352
353// this one is used to rule out only const char[N]
354// (const will be brought in by 'const T&' in the function call)
355// msvc needs const char[N] here (not sure whether gcc or msvc
356// are right, it doesn't matter).
357 template< typename T >
358 struct ExceptCharArrayDetector
359{
360 typedef Dummy Type;
361};
362 template< int N >
363 struct ExceptCharArrayDetector< char[ N ] >
364{
365};
366 template< int N >
367 struct ExceptCharArrayDetector< const char[ N ] >
368{
369};
370 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
371 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
372 template<> struct ExceptCharArrayDetector<OUStringChar_> {};
373
374#endif
375
376 template< typename T1, typename T2 = void >
377 struct SalUnicodePtrDetector
378{
379 static const bool ok = false;
380};
381 template< typename T >
382 struct SalUnicodePtrDetector< const sal_Unicode*, T >
383{
384 typedef T Type;
385 static const bool ok = true;
386};
387 template< typename T >
388 struct SalUnicodePtrDetector< sal_Unicode*, T >
389{
390 typedef T Type;
391 static const bool ok = true;
392};
393
394// SFINAE helper class
395 template< typename T, bool >
396 struct Enable
397 {
398 };
399
400 template< typename T >
401 struct Enable< T, true >
402 {
403 typedef T Type;
404 };
405
406
407} /* Namespace */
408
409} /* Namespace */
410
411#endif // INCLUDED_RTL_STRINGUTILS_HXX
412
413/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
types.h
sal_Unicode
sal_uInt16 sal_Unicode
Definition types.h:123
SAL_WARN_UNUSED
#define SAL_WARN_UNUSED
Annotate classes where a compiler should warn if an instance is unused.
Definition types.h:611
config.h
rtl
Definition bootstrap.hxx:34
rtl::libreoffice_internal
Definition stringutils.hxx:119
rtl::libreoffice_internal::Dummy
Definition stringutils.hxx:178
rtl::libreoffice_internal::CharPtrDetector
Definition stringutils.hxx:181
rtl::libreoffice_internal::CharPtrDetector::ok
static const bool ok
Definition stringutils.hxx:182
rtl::libreoffice_internal::CharPtrDetector< const char *, T >::Type
T Type
Definition stringutils.hxx:187
rtl::libreoffice_internal::CharPtrDetector< const char *, T >::ok
static const bool ok
Definition stringutils.hxx:188
rtl::libreoffice_internal::CharPtrDetector< char *, T >::Type
T Type
Definition stringutils.hxx:193
rtl::libreoffice_internal::CharPtrDetector< char *, T >::ok
static const bool ok
Definition stringutils.hxx:194
rtl::libreoffice_internal::NonConstCharArrayDetector
Definition stringutils.hxx:205
rtl::libreoffice_internal::NonConstCharArrayDetector< char[N], T >::Type
T Type
Definition stringutils.hxx:210
rtl::libreoffice_internal::ConstCharArrayDetector
Definition stringutils.hxx:233
rtl::libreoffice_internal::ConstCharArrayDetector::ok
static const bool ok
Definition stringutils.hxx:234
rtl::libreoffice_internal::ConstCharArrayDetector< const char[N], T >::toPointer
static char const * toPointer(char const (&literal)[N])
Definition stringutils.hxx:256
rtl::libreoffice_internal::ConstCharArrayDetector< const char[N], T >::ok
static const bool ok
Definition stringutils.hxx:241
rtl::libreoffice_internal::ConstCharArrayDetector< const char[N], T >::Type
T Type
Definition stringutils.hxx:239
rtl::libreoffice_internal::ConstCharArrayDetector< const char[N], T >::isValid
static bool isValid(char const (&literal)[N])
Definition stringutils.hxx:245
rtl::libreoffice_internal::ConstCharArrayDetector< const char[N], T >::length
static const std::size_t length
Definition stringutils.hxx:240
rtl::libreoffice_internal::SalUnicodePtrDetector
Definition stringutils.hxx:378
rtl::libreoffice_internal::SalUnicodePtrDetector::ok
static const bool ok
Definition stringutils.hxx:379
rtl::libreoffice_internal::SalUnicodePtrDetector< const sal_Unicode *, T >::Type
T Type
Definition stringutils.hxx:384
rtl::libreoffice_internal::SalUnicodePtrDetector< const sal_Unicode *, T >::ok
static const bool ok
Definition stringutils.hxx:385
rtl::libreoffice_internal::SalUnicodePtrDetector< sal_Unicode *, T >::ok
static const bool ok
Definition stringutils.hxx:391
rtl::libreoffice_internal::SalUnicodePtrDetector< sal_Unicode *, T >::Type
T Type
Definition stringutils.hxx:390
rtl::libreoffice_internal::Enable
Definition stringutils.hxx:397
rtl::libreoffice_internal::Enable< T, true >::Type
T Type
Definition stringutils.hxx:403