Coverage Report

Created: 2024-04-30 09:35

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
            return cmp;
363
364
2.66k
        if (size() < other.size())
365
22
            return -1;
366
2.64k
        else if (size() > other.size())
367
53
            return 1;
368
2.59k
        else
369
2.59k
            return 0;
370
2.66k
    }
371
372
    /**
373
     * Compare this string view to other.
374
     *
375
     * \param pos1 Start position in this view.
376
     * \param count1 Number of elements in the view.
377
     * \param other Second string view.
378
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
379
     * >0, if this view is considered greater than the other.
380
     */
381
    int compare(size_type pos1, size_type count1, BasicStringView other) const
382
5
    {
383
5
        return substr(pos1, count1).compare(other);
384
5
    }
385
386
    /**
387
     * Compare this string view to other.
388
     *
389
     * \param pos1 Start position in this view.
390
     * \param count1 Number of elements in the view.
391
     * \param other Second string view.
392
     * \param pos2 Start position in the other view.
393
     * \param count2 Number of element in the other view.
394
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
395
     * >0, if this view is considered greater than the other.
396
     */
397
    int compare(size_type pos1, size_type count1, BasicStringView other, size_type pos2, size_type count2) const
398
5
    {
399
5
        return substr(pos1, count1).compare(other.substr(pos2, count2));
400
5
    }
401
402
    /**
403
     * Compare this string view to other.
404
     *
405
     * \param str String to compare with.
406
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
407
     * >0, if this view is considered greater than the other.
408
     */
409
    int compare(const CharT* str) const
410
19
    {
411
19
        return compare(BasicStringView(str));
412
19
    }
413
414
    /**
415
     * Compare this string view to other.
416
     *
417
     * \param pos1 Start position in this view.
418
     * \param count1 Number of elements in the view.
419
     * \param str String to compare with.
420
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
421
     * >0, if this view is considered greater than the other.
422
     */
423
    int compare(size_type pos1, size_type count1, const CharT* str) const
424
5
    {
425
5
        return substr(pos1, count1).compare(BasicStringView(str));
426
5
    }
427
428
    /**
429
     * Compare this string view to other.
430
     *
431
     * \param pos1 Start position in this view.
432
     * \param count1 Number of elements in the view.
433
     * \param str String to compare with.
434
     * \param count2 Number of element in the str.
435
     * \return <0, if this view is considered less than the other, ==0, if both views are same,
436
     * >0, if this view is considered greater than the other.
437
     */
438
    int compare(size_type pos1, size_type count1, const CharT* str, size_type count2) const
439
5
    {
440
5
        return substr(pos1, count1).compare(BasicStringView(str, count2));
441
5
    }
442
443
    /**
444
     * Find position of given string view in this string view.
445
     *
446
     * \param str String to search.
447
     * \param pos Position where the start the search.
448
     * \return Index of the found string or npos if the string was not found.
449
     */
450
    size_type find(BasicStringView str, size_type pos = 0) const noexcept
451
1.17k
    {
452
1.17k
        if (pos >= size() || 
str.size() > size() - pos1.16k
)
453
15
            return npos; // the string cannot be there
454
455
1.15k
        if (str.size() == 0)
456
4
            return pos; // zero-sized search, this defaults to the match at the beginning
457
458
1.15k
        const const_pointer startPtr = data() + pos; // where the searching will start
459
1.15k
        const const_pointer endPtr = data() + (size() - str.size()) + 1; // where the searching will end
460
461
        // initial position
462
1.15k
        const_pointer ptr = Traits::find(startPtr, static_cast<size_t>(endPtr - startPtr), str[0]);
463
1.15k
        while (ptr)
464
971
        {
465
            // check if the searched string is present
466
971
            if (Traits::compare(ptr, str.data(), str.size()) == 0)
467
968
            {
468
968
                return static_cast<size_t>(ptr - data());
469
968
            }
470
471
            // go to next position
472
3
            ptr = Traits::find(ptr + 1, static_cast<size_t>(endPtr - ptr - 1), str[0]);
473
3
        }
474
475
183
        return npos;
476
1.15k
    }
477
478
    /**
479
     * Find position of given char in this string view.
480
     *
481
     * \param character Char to search.
482
     * \param pos Position where the start the search.
483
     * \return Index of the found char or npos if the string was not found.
484
     */
485
    size_type find(CharT character, size_type pos = 0) const noexcept
486
1.11k
    {
487
1.11k
        return find(BasicStringView(std::addressof(character), 1), pos);
488
1.11k
    }
489
490
    /**
491
     * Find position of given string in this string view.
492
     *
493
     * \param str String to search.
494
     * \param pos Position where the start the search.
495
     * \param count Length of str.
496
     * \return Index of the found string or npos if the string was not found.
497
     */
498
    size_type find(const CharT* str, size_type pos, size_type count) const
499
16
    {
500
16
        return find(BasicStringView(str, count), pos);
501
16
    }
502
503
    /**
504
     * Find position of given null-terminated string in this string view.
505
     *
506
     * \param str String to search.
507
     * \param pos Position where the start the search.
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 = 0) const
511
16
    {
512
16
        return find(BasicStringView(str), pos);
513
16
    }
514
515
    /**
516
     * Find position of given string view in this string view, starting from the view end.
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 rfind(BasicStringView str, size_type pos = npos) const noexcept
523
53
    {
524
53
        if (str.size() > size())
525
6
            return npos;
526
527
238
        
for (size_t p = std::min(static_cast<size_type>(size() - str.size()), pos) + 1; 47
p > 0;
--p191
)
528
222
        {
529
222
            if (Traits::compare(data() + p - 1, str.data(), str.size()) == 0)
530
31
                return p - 1;
531
222
        }
532
533
16
        return npos;
534
47
    }
535
536
    /**
537
     * Find position of given char in this string view, starting from the view end.
538
     *
539
     * \param character Char to search.
540
     * \param pos Position where the start the search.
541
     * \return Index of the found char or npos if the string was not found.
542
     */
543
    size_type rfind(CharT character, size_type pos = npos) const noexcept
544
4
    {
545
4
        return rfind(BasicStringView(std::addressof(character), 1), pos);
546
4
    }
547
548
    /**
549
     * Find position of given null-terminated string in this string view, starting from the view end.
550
     *
551
     * \param str String to search.
552
     * \param pos Position where the start the search.
553
     * \return Index of the found string or npos if the string was not found.
554
     */
555
    size_type rfind(const CharT* str, size_type pos, size_type count) const
556
16
    {
557
16
        return rfind(BasicStringView(str, count), pos);
558
16
    }
559
560
    /**
561
     * Find position of given null-terminated string in this string view, starting from the view end.
562
     *
563
     * \param str String to search.
564
     * \param pos Position where the start the search.
565
     * \return Index of the found string or npos if the string was not found.
566
     */
567
    size_type rfind(const CharT* str, size_type pos = npos) const
568
16
    {
569
16
        return rfind(BasicStringView(str), pos);
570
16
    }
571
572
    /**
573
     * Find the position of the first character equal to any of the characters in the given character sequence.
574
     *
575
     * \param str Sequence to search.
576
     * \param pos Position where to start the search.
577
     * \return Found position or npos if no such character was found.
578
     */
579
    size_type find_first_of(BasicStringView str, size_type pos = 0) const noexcept
580
40
    {
581
40
        if (str.size() == 0 || 
pos >= size()37
)
582
7
            return npos;
583
584
109
        
for (size_type idx = pos; 33
idx < size();
++idx76
)
585
100
        {
586
100
            if (Traits::find(str.data(), str.size(), data()[idx]) != nullptr)
587
24
                return idx;
588
100
        }
589
590
9
        return npos;
591
33
    }
592
593
    /**
594
     * Find the position of the first character equal to the given character.
595
     *
596
     * \param character Character to search.
597
     * \param pos Position where to start the search.
598
     * \return Found position or npos if no such character was found.
599
     */
600
    size_type find_first_of(CharT character, size_type pos = 0) const noexcept
601
7
    {
602
7
        return find_first_of(BasicStringView(std::addressof(character), 1), pos);
603
7
    }
604
605
    /**
606
     * Find the position of the first character equal to any of the characters in the given character sequence.
607
     *
608
     * \param str Sequence to search.
609
     * \param pos Position where to start the search.
610
     * \param count Number of character in str.
611
     * \return Found position or npos if no such character was found.
612
     */
613
    size_type find_first_of(const CharT* str, size_type pos, size_type count) const
614
11
    {
615
11
        return find_first_of(BasicStringView(str, count), pos);
616
11
    }
617
618
    /**
619
     * Find the position of the first character equal to any of the characters in the given character sequence.
620
     *
621
     * \param str Sequence to search.
622
     * \param pos Position where to start the search.
623
     * \return Found position or npos if no such character was found.
624
     */
625
    size_type find_first_of(const CharT* str, size_type pos = 0) const
626
11
    {
627
11
        return find_first_of(BasicStringView(str), pos);
628
11
    }
629
630
    /**
631
     * Find the last character not equal to any of the characters in the given character sequence.
632
     *
633
     * \param str Sequence to search.
634
     * \param pos Position where to start the search.
635
     * \return Found position or npos if no such character was found.
636
     */
637
    size_type find_last_of(BasicStringView str, size_type pos = npos) const noexcept
638
34
    {
639
34
        if (str.empty() || 
empty()30
)
640
5
            return npos;
641
642
99
        
for (size_type idx = std::min(pos + 1, size()); 29
idx > 0;
--idx70
)
643
94
        {
644
94
            if (Traits::find(str.data(), str.size(), data()[idx - 1]) != nullptr)
645
24
                return idx - 1;
646
94
        }
647
648
5
        return npos;
649
29
    }
650
651
    /**
652
     * Find the last character not equal to the given character.
653
     *
654
     * \param character Character to search.
655
     * \param pos Position where to start the search.
656
     * \return Found position or npos if no such character was found.
657
     */
658
    size_type find_last_of(CharT character, size_type pos = npos) const noexcept
659
5
    {
660
5
        return find_last_of(BasicStringView(std::addressof(character), 1), pos);
661
5
    }
662
663
    /**
664
     * Find the last character not equal to any of the characters in the given character sequence.
665
     *
666
     * \param str Sequence to search.
667
     * \param pos Position where to start the search.
668
     * \param count Number of characters in str.
669
     * \return Found position or npos if no such character was found.
670
     */
671
    size_type find_last_of(const CharT* str, size_type pos, size_type count) const
672
9
    {
673
9
        return find_last_of(BasicStringView(str, count), pos);
674
9
    }
675
676
    /**
677
     * Find the last character not equal to any of the characters in the given character sequence.
678
     *
679
     * \param str Sequence to search.
680
     * \param pos Position where to start the search.
681
     * \return Found position or npos if no such character was found.
682
     */
683
    size_type find_last_of(const CharT* str, size_type pos = npos) const
684
9
    {
685
9
        return find_last_of(BasicStringView(str), pos);
686
9
    }
687
688
    /**
689
     * Finds the first character not equal to any of the characters in the given character sequence.
690
     *
691
     * \param str Sequence to search.
692
     * \param pos Position where to start the search.
693
     * \return Found position or npos if no such character was found.
694
     */
695
    size_type find_first_not_of(BasicStringView str, size_type pos = 0) const noexcept
696
32
    {
697
32
        if (str.size() == 0 || 
pos >= size()29
)
698
7
            return npos;
699
700
83
        
for (size_type idx = pos; 25
idx < size();
++idx58
)
701
77
        {
702
77
            if (Traits::find(str.data(), str.size(), data()[idx]) == nullptr)
703
19
                return idx;
704
77
        }
705
706
6
        return npos;
707
25
    }
708
709
    /**
710
     * Finds the first character not equal to the given character.
711
     *
712
     * \param character Character to search.
713
     * \param pos Position where to start the search.
714
     * \return Found position or npos if no such character was found.
715
     */
716
    size_type find_first_not_of(CharT character, size_type pos = 0) const noexcept
717
5
    {
718
5
        return find_first_not_of(BasicStringView(std::addressof(character), 1), pos);
719
5
    }
720
721
    /**
722
     * Finds the first character not equal to any of the characters in the given character sequence.
723
     *
724
     * \param str Sequence to search.
725
     * \param pos Position where to start the search.
726
     * \param count Number of characters in str.
727
     * \return Found position or npos if no such character was found.
728
     */
729
    size_type find_first_not_of(const CharT* str, size_type pos, size_type count) const
730
9
    {
731
9
        return find_first_not_of(BasicStringView(str, count), pos);
732
9
    }
733
734
    /**
735
     * Finds the first character not equal to any of the characters in the given character sequence.
736
     *
737
     * \param str Sequence to search.
738
     * \param pos Position where to start the search.
739
     * \return Found position or npos if no such character was found.
740
     */
741
    size_type find_first_not_of(const CharT* str, size_type pos = 0) const
742
9
    {
743
9
        return find_first_not_of(BasicStringView(str), pos);
744
9
    }
745
746
    /**
747
     * Find the last character not equal to any of the characters in the given character sequence.
748
     *
749
     * \param str Sequence to search.
750
     * \param pos Position where to start the search.
751
     * \return Found position or npos if no such character was found.
752
     */
753
    size_type find_last_not_of(BasicStringView str, size_type pos = npos) const noexcept
754
32
    {
755
32
        if (str.empty() || 
empty()28
)
756
5
            return npos;
757
758
79
        
for (size_type idx = std::min(pos + 1, size()); 27
idx > 0;
--idx52
)
759
75
        {
760
75
            if (Traits::find(str.data(), str.size(), data()[idx - 1]) == nullptr)
761
23
                return idx - 1;
762
75
        }
763
764
4
        return npos;
765
27
    }
766
767
    /**
768
     * Find the last character not equal to the given character.
769
     *
770
     * \param character Character to search.
771
     * \param pos Position where to start the search.
772
     * \return Found position or npos if no such character was found.
773
     */
774
    size_type find_last_not_of(CharT character, size_type pos = npos) const noexcept
775
6
    {
776
6
        return find_last_not_of(BasicStringView(std::addressof(character), 1), pos);
777
6
    }
778
779
    /**
780
     * Find the last character not equal to any of the characters in the given character sequence.
781
     *
782
     * \param str Sequence to search.
783
     * \param pos Position where to start the search.
784
     * \param count Number of characters in str.
785
     * \return Found position or npos if no such character was found.
786
     */
787
    size_type find_last_not_of(const CharT* str, size_type pos, size_type count) const
788
8
    {
789
8
        return find_last_not_of(BasicStringView(str, count), pos);
790
8
    }
791
792
    /**
793
     * Find the last character not equal to any of the characters in the given character sequence.
794
     *
795
     * \param str Sequence to search.
796
     * \param pos Position where to start the search.
797
     * \return Found position or npos if no such character was found.
798
     */
799
    size_type find_last_not_of(const CharT* str, size_type pos = npos) const
800
8
    {
801
8
        return find_last_not_of(BasicStringView(str), pos);
802
8
    }
803
804
private:
805
    const_pointer m_data = nullptr;
806
    size_type m_size = 0;
807
};
808
809
template <typename CharT, class Traits>
810
constexpr std::size_t const BasicStringView<CharT, Traits>::npos;
811
812
/**
813
 * Comparison operator.
814
 *
815
 * \param lhs Left hand side operator.
816
 * \param rhs Right hand side operator.
817
 * \return True if lhs is equal to rhs.
818
 */
819
template <typename CharT, class Traits>
820
constexpr bool operator==(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
821
4.50k
{
822
4.50k
    return lhs.compare(rhs) == 0;
823
4.50k
}
824
825
/**
826
 * Comparison operator.
827
 *
828
 * \param lhs Left hand side operator.
829
 * \param rhs Right hand side operator.
830
 * \return True if lhs is not equal to rhs.
831
 */
832
template <typename CharT, class Traits>
833
constexpr bool operator!=(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
834
151
{
835
151
    return lhs.compare(rhs) != 0;
836
151
}
837
838
/**
839
 * Comparison operator.
840
 *
841
 * \param lhs Left hand side operator.
842
 * \param rhs Right hand side operator.
843
 * \return True if lhs is less than rhs.
844
 */
845
template <typename CharT, class Traits>
846
constexpr bool operator<(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
847
1.07k
{
848
1.07k
    return lhs.compare(rhs) < 0;
849
1.07k
}
850
851
/**
852
 * Comparison operator.
853
 *
854
 * \param lhs Left hand side operator.
855
 * \param rhs Right hand side operator.
856
 * \return True if lhs is less or equal to rhs.
857
 */
858
template <typename CharT, class Traits>
859
constexpr bool operator<=(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
860
1
{
861
1
    return lhs.compare(rhs) <= 0;
862
1
}
863
864
/**
865
 * Comparison operator.
866
 *
867
 * \param lhs Left hand side operator.
868
 * \param rhs Right hand side operator.
869
 * \return True if lhs is greater than rhs.
870
 */
871
template <typename CharT, class Traits>
872
constexpr bool operator>(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
873
1
{
874
1
    return lhs.compare(rhs) > 0;
875
1
}
876
877
/**
878
 * Comparison operator.
879
 *
880
 * \param lhs Left hand side operator.
881
 * \param rhs Right hand side operator.
882
 * \return True if lhs is greater or equal to rhs.
883
 */
884
template <typename CharT, class Traits>
885
constexpr bool operator>=(BasicStringView<CharT, Traits> lhs, BasicStringView<CharT, Traits> rhs) noexcept
886
1
{
887
1
    return lhs.compare(rhs) >= 0;
888
1
}
889
890
/**
891
 * Convenience function that initializes a string view to given array of chars.
892
 *
893
 * \param str Input string in form of array of characters.
894
 * \return String view to given input string.
895
 */
896
template <typename CharT, size_t N>
897
constexpr BasicStringView<CharT> makeStringView(const CharT (&str)[N])
898
2.46k
{
899
2.46k
    static_assert(N != 0, "Zero length arrays C++ extension is not supported!");
900
2.46k
    return BasicStringView<CharT>(str, str[N - 1] == CharT() ? 
(N - 1)2.46k
:
N1
);
901
2.46k
}
902
903
/**
904
 * Convenience function that constructs string from a string view and allocator.
905
 *
906
 * \param stringView String view to convert.
907
 * \param allocator Allocator to use for the string construction.
908
 *
909
 * \return String constructed from the string view and allocator.
910
 */
911
template <typename CharT, typename Traits, typename ALLOC = std::allocator<char>>
912
std::basic_string<CharT, Traits, RebindAlloc<ALLOC, CharT>> stringViewToString(
913
        BasicStringView<CharT, Traits> stringView, const ALLOC& allocator = ALLOC())
914
422
{
915
422
    return std::basic_string<CharT, Traits, RebindAlloc<ALLOC, CharT>>(
916
422
            stringView.data(), stringView.size(), allocator);
917
422
}
918
919
/**
920
 * Append string view to string.
921
 *
922
 * \param first String to which the second string should be appended.
923
 * \param second String view to append to the first.
924
 * \return first.
925
 */
926
template <typename CharT, typename Traits, typename ALLOC = std::allocator<char>>
927
std::basic_string<CharT, Traits, ALLOC>& operator+=(
928
        std::basic_string<CharT, Traits, ALLOC>& first, BasicStringView<CharT, Traits> second)
929
30
{
930
30
    return first.append(second.data(), second.size());
931
30
}
932
933
/**
934
 * Specialization of BasicStringView for char.
935
 */
936
using StringView = BasicStringView<char, std::char_traits<char>>;
937
938
/**
939
 * Converts a string view to string using the given allocator. Defined for convenience.
940
 *
941
 * \param value String view to convert.
942
 * \param allocator Allocator to use for the string allocation.
943
 */
944
template <typename ALLOC>
945
string<ALLOC> toString(StringView value, const ALLOC& allocator = ALLOC())
946
353
{
947
353
    return stringViewToString(value, allocator);
948
353
}
949
950
/**
951
 * Allows to append StringView to CppRuntimeException.
952
 *
953
 * \param exception Exception to modify.
954
 * \param view String view.
955
 *
956
 * \return Reference to the exception to allow operator chaining.
957
 */
958
inline CppRuntimeException& operator<<(CppRuntimeException& exception, StringView view)
959
15.5k
{
960
15.5k
    exception.append(view.data(), view.size());
961
15.5k
    return exception;
962
15.5k
}
963
964
inline namespace literals
965
{
966
967
/**
968
 * User-defined literal for StringView.
969
 */
970
constexpr ::zserio::StringView operator"" _sv(const char* str, std::size_t len) noexcept
971
1.64k
{
972
1.64k
    return ::zserio::StringView(str, len);
973
1.64k
}
974
975
} // namespace literals
976
977
} // namespace zserio
978
979
#endif // ZSERIO_STRING_VIEW_H_INC