Coverage Report

Created: 2023-12-13 14:58

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