CsString  1.4.0
cs_string_view.h
1 /***********************************************************************
2 *
3 * Copyright (c) 2017-2024 Barbara Geller
4 * Copyright (c) 2017-2024 Ansel Sermersheim
5 *
6 * This file is part of CsString.
7 *
8 * CsString is free software, released under the BSD 2-Clause license.
9 * For license details refer to LICENSE provided with this project.
10 *
11 * CsString is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 *
15 * https://opensource.org/licenses/BSD-2-Clause
16 *
17 ***********************************************************************/
18 
19 #ifndef LIB_CS_STRING_VIEW_H
20 #define LIB_CS_STRING_VIEW_H
21 
22 #include <cs_string.h>
23 
24 namespace CsString {
25 
26 template <typename S>
27 class CsBasicStringView;
28 
29 using CsStringView = CsBasicStringView<CsBasicString<utf8>>;
30 using CsStringView_utf8 = CsBasicStringView<CsBasicString<utf8>>;
31 using CsStringView_utf16 = CsBasicStringView<CsBasicString<utf16>>;
32 
33 template <typename S>
34 class CsBasicStringView
35 {
36  public:
37  using difference_type = typename S::difference_type;
38  using size_type = typename S::difference_type;
39  using value_type = typename S::value_type;
40 
41  using const_iterator = typename S::const_iterator;
42  using iterator = typename S::const_iterator;
43  using const_reverse_iterator = typename S::const_reverse_iterator;
44  using reverse_iterator = typename S::const_reverse_iterator;
45 
46  using const_storage_iterator = typename S::const_storage_iterator;
47  using const_storage_reverse_iterator = typename S::const_storage_reverse_iterator;
48 
49  static constexpr const size_type npos = -1;
50 
51  CsBasicStringView() = default;
52 
53  CsBasicStringView(const CsBasicStringView &str) = default;
54  CsBasicStringView(CsBasicStringView &&str) = default;
55 
56  CsBasicStringView(const S &str)
57  : m_begin(str.cbegin()), m_end(str.cend())
58  {
59  }
60 
61  CsBasicStringView(S &&str) = delete;
62 
63  // initialize with a range from another string type container
64  CsBasicStringView(const_iterator begin, const_iterator end)
65  : m_begin(begin), m_end(end)
66  {
67  }
68 
69  // operators
70  CsBasicStringView<S> &operator=(const CsBasicStringView &str) = default;
71  CsBasicStringView<S> &operator=(CsBasicStringView &&str) = default;
72 
73  value_type operator[](size_type index) const;
74 
75  // methods
76  value_type at(size_type index) const;
77  value_type back() const;
78 
79  int compare(CsBasicStringView str) const;
80 
81  bool empty() const;
82  bool endsWith(CsBasicStringView str) const;
83 
84  // ** uses an iterator, returns an iterator
85  const_iterator find_fast(value_type c) const;
86  const_iterator find_fast(value_type c, const_iterator iter_begin) const;
87 
88  const_iterator find_fast(CsBasicStringView str) const;
89  const_iterator find_fast(CsBasicStringView str, const_iterator iter_begin) const;
90 
91  // for a const char * and char *
92  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
93  std::is_same<T, char *>::value>::type>
94  const_iterator find_fast(const T &str, const_iterator iter_begin, size_type size) const;
95 
96  // for an array of chars
97  template <int N>
98  const_iterator find_fast(const char (&str)[N], const_iterator iter_begin, size_type size) const;
99 
100  // for a const char * and char *
101  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
102  std::is_same<T, char *>::value>::type>
103  const_iterator find_fast(const T &str) const;
104 
105  // for a const char * and char *
106  template <typename T, typename = typename std::enable_if<std::is_same<T, const char *>::value ||
107  std::is_same<T, char *>::value>::type>
108  const_iterator find_fast(const T &str, const_iterator iter_begin) const;
109 
110  // for an array of chars
111  template <int N>
112  const_iterator find_fast(const char (&str)[N]) const;
113 
114  // for an array of chars
115  template <int N>
116  const_iterator find_fast(const char (&str)[N], const_iterator iter_begin) const;
117 
118  //
119  const_iterator rfind_fast(value_type c) const;
120  const_iterator rfind_fast(value_type c, const_iterator iter_end) const;
121 
122  const_iterator rfind_fast(CsBasicStringView str) const;
123  const_iterator rfind_fast(CsBasicStringView str, const_iterator iter_end) const;
124 
125  value_type front() const;
126  size_type length() const;
127 
128  size_type size() const;
129  bool startsWith(CsBasicStringView str) const;
130 
131  CsBasicStringView<S> remove_prefix(size_type size) const;
132  CsBasicStringView<S> remove_suffix(size_type size) const;
133 
134  CsBasicStringView<S> substr(size_type indexStart = 0, size_type size = npos) const;
135  void swap(CsBasicStringView &str);
136 
137  // iterators
138  iterator begin() {
139  return m_begin;
140  }
141 
142  const_iterator begin() const {
143  return m_begin;
144  }
145 
146  const_iterator cbegin() const {
147  return m_begin;
148  }
149 
150  const_iterator constBegin() const {
151  return m_begin;
152  }
153 
154  iterator end() {
155  return m_end;
156  }
157 
158  const_iterator end() const {
159  return m_end;
160  }
161 
162  const_iterator cend() const {
163  return m_end;
164  }
165 
166  const_iterator constEnd() const {
167  return m_end;
168  }
169 
170  reverse_iterator rbegin() {
171  return m_end;
172  }
173 
174  const_reverse_iterator rbegin() const {
175  return m_end;
176  }
177 
178  reverse_iterator rend() {
179  return m_begin;
180  }
181 
182  const_reverse_iterator rend() const {
183  return m_begin;
184  }
185 
186  const_reverse_iterator crbegin() const {
187  return m_end;
188  }
189 
190  const_reverse_iterator crend() const {
191  return m_begin;
192  }
193 
194  // storage iterators
195 
196  const_storage_iterator storage_begin() const{
197  return m_begin.codePointBegin();
198  }
199 
200  const_storage_iterator storage_end() const {
201  return m_end.codePointBegin();
202  }
203 
204  const_storage_reverse_iterator storage_rbegin() const {
205  return std::make_reverse_iterator(m_end.codePointBegin());
206  }
207 
208  const_storage_reverse_iterator storage_rend() const {
209  return std::make_reverse_iterator(m_begin.codePointBegin());
210  }
211 
212  private:
213  const_iterator m_begin;
214  const_iterator m_end;
215 };
216 
217 // free functions
218 template <typename S>
219 inline bool operator==(CsBasicStringView<S> &str1, CsBasicStringView<S> &str2)
220 {
221  return str1.compare(str2) == 0;
222 }
223 
224 template <typename S>
225 inline bool operator!=(CsBasicStringView<S> &str1, CsBasicStringView<S> &str2)
226 {
227  return str1.compare(str2) != 0;
228 }
229 
230 template <typename S>
231 inline bool operator<(CsBasicStringView<S> &str1, CsBasicStringView<S> &str2)
232 {
233  return str1.compare(str2) < 0;
234 }
235 
236 template <typename S>
237 inline bool operator>(CsBasicStringView<S> &str1, CsBasicStringView<S> &str2)
238 {
239  return str1.compare(str2) > 0;
240 }
241 
242 template <typename S>
243 inline bool operator<=(CsBasicStringView<S> &str1, CsBasicStringView<S> &str2)
244 {
245  return str1.compare(str2) <= 0;
246 }
247 
248 template <typename S>
249 inline bool operator>=(CsBasicStringView<S> &str1, CsBasicStringView<S> &str2)
250 {
251  return str1.compare(str2) >= 0;
252 }
253 
254 // operators
255 template <typename S>
256 typename CsBasicStringView<S>::value_type CsBasicStringView<S>::operator[](size_type index) const
257 {
258  const_iterator iter = cbegin();
259  std::advance(iter, index);
260 
261  return *iter;
262 }
263 
264 // methods
265 template <typename S>
266 typename CsBasicStringView<S>::value_type CsBasicStringView<S>::at(size_type index) const
267 {
268  const_iterator iter = cbegin();
269  std::advance(iter, index);
270 
271  return *iter;
272 }
273 
274 template <typename S>
275 typename CsBasicStringView<S>::value_type CsBasicStringView<S>::back() const
276 {
277  return *(--cend());
278 }
279 
280 template <typename S>
281 int CsBasicStringView<S>::compare(CsBasicStringView str) const
282 {
283  auto iter_a = cbegin();
284  auto iter_b = str.cbegin();
285 
286  while (iter_a != cend() && iter_b != str.cend()) {
287 
288  auto value_a = *iter_a;
289  auto value_b = *iter_b;
290 
291  if (value_a < value_b) {
292  return -1;
293 
294  } else if (value_a > value_b) {
295  return 1;
296 
297  }
298 
299  ++iter_a;
300  ++iter_b;
301  }
302 
303  if (iter_b != str.cend()) {
304  return -1;
305 
306  } else if (iter_a != cend()) {
307  return 1;
308 
309  }
310 
311  return 0;
312 }
313 
314 template <typename S>
315 bool CsBasicStringView<S>::empty() const
316 {
317  return (m_begin == m_end);
318 }
319 
320 template <typename S>
321 bool CsBasicStringView<S>::endsWith(CsBasicStringView<S> str) const
322 {
323  if (str.empty() ){
324  return true;
325 
326  } else if (empty()) {
327  return false;
328  }
329 
330  auto iter = crbegin();
331 
332  for (auto iter_other = str.crbegin(); iter_other != str.crend(); ++iter_other) {
333 
334  if (iter == crend()) {
335  return false;
336  }
337 
338  if (*iter != *iter_other) {
339  return false;
340  }
341 
342  ++iter;
343  }
344 
345  return true;
346 }
347 
348 template <typename S>
349 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(CsBasicStringView str) const
350 {
351  return find_fast(str, cbegin());
352 }
353 
354 template <typename S>
355 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(CsBasicStringView str,
356  const_iterator iter_begin) const
357 {
358  const_iterator iter_end = cend();
359 
360  if (iter_begin == iter_end) {
361  return iter_end;
362  }
363 
364  if (str.empty()) {
365  return iter_begin;
366  }
367 
368  auto iter = iter_begin;
369 
370  while (iter != iter_end) {
371 
372  if (*iter == str[0]) {
373  auto text_iter = iter + 1;
374  auto pattern_iter = str.cbegin() + 1;
375 
376  while (text_iter != iter_end && pattern_iter != str.cend()) {
377 
378  if (*text_iter == *pattern_iter) {
379  ++text_iter;
380  ++pattern_iter;
381 
382  } else {
383  break;
384 
385  }
386  }
387 
388  if (pattern_iter == str.cend()) {
389  // found a match
390  return iter;
391  }
392  }
393 
394  ++iter;
395  }
396 
397  return iter_end;
398 }
399 
400 // for a const char * and char *
401 template <typename S>
402 template <typename T, typename>
403 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(const T &str, const_iterator iter_begin,
404  size_type size) const
405 {
406 #ifndef CS_STRING_ALLOW_UNSAFE
407  static_assert(! std::is_same<T, T>::value, "Unsafe operations not allowed, unknown encoding for this operation");
408 #endif
409 
410  const_iterator iter_end = cend();
411 
412  if (iter_begin == iter_end) {
413  return iter_end;
414  }
415 
416  if (str == nullptr || str[0] == 0) {
417  return iter_begin;
418  }
419 
420  auto iter = iter_begin;
421 
422  while (iter != iter_end) {
423 
424  if (*iter == str[0]) {
425  auto text_iter = iter + 1;
426  auto pattern_iter = str + 1;
427 
428  int count = 0;
429 
430  while (text_iter != iter_end && *pattern_iter != 0 && count < size) {
431 
432  if (*text_iter == *pattern_iter) {
433  ++text_iter;
434  ++pattern_iter;
435 
436  ++count;
437 
438  } else {
439  break;
440 
441  }
442  }
443 
444  if (*pattern_iter == 0) {
445  // found a match
446  return iter;
447  }
448  }
449 
450  ++iter;
451  }
452 
453  return iter_end;
454 }
455 
456 // for an array of chars
457 template <typename S>
458 template <int N>
459 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(const char (&str)[N],
460  const_iterator iter_begin, size_type size) const
461 {
462  // make this safe by treating str as utf8
463  return find_fast(S::fromUtf8(str, size), iter_begin);
464 }
465 
466 // for a const char * and char *
467 template <typename S>
468 template <typename T, typename>
469 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(const T &str) const
470 {
471  return find_fast(str, cbegin());
472 }
473 
474 // for a const char * and char *
475 template <typename S>
476 template <typename T, typename>
477 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(const T &str, const_iterator iter_begin) const
478 {
479 #ifndef CS_STRING_ALLOW_UNSAFE
480  static_assert(! std::is_same<T, T>::value, "Unsafe operations not allowed, unknown encoding for this operation");
481 #endif
482 
483  const_iterator iter_end = cend();
484 
485  if (iter_begin == iter_end) {
486  return iter_end;
487  }
488 
489  if (str == nullptr || str[0] == 0) {
490  return iter_begin;
491  }
492 
493  auto iter = iter_begin;
494 
495  while (iter != iter_end) {
496 
497  if (*iter == str[0]) {
498  auto text_iter = iter + 1;
499  auto pattern_iter = str + 1;
500 
501  while (text_iter != iter_end && *pattern_iter != 0) {
502 
503  if (*text_iter == *pattern_iter) {
504  ++text_iter;
505  ++pattern_iter;
506 
507  } else {
508  break;
509 
510  }
511  }
512 
513  if (*pattern_iter == 0) {
514  // found a match
515  return iter;
516  }
517  }
518 
519  ++iter;
520  }
521 
522  return iter_end;
523 }
524 
525 // for an array of chars
526 template <typename S>
527 template <int N>
528 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(const char (&str)[N]) const
529 {
530  return find_fast(str, cbegin());
531 }
532 
533 // for an array of chars
534 template <typename S>
535 template <int N>
536 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(const char (&str)[N],
537  const_iterator iter_begin) const
538 {
539  // make this safe by treating str as utf8
540  return find_fast(S::fromUtf8(str, N - 1), iter_begin);
541 }
542 
543 template <typename S>
544 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(value_type c) const
545 {
546  return find_fast(c, cbegin());
547 }
548 
549 template <typename S>
550 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::find_fast(value_type c, const_iterator iter_begin) const
551 {
552  const_iterator iter_end = cend();
553 
554  if (iter_begin == iter_end) {
555  return iter_end;
556  }
557 
558  auto iter = iter_begin;
559 
560  while (iter != iter_end) {
561 
562  if (*iter == c) {
563  return iter;
564  }
565 
566  ++iter;
567  }
568 
569  return iter_end;
570 }
571 
572 template <typename S>
573 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::rfind_fast(value_type c) const
574 {
575  return rfind_fast(c, cend());
576 }
577 
578 template <typename S>
579 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::rfind_fast(value_type c, const_iterator iter_end) const
580 {
581  const_iterator iter_begin = cbegin();
582 
583  if (iter_begin == iter_end) {
584  return cend();
585  }
586 
587  auto iter = iter_end;
588 
589  while (iter != cbegin()) {
590  --iter;
591 
592  if (*iter == c) {
593  // found a match
594  return iter;
595  }
596  }
597 
598  return cend();
599 }
600 
601 template <typename S>
602 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::rfind_fast(CsBasicStringView str) const
603 {
604  return rfind_fast(str, cend());
605 }
606 
607 template <typename S>
608 typename CsBasicStringView<S>::const_iterator CsBasicStringView<S>::rfind_fast(CsBasicStringView str, const_iterator iter_end) const
609 {
610  const_iterator iter_begin = cbegin();
611 
612  if (iter_begin == iter_end) {
613  return cend();
614  }
615 
616  if (str.empty()) {
617  return iter_end;
618  }
619 
620  auto iter = iter_end;
621  auto str_end = str.cend();
622 
623  while (iter != cbegin()) {
624  --iter;
625 
626  if (*iter == str[0]) {
627 
628  auto text_iter = iter + 1;
629  auto pattern_iter = str.cbegin() + 1;
630 
631  while (text_iter != cend() && pattern_iter != str_end) {
632 
633  if (*text_iter == *pattern_iter) {
634  ++text_iter;
635  ++pattern_iter;
636 
637  } else {
638  break;
639 
640  }
641  }
642 
643  if (pattern_iter == str_end) {
644  // found a match
645  return iter;
646  }
647  }
648 
649  }
650 
651  return cend();
652 }
653 
654 template <typename S>
655 typename CsBasicStringView<S>::value_type CsBasicStringView<S>::front() const
656 {
657  return *cbegin();
658 }
659 
660 template <typename S>
661 auto CsBasicStringView<S>::length() const -> size_type
662 {
663  return size();
664 }
665 
666 template <typename S>
667 bool CsBasicStringView<S>::startsWith(CsBasicStringView<S> str) const
668 {
669  if (str.empty()) {
670  return true;
671 
672  } else if (empty()) {
673  return false;
674 
675  }
676 
677  auto iter = cbegin();
678 
679  for (auto uc : str) {
680 
681  if (iter == cend()) {
682  return false;
683  }
684 
685  if (*iter != uc) {
686  return false;
687  }
688 
689  ++iter;
690  }
691 
692  return true;
693 }
694 
695 template <typename S>
696 auto CsBasicStringView<S>::size() const -> size_type
697 {
698  size_type retval = 0;
699 
700  for (auto item = cbegin(); item != cend(); ++item) {
701  ++retval;
702  }
703 
704  return retval;
705 }
706 
707 template <typename S>
708 CsBasicStringView<S> CsBasicStringView<S>::remove_prefix(size_type size) const
709 {
710  const_iterator iter_begin = cbegin();
711 
712  for (size_type i = 0; i < size && iter_begin != cend(); ++i) {
713  ++iter_begin;
714  }
715 
716  if (iter_begin == cend()) {
717  // index > size()
718  return CsBasicStringView();
719  }
720 
721  return CsBasicStringView(iter_begin, cend());
722 }
723 
724 template <typename S>
725 CsBasicStringView<S> CsBasicStringView<S>::remove_suffix(size_type size) const
726 {
727  const_iterator iter_end = cend();
728 
729  for (size_type i = 0; i < size && iter_end != cbegin(); ++i) {
730  --iter_end;
731  }
732 
733  return CsBasicStringView(cbegin(), iter_end);
734 }
735 
736 template <typename S>
737 CsBasicStringView<S> CsBasicStringView<S>::substr(size_type indexStart, size_type size) const
738 {
739  const_iterator iter_begin = cbegin();
740  const_iterator iter_end;
741 
742  for (size_type i = 0; i < indexStart && iter_begin != cend(); ++i) {
743  ++iter_begin;
744  }
745 
746  if (iter_begin == cend()) {
747  // index > size()
748  return CsBasicStringView();
749  }
750 
751  if (size >= 0) {
752  iter_end = iter_begin;
753 
754  for (size_type i = 0; i < size && iter_end != cend(); ++i) {
755  ++iter_end;
756  }
757 
758  } else {
759  iter_end = cend();
760 
761  }
762 
763  return CsBasicStringView(iter_begin, iter_end);
764 }
765 
766 template <typename S>
767 void CsBasicStringView<S>::swap(CsBasicStringView &str)
768 {
769  swap(m_begin, str.m_begin);
770  swap(m_end, str.m_end);
771 }
772 
773 
774 }
775 
776 #endif