CsString  1.4.0
cs_string.h
1 /***********************************************************************
2 *
3 * Copyright (c) 2017-2024 Barbara Geller
4 * Copyright (c) 2017-2024 Ansel Sermersheim
5 *
6 * This file is part of CsString.
7 *
8 * CsString is free software, released under the BSD 2-Clause license.
9 * For license details refer to LICENSE provided with this project.
10 *
11 * CsString is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 *
15 * https://opensource.org/licenses/BSD-2-Clause
16 *
17 ***********************************************************************/
18 
19 #ifndef LIB_CS_STRING_H
20 #define LIB_CS_STRING_H
21 
22 #include <algorithm>
23 #include <cstring>
24 #include <cstddef>
25 #include <exception>
26 #include <iterator>
27 #include <stdexcept>
28 #include <string>
29 #include <tuple>
30 #include <type_traits>
31 #include <vector>
32 
33 #include <cs_char.h>
34 #include <cs_string_iterator.h>
35 #include <cs_encoding.h>
36 
37 #define UCHAR(x) (U ## x)
38 
39 namespace CsString {
40 
41 template <typename S>
42 class CsBasicStringView;
43 
44 using CsString = CsBasicString<utf8>;
45 using CsString_utf8 = CsBasicString<utf8>;
46 using CsString_utf16 = CsBasicString<utf16>;
47 
48 template <typename E, typename A>
49 class CsBasicString
50 {
51  public:
52  using difference_type = std::ptrdiff_t;
53  using size_type = std::ptrdiff_t;
54  using value_type = CsChar;
55 
56  using const_iterator = CsStringIterator<E, A>;
57  using iterator = CsStringIterator<E, A>;
58  using const_reverse_iterator = CsStringReverseIterator<const_iterator>;
59  using reverse_iterator = CsStringReverseIterator<iterator>;
60 
61  using const_storage_iterator = typename std::vector<typename E::storage_unit, A>::const_iterator;
62  using const_storage_reverse_iterator = typename std::vector<typename E::storage_unit, A>::const_reverse_iterator;
63 
64  static constexpr const size_type npos = -1;
65 
66  CsBasicString()
67  : m_string(1, 0)
68  {
69  }
70 
71  explicit CsBasicString(const A &a)
72  : m_string(1, 0, a)
73  {
74  }
75 
76  // for a const char * and char *
77  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
78  std::is_same<T, char *>::value>::type>
79  CsBasicString(const T &str, const A &a = A());
80 
81  // for an array of chars
82  template <int N>
83  CsBasicString(const char (&str)[N], const A &a = A());
84 
85 
86  // for a const char * and char *
87  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
88  std::is_same<T, char *>::value>::type>
89  CsBasicString(const T &str, size_type size, const A &a = A());
90 
91  // for an array of chars
92  template <int N>
93  CsBasicString(const char (&str)[N], size_type size, const A &a = A());
94 
95 
96  CsBasicString(const char16_t *str, const A &a = A());
97  CsBasicString(const char16_t *str, size_type size, const A &a = A());
98 
99  CsBasicString(const char32_t *str, const A &a = A());
100  CsBasicString(const char32_t *str, size_type size, const A &a = A());
101 
102 
103  // substring constructors
104  CsBasicString(const CsBasicString &str, size_type indexStart, const A &a = A());
105  CsBasicString(const CsBasicString &str, size_type indexStart, size_type size, const A &a = A());
106 
107  // fixed size string with same single code point
108  CsBasicString(size_type count, CsChar c, const A &a = A());
109 
110  // unknown encoding
111  // CsBasicString(std::initializer_list<char> str, const A &a = A());
112 
113  template <typename U, typename = typename std::enable_if< std::is_convertible<
114  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
115  CsBasicString(CsBasicStringView<U> str, const A &a = A());
116 
117  template <typename U, typename = typename std::enable_if< std::is_convertible<
118  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
119  CsBasicString(CsBasicStringView<U> str, size_type indexStart, size_type size, const A &a = A());
120 
121  // copy a range of CsChar from another string type container
122  template <typename Iterator>
123  CsBasicString(Iterator begin, Iterator end, const A &a = A());
124 
125  CsBasicString(const_iterator begin, const_iterator end, const A &a = A());
126 
127  // copy constructor
128  CsBasicString(const CsBasicString &str) = default;
129  CsBasicString(const CsBasicString &str, const A &a);
130 
131  // move constructor
132  CsBasicString(CsBasicString && str) = default;
133  CsBasicString(CsBasicString && str, const A &a);
134 
135 
136 #if defined(__cpp_char8_t)
137  // support new data type added in C++20
138 
139  CsBasicString(const char8_t *str, const A &a = A());
140  CsBasicString(const char8_t *str, size_type size, const A &a = A());
141 
142  static CsBasicString fromUtf8(const char8_t *str, size_type numOfChars = -1, const A &a = A());
143 #endif
144 
145 
146  // ** operators
147  CsBasicString &operator=(const CsBasicString &str) = default;
148  CsBasicString &operator=(CsBasicString &&str) = default;
149 
150  // unknown encoding
151  // CsBasicString &operator=(char c);
152 
153  CsBasicString &operator=(CsChar c);
154 
155  // for a const char * and char * -or- an array of chars
156  template <typename T>
157  CsBasicString &operator=(const T &str);
158 
159  // unknown encoding
160  // CsBasicString &operator=(std::initializer_list<char> list);
161 
162  template <typename U, typename = typename std::enable_if< std::is_convertible<
163  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
164  CsBasicString &operator=(CsBasicStringView<U> str);
165 
166  CsBasicString &operator+=(const CsBasicString &str);
167 
168  // unknown encoding
169  // CsBasicString &operator+=(char c);
170 
171  CsBasicString &operator+=(CsChar c);
172 
173  // for a const char * and char * -or- an array of chars
174  template <typename T>
175  CsBasicString &operator+=(const T &str);
176 
177  // unknown encoding
178  // CsBasicString &operator+=(std::initializer_list<char> list);
179 
180  template <typename U, typename = typename std::enable_if< std::is_convertible<
181  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
182  CsBasicString &operator+=(CsBasicStringView<U> str);
183 
184  CsChar operator[](size_type index) const;
185 
186  const_iterator advance(const_iterator begin, size_type count) const;
187  iterator advance(iterator begin, size_type count);
188 
189  // ** methods
190  CsBasicString &append(const CsBasicString &str);
191  CsBasicString &append(const CsBasicString &str, size_type indexStart, size_type size = npos);
192 
193  CsBasicString &append(CsChar c);
194  CsBasicString &append(size_type count, CsChar c);
195 
196  template <typename Iterator>
197  CsBasicString &append(Iterator begin, Iterator end);
198 
199  CsBasicString &append(const_iterator begin, const_iterator end);
200 
201 
202  // for a const char * and char *
203  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
204  std::is_same<T, char *>::value>::type>
205  CsBasicString &append(const T &str, size_type size);
206 
207  // for an array of chars
208  template <int N>
209  CsBasicString &append(const char (&str)[N], size_type size);
210 
211 
212  // for a const char * and char *
213  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
214  std::is_same<T, char *>::value>::type>
215  CsBasicString &append(const T &str);
216 
217 
218  // for an array of chars
219  template <int N>
220  CsBasicString &append(const char (&str)[N]);
221 
222  // unknown encoding
223  // CsBasicString &append(std::initializer_list<char> str);
224 
225  template <typename U, typename = typename std::enable_if< std::is_convertible<
226  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
227  CsBasicString &append(CsBasicStringView<U> str);
228 
229  template <typename U, typename = typename std::enable_if< std::is_convertible<
230  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
231  CsBasicString &append(CsBasicStringView<U> str, size_type indexStart, size_type size);
232 
233  CsBasicString &assign(size_type count, CsChar c);
234  CsBasicString &assign(const CsBasicString &str);
235  CsBasicString &assign(const CsBasicString &str, size_type indexStart, size_type size = npos);
236  CsBasicString &assign(CsBasicString &&str);
237 
238  // for a const char * and char * -or- an array of chars
239  template <typename T>
240  CsBasicString &assign(const T &str, size_type size);
241 
242  // for a const char * and char * -or- an array of chars
243  template <typename T>
244  CsBasicString &assign(const T &str);
245 
246  template <typename Iterator>
247  CsBasicString &assign(Iterator begin, Iterator end);
248 
249  // unknown encoding
250  // CsBasicString &assign(std::initializer_list<CsChar> str)
251 
252  template <typename U, typename = typename std::enable_if< std::is_convertible<
253  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
254  CsBasicString &assign(CsBasicStringView<U> str);
255 
256  template <typename U, typename = typename std::enable_if< std::is_convertible<
257  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
258  CsBasicString &assign(CsBasicStringView<U> str, size_type indexStart, size_type size);
259 
260  CsChar at(size_type index) const;
261  CsChar back() const;
262  void clear();
263 
264  bool empty() const;
265 
266  CsBasicString &erase(size_type indexStart = 0, size_type size = npos);
267  iterator erase(const_iterator iter);
268  iterator erase(const_iterator iter_begin, const_iterator iter_end);
269 
270  // ** uses an iterator, returns an iterator
271  const_iterator find_fast(CsChar c) const;
272  const_iterator find_fast(CsChar c, const_iterator iter_begin) const;
273 
274  const_iterator find_fast(const CsBasicString &str) const;
275  const_iterator find_fast(const CsBasicString &str, const_iterator iter_begin) const;
276 
277  // for a const char * and char *
278  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
279  std::is_same<T, char *>::value>::type>
280  const_iterator find_fast(const T &str, const_iterator iter_begin, size_type size) const;
281 
282  // for an array of chars
283  template <int N>
284  const_iterator find_fast(const char (&str)[N], const_iterator iter_begin, size_type size) const;
285 
286  // for a const char * and char *
287  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
288  std::is_same<T, char *>::value>::type>
289  const_iterator find_fast(const T &str) const;
290 
291  // for a const char * and char *
292  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
293  std::is_same<T, char *>::value>::type>
294  const_iterator find_fast(const T &str, const_iterator iter_begin) const;
295 
296  // for an array of chars
297  template <int N>
298  const_iterator find_fast(const char (&str)[N]) const;
299 
300  // for an array of chars
301  template <int N>
302  const_iterator find_fast(const char (&str)[N], const_iterator iter_begin) const;
303 
304  //
305  const_iterator rfind_fast(CsChar c) const;
306  const_iterator rfind_fast(CsChar c, const_iterator iter_end) const;
307 
308  const_iterator rfind_fast(const CsBasicString &str) const;
309  const_iterator rfind_fast(const CsBasicString &str, const_iterator iter_end) const;
310 
311  // ** uses an index, returns an index
312  size_type find(const CsBasicString &str, size_type indexStart = 0) const;
313 
314  // for a const char * and char *
315  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
316  std::is_same<T, char *>::value>::type>
317  size_type find(const T &str, size_type indexStart, size_type size) const;
318 
319  // for an array of chars
320  template <int N>
321  size_type find(const char (&str)[N], size_type indexStart, size_type size) const;
322 
323  // for a const char * and char *
324  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
325  std::is_same<T, char *>::value>::type>
326  size_type find(const T &str, size_type indexStart = 0) const;
327 
328  // for an array of chars
329  template <int N>
330  size_type find(const char (&str)[N], size_type indexStart = 0) const;
331 
332  size_type find(CsChar c, size_type indexStart = 0) const;
333 
334  // template <typename U, typename = typename std::enable_if< std::is_convertible<
335  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
336  // size_type find(CsBasicStringView<U> str, size_type indexStart = 0) const;
337 
338 
339  size_type find_first_of(const CsBasicString &str, size_type indexStart = 0) const;
340 
341  // for a const char * and char *
342  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
343  std::is_same<T, char *>::value>::type>
344  size_type find_first_of(const T &str, size_type indexStart, size_type size) const;
345 
346  // for an array of chars
347  template <int N>
348  size_type find_first_of(const char (&str)[N], size_type indexStart, size_type size) const;
349 
350  // for a const char * and char *
351  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
352  std::is_same<T, char *>::value>::type>
353  size_type find_first_of(const T &str, size_type indexStart = 0) const;
354 
355  // for an array of chars
356  template <int N>
357  size_type find_first_of(const char (&str)[N], size_type indexStart = 0) const;
358 
359  size_type find_first_of(CsChar c, size_type indexStart = 0) const;
360 
361  // template <typename U, typename = typename std::enable_if< std::is_convertible<
362  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
363  // size_type find_first_of(CsBasicStringView<U> str, size_type indexStart = 0 ) const;
364 
365 
366  size_type find_last_of(const CsBasicString &str, size_type indexStart = npos) const;
367 
368  // for a const char * and char *
369  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
370  std::is_same<T, char *>::value>::type>
371  size_type find_last_of(const T &str, size_type indexStart, size_type size) const;
372 
373  // for an array of chars
374  template <int N>
375  size_type find_last_of(const char (&str)[N], size_type indexStart, size_type size) const;
376 
377  // for a const char * and char *
378  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
379  std::is_same<T, char *>::value>::type>
380  size_type find_last_of(const T &str, size_type indexStart = npos) const;
381 
382  // for an array of chars
383  template <int N>
384  size_type find_last_of(const char (&str)[N], size_type indexStart = npos) const;
385 
386  size_type find_last_of(CsChar c, size_type indexStart = npos) const;
387 
388  // template <typename U, typename = typename std::enable_if< std::is_convertible<
389  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
390  // size_type find_last_of(CsBasicStringView<U> str, size_type indexStart = npos) const
391 
392 
393  size_type find_first_not_of(const CsBasicString &str, size_type indexStart = 0) const;
394 
395  // for a const char * and char *
396  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
397  std::is_same<T, char *>::value>::type>
398  size_type find_first_not_of(const T &str, size_type indexStart, size_type size) const;
399 
400  // for an array of chars
401  template <int N>
402  size_type find_first_not_of(const char (&str)[N], size_type indexStart, size_type size) const;
403 
404  // for a const char * and char *
405  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
406  std::is_same<T, char *>::value>::type>
407  size_type find_first_not_of(const T &strc, size_type indexStart = 0) const;
408 
409  // for an array of chars
410  template <int N>
411  size_type find_first_not_of(const char (&str)[N], size_type indexStart = 0) const;
412 
413  size_type find_first_not_of(CsChar c, size_type indexStart= 0) const;
414 
415  // template <typename U, typename = typename std::enable_if< std::is_convertible<
416  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
417  // size_type find_first_not_of(CsBasicStringView<U> str, size_type indexStart = 0) const;
418 
419 
420  size_type find_last_not_of(const CsBasicString &str, size_type indexStart = npos) const;
421 
422  // for a const char * and char *
423  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
424  std::is_same<T, char *>::value>::type>
425  size_type find_last_not_of(const T &str, size_type indexStart, size_type size) const;
426 
427  // for an array of chars
428  template <int N>
429  size_type find_last_not_of(const char (&str)[N], size_type indexStart, size_type size) const;
430 
431  // for a const char * and char *
432  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
433  std::is_same<T, char *>::value>::type>
434  size_type find_last_not_of(const T &str, size_type indexStart = npos) const;
435 
436  // for an array of chars
437  template <int N>
438  size_type find_last_not_of(const char (&str)[N], size_type indexStart = npos) const;
439 
440  size_type find_last_not_of(CsChar c, size_type indexStart = npos) const;
441 
442  // template <typename U, typename = typename std::enable_if< std::is_convertible<
443  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
444  // size_type find_last_of(CsBasicStringView<U> str, size_type indexStart = npos) const;
445 
446 
447  size_type rfind(const CsBasicString &str, size_type indexStart = npos) const;
448 
449  // for a const char * and char *
450  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
451  std::is_same<T, char *>::value>::type>
452  size_type rfind(const T &str, size_type indexStart, size_type size) const;
453 
454  // for an array of chars
455  template <int N>
456  size_type rfind(const char (&str)[N], size_type indexStart, size_type size) const;
457 
458  // for a const char * and char *
459  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
460  std::is_same<T, char *>::value>::type>
461  size_type rfind(const T &str, size_type indexStart = npos) const;
462 
463  // for an array of chars
464  template <int N>
465  size_type rfind(const char (&str)[N], size_type indexStart = npos) const;
466 
467  size_type rfind(CsChar c, size_type indexStart = npos) const;
468 
469  // template <typename U, typename = typename std::enable_if< std::is_convertible<
470  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
471  // size_type rfind(CsBasicStringView<U> str, size_type indexStart = npos) const;
472 
473  CsChar front() const;
474 
475  static CsBasicString fromUtf8(const char *str, size_type numOfChars = -1, const A &a = A());
476  static CsBasicString fromUtf16(const char16_t *str, size_type numOfChars = -1, const A &a = A());
477 
478  A getAllocator() const;
479 
480  CsBasicString &insert(size_type indexStart, size_type count, CsChar c);
481 
482  // for a const char * and char *
483  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
484  std::is_same<T, char *>::value>::type>
485  CsBasicString &insert(size_type indexStart, const T &str);
486 
487  // for an array of chars
488  template <int N>
489  CsBasicString &insert(size_type indexStart, const char (&str)[N]);
490 
491  // for a const char * and char *
492  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
493  std::is_same<T, char *>::value>::type>
494  CsBasicString &insert(size_type indexStart, const T &str, size_type size);
495 
496  // for an array of chars
497  template <int N>
498  CsBasicString &insert(size_type indexStart, const char (&str)[N], size_type size);
499 
500  CsBasicString &insert(size_type indexStart, const CsBasicString &str);
501 
502  CsBasicString &insert(size_type indexStart, const CsBasicString &str,
503  size_type srcStart, size_type size = npos);
504 
505  iterator insert(const_iterator posStart, CsChar c);
506  iterator insert(const_iterator posStart, size_type count, CsChar c);
507  iterator insert(const_iterator posStart, const CsBasicString &str);
508 
509  // for a const char * and char *
510  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
511  std::is_same<T, char *>::value>::type>
512  iterator insert(const_iterator posStart, const T &str, size_type size);
513 
514  // for an array of chars
515  template <int N>
516  iterator insert(const_iterator posStart, const char (&str)[N], size_type size);
517 
518  template <typename Iterator>
519  iterator insert(const_iterator posStart, Iterator begin, Iterator end);
520 
521  // unknown encoding
522  // iterator insert(const_iterator posStart, std::initializer_list<CsChar> str);
523 
524  template <typename U, typename = typename std::enable_if< std::is_convertible<
525  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
526  iterator insert(size_type indexStart, CsBasicStringView<U> str);
527 
528  template <typename U, typename = typename std::enable_if< std::is_convertible<
529  decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
530  iterator insert(size_type indexStart, CsBasicStringView<U> str, size_type srcStart, size_type size = npos);
531 
532  void pop_back();
533  void push_back(CsChar c);
534 
535  CsBasicString &replace(size_type indexStart, size_type size, const CsBasicString &str);
536  CsBasicString &replace(const_iterator first, const_iterator last, const CsBasicString &str);
537 
538  CsBasicString &replace(size_type indexStart, size_type count, const CsBasicString &str,
539  size_type srcStart, size_type size = npos);
540 
541  template <class Iterator>
542  CsBasicString &replace(const_iterator first1, const_iterator last1, Iterator first2, Iterator last2);
543 
544  // for a const char * and char *
545  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
546  std::is_same<T, char *>::value>::type>
547  CsBasicString &replace(size_type indexStart, size_type count, const T &str, size_type size);
548 
549  // for an array of chars
550  template <int N>
551  CsBasicString &replace(size_type indexStart, size_type count, const char (&str)[N], size_type size);
552 
553  // for a const char * and char *
554  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
555  std::is_same<T, char *>::value>::type>
556  CsBasicString &replace(const_iterator first, const_iterator last, const T &str, size_type size);
557 
558  // for an array of chars
559  template <int N>
560  CsBasicString &replace(const_iterator first, const_iterator last, const char (&str)[N], size_type size);
561 
562  // for a const char * and char *
563  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
564  std::is_same<T, char *>::value>::type>
565  CsBasicString &replace(size_type indexStart, size_type size, const T &str);
566 
567  // for an array of chars
568  template <int N>
569  CsBasicString &replace(size_type indexStart, size_type size, const char (&str)[N]);
570 
571  // for a const char * and char *
572  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
573  std::is_same<T, char *>::value>::type>
574  CsBasicString &replace(const_iterator first, const_iterator last, const T &str);
575 
576  // for an array of chars
577  template <int N>
578  CsBasicString &replace(const_iterator first, const_iterator last, const char (&str)[N]);
579 
580  CsBasicString &replace(size_type indexStart, size_type size, size_type count, CsChar c);
581  CsBasicString &replace(const_iterator first, const_iterator last, size_type count, CsChar c);
582 
583  // unknown encoding
584  // CsBasicString &replace(const_iterator first, const_iterator last, std::initializer_list<CsChar> str);
585 
586  // template <typename U, typename = typename std::enable_if< std::is_convertible<
587  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
588  // basic_string &replace(size_type pos, size_type size, CsBasicStringView<U> str);
589 
590  // template <typename U, typename = typename std::enable_if< std::is_convertible<
591  // decltype(*(std::declval<typename U::const_iterator>())), CsChar>::value>::type>
592  // basic_string &replace(const_iterator first, const_iterator last, CsBasicStringView<U> str);
593 
594  template <class T>
595  CsBasicString &replace(size_type indexStart, size_type count, const T &str,
596  size_type srcStart, size_type size = npos);
597 
598  template <class T>
599  CsBasicString &replace(const_iterator first, const_iterator last, const T &str,
600  size_type srcStart, size_type size = npos);
601 
602  iterator replace(const_iterator iter, const CsBasicString &str);
603 
604  void resize(size_type size);
605  void resize(size_type size, CsChar c);
606 
607  void shrink_to_fit();
608 
609  size_type size_storage() const;
610 
611  // following 3 do the same thing
612  size_type size_codePoints() const;
613  size_type size() const;
614  size_type length() const;
615 
616  CsBasicString substr(size_type indexStart = 0, size_type size = npos) const;
617  void swap(CsBasicString &str);
618 
619  // ** iterators
620  const_iterator begin() const;
621  const_iterator cbegin() const;
622 
623  const_iterator end() const;
624  const_iterator cend() const;
625 
626  const_reverse_iterator rbegin() const;
627  const_reverse_iterator crbegin() const;
628 
629  const_reverse_iterator rend() const;
630  const_reverse_iterator crend() const;
631 
632  // storage iterators
633  const_storage_iterator storage_begin() const;
634  const_storage_iterator storage_end() const;
635 
636  const_storage_reverse_iterator storage_rbegin() const;
637  const_storage_reverse_iterator storage_rend() const;
638 
639  // returns const ptr to the raw data
640  const typename E::storage_unit *constData() const
641  {
642  return &m_string[0];
643  }
644 
645  private:
646  using str_type = typename std::vector<typename E::storage_unit, A>;
647  using str_iter = typename std::vector<typename E::storage_unit, A>::const_iterator;
648 
649  str_type m_string;
650 };
651 
652 // constructors
653 template <typename E, typename A>
654 CsBasicString<E, A>::CsBasicString(const CsBasicString &str, const A &a)
655  : m_string(str.m_string, a)
656 {
657 }
658 
659 template <typename E, typename A>
660 CsBasicString<E, A>::CsBasicString(CsBasicString &&str, const A &a)
661  : m_string(std::move(str.m_string), a)
662 {
663 }
664 
665 template <typename E, typename A>
666 template <typename T, typename>
667 CsBasicString<E, A>::CsBasicString(const T &str, const A &a)
668 {
669 #ifndef CS_STRING_ALLOW_UNSAFE
670  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
671 #endif
672 
673  // make this safe by treating str as utf8
674  *this = CsBasicString::fromUtf8(str, -1, a);
675 }
676 
677 template <typename E, typename A>
678 template <int N>
679 CsBasicString<E, A>::CsBasicString(const char (&str)[N], const A &a)
680 {
681 #if defined(Q_CC_MSVC)
682  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
683 #endif
684 
685  // make this safe by treating str as utf8
686  *this = CsBasicString::fromUtf8(str, N-1, a);
687 }
688 
689 template <typename E, typename A>
690 template <typename T, typename>
691 CsBasicString<E, A>::CsBasicString(const T &str, size_type size, const A &a)
692 {
693 #ifndef CS_STRING_ALLOW_UNSAFE
694  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
695 #endif
696 
697  // str is a const char *
698  *this = CsBasicString::fromUtf8(str, size, a);
699 }
700 
701 template <typename E, typename A>
702 template <int N>
703 CsBasicString<E, A>::CsBasicString(const char (&str)[N], size_type size, const A &a)
704 {
705 #if defined(Q_CC_MSVC)
706  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
707 #endif
708 
709  // make this safe by treating str as utf8
710  *this = CsBasicString::fromUtf8(str, size, a);
711 }
712 
713 template <typename E, typename A>
714 CsBasicString<E, A>::CsBasicString(const char16_t *str, const A &a)
715 {
716  *this = CsBasicString::fromUtf16(str, -1, a);
717 }
718 
719 template <typename E, typename A>
720 CsBasicString<E, A>::CsBasicString(const char16_t *str, size_type size, const A &a)
721 {
722  *this = CsBasicString::fromUtf16(str, size, a);
723 }
724 
725 template <typename E, typename A>
726 CsBasicString<E, A>::CsBasicString(const char32_t *str, const A &a)
727  : m_string(1, 0, a)
728 {
729  const char32_t *c = str;
730 
731  while (*c != 0) {
732  E::insert(m_string, m_string.end() - 1, *c);
733  ++c;
734  }
735 }
736 
737 template <typename E, typename A>
738 CsBasicString<E, A>::CsBasicString(const char32_t *str, size_type size, const A &a)
739  : m_string(1, 0, a)
740 {
741  const char32_t *c = str;
742 
743  size_type count = 0;
744 
745  while (*c != 0) {
746 
747  if (size >= 0) {
748  if (count >= size) {
749  break;
750  }
751 
752  ++count;
753  }
754 
755  E::insert(m_string, m_string.end() - 1, *c);
756  ++c;
757  }
758 }
759 
760 template <typename E, typename A>
761 CsBasicString<E, A>::CsBasicString(const CsBasicString &str, size_type indexStart, const A &a)
762  : m_string(1, 0, a)
763 {
764  const_iterator iter_begin = str.cbegin();
765  const_iterator iter_end = str.cend();
766 
767  for (size_type i = 0; i < indexStart && iter_begin != str.cend(); ++i) {
768  ++iter_begin;
769  }
770 
771  if (iter_begin == str.cend()) {
772  // index_start > length
773  return;
774  }
775 
776  append(iter_begin, iter_end);
777 }
778 
779 template <typename E, typename A>
780 CsBasicString<E, A>::CsBasicString(const CsBasicString &str, size_type indexStart, size_type size, const A &a)
781  : m_string(1, 0, a)
782 {
783  const_iterator iter_begin = str.cbegin();
784  const_iterator iter_end;
785 
786  for (size_type i = 0; i < indexStart && iter_begin != str.cend(); ++i) {
787  ++iter_begin;
788  }
789 
790  if (iter_begin == str.cend()) {
791  // indexStart > length
792  return;
793  }
794 
795  if (size >= 0) {
796  iter_end = iter_begin;
797 
798  for (size_type i = 0; i < size && iter_end != str.cend(); ++i) {
799  ++iter_end;
800  }
801 
802  } else {
803  iter_end = str.cend();
804 
805  }
806 
807  append(iter_begin, iter_end);
808 }
809 
810 template <typename E, typename A>
811 CsBasicString<E, A>::CsBasicString(size_type count, CsChar c, const A &a)
812  : m_string(1, 0, a)
813 {
814  E::insert(m_string, m_string.end() - 1, c, count);
815 }
816 
817 template <typename E, typename A>
818 template <typename U, typename>
819 CsBasicString<E, A>::CsBasicString(CsBasicStringView<U> str, const A &a)
820  : CsBasicString(str.begin(), str.end(), a)
821 {
822  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
823  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
824  "incompatible with the encoding for U");
825 }
826 
827 template <typename E, typename A>
828 template <typename U, typename>
829 CsBasicString<E, A>::CsBasicString(CsBasicStringView<U> str, size_type indexStart, size_type size, const A &a)
830  : m_string(1, 0, a)
831 {
832  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
833  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
834  "incompatible with the encoding for U");
835 
836  typename U::const_iterator iter_begin = str.cbegin();
837  typename U::const_iterator iter_end;
838 
839  for (size_type i = 0; i < indexStart && iter_begin != str.cend(); ++i) {
840  ++iter_begin;
841  }
842 
843  if (iter_begin == str.cend()) {
844  // indexStart > length
845  return;
846  }
847 
848  if (size >= 0) {
849  iter_end = iter_begin;
850 
851  for (size_type i = 0; i < size && iter_end != str.cend(); ++i) {
852  ++iter_end;
853  }
854 
855  } else {
856  iter_end = str.cend();
857 
858  }
859 
860  append(iter_begin, iter_end);
861 }
862 
863 template <typename E, typename A>
864 template <typename Iterator>
865 CsBasicString<E, A>::CsBasicString(Iterator begin, Iterator end, const A &a)
866  : m_string(1, 0, a)
867 {
868  for (Iterator item = begin; item != end; ++item) {
869  E::insert(m_string, m_string.end() - 1, *item);
870  }
871 }
872 
873 template <typename E, typename A>
874 CsBasicString<E, A>::CsBasicString(const_iterator begin, const_iterator end, const A &a)
875  : m_string(begin.codePointBegin(), end.codePointBegin(), a)
876 {
877  m_string.push_back(0);
878 }
879 
880 // operators
881 template <typename E, typename A>
882 CsBasicString<E, A> &CsBasicString<E, A>::operator=(CsChar c)
883 {
884  m_string.clear();
885  m_string.push_back(0);
886 
887  append(c);
888  return *this;
889 }
890 
891 template <typename E, typename A>
892 template <typename T>
893 CsBasicString<E, A> &CsBasicString<E, A>::operator=(const T &str)
894 {
895  // str is a const char * -or- an array of chars
896 
897  m_string.clear();
898  m_string.push_back(0);
899 
900  append(str);
901  return *this;
902 }
903 
904 template <typename E, typename A>
905 template <typename U, typename>
906 CsBasicString<E, A> &CsBasicString<E,A>::operator=(CsBasicStringView<U> str)
907 {
908  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
909  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
910  "incompatible with the encoding for U");
911 
912  m_string.clear();
913  m_string.push_back(0);
914 
915  append(str);
916  return *this;
917 }
918 
919 template <typename E, typename A>
920 CsBasicString<E, A> &CsBasicString<E, A>::operator+=(const CsBasicString &str)
921 {
922  append(str);
923  return *this;
924 }
925 
926 template <typename E, typename A>
927 CsBasicString<E, A> &CsBasicString<E, A>::operator+=(CsChar c)
928 {
929  append(c);
930  return *this;
931 }
932 
933 template <typename E, typename A>
934 template <typename T>
935 CsBasicString<E, A> &CsBasicString<E, A>::operator+=(const T &str)
936 {
937  // str is a const char * -or- an array of chars
938 
939  append(str);
940  return *this;
941 }
942 
943 template <typename E, typename A>
944 template <typename U, typename>
945 CsBasicString<E, A> &CsBasicString<E,A>::operator+=(CsBasicStringView<U> str)
946 {
947  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
948  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
949  "incompatible with the encoding for U");
950 
951  append(str);
952  return *this;
953 }
954 
955 template <typename E, typename A>
956 CsChar CsBasicString<E, A>::operator[](size_type index) const
957 {
958  const_iterator iter = begin();
959  std::advance(iter, index);
960 
961  return *iter;
962 }
963 
964 
965 // methods
966 template <typename E, typename A>
967 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::advance(const_iterator begin, size_type count) const
968 {
969  return const_iterator(E::advance(begin.codePointBegin(), cend().codePointBegin(), count));
970 }
971 
972 template <typename E, typename A>
973 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::advance(iterator begin, size_type count)
974 {
975  return iterator(E::advance(begin.codePointBegin(), end().codePointBegin(), count));
976 }
977 
978 template <typename E, typename A>
979 CsBasicString<E, A> &CsBasicString<E, A>::append(const CsBasicString &str)
980 {
981  insert(end(), str);
982  return *this;
983 }
984 
985 template <typename E, typename A>
986 CsBasicString<E, A> &CsBasicString<E, A>::append(const CsBasicString &str, size_type indexStart, size_type size)
987 {
988  size_type stringLen = this->size();
989  insert(stringLen, str, indexStart, size);
990 
991  return *this;
992 }
993 
994 template <typename E, typename A>
995 CsBasicString<E, A> &CsBasicString<E, A>::append(CsChar c)
996 {
997  E::insert(m_string, m_string.end() - 1, c);
998  return *this;
999 }
1000 
1001 template <typename E, typename A>
1002 CsBasicString<E, A> &CsBasicString<E, A>::append(size_type count, CsChar c)
1003 {
1004  E::insert(m_string, m_string.end() - 1, c, count);
1005  return *this;
1006 }
1007 
1008 template <typename E, typename A>
1009 template <typename Iterator>
1010 CsBasicString<E, A> &CsBasicString<E, A>::append(Iterator begin, Iterator end)
1011 {
1012  for (Iterator item = begin; item != end; ++item) {
1013  E::insert(m_string, m_string.end() - 1, *item);
1014  }
1015 
1016  return *this;
1017 }
1018 
1019 template <typename E, typename A>
1020 CsBasicString<E, A> &CsBasicString<E, A>::append(const_iterator begin, const_iterator end)
1021 {
1022  m_string.insert(m_string.end() - 1, begin.codePointBegin(), end.codePointBegin());
1023 
1024  return *this;
1025 }
1026 
1027 template <typename E, typename A>
1028 template <typename T, typename>
1029 CsBasicString<E, A> &CsBasicString<E, A>::append(const T &str, size_type size)
1030 {
1031 #ifndef CS_STRING_ALLOW_UNSAFE
1032  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1033 #endif
1034 
1035  // str is a const char *
1036  if (str == nullptr) {
1037  return *this;
1038  }
1039 
1040  // make this safe by treating str as utf8
1041  this->append(CsBasicString::fromUtf8(str, size));
1042 
1043  return *this;
1044 }
1045 
1046 template <typename E, typename A>
1047 template <int N>
1048 CsBasicString<E, A> &CsBasicString<E, A>::append(const char (&str)[N], size_type size)
1049 {
1050 #if defined(Q_CC_MSVC)
1051  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1052 #endif
1053 
1054  // make this safe by treating str as utf8
1055  this->append(CsBasicString::fromUtf8(str, size));
1056 
1057  return *this;
1058 }
1059 
1060 template <typename E, typename A>
1061 template <typename T, typename>
1062 CsBasicString<E, A> &CsBasicString<E, A>::append(const T &str)
1063 {
1064 #ifndef CS_STRING_ALLOW_UNSAFE
1065  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1066 #endif
1067 
1068  // str is a const char *
1069  if (str == nullptr) {
1070  return *this;
1071  }
1072 
1073  // make this safe by treating str as utf8
1074  this->append(CsBasicString::fromUtf8(str));
1075 
1076  return *this;
1077 }
1078 
1079 template <typename E, typename A>
1080 template <int N>
1081 CsBasicString<E, A> &CsBasicString<E, A>::append(const char (&str)[N])
1082 {
1083 #if defined(Q_CC_MSVC)
1084  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1085 #endif
1086 
1087  // make this safe by treating str as utf8
1088  this->append(CsBasicString::fromUtf8(str, N-1));
1089 
1090  return *this;
1091 }
1092 
1093 template <typename E, typename A>
1094 template <typename U, typename>
1095 CsBasicString<E, A> &CsBasicString<E, A>::append(CsBasicStringView<U> str)
1096 {
1097  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
1098  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
1099  "incompatible with the encoding for U");
1100 
1101  append(str.cbegin(), str.cend());
1102  return *this;
1103 }
1104 
1105 template <typename E, typename A>
1106 template <typename U, typename>
1107 CsBasicString<E, A> &CsBasicString<E, A>::append(CsBasicStringView<U> str, size_type indexStart, size_type size)
1108 {
1109  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
1110  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
1111  "incompatible with the encoding for U");
1112 
1113  typename U::const_iterator iter_begin = str.cbegin();
1114  typename U::const_iterator iter_end;
1115 
1116  for (size_type i = 0; i < indexStart && iter_begin != str.cend(); ++i) {
1117  ++iter_begin;
1118  }
1119 
1120  if (iter_begin == str.cend()) {
1121  return *this;
1122  }
1123 
1124  if (size >= 0) {
1125  iter_end = iter_begin;
1126 
1127  for (size_type i = 0; i < size && iter_end != str.cend(); ++i) {
1128  ++iter_end;
1129  }
1130 
1131  } else {
1132  iter_end = str.cend();
1133 
1134  }
1135 
1136  append(iter_begin, iter_end);
1137  return *this;
1138 }
1139 
1140 template <typename E, typename A>
1141 CsBasicString<E, A> &CsBasicString<E, A>::assign(size_type count, CsChar c)
1142 {
1143  clear();
1144  append(count, c);
1145 
1146  return *this;
1147 }
1148 
1149 template <typename E, typename A>
1150 CsBasicString<E, A> &CsBasicString<E, A>::assign(const CsBasicString &str)
1151 {
1152  clear();
1153  append(str);
1154 
1155  return *this;
1156 }
1157 
1158 template <typename E, typename A>
1159 CsBasicString<E, A> &CsBasicString<E, A>::assign(const CsBasicString &str, size_type indexStart, size_type size)
1160 {
1161  clear();
1162  append(str, indexStart, size);
1163 
1164  return *this;
1165 }
1166 
1167 template <typename E, typename A>
1168 CsBasicString<E, A> &CsBasicString<E, A>::assign(CsBasicString &&str)
1169 {
1170  clear();
1171  append(std::move(str));
1172 
1173  return *this;
1174 }
1175 
1176 template <typename E, typename A>
1177 template <typename T>
1178 CsBasicString<E, A> &CsBasicString<E, A>::assign(const T &str, size_type size)
1179 {
1180  // str is a const char * -or- an array of chars
1181 
1182  clear();
1183  append(str, size);
1184 
1185  return *this;
1186 }
1187 
1188 template <typename E, typename A>
1189 template <typename T>
1190 CsBasicString<E, A> &CsBasicString<E, A>::assign(const T &str)
1191 {
1192  // str is a const char * -or- an array of chars
1193 
1194  clear();
1195  append(str);
1196 
1197  return *this;
1198 }
1199 
1200 template <typename E, typename A>
1201 template <typename Iterator>
1202 CsBasicString<E, A> &CsBasicString<E, A>::assign(Iterator begin, Iterator end)
1203 {
1204  clear();
1205  append(begin, end);
1206 
1207  return *this;
1208 }
1209 
1210 template <typename E, typename A>
1211 template <typename U, typename>
1212 CsBasicString<E, A> &CsBasicString<E, A>::assign(CsBasicStringView<U> str)
1213 {
1214  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
1215  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
1216  "incompatible with the encoding for U");
1217 
1218  clear();
1219  append(str.cbegin(), str.cend());
1220 
1221  return *this;
1222 }
1223 
1224 template <typename E, typename A>
1225 template <typename U, typename>
1226 CsBasicString<E, A> &CsBasicString<E, A>::assign(CsBasicStringView<U> str, size_type indexStart, size_type size)
1227 {
1228  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
1229  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
1230  "incompatible with the encoding for U");
1231 
1232  clear();
1233  append(str, indexStart, size);
1234 
1235  return *this;
1236 }
1237 
1238 template <typename E, typename A>
1239 CsChar CsBasicString<E, A>::at(size_type index) const
1240 {
1241  const_iterator iter = begin();
1242  std::advance(iter, index);
1243 
1244  return *iter;
1245 }
1246 
1247 template <typename E, typename A>
1248 CsChar CsBasicString<E, A>::back() const
1249 {
1250  return *(--end());
1251 }
1252 
1253 template <typename E, typename A>
1254 void CsBasicString<E, A>::clear()
1255 {
1256  m_string.clear();
1257  m_string.push_back(0);
1258 }
1259 
1260 template <typename E, typename A>
1261 bool CsBasicString<E, A>::empty() const
1262 {
1263  return (m_string.size() == 1);
1264 }
1265 
1266 template <typename E, typename A>
1267 CsBasicString<E, A> &CsBasicString<E, A>::erase(size_type indexStart, size_type size)
1268 {
1269  const_iterator iter_begin = cbegin();
1270  const_iterator iter_end;
1271 
1272  for (size_type i = 0; i < indexStart && iter_begin != cend(); ++i) {
1273  ++iter_begin;
1274  }
1275 
1276  if (iter_begin == cend()) {
1277  return *this;
1278  }
1279 
1280  if (size >= 0) {
1281  iter_end = iter_begin;
1282 
1283  for (size_type i = 0; i < size && iter_end != cend(); ++i) {
1284  ++iter_end;
1285  }
1286 
1287  } else {
1288  iter_end = cend();
1289 
1290  }
1291 
1292  erase(iter_begin, iter_end);
1293 
1294  return *this;
1295 }
1296 
1297 template <typename E, typename A>
1298 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::erase(const_iterator iter)
1299 {
1300  auto [vbegin, vend] = iter.codePointRange();
1301  auto retval = m_string.erase(vbegin, vend);
1302 
1303  return const_iterator(retval);
1304 }
1305 
1306 template <typename E, typename A>
1307 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::erase(const_iterator iter_begin, const_iterator iter_end)
1308 {
1309  auto retval = m_string.erase(iter_begin.codePointBegin(), iter_end.codePointBegin());
1310  return const_iterator(retval);
1311 }
1312 
1313 template <typename E, typename A>
1314 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const CsBasicString &str) const
1315 {
1316  return find_fast(str, begin());
1317 }
1318 
1319 template <typename E, typename A>
1320 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const CsBasicString &str,
1321  const_iterator iter_begin) const
1322 {
1323  const_iterator iter_end = end();
1324 
1325  if (iter_begin == iter_end) {
1326  return iter_end;
1327  }
1328 
1329  if (str.empty()) {
1330  return iter_begin;
1331  }
1332 
1333  auto iter = iter_begin;
1334  auto ch = str[0];
1335 
1336  while (iter != iter_end) {
1337 
1338  if (*iter == ch) {
1339  auto text_iter = iter + 1;
1340  auto pattern_iter = str.begin() + 1;
1341 
1342  while (text_iter != iter_end && pattern_iter != str.end()) {
1343 
1344  if (*text_iter == *pattern_iter) {
1345  ++text_iter;
1346  ++pattern_iter;
1347 
1348  } else {
1349  break;
1350 
1351  }
1352  }
1353 
1354  if (pattern_iter == str.end()) {
1355  // found a match
1356  return iter;
1357  }
1358  }
1359 
1360  ++iter;
1361  }
1362 
1363  return iter_end;
1364 }
1365 
1366 // for a const char * and char *
1367 template <typename E, typename A>
1368 template <typename T, typename>
1369 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const T &str, const_iterator iter_begin,
1370  size_type size) const
1371 {
1372 #ifndef CS_STRING_ALLOW_UNSAFE
1373  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1374 #endif
1375 
1376  const_iterator iter_end = cend();
1377 
1378  if (iter_begin == iter_end) {
1379  return iter_end;
1380  }
1381 
1382  if (str == nullptr || str[0] == '\0') {
1383  return iter_begin;
1384  }
1385 
1386  // make this safe by treating str as utf8
1387  return find_fast(CsBasicString::fromUtf8(str, size), iter_begin);
1388 }
1389 
1390 // for an array of chars
1391 template <typename E, typename A>
1392 template <int N>
1393 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const char (&str)[N], const_iterator iter_begin,
1394  size_type size) const
1395 {
1396 #if defined(Q_CC_MSVC)
1397  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1398 #endif
1399 
1400  // make this safe by treating str as utf8
1401  return find_fast(CsBasicString::fromUtf8(str, size), iter_begin);
1402 }
1403 
1404 // for a const char * and char *
1405 template <typename E, typename A>
1406 template <typename T, typename>
1407 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const T &str) const
1408 {
1409  return find_fast(str, cbegin());
1410 }
1411 
1412 // for a const char * and char *
1413 template <typename E, typename A>
1414 template <typename T, typename>
1415 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const T &str, const_iterator iter_begin) const
1416 {
1417 #ifndef CS_STRING_ALLOW_UNSAFE
1418  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1419 #endif
1420 
1421  const_iterator iter_end = cend();
1422 
1423  if (iter_begin == iter_end) {
1424  return iter_end;
1425  }
1426 
1427  if (str == nullptr || str[0] == '\0') {
1428  return iter_begin;
1429  }
1430 
1431  // make this safe by treating str as utf8
1432  return find_fast(CsBasicString::fromUtf8(str), iter_begin);
1433 }
1434 
1435 // for an array of chars
1436 template <typename E, typename A>
1437 template <int N>
1438 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const char (&str)[N]) const
1439 {
1440  return find_fast(str, cbegin());
1441 }
1442 
1443 // for an array of chars
1444 template <typename E, typename A>
1445 template <int N>
1446 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(const char (&str)[N], const_iterator iter_begin) const
1447 {
1448 #if defined(Q_CC_MSVC)
1449  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1450 #endif
1451 
1452  // make this safe by treating str as utf8
1453  return find_fast(CsBasicString::fromUtf8(str, N-1), iter_begin);
1454 }
1455 
1456 template <typename E, typename A>
1457 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(CsChar c) const
1458 {
1459  return find_fast(c, begin());
1460 }
1461 
1462 template <typename E, typename A>
1463 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::find_fast(CsChar c, const_iterator iter_begin) const
1464 {
1465  const_iterator iter_end = end();
1466 
1467  if (iter_begin == iter_end) {
1468  return iter_end;
1469  }
1470 
1471  auto iter = iter_begin;
1472 
1473  while (iter != iter_end) {
1474 
1475  if (*iter == c) {
1476  return iter;
1477  }
1478 
1479  ++iter;
1480  }
1481 
1482  return iter_end;
1483 }
1484 
1485 template <typename E, typename A>
1486 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::rfind_fast(CsChar c) const
1487 {
1488  return rfind_fast(c, end());
1489 }
1490 
1491 template <typename E, typename A>
1492 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::rfind_fast(CsChar c, const_iterator iter_end) const
1493 {
1494  const_iterator iter_begin = begin();
1495 
1496  if (iter_begin == iter_end) {
1497  return end();
1498  }
1499 
1500  auto iter = iter_end;
1501 
1502  while (iter != begin()) {
1503  --iter;
1504 
1505  if (*iter == c) {
1506  // found a match
1507  return iter;
1508  }
1509  }
1510 
1511  return end();
1512 }
1513 
1514 template <typename E, typename A>
1515 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::rfind_fast(const CsBasicString &str) const
1516 {
1517  return rfind_fast(str, end());
1518 }
1519 
1520 template <typename E, typename A>
1521 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::rfind_fast(const CsBasicString &str,
1522  const_iterator iter_end) const
1523 {
1524  const_iterator iter_begin = begin();
1525 
1526  if (iter_begin == iter_end) {
1527  return end();
1528  }
1529 
1530  if (str.empty()) {
1531  return iter_end;
1532  }
1533 
1534  auto iter = iter_end;
1535  auto str_end = str.end();
1536  auto ch = str[0];
1537 
1538  while (iter != begin()) {
1539  --iter;
1540 
1541  if (*iter == ch) {
1542 
1543  auto text_iter = iter + 1;
1544  auto pattern_iter = str.begin() + 1;
1545 
1546  while (text_iter != end() && pattern_iter != str_end) {
1547 
1548  if (*text_iter == *pattern_iter) {
1549  ++text_iter;
1550  ++pattern_iter;
1551 
1552  } else {
1553  break;
1554 
1555  }
1556  }
1557 
1558  if (pattern_iter == str_end) {
1559  // found a match
1560  return iter;
1561  }
1562  }
1563 
1564  }
1565 
1566  return end();
1567 }
1568 
1569 template <typename E, typename A>
1570 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find(CsChar c, size_type indexStart) const
1571 {
1572  const_iterator iter_begin = cbegin();
1573 
1574  for (size_type i = 0; i < indexStart && iter_begin != cend(); ++i) {
1575  ++iter_begin;
1576  }
1577 
1578  if (iter_begin == cend()) {
1579  // indexStart > length
1580  return -1;
1581  }
1582 
1583  size_type retval = indexStart;
1584 
1585  while (iter_begin != end()) {
1586 
1587  if (*iter_begin == c) {
1588  return retval;
1589  }
1590 
1591  ++iter_begin;
1592  ++retval;
1593  }
1594 
1595  return -1;
1596 }
1597 
1598 template <typename E, typename A>
1599 template <typename T, typename>
1600 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find(const T &str, size_type indexStart,
1601  size_type size) const
1602 {
1603 #ifndef CS_STRING_ALLOW_UNSAFE
1604  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1605 #endif
1606 
1607  // make this safe by treating str as utf8
1608  return find(CsBasicString::fromUtf8(str, size), indexStart);
1609 }
1610 
1611 template <typename E, typename A>
1612 template <int N>
1613 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find(const char (&str)[N], size_type indexStart,
1614  size_type size) const
1615 {
1616 #if defined(Q_CC_MSVC)
1617  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1618 #endif
1619 
1620  // make this safe by treating str as utf8
1621  return find(CsBasicString::fromUtf8(str, size), indexStart);
1622 }
1623 
1624 template <typename E, typename A>
1625 template <typename T, typename>
1626 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find(const T &str, size_type indexStart) const
1627 {
1628 #ifndef CS_STRING_ALLOW_UNSAFE
1629  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1630 #endif
1631 
1632  // str is a const char *
1633  size_type stringLen = this->size();
1634 
1635  if (str == nullptr || *str == '\0') {
1636 
1637  if (indexStart > stringLen) {
1638  return -1;
1639  } else {
1640  return indexStart;
1641  }
1642  }
1643 
1644  if (indexStart >= stringLen) {
1645  return -1;
1646  }
1647 
1648  // make this safe by treating str as utf8
1649  return find(CsBasicString::fromUtf8(str), indexStart);
1650 }
1651 
1652 template <typename E, typename A>
1653 template <int N>
1654 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find(const char (&str)[N], size_type indexStart) const
1655 {
1656 #if defined(Q_CC_MSVC)
1657  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1658 #endif
1659 
1660  // make this safe by treating str as utf8
1661  return find(CsBasicString::fromUtf8(str, N-1), indexStart);
1662 }
1663 
1664 template <typename E, typename A>
1665 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find(const CsBasicString &str, size_type indexStart) const
1666 {
1667  size_type stringLen = this->size();
1668 
1669  if (str.empty()) {
1670 
1671  if (indexStart > stringLen) {
1672  return -1;
1673  } else {
1674  return indexStart;
1675  }
1676  }
1677 
1678  if (indexStart >= stringLen) {
1679  return -1;
1680  }
1681 
1682  size_type retval = indexStart;
1683  auto iter = begin() + indexStart;
1684  auto ch = str[0];
1685 
1686  while (iter != end()) {
1687 
1688  if (*iter == ch) {
1689  auto text_iter = iter + 1;
1690  auto pattern_iter = str.begin() + 1;
1691 
1692  while (text_iter != end() && pattern_iter != str.end()) {
1693 
1694  if (*text_iter == *pattern_iter) {
1695  ++text_iter;
1696  ++pattern_iter;
1697 
1698  } else {
1699  break;
1700 
1701  }
1702  }
1703 
1704  if (pattern_iter == str.end()) {
1705  // found a match
1706  return retval;
1707  }
1708  }
1709 
1710  ++iter;
1711  ++retval;
1712  }
1713 
1714  return -1;
1715 }
1716 
1717 template <typename E, typename A>
1718 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_of(CsChar c, size_type indexStart) const
1719 {
1720  return find(c, indexStart);
1721 }
1722 
1723 template <typename E, typename A>
1724 template <typename T, typename>
1725 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_of(const T &str, size_type indexStart,
1726  size_type size) const
1727 {
1728 #ifndef CS_STRING_ALLOW_UNSAFE
1729  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1730 #endif
1731 
1732  // str is a const char *
1733  if (str == nullptr || *str == '\0' || indexStart >= this->size()) {
1734  return -1;
1735  }
1736 
1737  // make this safe by treating str as utf8
1738  return find_first_of(CsBasicString::fromUtf8(str, size), indexStart);
1739 }
1740 
1741 template <typename E, typename A>
1742 template <int N>
1743 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_of(const char (&str)[N], size_type indexStart,
1744  size_type size) const
1745 {
1746 #if defined(Q_CC_MSVC)
1747  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1748 #endif
1749 
1750  // make this safe by treating str as utf8
1751  return find_first_of(CsBasicString::fromUtf8(str, size), indexStart);
1752 }
1753 
1754 template <typename E, typename A>
1755 template <typename T, typename>
1756 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_of(const T &str, size_type indexStart) const
1757 {
1758 #ifndef CS_STRING_ALLOW_UNSAFE
1759  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1760 #endif
1761 
1762  // str is a const char *
1763  if (str == nullptr || *str == '\0' || indexStart >= this->size()) {
1764  return -1;
1765  }
1766 
1767  // make this safe by treating str as utf8
1768  return find_first_of(CsBasicString::fromUtf8(str), indexStart);
1769 }
1770 
1771 template <typename E, typename A>
1772 template <int N>
1773 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_of(const char (&str)[N],
1774  size_type indexStart) const
1775 {
1776 #if defined(Q_CC_MSVC)
1777  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1778 #endif
1779 
1780  // make this safe by treating str as utf8
1781  return find_first_of(CsBasicString::fromUtf8(str, N-1), indexStart);
1782 }
1783 
1784 template <typename E, typename A>
1785 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_of(const CsBasicString &str,
1786  size_type indexStart) const
1787 {
1788  if (str.empty() || indexStart >= this->size()) {
1789  return -1;
1790  }
1791 
1792  size_type retval = indexStart;
1793  auto iter = begin() + indexStart;
1794 
1795  while (iter != end()) {
1796  for (auto c : str) {
1797 
1798  if (*iter == c) {
1799  // found a match
1800  return retval;
1801  }
1802  }
1803 
1804  ++iter;
1805  ++retval;
1806  }
1807 
1808  return -1;
1809 }
1810 
1811 template <typename E, typename A>
1812 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_of(CsChar c, size_type indexStart) const
1813 {
1814  return rfind(c, indexStart);
1815 }
1816 
1817 template <typename E, typename A>
1818 template <typename T, typename>
1819 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_of(const T &str, size_type indexStart,
1820  size_type size) const
1821 {
1822 #ifndef CS_STRING_ALLOW_UNSAFE
1823  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1824 #endif
1825 
1826  // str is a const char *
1827  size_type stringLen = this->size();
1828 
1829  if (str == nullptr || *str == '\0' || indexStart >= stringLen) {
1830  return -1;
1831  }
1832 
1833  // make this safe by treating str as utf8
1834  return find_last_of(CsBasicString::fromUtf8(str, size), indexStart);
1835 }
1836 
1837 template <typename E, typename A>
1838 template <int N>
1839 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_of(const char (&str)[N],
1840  size_type indexStart, size_type size) const
1841 {
1842 #if defined(Q_CC_MSVC)
1843  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1844 #endif
1845 
1846  // make this safe by treating str as utf8
1847  return find_last_of(CsBasicString::fromUtf8(str, size), indexStart);
1848 }
1849 
1850 template <typename E, typename A>
1851 template <typename T, typename>
1852 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_of(const T &str, size_type indexStart) const
1853 {
1854 #ifndef CS_STRING_ALLOW_UNSAFE
1855  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1856 #endif
1857 
1858  // str is a const char *
1859  size_type stringLen = this->size();
1860 
1861  if (str == nullptr || *str == '\0' || indexStart >= stringLen) {
1862  return -1;
1863  }
1864 
1865  // make this safe by treating str as utf8
1866  return find_last_of(CsBasicString::fromUtf8(str), indexStart);
1867 }
1868 
1869 template <typename E, typename A>
1870 template <int N>
1871 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_of(const char (&str)[N],
1872  size_type indexStart) const
1873 {
1874 #if defined(Q_CC_MSVC)
1875  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1876 #endif
1877 
1878  // make this safe by treating str as utf8
1879  return find_last_of(CsBasicString::fromUtf8(str, N-1), indexStart);
1880 }
1881 
1882 template <typename E, typename A>
1883 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_of(const CsBasicString &str,
1884  size_type indexStart) const
1885 {
1886  size_type stringLen = this->size();
1887 
1888  if (str.empty() || indexStart >= stringLen) {
1889  return -1;
1890  }
1891 
1892  size_type retval;
1893  const_iterator iter;
1894 
1895  if (indexStart >= 0 && indexStart < stringLen) {
1896  retval = indexStart + 1;
1897  iter = begin() + indexStart + 1;
1898 
1899  } else {
1900  retval = stringLen;
1901  iter = end();
1902 
1903  }
1904 
1905  while (iter != begin()) {
1906  --iter;
1907  --retval;
1908 
1909  for (CsChar c : str) {
1910 
1911  if (*iter == c) {
1912  // found a match
1913  return retval;
1914  }
1915  }
1916  }
1917 
1918  return -1;
1919 }
1920 
1921 template <typename E, typename A>
1922 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_not_of(CsChar c, size_type indexStart) const
1923 {
1924  if (indexStart >= this->size()) {
1925  return -1;
1926  }
1927 
1928  size_type retval = indexStart;
1929  auto iter = begin() + indexStart;
1930 
1931  while (iter != end()) {
1932 
1933  if (*iter != c) {
1934  return retval;
1935  }
1936 
1937  ++iter;
1938  ++retval;
1939  }
1940 
1941  return -1;
1942 }
1943 
1944 template <typename E, typename A>
1945 template <typename T, typename>
1946 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_not_of(const T &str,
1947  size_type indexStart, size_type size) const
1948 {
1949 #ifndef CS_STRING_ALLOW_UNSAFE
1950  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1951 #endif
1952 
1953  // str is a const char *
1954  size_type stringLen = this->size();
1955 
1956  if (str == nullptr || *str == '\0') {
1957 
1958  if (indexStart >= stringLen) {
1959  return -1;
1960  } else {
1961  return indexStart;
1962  }
1963  }
1964 
1965  if (indexStart >= stringLen) {
1966  return -1;
1967  }
1968 
1969  // make this safe by treating str as utf8
1970  return find_first_not_of(CsBasicString::fromUtf8(str, size), indexStart);
1971 }
1972 
1973 template <typename E, typename A>
1974 template <int N>
1975 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_not_of(const char (&str)[N],
1976  size_type indexStart, size_type size) const
1977 {
1978 #if defined(Q_CC_MSVC)
1979  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
1980 #endif
1981 
1982  // make this safe by treating str as utf8
1983  return find_first_not_of(CsBasicString::fromUtf8(str, size), indexStart);
1984 }
1985 
1986 template <typename E, typename A>
1987 template <typename T, typename>
1988 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_not_of(const T &str,
1989  size_type indexStart) const
1990 {
1991 #ifndef CS_STRING_ALLOW_UNSAFE
1992  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
1993 #endif
1994 
1995  // str is a const char *
1996  size_type stringLen = this->size();
1997 
1998  if (str == nullptr || *str == '\0') {
1999 
2000  if (indexStart >= stringLen) {
2001  return -1;
2002  } else {
2003  return indexStart;
2004  }
2005  }
2006 
2007  if (indexStart >= stringLen) {
2008  return -1;
2009  }
2010 
2011  // make this safe by treating str as utf8
2012  return find_first_not_of(CsBasicString::fromUtf8(str), indexStart);
2013 }
2014 
2015 template <typename E, typename A>
2016 template <int N>
2017 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_not_of(const char (&str)[N],
2018  size_type indexStart) const
2019 {
2020 #if defined(Q_CC_MSVC)
2021  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2022 #endif
2023 
2024  // make this safe by treating str as utf8
2025  return find_first_not_of(CsBasicString::fromUtf8(str, N-1), indexStart);
2026 }
2027 
2028 template <typename E, typename A>
2029 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_first_not_of(const CsBasicString &str,
2030  size_type indexStart) const
2031 {
2032  size_type stringLen = this->size();
2033 
2034  if (str.empty()) {
2035 
2036  if (indexStart >= stringLen) {
2037  return -1;
2038  } else {
2039  return indexStart;
2040  }
2041  }
2042 
2043  if (indexStart >= stringLen) {
2044  return -1;
2045  }
2046 
2047  size_type retval = indexStart;
2048  auto iter = begin() + indexStart;
2049 
2050  auto str_end = str.end();
2051 
2052  while (iter != end()) {
2053  const_iterator pattern_iter = str.begin();
2054 
2055  while (pattern_iter != str_end) {
2056 
2057  if (*iter == *pattern_iter) {
2058  // found a match between the current character in m_string and the pattern
2059  break;
2060  }
2061 
2062  ++pattern_iter;
2063  }
2064 
2065  if (pattern_iter == str_end) {
2066  // current character in m_string did not match the pattern
2067  return retval;
2068  }
2069 
2070  ++iter;
2071  ++retval;
2072  }
2073 
2074  return -1;
2075 }
2076 
2077 template <typename E, typename A>
2078 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_not_of(CsChar c, size_type indexStart) const
2079 {
2080  size_type stringLen = this->size();
2081 
2082  if (indexStart >= stringLen) {
2083  return -1;
2084  }
2085 
2086  size_type retval;
2087  const_iterator iter;
2088 
2089  if (indexStart >= 0 && indexStart < stringLen) {
2090  retval = indexStart + 1;
2091  iter = begin() + indexStart + 1;
2092 
2093  } else {
2094  retval = stringLen;
2095  iter = end();
2096 
2097  }
2098 
2099  while (iter != begin()) {
2100  --iter;
2101  --retval;
2102 
2103  if (*iter != c) {
2104  return retval;
2105  }
2106  }
2107 
2108  return -1;
2109 }
2110 
2111 template <typename E, typename A>
2112 template <typename T, typename>
2113 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_not_of(const T &str, size_type indexStart,
2114  size_type size) const
2115 {
2116 #ifndef CS_STRING_ALLOW_UNSAFE
2117  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
2118 #endif
2119 
2120  // str is a const char *
2121  size_type stringLen = this->size();
2122 
2123  if (str == nullptr || *str == '\0') {
2124 
2125  if (indexStart > stringLen || indexStart == -1) {
2126  return stringLen - 1;
2127  } else {
2128  return indexStart;
2129  }
2130  }
2131 
2132  // make this safe by treating str as utf8
2133  return find_last_not_of(CsBasicString::fromUtf8(str, size), indexStart);
2134 }
2135 
2136 template <typename E, typename A>
2137 template <int N>
2138 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_not_of(const char (&str)[N],
2139  size_type indexStart, size_type size) const
2140 {
2141 #if defined(Q_CC_MSVC)
2142  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2143 #endif
2144 
2145  // make this safe by treating str as utf8
2146  return find_last_not_of(CsBasicString::fromUtf8(str, size), indexStart);
2147 }
2148 
2149 template <typename E, typename A>
2150 template <typename T, typename>
2151 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_not_of(const T &str, size_type indexStart) const
2152 {
2153 #ifndef CS_STRING_ALLOW_UNSAFE
2154  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
2155 #endif
2156 
2157  // str is a const char *
2158  size_type stringLen = this->size();
2159 
2160  if (str == nullptr || *str == '\0') {
2161 
2162  if (indexStart > stringLen || indexStart == -1) {
2163  return stringLen - 1;
2164  } else {
2165  return indexStart;
2166  }
2167  }
2168 
2169  // make this safe by treating str as utf8
2170  return find_last_not_of(CsBasicString::fromUtf8(str), indexStart);
2171 }
2172 
2173 template <typename E, typename A>
2174 template <int N>
2175 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_not_of(const char (&str)[N],
2176  size_type indexStart) const
2177 {
2178 #if defined(Q_CC_MSVC)
2179  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2180 #endif
2181 
2182  // make this safe by treating str as utf8
2183  return find_last_not_of(CsBasicString::fromUtf8(str, N-1), indexStart);
2184 }
2185 
2186 template <typename E, typename A>
2187 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::find_last_not_of(const CsBasicString &str,
2188  size_type indexStart) const
2189 {
2190  size_type stringLen = this->size();
2191 
2192  if (str.empty()) {
2193 
2194  if (indexStart > stringLen || indexStart == -1) {
2195  return stringLen - 1;
2196  } else {
2197  return indexStart;
2198  }
2199  }
2200 
2201  size_type retval;
2202  const_iterator iter;
2203 
2204  if (indexStart >= 0 && indexStart < stringLen) {
2205  retval = indexStart + 1;
2206  iter = begin() + indexStart + 1;
2207 
2208  } else {
2209  retval = stringLen;
2210  iter = end();
2211 
2212  }
2213 
2214  const_iterator str_end = str.end();
2215 
2216  while (iter != begin()) {
2217  --iter;
2218  --retval;
2219 
2220  const_iterator pattern_iter = str.begin();
2221 
2222  while (pattern_iter != str_end) {
2223 
2224  if (*iter == *pattern_iter) {
2225  // found a match between the current character in m_string and the pattern
2226  break;
2227  }
2228 
2229  ++pattern_iter;
2230  }
2231 
2232  if (pattern_iter == str_end) {
2233  // current character in m_string did not match the pattern
2234  return retval;
2235  }
2236  }
2237 
2238  return -1;
2239 }
2240 
2241 template <typename E, typename A>
2242 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::rfind(CsChar c, size_type indexStart) const
2243 {
2244  size_type stringLen = this->size();
2245 
2246  size_type retval;
2247  const_iterator iter;
2248 
2249  if (indexStart >= 0 && indexStart < stringLen) {
2250  retval = indexStart + 1;
2251  iter = begin() + indexStart + 1;
2252 
2253  } else {
2254  retval = stringLen;
2255  iter = end();
2256 
2257  }
2258 
2259  while (iter != begin()) {
2260  --iter;
2261  --retval;
2262 
2263  if (*iter == c) {
2264  return retval;
2265  }
2266  }
2267 
2268  return -1;
2269 }
2270 
2271 template <typename E, typename A>
2272 template <typename T, typename>
2273 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::rfind(const T &str, size_type indexStart,
2274  size_type size) const
2275 {
2276 #ifndef CS_STRING_ALLOW_UNSAFE
2277  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
2278 #endif
2279 
2280  // str is a const char *
2281  size_type stringLen = this->size();
2282 
2283  if (str == nullptr || *str == '\0') {
2284 
2285  if (indexStart > stringLen || indexStart == -1) {
2286  return stringLen;
2287  } else {
2288  return indexStart;
2289  }
2290  }
2291 
2292  // make this safe by treating str as utf8
2293  return rfind(CsBasicString::fromUtf8(str, size), indexStart);
2294 }
2295 
2296 template <typename E, typename A>
2297 template <int N>
2298 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::rfind(const char (&str)[N],
2299  size_type indexStart, size_type size) const
2300 {
2301 #if defined(Q_CC_MSVC)
2302  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2303 #endif
2304 
2305  // make this safe by treating str as utf8
2306  return rfind(CsBasicString::fromUtf8(str, size), indexStart);
2307 }
2308 
2309 template <typename E, typename A>
2310 template <typename T, typename>
2311 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::rfind(const T &str, size_type indexStart) const
2312 {
2313 #ifndef CS_STRING_ALLOW_UNSAFE
2314  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
2315 #endif
2316 
2317  // str is a const char *
2318  size_type stringLen = this->size();
2319 
2320  if (str == nullptr || *str == '\0') {
2321 
2322  if (indexStart > stringLen || indexStart == -1) {
2323  return stringLen;
2324  } else {
2325  return indexStart;
2326  }
2327  }
2328 
2329  // make this safe by treating str as utf8
2330  return rfind(CsBasicString::fromUtf8(str), indexStart);
2331 }
2332 
2333 template <typename E, typename A>
2334 template <int N>
2335 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::rfind(const char (&str)[N], size_type indexStart) const
2336 {
2337 #if defined(Q_CC_MSVC)
2338  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2339 #endif
2340 
2341  // make this safe by treating str as utf8
2342  return rfind(CsBasicString::fromUtf8(str, N-1), indexStart);
2343 }
2344 
2345 template <typename E, typename A>
2346 typename CsBasicString<E, A>::size_type CsBasicString<E, A>::rfind(const CsBasicString &str, size_type indexStart) const
2347 {
2348  size_type stringLen = this->size();
2349 
2350  if (str.empty()) {
2351 
2352  if (indexStart > stringLen || indexStart == -1) {
2353  return stringLen;
2354  } else {
2355  return indexStart;
2356  }
2357  }
2358 
2359  size_type retval;
2360  const_iterator iter;
2361 
2362  if (indexStart >= 0 && indexStart < stringLen) {
2363  retval = indexStart + 1;
2364  iter = begin() + indexStart + 1;
2365 
2366  } else {
2367  retval = stringLen;
2368  iter = end();
2369 
2370  }
2371 
2372  const_iterator str_end = str.end();
2373  auto ch = str[0];
2374 
2375  while (iter != begin()) {
2376  --iter;
2377  --retval;
2378 
2379  if (*iter == ch) {
2380 
2381  auto text_iter = iter + 1;
2382  auto pattern_iter = str.begin() + 1;
2383 
2384  while (text_iter != end() && pattern_iter != str_end) {
2385 
2386  if (*text_iter == *pattern_iter) {
2387  ++text_iter;
2388  ++pattern_iter;
2389 
2390  } else {
2391  break;
2392 
2393  }
2394  }
2395 
2396  if (pattern_iter == str_end) {
2397  // found a match
2398  return retval;
2399  }
2400  }
2401 
2402  }
2403 
2404  return -1;
2405 }
2406 
2407 template <typename E, typename A>
2408 CsChar CsBasicString<E, A>::front() const
2409 {
2410  return *begin();
2411 }
2412 
2413 template <typename E, typename A>
2414 CsBasicString<E,A> CsBasicString<E, A>::fromUtf8(const char *str, size_type numOfChars, const A &a)
2415 {
2416  CsBasicString retval(a);
2417 
2418  if (str == nullptr) {
2419  return retval;
2420  }
2421 
2422  if (numOfChars < 0) {
2423  numOfChars = std::strlen(str);
2424  }
2425 
2426  int multi_size = 0;
2427  char32_t data = 0;
2428 
2429  for (int i = 0; i < numOfChars; ++i) {
2430 
2431  if ((str[i] & 0x80) == 0) {
2432 
2433  if (multi_size != 0) {
2434  // multi byte sequence was too short
2435  multi_size = 0;
2436  retval.append(UCHAR('\uFFFD'));
2437  }
2438 
2439  retval.append(static_cast<char32_t>(str[i]));
2440 
2441  } else if ((str[i] & 0xC0) == 0x80) {
2442  // continuation char
2443 
2444  data = (data << 6) | (static_cast<char32_t>(str[i]) & 0x3F);
2445 
2446  if (multi_size == 2 && data >= 0x80 && data <= 0x7FF) {
2447  multi_size = 0;
2448  retval.append(data);
2449 
2450  } else if (multi_size == 3 && data >= 0x800 && data <= 0xFFFF) {
2451  multi_size = 0;
2452  retval.append(data);
2453 
2454  } else if (multi_size == 4 && data >= 0x10000 && data <= 0x10FFFF) {
2455  multi_size = 0;
2456  retval.append(data);
2457 
2458  }
2459 
2460  } else if ((str[i] & 0xE0) == 0xC0) {
2461  // begin two byte sequence
2462 
2463  if (multi_size != 0) {
2464  // preceding multi byte sequence was too short
2465  retval.append(UCHAR('\uFFFD'));
2466  }
2467 
2468  multi_size = 2;
2469  data = static_cast<char32_t>(str[i]) & 0x1F;
2470 
2471  } else if ((str[i] & 0xF0) == 0xE0) {
2472  // begin three byte sequence
2473 
2474  if (multi_size != 0) {
2475  // preceding multi byte sequence was too short
2476  retval.append(UCHAR('\uFFFD'));
2477  }
2478 
2479  multi_size = 3;
2480  data = static_cast<char32_t>(str[i]) & 0x0F;
2481 
2482  } else if ((str[i] & 0xF8) == 0xF0) {
2483  // begin four byte sequence
2484 
2485  if (multi_size != 0) {
2486  // preceding multi byte sequence was too short
2487  retval.append(UCHAR('\uFFFD'));
2488  }
2489 
2490  multi_size = 4;
2491  data = static_cast<char32_t>(str[i]) & 0x07;
2492 
2493  } else {
2494  // invalid character
2495 
2496  if (multi_size != 0) {
2497  // preceding multi byte sequence was too short
2498  multi_size = 0;
2499  retval.append(UCHAR('\uFFFD'));
2500  }
2501 
2502  retval.append(UCHAR('\uFFFD'));
2503  }
2504  }
2505 
2506  if (multi_size != 0) {
2507  // invalid character at the end of the string
2508  retval.append(UCHAR('\uFFFD'));
2509  }
2510 
2511  return retval;
2512 }
2513 
2514 #if defined(__cpp_char8_t)
2515  // support new data type added in C++20
2516 
2517 template <typename E, typename A>
2518 CsBasicString<E,A> CsBasicString<E, A>::fromUtf8(const char8_t *str, size_type numOfChars, const A &a)
2519 {
2520  CsBasicString retval(a);
2521 
2522  if (str == nullptr) {
2523  return retval;
2524  }
2525 
2526  if (numOfChars < 0) {
2527  numOfChars = std::char_traits<char8_t>::length(str);
2528  }
2529 
2530  int multi_size = 0;
2531  char32_t data = 0;
2532 
2533  for (int i = 0; i < numOfChars; ++i) {
2534 
2535  if ((str[i] & 0x80) == 0) {
2536 
2537  if (multi_size != 0) {
2538  // multi byte sequence was too short
2539  multi_size = 0;
2540  retval.append(UCHAR('\uFFFD'));
2541  }
2542 
2543  retval.append(static_cast<char32_t>(str[i]));
2544 
2545  } else if ((str[i] & 0xC0) == 0x80) {
2546  // continuation char
2547 
2548  data = (data << 6) | (static_cast<char32_t>(str[i]) & 0x3F);
2549 
2550  if (multi_size == 2 && data >= 0x80 && data <= 0x7FF) {
2551  multi_size = 0;
2552  retval.append(data);
2553 
2554  } else if (multi_size == 3 && data >= 0x800 && data <= 0xFFFF) {
2555  multi_size = 0;
2556  retval.append(data);
2557 
2558  } else if (multi_size == 4 && data >= 0x10000 && data <= 0x10FFFF) {
2559  multi_size = 0;
2560  retval.append(data);
2561 
2562  }
2563 
2564  } else if ((str[i] & 0xE0) == 0xC0) {
2565  // begin two byte sequence
2566 
2567  if (multi_size != 0) {
2568  // preceding multi byte sequence was too short
2569  retval.append(UCHAR('\uFFFD'));
2570  }
2571 
2572  multi_size = 2;
2573  data = static_cast<char32_t>(str[i]) & 0x1F;
2574 
2575  } else if ((str[i] & 0xF0) == 0xE0) {
2576  // begin three byte sequence
2577 
2578  if (multi_size != 0) {
2579  // preceding multi byte sequence was too short
2580  retval.append(UCHAR('\uFFFD'));
2581  }
2582 
2583  multi_size = 3;
2584  data = static_cast<char32_t>(str[i]) & 0x0F;
2585 
2586  } else if ((str[i] & 0xF8) == 0xF0) {
2587  // begin four byte sequence
2588 
2589  if (multi_size != 0) {
2590  // preceding multi byte sequence was too short
2591  retval.append(UCHAR('\uFFFD'));
2592  }
2593 
2594  multi_size = 4;
2595  data = static_cast<char32_t>(str[i]) & 0x07;
2596 
2597  } else {
2598  // invalid character
2599 
2600  if (multi_size != 0) {
2601  // preceding multi byte sequence was too short
2602  multi_size = 0;
2603  retval.append(UCHAR('\uFFFD'));
2604  }
2605 
2606  retval.append(UCHAR('\uFFFD'));
2607  }
2608  }
2609 
2610  if (multi_size != 0) {
2611  // invalid character at the end of the string
2612  retval.append(UCHAR('\uFFFD'));
2613  }
2614 
2615  return retval;
2616 }
2617 
2618 #endif
2619 
2620 template <typename E, typename A>
2621 CsBasicString<E,A> CsBasicString<E, A>::fromUtf16(const char16_t *str, size_type numOfChars, const A &a)
2622 {
2623  CsBasicString retval(a);
2624 
2625  if (str == nullptr) {
2626  return retval;
2627  }
2628 
2629  if (numOfChars < 0) {
2630  numOfChars = std::char_traits<char16_t>::length(str);
2631  }
2632 
2633  char32_t data = 0;
2634 
2635  for (int i = 0; i < numOfChars; ++i) {
2636 
2637  char16_t value = str[i];
2638 
2639  if (value < 0xD800 || value > 0xDFFF) {
2640  // not a surrogate, value must be less than 0xFFFF
2641 
2642  if (data == 0) {
2643  // do nothing
2644 
2645  } else {
2646  // invalid character
2647  retval.append(UCHAR('\uFFFD'));
2648  data = 0;
2649  }
2650 
2651  retval.append(static_cast<char32_t>(str[i]));
2652 
2653  } else if (value >= 0xD800 && value <= 0xDBFF) {
2654  // high surrogates
2655 
2656  if (data == 0) {
2657  // do nothing
2658 
2659  } else {
2660  // invalid character
2661  retval.append(UCHAR('\uFFFD'));
2662  data = 0;
2663  }
2664 
2665  data = static_cast<char32_t>(value) & 0x3FF;
2666 
2667  } else if (value >= 0xDC00 && value <= 0xDFFF) {
2668  // low surrogates
2669 
2670  if (data == 0) {
2671  // invalid character
2672  retval.append(UCHAR('\uFFFD'));
2673 
2674  } else {
2675  data = (data << 10) | (static_cast<char32_t>(value) & 0x3FF);
2676  data |= 0x010000;
2677 
2678  retval.append(data);
2679  }
2680 
2681  data = 0;
2682 
2683  } else {
2684  // invalid character ( unreachable code )
2685  retval.append(UCHAR('\uFFFD'));
2686  }
2687  }
2688 
2689  if (data != 0) {
2690  // invalid character at the end of the string
2691  retval.append(UCHAR('\uFFFD'));
2692  }
2693 
2694  return retval;
2695 }
2696 
2697 template <typename E, typename A>
2698 A CsBasicString<E, A>::getAllocator() const
2699 {
2700  return m_string.get_allocator();
2701 }
2702 
2703 template <typename E, typename A>
2704 CsBasicString<E, A> &CsBasicString<E, A>::insert(size_type indexStart, size_type count, CsChar c)
2705 {
2706  const_iterator iter_begin = cbegin();
2707  size_type i;
2708 
2709  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
2710  ++iter_begin;
2711  }
2712 
2713  if (i != indexStart) {
2714  throw std::out_of_range("CsString::insert index out of range");
2715  }
2716 
2717  E::insert(m_string, iter_begin.codePointBegin(), c, count);
2718 
2719  return *this;
2720 }
2721 
2722 template <typename E, typename A>
2723 template <typename T, typename>
2724 CsBasicString<E, A> &CsBasicString<E, A>::insert(size_type indexStart, const T &str)
2725 {
2726 #ifndef CS_STRING_ALLOW_UNSAFE
2727  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
2728 #endif
2729 
2730  // str is a const char *
2731  if (str == nullptr || *str == '\0') {
2732  return *this;
2733  }
2734 
2735  // make this safe by treating str as utf8
2736  return insert(indexStart, CsBasicString::fromUtf8(str));
2737 }
2738 
2739 template <typename E, typename A>
2740 template <int N>
2741 CsBasicString<E, A> &CsBasicString<E, A>::insert(size_type indexStart, const char (&str)[N])
2742 {
2743 #if defined(Q_CC_MSVC)
2744  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2745 #endif
2746 
2747  // make this safe by treating str as utf8
2748  return insert(indexStart, CsBasicString::fromUtf8(str, N -1));
2749 }
2750 
2751 template <typename E, typename A>
2752 template <typename T, typename>
2753 CsBasicString<E, A> &CsBasicString<E, A>::insert(size_type indexStart, const T &str, size_type size)
2754 {
2755 #ifndef CS_STRING_ALLOW_UNSAFE
2756  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
2757 #endif
2758 
2759  // str is a const char *
2760  if (str == nullptr || *str == '\0') {
2761  return *this;
2762  }
2763 
2764  // make this safe by treating str as utf8
2765  return insert(indexStart, CsBasicString::fromUtf8(str, size));
2766 }
2767 
2768 template <typename E, typename A>
2769 template <int N>
2770 CsBasicString<E, A> &CsBasicString<E, A>::insert(size_type indexStart, const char (&str)[N], size_type size)
2771 {
2772 #if defined(Q_CC_MSVC)
2773  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2774 #endif
2775 
2776  // make this safe by treating str as utf8
2777  return insert(indexStart, CsBasicString::fromUtf8(str, size));
2778 }
2779 
2780 template <typename E, typename A>
2781 CsBasicString<E, A> &CsBasicString<E, A>::insert(size_type indexStart, const CsBasicString &str)
2782 {
2783  const_iterator iter_begin = cbegin();
2784  size_type i;
2785 
2786  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
2787  ++iter_begin;
2788  }
2789 
2790  if (i != indexStart) {
2791  throw std::out_of_range("CsString::insert index out of range");
2792  }
2793 
2794  for (CsChar c : str) {
2795  str_iter iter_tmp = E::insert(m_string, iter_begin.codePointBegin(), c);
2796 
2797  iter_begin = CsStringIterator<E, A>(iter_tmp);
2798  ++iter_begin;
2799  }
2800 
2801  return *this;
2802 }
2803 
2804 template <typename E, typename A>
2805 CsBasicString<E, A> &CsBasicString<E, A>::insert(size_type indexStart, const CsBasicString &str,
2806  size_type srcStart, size_type size)
2807 {
2808  const_iterator iter_begin = cbegin();
2809  size_type i;
2810 
2811  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
2812  ++iter_begin;
2813  }
2814 
2815  if (i != indexStart) {
2816  throw std::out_of_range("CsString::insert index out of range");
2817  }
2818 
2819  const_iterator srcIter_begin = str.begin() + srcStart;
2820  const_iterator srcIter_end = srcIter_begin + size;
2821 
2822  for (auto srcIter = srcIter_begin; srcIter != srcIter_end; ++srcIter) {
2823  // *srcIter is a CsChar
2824  str_iter iter_tmp = E::insert(m_string, iter_begin.codePointBegin(), *srcIter);
2825 
2826  iter_begin = CsStringIterator<E, A>(iter_tmp);
2827  ++iter_begin;
2828  }
2829 
2830  return *this;
2831 }
2832 
2833 template <typename E, typename A>
2834 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(const_iterator posStart, CsChar c)
2835 {
2836  str_iter iter_tmp = E::insert(m_string, posStart.codePointBegin(), c);
2837  return CsStringIterator<E, A>(iter_tmp);
2838 }
2839 
2840 template <typename E, typename A>
2841 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(const_iterator posStart, size_type count, CsChar c)
2842 {
2843  str_iter iter_tmp = E::insert(m_string, posStart.codePointBegin(), c, count);
2844  return CsStringIterator<E, A>(iter_tmp);
2845 }
2846 
2847 template <typename E, typename A>
2848 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(const_iterator posStart, const CsBasicString &str)
2849 {
2850  const_iterator iter = posStart;
2851  int count = 0;
2852 
2853  for (auto c : str) {
2854  str_iter iter_tmp = E::insert(m_string, iter.codePointBegin(), c);
2855 
2856  iter = CsStringIterator<E, A>(iter_tmp);
2857  ++iter;
2858 
2859  ++count;
2860  }
2861 
2862  return (iter);
2863 }
2864 
2865 template <typename E, typename A>
2866 template <typename T, typename>
2867 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(const_iterator posStart, const T &str,
2868  size_type size)
2869 {
2870 #ifndef CS_STRING_ALLOW_UNSAFE
2871  static_assert(! std::is_same<E, E>::value, "Unsafe operations not allowed, unknown encoding for this operation");
2872 #endif
2873 
2874  // str is a const char *
2875  if (str == nullptr || *str == '\0') {
2876  return posStart;
2877  }
2878 
2879  // make this safe by treating str as utf8
2880  return insert(posStart, CsBasicString::fromUtf8(str, size));
2881 }
2882 
2883 template <typename E, typename A>
2884 template <int N>
2885 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(const_iterator posStart, const char (&str)[N], size_type size)
2886 {
2887 #if defined(Q_CC_MSVC)
2888  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
2889 #endif
2890 
2891  // make this safe by treating str as utf8
2892  return insert(posStart, CsBasicString::fromUtf8(str, size));
2893 }
2894 
2895 template <typename E, typename A>
2896 template <typename Iterator>
2897 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(const_iterator posStart,
2898  Iterator begin, Iterator end)
2899 {
2900  const_iterator iter = posStart;
2901  int count = 0;
2902 
2903  for (auto item = begin; item != end; ++item) {
2904  CsChar c = *item;
2905 
2906  str_iter iter_tmp = E::insert(m_string, iter.codePointBegin(), c);
2907 
2908  iter = CsStringIterator<E, A>(iter_tmp);
2909  ++iter;
2910 
2911  ++count;
2912  }
2913 
2914  return (iter - count);
2915 }
2916 
2917 template <typename E, typename A>
2918 template <typename U, typename>
2919 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(size_type indexStart, CsBasicStringView<U> str)
2920 {
2921  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
2922  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
2923  "incompatible with the encoding for U");
2924 
2925  const_iterator iter_begin = cbegin();
2926  size_type i;
2927 
2928  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
2929  ++iter_begin;
2930  }
2931 
2932  if (i != indexStart) {
2933  throw std::out_of_range("CsString::insert index out of range");
2934  }
2935 
2936  for (CsChar c : str) {
2937  str_iter iter_tmp = E::insert(m_string, iter_begin.codePointBegin(), c);
2938 
2939  iter_begin = CsStringIterator<E, A>(iter_tmp);
2940  ++iter_begin;
2941  }
2942 
2943  return iter_begin;
2944 }
2945 
2946 template <typename E, typename A>
2947 template <typename U, typename>
2948 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::insert(size_type indexStart, CsBasicStringView<U> str,
2949  size_type srcStart, size_type size)
2950 {
2951  static_assert(std::is_base_of<CsBasicString<E,A>, U>::value,
2952  "Unable to construct a CsBasicString using a CsBasicStringView, encoding E is "
2953  "incompatible with the encoding for U");
2954 
2955  const_iterator iter_begin = cbegin();
2956  size_type i;
2957 
2958  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
2959  ++iter_begin;
2960  }
2961 
2962  if (i != indexStart) {
2963  throw std::out_of_range("CsString::insert index out of range");
2964  }
2965 
2966  typename U::const_iterator srcIter_begin = str.begin() + srcStart;
2967  typename U::const_iterator srcIter_end = srcIter_begin + size;
2968 
2969  for (auto srcIter = srcIter_begin; srcIter != srcIter_end; ++srcIter) {
2970  // *srcIter is a CsChar
2971  str_iter iter_tmp = E::insert(m_string, iter_begin.codePointBegin(), *srcIter);
2972 
2973  iter_begin = CsStringIterator<E, A>(iter_tmp);
2974  ++iter_begin;
2975  }
2976 
2977  return iter_begin;
2978 }
2979 
2980 template <typename E, typename A>
2981 auto CsBasicString<E, A>::length() const -> size_type
2982 {
2983  return size();
2984 }
2985 
2986 template <typename E, typename A>
2987 void CsBasicString<E, A>::pop_back()
2988 {
2989  if (empty()) {
2990  return;
2991  }
2992 
2993  const_iterator iter = --end();
2994  erase(iter);
2995 }
2996 
2997 template <typename E, typename A>
2998 void CsBasicString<E, A>::push_back(CsChar c)
2999 {
3000  append(c);
3001 }
3002 
3003 template <typename E, typename A>
3004 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type size, const CsBasicString &str)
3005 {
3006  const_iterator iter_begin = cbegin();
3007  const_iterator iter_end;
3008  size_type i;
3009 
3010  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
3011  ++iter_begin;
3012  }
3013 
3014  if (i != indexStart) {
3015  throw std::out_of_range("CsString::replace index out of range");
3016  }
3017 
3018  if (size >= 0) {
3019  iter_end = iter_begin;
3020 
3021  for (size_type j = 0; j < size && iter_end != cend(); ++j) {
3022  ++iter_end;
3023  }
3024 
3025  } else {
3026  iter_end = cend();
3027 
3028  }
3029 
3030  auto iter = erase(iter_begin, iter_end);
3031  insert(iter, str);
3032 
3033  return *this;
3034 }
3035 
3036 template <typename E, typename A>
3037 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first, const_iterator last, const CsBasicString &str)
3038 {
3039  auto iter = erase(first, last);
3040  insert(iter, str);
3041 
3042  return *this;
3043 }
3044 
3045 template <typename E, typename A>
3046 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type count, const CsBasicString &str,
3047  size_type srcStart, size_type size)
3048 {
3049  const_iterator iter_begin = cbegin();
3050  const_iterator iter_end;
3051  size_type i;
3052 
3053  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
3054  ++iter_begin;
3055  }
3056 
3057  if (i != indexStart) {
3058  throw std::out_of_range("CsString::replace index out of range");
3059  }
3060 
3061  if (count >= 0) {
3062  iter_end = iter_begin;
3063 
3064  for (size_type j = 0; j < count && iter_end != cend(); ++j) {
3065  ++iter_end;
3066  }
3067 
3068  } else {
3069  iter_end = cend();
3070 
3071  }
3072 
3073  const_iterator srcIter_begin = str.begin() + srcStart;
3074  const_iterator srcIter_end = srcIter_begin + size;
3075 
3076  auto iter = erase(iter_begin, iter_end);
3077  insert(iter, srcIter_begin, srcIter_end);
3078 
3079  return *this;
3080 }
3081 
3082 template <typename E, typename A>
3083 template <class Iterator>
3084 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first1, const_iterator last1,
3085  Iterator first2, Iterator last2)
3086 {
3087  auto iter = erase(first1, last1);
3088  insert(iter, first2, last2);
3089 
3090  return *this;
3091 }
3092 
3093 template <typename E, typename A>
3094 template <typename T, typename>
3095 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type count,
3096  const T &str, size_type size)
3097 {
3098  // str is a const char *
3099 
3100  // make this safe by treating str as utf8
3101  return replace(indexStart, count, CsBasicString::fromUtf8(str, size));
3102 }
3103 
3104 template <typename E, typename A>
3105 template <int N>
3106 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type count, const char (&str)[N], size_type size)
3107 {
3108 #if defined(Q_CC_MSVC)
3109  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
3110 #endif
3111 
3112  // make this safe by treating str as utf8
3113  return replace(indexStart, count, CsBasicString::fromUtf8(str, size));
3114 }
3115 
3116 template <typename E, typename A>
3117 template <typename T, typename>
3118 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first, const_iterator last,
3119  const T &str, size_type size)
3120 {
3121  // str is a const char *
3122 
3123  auto iter = erase(first, last);
3124  insert(iter, str, size);
3125 
3126  return *this;
3127 }
3128 
3129 template <typename E, typename A>
3130 template <int N>
3131 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first, const_iterator last,
3132  const char (&str)[N], size_type size )
3133 {
3134  auto iter = erase(first, last);
3135  insert(iter, str, size);
3136 
3137  return *this;
3138 }
3139 
3140 template <typename E, typename A>
3141 template <typename T, typename>
3142 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type count, const T &str)
3143 {
3144  // str is a const char *
3145 
3146  // make this safe by treating str as utf8
3147  return replace(indexStart, count, CsBasicString::fromUtf8(str));
3148 }
3149 
3150 template <typename E, typename A>
3151 template <int N>
3152 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type count, const char (&str)[N])
3153 {
3154 #if defined(Q_CC_MSVC)
3155  static_assert("¿"[0] == static_cast<char>(0xC2), "Compiler runtime encoding was not set to UTF-8");
3156 #endif
3157 
3158  // make this safe by treating str as utf8
3159  return replace(indexStart, count, CsBasicString::fromUtf8(str, N-1));
3160 }
3161 
3162 template <typename E, typename A>
3163 template <typename T, typename>
3164 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first, const_iterator last, const T &str)
3165 {
3166  // str is a const char *
3167 
3168  auto iter = erase(first, last);
3169  insert(iter, str);
3170 
3171  return *this;
3172 }
3173 
3174 template <typename E, typename A>
3175 template <int N>
3176 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first, const_iterator last,
3177  const char (&str)[N])
3178 {
3179  auto iter = erase(first, last);
3180  insert(iter, str);
3181 
3182  return *this;
3183 }
3184 
3185 template <typename E, typename A>
3186 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type size,
3187  size_type count, CsChar c)
3188 {
3189  const_iterator iter_begin = cbegin();
3190  const_iterator iter_end;
3191  size_type i;
3192 
3193  for (i = 0; i < indexStart && iter_begin != cend(); ++i) {
3194  ++iter_begin;
3195  }
3196 
3197  if (i != indexStart) {
3198  throw std::out_of_range("CsString::replace index out of range");
3199  }
3200 
3201  if (size >= 0) {
3202  iter_end = iter_begin;
3203 
3204  for (size_type j = 0; j < size && iter_end != cend(); ++j) {
3205  ++iter_end;
3206  }
3207 
3208  } else {
3209  iter_end = cend();
3210 
3211  }
3212 
3213  auto iter = erase(iter_begin, iter_end);
3214  insert(iter, count, c);
3215 
3216  return *this;
3217 }
3218 
3219 template <typename E, typename A>
3220 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first, const_iterator last,
3221  size_type count, CsChar c)
3222 {
3223  auto iter = erase(first, last);
3224  insert(iter, count, c);
3225 
3226  return *this;
3227 }
3228 
3229 template <typename E, typename A>
3230 template <class T>
3231 CsBasicString<E, A> &CsBasicString<E, A>::replace(size_type indexStart, size_type count, const T &str,
3232  size_type srcStart, size_type size)
3233 {
3234  // str is a const char *
3235 
3236  // make this safe by treating str as utf8
3237  return replace(indexStart, count, CsBasicString::fromUtf8(str + srcStart, size));
3238 }
3239 
3240 template <typename E, typename A>
3241 template <class T>
3242 CsBasicString<E, A> &CsBasicString<E, A>::replace(const_iterator first, const_iterator last, const T &str,
3243  size_type srcStart, size_type size)
3244 {
3245  auto iter = erase(first, last);
3246  insert(iter, str, srcStart, size);
3247 
3248  return *this;
3249 }
3250 
3251 template <typename E, typename A>
3252 typename CsBasicString<E, A>::iterator CsBasicString<E, A>::replace(const_iterator iter, const CsBasicString &str)
3253 {
3254  auto tmpIter = erase(iter);
3255  return insert(tmpIter, str);
3256 }
3257 
3258 template <typename E, typename A>
3259 void CsBasicString<E, A>::resize(size_type size)
3260 {
3261  if (size < 0) {
3262  size = 0;
3263  }
3264 
3265  size_type stringLen = this->size();
3266  size_type count = size - stringLen;
3267 
3268  CsChar c;
3269 
3270  if (count > 0) {
3271  append(count, c);
3272 
3273  } else if (count < 0) {
3274  auto end = this->end();
3275  auto begin = end + count;
3276 
3277  erase(begin, end);
3278  }
3279 }
3280 
3281 template <typename E, typename A>
3282 void CsBasicString<E, A>::resize(size_type size, CsChar c)
3283 {
3284  if (size < 0) {
3285  size = 0;
3286  }
3287 
3288  size_type stringLen = this->size();
3289  size_type count = size - stringLen;
3290 
3291  if (count > 0) {
3292  append(count, c);
3293 
3294  } else if (count < 0) {
3295  erase(size, -count);
3296 
3297  }
3298 }
3299 
3300 template <typename E, typename A>
3301 auto CsBasicString<E, A>::size_storage() const -> size_type
3302 {
3303  // remove one for the null terminator
3304  return m_string.size() - 1;
3305 }
3306 
3307 template <typename E, typename A>
3308 auto CsBasicString<E, A>::size_codePoints() const -> size_type
3309 {
3310  return size();
3311 }
3312 
3313 template <typename E, typename A>
3314 auto CsBasicString<E, A>::size() const -> size_type
3315 {
3316  return E::distance(m_string.cbegin(), m_string.cend() - 1);
3317 }
3318 
3319 template <typename E, typename A>
3320 void CsBasicString<E, A>::shrink_to_fit()
3321 {
3322  m_string.shrink_to_fit();
3323 }
3324 
3325 template <typename E, typename A>
3326 CsBasicString<E, A> CsBasicString<E, A>::substr(size_type indexStart, size_type size) const
3327 {
3328  const_iterator iter_begin = cbegin();
3329  const_iterator iter_end;
3330 
3331  for (size_type i = 0; i < indexStart && iter_begin != cend(); ++i) {
3332  ++iter_begin;
3333  }
3334 
3335  if (iter_begin == cend()) {
3336  // indexStart > length
3337  return CsBasicString();
3338  }
3339 
3340  if (size >= 0) {
3341  iter_end = iter_begin;
3342 
3343  for (size_type i = 0; i < size && iter_end != cend(); ++i) {
3344  ++iter_end;
3345  }
3346 
3347  } else {
3348  iter_end = cend();
3349 
3350  }
3351 
3352  return CsBasicString(iter_begin, iter_end);
3353 }
3354 
3355 template <typename E, typename A>
3356 void CsBasicString<E, A>::swap(CsBasicString &str)
3357 {
3358  m_string.swap(str.m_string);
3359 }
3360 
3361 // iterator methods
3362 template <typename E, typename A>
3363 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::begin() const
3364 {
3365  return CsStringIterator<E, A> (m_string.begin());
3366 }
3367 
3368 template <typename E, typename A>
3369 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::cbegin() const
3370 {
3371  return CsStringIterator<E, A> (m_string.cbegin());
3372 }
3373 
3374 template <typename E, typename A>
3375 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::end() const
3376 {
3377 
3378  return CsStringIterator<E, A> (m_string.end() - 1);
3379 }
3380 
3381 template <typename E, typename A>
3382 typename CsBasicString<E, A>::const_iterator CsBasicString<E, A>::cend() const
3383 {
3384 
3385  return CsStringIterator<E, A> (m_string.cend() - 1);
3386 }
3387 
3388 template <typename E, typename A>
3389 typename CsBasicString<E, A>::const_reverse_iterator CsBasicString<E, A>::rbegin() const
3390 {
3391  return const_reverse_iterator(end());
3392 }
3393 
3394 template <typename E, typename A>
3395 typename CsBasicString<E, A>::const_reverse_iterator CsBasicString<E, A>::crbegin() const
3396 {
3397  return const_reverse_iterator(cend());
3398 }
3399 
3400 template <typename E, typename A>
3401 typename CsBasicString<E, A>::const_reverse_iterator CsBasicString<E, A>::rend() const
3402 {
3403  return const_reverse_iterator(begin());
3404 }
3405 
3406 template <typename E, typename A>
3407 typename CsBasicString<E, A>::const_reverse_iterator CsBasicString<E, A>::crend() const
3408 {
3409  return const_reverse_iterator(cbegin());
3410 }
3411 
3412 template <typename E, typename A>
3413 typename CsBasicString<E, A>::const_storage_iterator CsBasicString<E, A>::storage_begin() const
3414 {
3415  return m_string.cbegin();
3416 }
3417 
3418 template <typename E, typename A>
3419 typename CsBasicString<E, A>::const_storage_iterator CsBasicString<E, A>::storage_end() const
3420 {
3421  return m_string.cend() - 1;
3422 }
3423 
3424 template <typename E, typename A>
3425 typename CsBasicString<E, A>::const_storage_reverse_iterator CsBasicString<E, A>::storage_rbegin() const
3426 {
3427  return m_string.crbegin() + 1;
3428 }
3429 
3430 template <typename E, typename A>
3431 typename CsBasicString<E, A>::const_storage_reverse_iterator CsBasicString<E, A>::storage_rend() const
3432 {
3433  return m_string.crend();
3434 }
3435 
3436 // functions
3437 template <typename E_FROM, typename A_FROM, typename E_TO, typename A_TO>
3438 void convert(const CsBasicString<E_FROM, A_FROM> &str_from, CsBasicString<E_TO, A_TO> &str_to)
3439 {
3440  str_to.assign(str_from.begin(), str_from.end());
3441 }
3442 
3443 template <typename E, typename A>
3444 void swap(CsBasicString<E, A> &str1, CsBasicString<E, A> &str2)
3445 {
3446  str1.swap(str2);
3447 }
3448 
3449 template <typename E1, typename A1, typename E2, typename A2>
3450 bool operator==(const CsBasicString<E1, A1> &str1, const CsBasicString<E2, A2> &str2)
3451 {
3452  // E1 and E2 are different
3453 
3454  auto iter1 = str1.begin();
3455  auto iter2 = str2.begin();
3456 
3457  auto end1 = str1.end();
3458  auto end2 = str2.end();
3459 
3460  while (iter1 != end1 && iter2 != end2) {
3461 
3462  if (*iter1 != *iter2) {
3463  return false;
3464  }
3465 
3466  ++iter1;
3467  ++iter2;
3468  }
3469 
3470  if (iter1 == end1 && iter2 == end2) {
3471  return true;
3472  }
3473 
3474  return false;
3475 }
3476 
3477 template <typename E, typename A>
3478 bool operator==(const CsBasicString<E, A> &str1, const CsBasicString<E, A> &str2)
3479 {
3480  // E is the same
3481 
3482  // are the vectors equal
3483  return std::equal(str1.storage_begin(), str1.storage_end(), str2.storage_begin(), str2.storage_end());
3484 }
3485 
3486 inline bool operator==(const CsString_utf8 &str1, const CsString_utf8 &str2)
3487 {
3488  // are the vectors equal
3489  return std::equal(str1.storage_begin(), str1.storage_end(), str2.storage_begin(), str2.storage_end());
3490 }
3491 
3492 inline bool operator==(const CsString_utf16 &str1, const CsString_utf16 &str2)
3493 {
3494  // are the vectors equal
3495  return std::equal(str1.storage_begin(), str1.storage_end(), str2.storage_begin(), str2.storage_end());
3496 }
3497 
3498 template <int N>
3499 inline bool operator==(const CsString_utf8 &str1, const char (& str2)[N])
3500 {
3501  return std::equal(str1.storage_begin(), str1.storage_end(), str2, str2+N-1,
3502  [] (auto a, auto b) { return static_cast<uint8_t>(a) == static_cast<uint8_t>(b);} );
3503 }
3504 
3505 template <int N>
3506 inline bool operator==(const char (& str1)[N], const CsString_utf8 &str2)
3507 {
3508  return std::equal(str1, str1+N-1, str2.storage_begin(), str2.storage_end(),
3509  [] (auto a, auto b) { return static_cast<uint8_t>(a) == static_cast<uint8_t>(b);} );
3510 }
3511 
3512 template <int N>
3513 inline bool operator==(const CsString_utf16 &str1, const char16_t (& str2)[N])
3514 {
3515  return std::equal(str1.storage_begin(), str1.storage_end(), str2, str2+N-1);
3516 }
3517 
3518 template <int N>
3519 inline bool operator==(const char16_t (& str1)[N], const CsString_utf16 &str2)
3520 {
3521  return std::equal(str1, str1+N-1, str2.storage_begin(), str2.storage_end());
3522 }
3523 
3524 template <typename E1, typename A1, typename E2, typename A2>
3525 bool operator!=(const CsBasicString<E1, A1> &str1, const CsBasicString<E2, A2> &str2)
3526 {
3527  return ! (str1 == str2);
3528 }
3529 
3530 template <typename E, typename A>
3531 bool operator!=(const CsBasicString<E, A> &str1, const CsBasicString<E, A> &str2)
3532 {
3533  return ! (str1 == str2);
3534 }
3535 
3536 inline bool operator!=(const CsString_utf8 &str1, const CsString_utf8 &str2)
3537 {
3538  return ! (str1 == str2);
3539 }
3540 
3541 inline bool operator!=(const CsString_utf16 &str1, const CsString_utf16 &str2)
3542 {
3543  return ! (str1 == str2);
3544 }
3545 
3546 inline CsString_utf8 operator+(CsString_utf8 str1, const CsString_utf8 &str2)
3547 {
3548  str1.append(str2);
3549 
3550  return str1;
3551 }
3552 
3553 inline CsString_utf16 operator+(CsString_utf16 str1, const CsString_utf16 &str2)
3554 {
3555  str1.append(str2);
3556 
3557  return str1;
3558 }
3559 
3560 template <typename E, typename A>
3561 CsBasicString<E, A> operator+(const CsBasicString<E, A> &str, CsChar c)
3562 {
3563  CsBasicString<E, A> retval = str;
3564  retval.append(c);
3565 
3566  return retval;
3567 }
3568 
3569 template <typename E, typename A>
3570 CsBasicString<E, A> operator+(CsChar c, const CsBasicString<E, A> &str)
3571 {
3572  CsBasicString<E, A> retval = str;
3573  retval.insert(0, 1, c);
3574 
3575  return retval;
3576 }
3577 
3578 template <typename E, typename A>
3579 CsBasicString<E, A> operator+(CsBasicString<E, A> &&str, CsChar c)
3580 {
3581  str.append(c);
3582  return str;
3583 }
3584 
3585 template <typename E, typename A>
3586 CsBasicString<E, A> operator+(CsChar c, CsBasicString<E, A> &&str)
3587 {
3588  str.insert(0, 1, c);
3589  return str;
3590 }
3591 
3592 template <typename E, typename A, typename T, typename = typename std::enable_if<std::is_array<T>::value &&
3593  std::is_same<char, typename std::remove_extent<T>::type>::value>::type>
3594 CsBasicString<E, A> operator+(const CsBasicString<E, A> &str1, const T &str2)
3595 {
3596  CsBasicString<E, A> retval = str1;
3597  retval.append(str2);
3598 
3599  return retval;
3600 }
3601 
3602 template <typename E, typename A, typename T, typename = typename std::enable_if<std::is_array<T>::value &&
3603  std::is_same<char, typename std::remove_extent<T>::type>::value>::type>
3604 CsBasicString<E, A> operator+(const T &str1, const CsBasicString<E, A> &str2)
3605 {
3606  CsBasicString<E, A> retval = str1;
3607  retval.append(str2);
3608 
3609  return retval;
3610 }
3611 
3612 template <typename E1, typename A1, typename E2, typename A2>
3613 bool operator<(const CsBasicString<E1, A1> &str1, const CsBasicString<E2, A2> &str2)
3614 {
3615  return std::lexicographical_compare(str1.begin(), str1.end(), str2.begin(), str2.end());
3616 }
3617 
3618 template <typename E1, typename A1, typename E2, typename A2>
3619 bool operator<=(const CsBasicString<E1, A1> &str1, const CsBasicString<E2, A2> &str2)
3620 {
3621  return ! (str1 > str2);
3622 }
3623 
3624 template <typename E1, typename A1, typename E2, typename A2>
3625 bool operator>(const CsBasicString<E1, A1> &str1, const CsBasicString<E2, A2> &str2)
3626 {
3627  return std::lexicographical_compare(str2.begin(), str2.end(), str1.begin(), str1.end());
3628 }
3629 
3630 template <typename E1, typename A1, typename E2, typename A2>
3631 bool operator>=(const CsBasicString<E1, A1> &str1, const CsBasicString<E2, A2> &str2)
3632 {
3633  return ! (str1 < str2);
3634 }
3635 
3636 #if defined(__cpp_char8_t)
3637  // support new data type added in C++20
3638 
3639  template <typename E, typename A>
3640  CsBasicString<E, A>::CsBasicString(const char8_t *str, const A &a)
3641  {
3642  *this = CsBasicString::fromUtf8(str, -1, a);
3643  }
3644 
3645  template <typename E, typename A>
3646  CsBasicString<E, A>::CsBasicString(const char8_t *str, size_type size, const A &a)
3647  {
3648  *this = CsBasicString::fromUtf8(str, size, a);
3649  }
3650 #endif
3651 
3652 
3653 } // namespace
3654 
3655 #endif
#define UCHAR(x)
Definition: cs_string.h:37