Coverage Report

Created: 2024-07-18 11:41

src/zserio/StringView.h
Line
Count
Source
1
#ifndef ZSERIO_STRING_VIEW_H_INC
2
#define ZSERIO_STRING_VIEW_H_INC
3
4
#include <algorithm>
5
#include <cstddef>
6
#include <limits>
7
#include <memory>
8
#include <utility>
9
10
#include "zserio/CppRuntimeException.h"
11
#include "zserio/RebindAlloc.h"
12
#include "zserio/String.h"
13
#include "zserio/StringConvertUtil.h"
14
15
namespace zserio
16
{
17
18
/**
19
 * Non-owning constant view to a string. The user of this class is responsible of making sure, that the
20
 * referenced string is valid as long as the view is alive. Inspired by C++17 std::basic_string_view.
21
 */
22
template <typename CharT, typename Traits = std::char_traits<CharT>>
23
class BasicStringView
24
{
25
public:
26
    using traits_type = Traits;
27
    using value_type = CharT;
28
    using pointer = CharT*;
29
    using const_pointer = const CharT*;
30
    using reference = CharT&;
31
    using const_reference = const CharT&;
32
    using const_iterator = const_pointer;
33
    using iterator = const_iterator;
34
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
35
    using reverse_iterator = const_reverse_iterator;
36
    using size_type = size_t;
37
    using difference_type = ptrdiff_t;
38
39
    /**
40
     * Constant used to indicate end of view or "not a position", depending on context.
41
     */
42
    static constexpr const size_type npos = static_cast<size_type>(-1);
43
44
    /**
45
     * Constructor. Initializes empty view.
46
     */
47
3.77k
    constexpr BasicStringView() noexcept = default;
48
49
    /**
50
     * Constructor. Initializes string view to given null-terminated string.
51
     *
52
     * \param str Input null-terminated string.
53
     */
54
    BasicStringView(const const_pointer str) noexcept :
55
            m_data(str),
56
            m_size(Traits::length(str))
57
27.6k
    {}
58
59
    /**
60
     * Constructor. Initializes string view to given string with given length.
61
     *
62
     * \param str Input string.
63
     * \param count Length of the view. Shall not be longer than the input string.
64
     */
65
    constexpr BasicStringView(const const_pointer str, const size_type count) noexcept :
66
            m_data(str),
67
            m_size(count)
68
30.9k
    {}
69
70
    /**
71
     * Constructor. Initializes string view to given std::basic_string
72
     *
73
     * \param str Input string.
74
     */
75
    template <typename ALLOC>
76
    constexpr BasicStringView(const std::basic_string<CharT, Traits, ALLOC>& str) noexcept :
77
            m_data(str.data()),
78
            m_size(str.size())
79
1.33k
    {}
80
81
    /**
82
     * Method generated by default.
83
     * \{
84
     */
85
    ~BasicStringView() = default;
86
87
    BasicStringView(const BasicStringView&) noexcept = default;
88
    BasicStringView& operator=(const BasicStringView&) noexcept = default;
89
90
    BasicStringView(BasicStringView&&) noexcept = default;
91
    BasicStringView& operator=(BasicStringView&&) noexcept = default;
92
    /**
93
     * \}
94
     */
95
96
    /**
97
     * Begin iteration.
98
     *
99
     * \return Iterator to the beginning of the referenced string.
100
     */
101
    constexpr const_iterator begin() const noexcept
102
65.7k
    {
103
65.7k
        return m_data;
104
65.7k
    }
105
106
    /**
107
     * Begin iteration.
108
     *
109
     * \return Iterator to the beginning of the referenced string.
110
     */
111
    constexpr const_iterator cbegin() const noexcept
112
1
    {
113
1
        return begin();
114
1
    }
115
116
    /**
117
     * End iteration.
118
     *
119
     * \return Iterator one-past-end of the referenced string.
120
     */
121
    constexpr const_iterator end() const noexcept
122
140k
    {
123
140k
        return m_data + m_size;
124
140k
    }
125
126
    /**
127
     * End iteration.
128
     *
129
     * \return Iterator one-past-end of the referenced string.
130
     */
131
    constexpr const_iterator cend() const noexcept
132
11
    {
133
11
        return end();
134
11
    }
135
136
    /**
137
     * Begin reverse iteration.
138
     *
139
     * \return Reverse iterator to the end of the referenced string.
140
     */
141
    constexpr const_reverse_iterator rbegin() const noexcept
142
2
    {
143
2
        return const_reverse_iterator(end());
144
2
    }
145
146
    /**
147
     * Begin reverse iteration.
148
     *
149
     * \return Reverse iterator to the end of the referenced string.
150
     */
151
    constexpr const_reverse_iterator crbegin() const noexcept
152
1
    {
153
1
        return rbegin();
154
1
    }
155
156
    /**
157
     * End reverse iteration.
158
     *
159
     * \return Reverse iterator one-before-beginning of the referenced string.
160
     */
161
    constexpr const_reverse_iterator rend() const noexcept
162
22
    {
163
22
        return const_reverse_iterator(begin());
164
22
    }
165
166
    /**
167
     * End reverse iteration.
168
     *
169
     * \return Reverse iterator one-before-beginning of the referenced string.
170
     */
171
    constexpr const_reverse_iterator crend() const noexcept
172
11
    {
173
11
        return rend();
174
11
    }
175
176
    /**
177
     * Element access operator. Returns reference to the element of the referenced string at given index.
178
     *
179
     * \param pos Index of the element to access. Shall be less than size().
180
     * \return Reference to the string element at given index.
181
     */
182
    constexpr const_reference operator[](const size_type pos) const noexcept
183
27.3k
    {
184
27.3k
        return m_data[pos];
185
27.3k
    }
186
187
    /**
188
     * Element access operator. Returns reference to the element of the referenced string at given index.
189
     *
190
     * \param pos Index of the element to access.
191
     * \return Reference to the string element at given index.
192
     *
193
     * \throw CppRuntimeException if pos is not less than size().
194
     */
195
    const_reference at(const size_type pos) const
196
11
    {
197
11
        if (pos >= size())
198
1
        {
199
1
            throw CppRuntimeException("StringView: Position ")
200
1
                    << pos << " out of range for view size " << size() << "!";
201
1
        }
202
10
        return m_data[pos];
203
11
    }
204
205
    /**
206
     * Get reference to the first element of the string. The string shall not be empty.
207
     *
208
     * \return Reference to the first element of the string.
209
     */
210
    constexpr const_reference front() const noexcept
211
1
    {
212
1
        return m_data[0];
213
1
    }
214
215
    /**
216
     * Get reference to the last element of the string. The string shall not be empty.
217
     *
218
     * \return Reference to the last element of the string.
219
     */
220
    constexpr const_reference back() const noexcept
221
1
    {
222
1
        return m_data[m_size - 1];
223
1
    }
224
225
    /**
226
     * Get pointer to the beginning of the referenced string.
227
     *
228
     * \return Pointer to the beginning of the referenced string.
229
     */
230
    constexpr const_pointer data() const noexcept
231
32.9k
    {
232
32.9k
        return m_data;
233
32.9k
    }
234
235
    /**
236
     * Get referenced string length.
237
     *
238
     * \return The string length.
239
     */
240
    constexpr size_type size() const noexcept
241
124k
    {
242
124k
        return m_size;
243
124k
    }
244
245
    /**
246
     * Get referenced string length.
247
     *
248
     * \return The string length.
249
     */
250
    constexpr size_type length() const noexcept
251
1
    {
252
1
        return size();
253
1
    }
254
255
    /**
256
     * Get max. allowed string length.
257
     *
258
     * \return Max. allowed string length.
259
     */
260
    constexpr size_type max_size() const noexcept
261
1
    {
262
1
        return std::numeric_limits<size_type>::max();
263
1
    }
264
265
    /**
266
     * Check if the string is empty.
267
     *
268
     * \return True if the string is empty, false otherwise.
269
     */
270
    constexpr bool empty() const noexcept
271
24.7k
    {
272
24.7k
        return size() == 0;
273
24.7k
    }
274
275
    /**
276
     * Modify the string view so that it skips specified amount of elements at the beginning.
277
     *
278
     * \param n Number of elements to skip. Shall not be greater than size().
279
     */
280
    void remove_prefix(size_type n)
281
2
    {
282
2
        m_data += n;
283
2
        m_size -= n;
284
2
    }
285
286
    /**
287
     * Modify the string view so that it skips specified amount of elements at the end.
288
     *
289
     * \param n Number of elements to skip. Shall not be greater than size().
290
     */
291
    void remove_suffix(size_type n)
292
2
    {
293
2
        m_size -= n;
294
2
    }
295
296
    /**
297
     * Swap the content with another string view.
298
     *
299
     * \param other Another string view
300
     */
301
    void swap(BasicStringView& other) noexcept
302
1
    {
303
1
        std::swap(m_data, other.m_data);
304
1
        std::swap(m_size, other.m_size);
305
1
    }
306
307
    /**
308
     * Copy the specified amount of elements from the string view to given buffer.
309
     *
310
     * \param dest Buffer where the substring should be copied.
311
     * \param count Number of elements to copy.
312
     * \param pos Offset in the string view, where the copy should begin.
313
     * \return Number of elements actually copied.
314
     *
315
     * \throw CppRuntimeException if pos is > size().
316
     */
317
    size_type copy(CharT* dest, size_type count, size_type pos = 0) const
318
2
    {
319
2
        if (pos > size())
320
1
        {
321
1
            throw CppRuntimeException("StringView: Position ")
322
1
                    << pos << " out of range for view size " << size() << "!";
323
1
        }
324
1
        const size_t rcount = std::min(count, size() - pos);
325
1
        Traits::copy(dest, data() + pos, rcount);
326
1
        return rcount;
327
2
    }
328
329
    /**
330
     * Calculate string sub-view.
331
     *
332
     * \param pos Position in this view, where the sub-view should start.
333
     * \param count Number of element in the sub-view.
334
     * \return Calculated sub-view.
335
     *
336
     * \throw CppRuntimeException if pos is > size().
337
     */
338
    BasicStringView substr(size_type pos = 0, size_type count = npos) const
339
25.6k
    {
340
25.6k
        if (pos > size())
341
1
        {
342
1
            throw CppRuntimeException("StringView: Position ")
343
1
                    << pos << " out of range for view size " << size() << "!";
344
1
        }
345
25.6k
        const size_t rcount = std::min(count, size() - pos);
346
25.6k
        return BasicStringView(m_data + pos, rcount);
347
25.6k
    }
348
349
    /**
350
     * Compare this string view to other.
351
     *
352
     * \param other Second string view.
353
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
354
     * >0, if this view is considered greater than the other.
355
     */
356
    int compare(BasicStringView other) const noexcept
357
5.77k
    {
358
5.77k
        const size_type rlen = std::min(size(), other.size());
359
5.77k
        const int cmp = Traits::compare(data(), other.data(), rlen);
360
361
5.77k
        if (cmp != 0)
362
3.10k
        {
363
3.10k
            return cmp;
364
3.10k
        }
365
366
2.66k
        if (size() < other.size())
367
22
        {
368
22
            return -1;
369
22
        }
370
2.64k
        else if (size() > other.size())
371
53
        {
372
53
            return 1;
373
53
        }
374
2.59k
        else
375
2.59k
        {
376
2.59k
            return 0;
377
2.59k
        }
378
2.66k
    }
379
380
    /**
381
     * Compare this string view to other.
382
     *
383
     * \param pos1 Start position in this view.
384
     * \param count1 Number of elements in the view.
385
     * \param other Second string view.
386
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
387
     * >0, if this view is considered greater than the other.
388
     */
389
    int compare(size_type pos1, size_type count1, BasicStringView other) const
390
5
    {
391
5
        return substr(pos1, count1).compare(other);
392
5
    }
393
394
    /**
395
     * Compare this string view to other.
396
     *
397
     * \param pos1 Start position in this view.
398
     * \param count1 Number of elements in the view.
399
     * \param other Second string view.
400
     * \param pos2 Start position in the other view.
401
     * \param count2 Number of element in the other view.
402
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
403
     * >0, if this view is considered greater than the other.
404
     */
405
    int compare(size_type pos1, size_type count1, BasicStringView other, size_type pos2, size_type count2) const
406
5
    {
407
5
        return substr(pos1, count1).compare(other.substr(pos2, count2));
408
5
    }
409
410
    /**
411
     * Compare this string view to other.
412
     *
413
     * \param str String to compare with.
414
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
415
     * >0, if this view is considered greater than the other.
416
     */
417
    int compare(const CharT* str) const
418
19
    {
419
19
        return compare(BasicStringView(str));
420
19
    }
421
422
    /**
423
     * Compare this string view to other.
424
     *
425
     * \param pos1 Start position in this view.
426
     * \param count1 Number of elements in the view.
427
     * \param str String to compare with.
428
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
429
     * >0, if this view is considered greater than the other.
430
     */
431
    int compare(size_type pos1, size_type count1, const CharT* str) const
432
5
    {
433
5
        return substr(pos1, count1).compare(BasicStringView(str));
434
5
    }
435
436
    /**
437
     * Compare this string view to other.
438
     *
439
     * \param pos1 Start position in this view.
440
     * \param count1 Number of elements in the view.
441
     * \param str String to compare with.
442
     * \param count2 Number of element in the str.
443
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
444
     * >0, if this view is considered greater than the other.
445
     */
446
    int compare(size_type pos1, size_type count1, const CharT* str, size_type count2) const
447
5
    {
448
5
        return substr(pos1, count1).compare(BasicStringView(str, count2));
449
5
    }
450
451
    /**
452
     * Find position of given string view in this string view.
453
     *
454
     * \param str String to search.
455
     * \param pos Position where the start the search.
456
     * \return Index of the found string or npos if the string was not found.
457
     */
458
    size_type find(BasicStringView str, size_type pos = 0) const noexcept
459
1.17k
    {
460
1.17k
        if (pos >= size() || 
str.size() > size() - pos1.16k
)
461
15
        {
462
15
            return npos; // the string cannot be there
463
15
        }
464
465
1.15k
        if (str.size() == 0)
466
4
        {
467
4
            return pos; // zero-sized search, this defaults to the match at the beginning
468
4
        }
469
470
1.15k
        const const_pointer startPtr = data() + pos; // where the searching will start
471
1.15k
        const const_pointer endPtr = data() + (size() - str.size()) + 1; // where the searching will end
472
473
        // initial position
474
1.15k
        const_pointer ptr = Traits::find(startPtr, static_cast<size_t>(endPtr - startPtr), str[0]);
475
1.15k
        while (ptr)
476
971
        {
477
            // check if the searched string is present
478
971
            if (Traits::compare(ptr, str.data(), str.size()) == 0)
479
968
            {
480
968
                return static_cast<size_t>(ptr - data());
481
968
            }
482
483
            // go to next position
484
3
            ptr = Traits::find(ptr + 1, static_cast<size_t>(endPtr - ptr - 1), str[0]);
485
3
        }
486
487
183
        return npos;
488
1.15k
    }
489
490
    /**
491
     * Find position of given char in this string view.
492
     *
493
     * \param character Char to search.
494
     * \param pos Position where the start the search.
495
     * \return Index of the found char or npos if the string was not found.
496
     */
497
    size_type find(CharT character, size_type pos = 0) const noexcept
498
1.11k
    {
499
1.11k
        return find(BasicStringView(std::addressof(character), 1), pos);
500
1.11k
    }
501
502
    /**
503
     * Find position of given string in this string view.
504
     *
505
     * \param str String to search.
506
     * \param pos Position where the start the search.
507
     * \param count Length of str.
508
     * \return Index of the found string or npos if the string was not found.
509
     */
510
    size_type find(const CharT* str, size_type pos, size_type count) const
511
16
    {
512
16
        return find(BasicStringView(str, count), pos);
513
16
    }
514
515
    /**
516
     * Find position of given null-terminated string in this string view.
517
     *
518
     * \param str String to search.
519
     * \param pos Position where the start the search.
520
     * \return Index of the found string or npos if the string was not found.
521
     */
522
    size_type find(const CharT* str, size_type pos = 0) const
523
16
    {
524
16
        return find(BasicStringView(str), pos);
525
16
    }
526
527
    /**
528
     * Find position of given string view in this string view, starting from the view end.
529
     *
530
     * \param str String to search.
531
     * \param pos Position where the start the search.
532
     * \return Index of the found string or npos if the string was not found.
533
     */
534
    size_type rfind(BasicStringView str, size_type pos = npos) const noexcept
535
53
    {
536
53
        if (str.size() > size())
537
6
        {
538
6
            return npos;
539
6
        }
540
541
238
        
for (size_t p = std::min(static_cast<size_type>(size() - str.size()), pos) + 1; 47
p > 0;
--p191
)
542
222
        {
543
222
            if (Traits::compare(data() + p - 1, str.data(), str.size()) == 0)
544
31
            {
545
31
                return p - 1;
546
31
            }
547
222
        }
548
549
16
        return npos;
550
47
    }
551
552
    /**
553
     * Find position of given char in this string view, starting from the view end.
554
     *
555
     * \param character Char to search.
556
     * \param pos Position where the start the search.
557
     * \return Index of the found char or npos if the string was not found.
558
     */
559
    size_type rfind(CharT character, size_type pos = npos) const noexcept
560
4
    {
561
4
        return rfind(BasicStringView(std::addressof(character), 1), pos);
562
4
    }
563
564
    /**
565
     * Find position of given null-terminated string in this string view, starting from the view end.
566
     *
567
     * \param str String to search.
568
     * \param pos Position where the start the search.
569
     * \return Index of the found string or npos if the string was not found.
570
     */
571
    size_type rfind(const CharT* str, size_type pos, size_type count) const
572
16
    {
573
16
        return rfind(BasicStringView(str, count), pos);
574
16
    }
575
576
    /**
577
     * Find position of given null-terminated string in this string view, starting from the view end.
578
     *
579
     * \param str String to search.
580
     * \param pos Position where the start the search.
581
     * \return Index of the found string or npos if the string was not found.
582
     */
583
    size_type rfind(const CharT* str, size_type pos = npos) const
584
16
    {
585
16
        return rfind(BasicStringView(str), pos);
586
16
    }
587
588
    /**
589
     * Find the position of the first character equal to any of the characters in the given character sequence.
590
     *
591
     * \param str Sequence to search.
592
     * \param pos Position where to start the search.
593
     * \return Found position or npos if no such character was found.
594
     */
595
    size_type find_first_of(BasicStringView str, size_type pos = 0) const noexcept
596
40
    {
597
40
        if (str.size() == 0 || 
pos >= size()37
)
598
7
        {
599
7
            return npos;
600
7
        }
601
602
109
        
for (size_type idx = pos; 33
idx < size();
++idx76
)
603
100
        {
604
100
            if (Traits::find(str.data(), str.size(), data()[idx]) != nullptr)
605
24
            {
606
24
                return idx;
607
24
            }
608
100
        }
609
610
9
        return npos;
611
33
    }
612
613
    /**
614
     * Find the position of the first character equal to the given character.
615
     *
616
     * \param character Character to search.
617
     * \param pos Position where to start the search.
618
     * \return Found position or npos if no such character was found.
619
     */
620
    size_type find_first_of(CharT character, size_type pos = 0) const noexcept
621
7
    {
622
7
        return find_first_of(BasicStringView(std::addressof(character), 1), pos);
623
7
    }
624
625
    /**
626
     * Find the position of the first character equal to any of the characters in the given character sequence.
627
     *
628
     * \param str Sequence to search.
629
     * \param pos Position where to start the search.
630
     * \param count Number of character in str.
631
     * \return Found position or npos if no such character was found.
632
     */
633
    size_type find_first_of(const CharT* str, size_type pos, size_type count) const
634
11
    {
635
11
        return find_first_of(BasicStringView(str, count), pos);
636
11
    }
637
638
    /**
639
     * Find the position of the first character equal to any of the characters in the given character sequence.
640
     *
641
     * \param str Sequence to search.
642
     * \param pos Position where to start the search.
643
     * \return Found position or npos if no such character was found.
644
     */
645
    size_type find_first_of(const CharT* str, size_type pos = 0) const
646
11
    {
647
11
        return find_first_of(BasicStringView(str), pos);
648
11
    }
649
650
    /**
651
     * Find the last character not equal to any of the characters in the given character sequence.
652
     *
653
     * \param str Sequence to search.
654
     * \param pos Position where to start the search.
655
     * \return Found position or npos if no such character was found.
656
     */
657
    size_type find_last_of(BasicStringView str, size_type pos = npos) const noexcept
658
34
    {
659
34
        if (str.empty() || 
empty()30
)
660
5
        {
661
5
            return npos;
662
5
        }
663
664
99
        
for (size_type idx = std::min(pos + 1, size()); 29
idx > 0;
--idx70
)
665
94
        {
666
94
            if (Traits::find(str.data(), str.size(), data()[idx - 1]) != nullptr)
667
24
            {
668
24
                return idx - 1;
669
24
            }
670
94
        }
671
672
5
        return npos;
673
29
    }
674
675
    /**
676
     * Find the last character not equal to the given character.
677
     *
678
     * \param character Character to search.
679
     * \param pos Position where to start the search.
680
     * \return Found position or npos if no such character was found.
681
     */
682
    size_type find_last_of(CharT character, size_type pos = npos) const noexcept
683
5
    {
684
5
        return find_last_of(BasicStringView(std::addressof(character), 1), pos);
685
5
    }
686
687
    /**
688
     * Find the last character not equal to any of the characters in the given character sequence.
689
     *
690
     * \param str Sequence to search.
691
     * \param pos Position where to start the search.
692
     * \param count Number of characters in str.
693
     * \return Found position or npos if no such character was found.
694
     */
695
    size_type find_last_of(const CharT* str, size_type pos, size_type count) const
696
9
    {
697
9
        return find_last_of(BasicStringView(str, count), pos);
698
9
    }
699
700
    /**
701
     * Find the last character not equal to any of the characters in the given character sequence.
702
     *
703
     * \param str Sequence to search.
704
     * \param pos Position where to start the search.
705
     * \return Found position or npos if no such character was found.
706
     */
707
    size_type find_last_of(const CharT* str, size_type pos = npos) const
708
9
    {
709
9
        return find_last_of(BasicStringView(str), pos);
710
9
    }
711
712
    /**
713
     * Finds the first character not equal to any of the characters in the given character sequence.
714
     *
715
     * \param str Sequence to search.
716
     * \param pos Position where to start the search.
717
     * \return Found position or npos if no such character was found.
718
     */
719
    size_type find_first_not_of(BasicStringView str, size_type pos = 0) const noexcept
720
32
    {
721
32
        if (str.size() == 0 || 
pos >= size()29
)
722
7
        {
723
7
            return npos;
724
7
        }
725
726
83
        
for (size_type idx = pos; 25
idx < size();
++idx58
)
727
77
        {
728
77
            if (Traits::find(str.data(), str.size(), data()[idx]) == nullptr)
729
19
            {
730
19
                return idx;
731
19
            }
732
77
        }
733
734
6
        return npos;
735
25
    }
736
737
    /**
738
     * Finds the first character not equal to the given character.
739
     *
740
     * \param character Character to search.
741
     * \param pos Position where to start the search.
742
     * \return Found position or npos if no such character was found.
743
     */
744
    size_type find_first_not_of(CharT character, size_type pos = 0) const noexcept
745
5
    {
746
5
        return find_first_not_of(BasicStringView(std::addressof(character), 1), pos);
747
5
    }
748
749
    /**
750
     * Finds the first character not equal to any of the characters in the given character sequence.
751
     *
752
     * \param str Sequence to search.
753
     * \param pos Position where to start the search.
754
     * \param count Number of characters in str.
755
     * \return Found position or npos if no such character was found.
756
     */
757
    size_type find_first_not_of(const CharT* str, size_type pos, size_type count) const
758
9
    {
759
9
        return find_first_not_of(BasicStringView(str, count), pos);
760
9
    }
761
762
    /**
763
     * Finds the first character not equal to any of the characters in the given character sequence.
764
     *
765
     * \param str Sequence to search.
766
     * \param pos Position where to start the search.
767
     * \return Found position or npos if no such character was found.
768
     */
769
    size_type find_first_not_of(const CharT* str, size_type pos = 0) const
770
9
    {
771
9
        return find_first_not_of(BasicStringView(str), pos);
772
9
    }
773
774
    /**
775
     * Find the last character not equal to any of the characters in the given character sequence.
776
     *
777
     * \param str Sequence to search.
778
     * \param pos Position where to start the search.
779
     * \return Found position or npos if no such character was found.
780
     */
781
    size_type find_last_not_of(BasicStringView str, size_type pos = npos) const noexcept
782
32
    {
783
32
        if (str.empty() || 
empty()28
)
784
5
        {
785
5
            return npos;
786
5
        }
787
788
79
        
for (size_type idx = std::min(pos + 1, size()); 27
idx > 0;
--idx52
)
789
75
        {
790
75
            if (Traits::find(str.data(), str.size(), data()[idx - 1]) == nullptr)
791
23
            {
792
23
                return idx - 1;
793
23
            }
794
75
        }
795
796
4
        return npos;
797
27
    }
798
799
    /**
800
     * Find the last character not equal to the given character.
801
     *
802
     * \param character Character to search.
803
     * \param pos Position where to start the search.
804
     * \return Found position or npos if no such character was found.
805
     */
806
    size_type find_last_not_of(CharT character, size_type pos = npos) const noexcept
807
6
    {
808
6
        return find_last_not_of(BasicStringView(std::addressof(character), 1), pos);
809
6
    }
810
811
    /**
812
     * Find the last character not equal to any of the characters in the given character sequence.
813
     *
814
     * \param str Sequence to search.
815
     * \param pos Position where to start the search.
816
     * \param count Number of characters in str.
817
     * \return Found position or npos if no such character was found.
818
     */
819
    size_type find_last_not_of(const CharT* str, size_type pos, size_type count) const
820
8
    {
821
8
        return find_last_not_of(BasicStringView(str, count), pos);
822
8
    }
823
824
    /**
825
     * Find the last character not equal to any of the characters in the given character sequence.
826
     *
827
     * \param str Sequence to search.
828
     * \param pos Position where to start the search.
829
     * \return Found position or npos if no such character was found.
830
     */
831
    size_type find_last_not_of(const CharT* str, size_type pos = npos) const
832
8
    {
833
8
        return find_last_not_of(BasicStringView(str), pos);
834
8
    }
835
836
private:
837
    const_pointer m_data = nullptr;
838
    size_type m_size = 0;
839
};
840
841
template <typename CharT, class Traits>
842
constexpr std::size_t const BasicStringView<CharT, Traits>::npos;
843
844
/**
845
 * Comparison operator.
846
 *
847
 * \param lhs Left hand side operator.
848
 * \param rhs Right hand side operator.
849
 * \return True if lhs is equal to rhs.
850
 */
851
template <typename CharT, class Traits>
852
constexpr bool operator==(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
853
4.50k
{
854
4.50k
    return lhs.compare(rhs) == 0;
855
4.50k
}
856
857
/**
858
 * Comparison operator.
859
 *
860
 * \param lhs Left hand side operator.
861
 * \param rhs Right hand side operator.
862
 * \return True if lhs is not equal to rhs.
863
 */
864
template <typename CharT, class Traits>
865
constexpr bool operator!=(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
866
151
{
867
151
    return lhs.compare(rhs) != 0;
868
151
}
869
870
/**
871
 * Comparison operator.
872
 *
873
 * \param lhs Left hand side operator.
874
 * \param rhs Right hand side operator.
875
 * \return True if lhs is less than rhs.
876
 */
877
template <typename CharT, class Traits>
878
constexpr bool operator<(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
879
1.07k
{
880
1.07k
    return lhs.compare(rhs) < 0;
881
1.07k
}
882
883
/**
884
 * Comparison operator.
885
 *
886
 * \param lhs Left hand side operator.
887
 * \param rhs Right hand side operator.
888
 * \return True if lhs is less or equal to rhs.
889
 */
890
template <typename CharT, class Traits>
891
constexpr bool operator<=(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
892
1
{
893
1
    return lhs.compare(rhs) <= 0;
894
1
}
895
896
/**
897
 * Comparison operator.
898
 *
899
 * \param lhs Left hand side operator.
900
 * \param rhs Right hand side operator.
901
 * \return True if lhs is greater than rhs.
902
 */
903
template <typename CharT, class Traits>
904
constexpr bool operator>(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
905
1
{
906
1
    return lhs.compare(rhs) > 0;
907
1
}
908
909
/**
910
 * Comparison operator.
911
 *
912
 * \param lhs Left hand side operator.
913
 * \param rhs Right hand side operator.
914
 * \return True if lhs is greater or equal to rhs.
915
 */
916
template <typename CharT, class Traits>
917
constexpr bool operator>=(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
918
1
{
919
1
    return lhs.compare(rhs) >= 0;
920
1
}
921
922
/**
923
 * Convenience function that initializes a string view to given array of chars.
924
 *
925
 * \param str Input string in form of array of characters.
926
 * \return String view to given input string.
927
 */
928
template <typename CharT, size_t N>
929
constexpr BasicStringView<CharT> makeStringView(const CharT (&str)[N])
930
2.46k
{
931
2.46k
    static_assert(N != 0, "Zero length arrays C++ extension is not supported!");
932
2.46k
    return BasicStringView<CharT>(str, str[N - 1] == CharT() ? 
(N - 1)2.46k
:
N1
);
933
2.46k
}
934
935
/**
936
 * Convenience function that constructs string from a string view and allocator.
937
 *
938
 * \param stringView String view to convert.
939
 * \param allocator Allocator to use for the string construction.
940
 *
941
 * \return String constructed from the string view and allocator.
942
 */
943
template <typename CharT, typename Traits, typename ALLOC = std::allocator<char>>
944
std::basic_string<CharT, Traits, RebindAlloc<ALLOC, CharT>> stringViewToString(
945
        BasicStringView<CharT, Traits> stringView, const ALLOC& allocator = ALLOC())
946
422
{
947
422
    return std::basic_string<CharT, Traits, RebindAlloc<ALLOC, CharT>>(
948
422
            stringView.data(), stringView.size(), allocator);
949
422
}
950
951
/**
952
 * Append string view to string.
953
 *
954
 * \param first String to which the second string should be appended.
955
 * \param second String view to append to the first.
956
 * \return first.
957
 */
958
template <typename CharT, typename Traits, typename ALLOC = std::allocator<char>>
959
std::basic_string<CharT, Traits, ALLOC>& operator+=(
960
        std::basic_string<CharT, Traits, ALLOC>& first, BasicStringView<CharT, Traits> second)
961
30
{
962
30
    return first.append(second.data(), second.size());
963
30
}
964
965
/**
966
 * Specialization of BasicStringView for char.
967
 */
968
using StringView = BasicStringView<char, std::char_traits<char>>;
969
970
/**
971
 * Converts a string view to string using the given allocator. Defined for convenience.
972
 *
973
 * \param value String view to convert.
974
 * \param allocator Allocator to use for the string allocation.
975
 */
976
template <typename ALLOC>
977
string<ALLOC> toString(StringView value, const ALLOC& allocator = ALLOC())
978
353
{
979
353
    return stringViewToString(value, allocator);
980
353
}
981
982
/**
983
 * Allows to append StringView to CppRuntimeException.
984
 *
985
 * \param exception Exception to modify.
986
 * \param view String view.
987
 *
988
 * \return Reference to the exception to allow operator chaining.
989
 */
990
inline CppRuntimeException& operator<<(CppRuntimeException& exception, StringView view)
991
15.5k
{
992
15.5k
    exception.append(view.data(), view.size());
993
15.5k
    return exception;
994
15.5k
}
995
996
inline namespace literals
997
{
998
999
/**
1000
 * User-defined literal for StringView.
1001
 */
1002
constexpr ::zserio::StringView operator"" _sv(const char* str, std::size_t len) noexcept
1003
1.64k
{
1004
1.64k
    return ::zserio::StringView(str, len);
1005
1.64k
}
1006
1007
} // namespace literals
1008
1009
} // namespace zserio
1010
1011
#endif // ZSERIO_STRING_VIEW_H_INC