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 |