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 
29 namespace 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 //
45 struct SAL_WARN_UNUSED OStringChar {
46  constexpr OStringChar(char theC): c(theC) {}
47  template<typename T> OStringChar(T &&) = delete;
48  char const c;
49 };
50 
93 struct 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 };
100 using OUStringChar = OUStringChar_ const;
101 
103 #endif
104 
105 namespace libreoffice_internal
106 {
107 /*
108 These templates use SFINAE (Substitution failure is not an error) to help distinguish the various
109 plain C string types: char*, const char*, char[N], const char[N], char[] and const char[].
110 There are 2 cases:
111 1) 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.
116 2) 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].
124 Additionally, char[] and const char[] (i.e. size unknown) are rather tricky. Their usage with 'T&' would
125 mean it would be 'char(&)[]', which seems to be invalid. But gcc and clang somehow manage when it is
126 a template. while msvc complains about no conversion from char[] to char[1]. And the reference cannot
127 be avoided, because 'const char[]' as argument type would match also 'const char[N]'
128 So char[] and const char[] should always be used with their contents specified (which automatically
129 turns them into char[N] or const char[N]), or char* and const char* should be used.
130 */
131 struct Dummy {};
132 template< typename T1, typename T2 = void >
134 {
135  static const bool ok = false;
136 };
137 template< typename T >
138 struct CharPtrDetector< const char*, T >
139 {
140  typedef T Type;
141  static const bool ok = true;
142 };
143 template< typename T >
144 struct CharPtrDetector< char*, T >
145 {
146  typedef T Type;
147  static const bool ok = true;
148 };
149 #if defined LIBO_INTERNAL_ONLY
150 template<typename T> struct CharPtrDetector<sal_Unicode *, T> { using TypeUtf16 = T; };
151 template<typename T> struct CharPtrDetector<sal_Unicode const *, T> { using TypeUtf16 = T; };
152 template<typename T> struct CharPtrDetector<sal_Unicode[], T> { using TypeUtf16 = T; };
153 template<typename T> struct CharPtrDetector<sal_Unicode const[], T> { using TypeUtf16 = T; };
154 #endif
155 
156 template< typename T1, typename T2 >
158 {
159 };
160 template< typename T, int N >
161 struct NonConstCharArrayDetector< char[ N ], T >
162 {
163  typedef T Type;
164 };
165 #ifdef RTL_STRING_UNITTEST
166 // never use, until all compilers handle this
167 template< typename T >
168 struct NonConstCharArrayDetector< char[], T >
169 {
170  typedef T Type;
171 };
172 template< typename T >
173 struct NonConstCharArrayDetector< const char[], T >
174 {
175  typedef T Type;
176 };
177 #endif
178 #if defined LIBO_INTERNAL_ONLY
179 template<typename T, std::size_t N> struct NonConstCharArrayDetector<sal_Unicode[N], T> {
180  using TypeUtf16 = T;
181 };
182 #endif
183 
184 template< typename T1, typename T2 = void >
186 {
187  static const bool ok = false;
188 };
189 template< std::size_t N, typename T >
190 struct 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
215 template< typename T >
216 struct 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
235 template<std::size_t N, typename T>
236 struct 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
254 template<std::size_t N, typename T>
255 struct 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
275 template<typename T>
276 struct 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 
289 template<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]
306 template< typename T >
307 struct ExceptConstCharArrayDetector
308 {
309  typedef Dummy Type;
310 };
311 template< int N >
312 struct ExceptConstCharArrayDetector< const char[ N ] >
313 {
314 };
315 template<std::size_t N>
316 struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
317 template<> 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).
326 template< typename T >
327 struct ExceptCharArrayDetector
328 {
329  typedef Dummy Type;
330 };
331 template< int N >
332 struct ExceptCharArrayDetector< char[ N ] >
333 {
334 };
335 template< int N >
336 struct ExceptCharArrayDetector< const char[ N ] >
337 {
338 };
339 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
340 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
341 template<> struct ExceptCharArrayDetector<OUStringChar_> {};
342 
343 #endif
344 
345 template< typename T1, typename T2 = void >
347 {
348  static const bool ok = false;
349 };
350 template< typename T >
352 {
353  typedef T Type;
354  static const bool ok = true;
355 };
356 template< typename T >
358 {
359  typedef T Type;
360  static const bool ok = true;
361 };
362 
363 // SFINAE helper class
364 template< typename T, bool >
365 struct Enable
366  {
367  };
368 
369 template< typename T >
370 struct 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: bootstrap.hxx:30
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