LibreOffice
LibreOffice 24.2 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 #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 
37 namespace rtl
38 {
39 
40 #ifdef RTL_STRING_UNITTEST
41 #undef rtl
42 #endif
43 
44 #if defined LIBO_INTERNAL_ONLY
45 
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 //
53 struct 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 
103 struct 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 };
111 using OUStringChar = OUStringChar_ const;
112 
114 #endif
115 
116 namespace libreoffice_internal
117 {
118 /*
119 These templates use SFINAE (Substitution failure is not an error) to help distinguish the various
120 plain C string types: char*, const char*, char[N], const char[N], char[] and const char[].
121 There are 2 cases:
122 1) 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.)
131 2) 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].
139 Additionally, char[] and const char[] (i.e. size unknown) are rather tricky. Their usage with 'T&' would
140 mean it would be 'char(&)[]', which seems to be invalid. But gcc and clang somehow manage when it is
141 a template. while msvc complains about no conversion from char[] to char[1]. And the reference cannot
142 be avoided, because 'const char[]' as argument type would match also 'const char[N]'
143 So char[] and const char[] should always be used with their contents specified (which automatically
144 turns them into char[N] or const char[N]), or char* and const char* should be used.
145 */
146 struct Dummy {};
147 template< typename T1, typename T2 = void >
149 {
150  static const bool ok = false;
151 };
152 template< typename T >
153 struct CharPtrDetector< const char*, T >
154 {
155  typedef T Type;
156  static const bool ok = true;
157 };
158 template< typename T >
159 struct CharPtrDetector< char*, T >
160 {
161  typedef T Type;
162  static const bool ok = true;
163 };
164 #if defined LIBO_INTERNAL_ONLY
165 template<typename T> struct CharPtrDetector<sal_Unicode *, T> { using TypeUtf16 = T; };
166 template<typename T> struct CharPtrDetector<sal_Unicode const *, T> { using TypeUtf16 = T; };
167 template<typename T> struct CharPtrDetector<sal_Unicode[], T> { using TypeUtf16 = T; };
168 template<typename T> struct CharPtrDetector<sal_Unicode const[], T> { using TypeUtf16 = T; };
169 #endif
170 
171 template< typename T1, typename T2 >
173 {
174 };
175 template< typename T, int N >
176 struct NonConstCharArrayDetector< char[ N ], T >
177 {
178  typedef T Type;
179 };
180 #ifdef RTL_STRING_UNITTEST
181 // never use, until all compilers handle this
182 template< typename T >
183 struct NonConstCharArrayDetector< char[], T >
184 {
185  typedef T Type;
186 };
187 template< typename T >
188 struct NonConstCharArrayDetector< const char[], T >
189 {
190  typedef T Type;
191 };
192 #endif
193 #if defined LIBO_INTERNAL_ONLY
194 template<typename T, std::size_t N> struct NonConstCharArrayDetector<sal_Unicode[N], T> {
195  using TypeUtf16 = T;
196 };
197 #endif
198 
199 template< typename T1, typename T2 = void >
201 {
202  static const bool ok = false;
203 };
204 template< std::size_t N, typename T >
205 struct 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
230 template< typename T >
231 struct 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)
251 template<std::size_t N, typename T>
252 struct 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
270 template<std::size_t N, typename T>
271 struct 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
291 template<typename T>
292 struct 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 
305 template<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]
322 template< typename T >
323 struct ExceptConstCharArrayDetector
324 {
325  typedef Dummy Type;
326 };
327 template< int N >
328 struct ExceptConstCharArrayDetector< const char[ N ] >
329 {
330 };
331 template<std::size_t N>
332 struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
333 template<> 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).
342 template< typename T >
343 struct ExceptCharArrayDetector
344 {
345  typedef Dummy Type;
346 };
347 template< int N >
348 struct ExceptCharArrayDetector< char[ N ] >
349 {
350 };
351 template< int N >
352 struct ExceptCharArrayDetector< const char[ N ] >
353 {
354 };
355 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
356 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
357 template<> struct ExceptCharArrayDetector<OUStringChar_> {};
358 
359 #endif
360 
361 template< typename T1, typename T2 = void >
363 {
364  static const bool ok = false;
365 };
366 template< typename T >
368 {
369  typedef T Type;
370  static const bool ok = true;
371 };
372 template< typename T >
374 {
375  typedef T Type;
376  static const bool ok = true;
377 };
378 
379 // SFINAE helper class
380 template< typename T, bool >
381 struct Enable
382  {
383  };
384 
385 template< typename T >
386 struct 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: */
Definition: stringutils.hxx:146
#define SAL_WARN_UNUSED
Annotate classes where a compiler should warn if an instance is unused.
Definition: types.h:587
static const bool ok
Definition: stringutils.hxx:364
Definition: stringutils.hxx:381
sal_uInt16 sal_Unicode
Definition: types.h:123
static const bool ok
Definition: stringutils.hxx:202
Definition: bootstrap.hxx:33
T Type
Definition: stringutils.hxx:388
static bool isValid(char const (&literal)[N])
Definition: stringutils.hxx:213
Definition: stringutils.hxx:148
static const bool ok
Definition: stringutils.hxx:150
static char const * toPointer(char const (&literal)[N])
Definition: stringutils.hxx:224