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