Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
static_string.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/assert.hpp>
4
5#include <algorithm>
6#include <array>
7#include <compare>
8#include <concepts>
9#include <cstddef>
10#include <format>
11#include <functional>
12#include <initializer_list>
13#include <istream>
14#include <iterator>
15#include <ostream>
16#include <ranges>
17#include <string>
18#include <string_view>
19
20namespace helios::container {
21
22/**
23 * @brief A fixed-capacity string class that owns its storage.
24 * @details Does not allocate heap memory.
25 * @tparam StrCapacity Maximum number of characters (excluding null terminator)
26 * @tparam CharT Character type
27 * @tparam Traits Character traits type
28 */
29template <size_t StrCapacity, typename CharT,
30 typename Traits = std::char_traits<CharT>>
31 requires(StrCapacity > 0)
33public:
34 using traits_type = Traits;
35 using value_type = CharT;
36 using pointer = CharT*;
37 using const_pointer = const CharT*;
38 using reference = CharT&;
39 using const_reference = const CharT&;
40 using iterator = CharT*;
41 using const_iterator = const CharT*;
42 using reverse_iterator = std::reverse_iterator<iterator>;
43 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
44 using size_type = size_t;
45 using difference_type = ptrdiff_t;
46
47 static constexpr size_type npos = static_cast<size_type>(-1);
48
49 /// @brief Default constructor. Creates an empty string.
50 constexpr BasicStaticString() noexcept { data_[0] = CharT{}; }
51
52 /**
53 * @brief Constructs from a string_view.
54 * @warning Triggers assertion if `sv.size() > StrCapacity`.
55 * @param sv Source string view
56 */
57 constexpr explicit BasicStaticString(
58 std::basic_string_view<CharT, Traits> sv) noexcept;
59
60 /**
61 * @brief Constructs a substring from a string_view with position and count.
62 * @warning Triggers assertion if `(pos + count) > sv.size()` or `count >
63 * StrCapacity`.
64 * @param sv Source string view
65 * @param pos Starting position in the view
66 * @param count Number of characters to copy (default: all remaining)
67 */
68 constexpr BasicStaticString(std::basic_string_view<CharT, Traits> sv,
69 size_type pos, size_type count = npos) noexcept;
70
71 /**
72 * @brief Constructs from a null-terminated C string.
73 * @warning Triggers assertion if string length > `StrCapacity`.
74 * @param str Source C string
75 */
76 constexpr explicit BasicStaticString(const CharT* str) noexcept
77 : BasicStaticString(std::basic_string_view<CharT, Traits>(str)) {}
78
79 /**
80 * @brief Constructs from a character array of known size.
81 * @warning Triggers assertion if `N-1 > StrCapacity` (excluding null
82 * terminator).
83 * @tparam N Size of the character array
84 * @param str Source character array
85 */
86 template <size_t N>
87 requires(N <= StrCapacity + 1)
88 constexpr explicit(false) BasicStaticString(const CharT (&str)[N]) noexcept;
89
90 /**
91 * @brief Constructs from count copies of character ch.
92 * @warning Triggers assertion if `count > StrCapacity`.
93 * @param count Number of characters
94 * @param ch Character to repeat
95 */
96 constexpr BasicStaticString(size_type count, CharT ch) noexcept;
97
98 /**
99 * @brief Constructs from a pointer and length.
100 * @warning Triggers assertion if `len > StrCapacity`.
101 * @param str Source string pointer
102 * @param len Length of the string
103 */
104 constexpr BasicStaticString(const CharT* str, size_type len) noexcept;
105
106 /**
107 * @brief Constructs from an iterator range.
108 * @warning Triggers assertion if `std::distance(first, last) > StrCapacity`.
109 * @tparam InputIt Input iterator type
110 * @param first Beginning of range
111 * @param last End of range
112 */
113 template <std::input_iterator InputIt>
114 constexpr BasicStaticString(InputIt first, InputIt last) noexcept;
115
116 /**
117 * @brief Constructs from a range using `std::from_range_t`.
118 * @warning Triggers assertion if range size > `StrCapacity`.
119 * @tparam Range Range type
120 * @param tag `std::from_range` tag to disambiguate from iterator constructor
121 * @param range Range to construct from
122 */
123 template <std::ranges::input_range Range>
124 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
125 constexpr BasicStaticString(std::from_range_t tag, Range&& range) noexcept;
126
127 /**
128 * @brief Constructs from an initializer list.
129 * @warning Triggers assertion if `ilist.size() > StrCapacity`.
130 * @param ilist Initializer list
131 */
132 constexpr BasicStaticString(std::initializer_list<CharT> ilist) noexcept;
133
134 BasicStaticString(std::nullptr_t) = delete;
135
136 constexpr BasicStaticString(const BasicStaticString&) noexcept = default;
137 constexpr BasicStaticString(BasicStaticString&&) noexcept = default;
138
139 /**
140 * @brief Copy constructor from smaller capacity string.
141 * @warning Triggers assertion if `other.Size() > StrCapacity`.
142 * @tparam OtherCapacity `StrCapacity` of source string (must be less than
143 * `StrCapacity`)
144 * @param other Source string with smaller capacity
145 */
146 template <size_t OtherCapacity>
147 requires(OtherCapacity < StrCapacity)
149 const BasicStaticString<OtherCapacity, CharT, Traits>& other) noexcept;
150
151 /**
152 * @brief Move constructor from smaller capacity string.
153 * @warning Triggers assertion if `other.Size() > StrCapacity`.
154 * @tparam OtherCapacity `StrCapacity` of source string (must be less than
155 * `StrCapacity`)
156 * @param other Source string with smaller capacity
157 */
158 template <size_t OtherCapacity>
159 requires(OtherCapacity < StrCapacity)
161 BasicStaticString<OtherCapacity, CharT, Traits>&& other) noexcept;
162
163 /**
164 * @brief Substring copy constructor from same capacity string.
165 * @warning Triggers assertion if `(pos + count) > other.Size()` or `count >
166 * StrCapacity`.
167 * @param other Source string
168 * @param pos Starting position (default: 0)
169 * @param count Number of characters to copy (default: all remaining)
170 */
171 constexpr BasicStaticString(const BasicStaticString& other, size_type pos,
172 size_type count = npos) noexcept;
173
174 /**
175 * @brief Substring move constructor from same capacity string (C++23).
176 * @warning Triggers assertion if `(pos + count) > other.Size()` or `count >
177 * StrCapacity`.
178 * @param other Source string
179 * @param pos Starting position (default: 0)
180 * @param count Number of characters to copy (default: all remaining)
181 */
183 size_type count = npos) noexcept;
184
185 /**
186 * @brief Substring copy constructor from smaller capacity string.
187 * @warning Triggers assertion if `(pos + count) > other.Size()` or `count >
188 * StrCapacity`.
189 * @tparam OtherCapacity `StrCapacity` of source string (must be less than
190 * `StrCapacity`)
191 * @param other Source string with smaller capacity
192 * @param pos Starting position (default: 0)
193 * @param count Number of characters to copy (default: all remaining)
194 */
195 template <size_t OtherCapacity>
196 requires(OtherCapacity < StrCapacity)
198 const BasicStaticString<OtherCapacity, CharT, Traits>& other,
199 size_type pos, size_type count = npos) noexcept;
200
201 /**
202 * @brief Substring move constructor from smaller capacity string (C++23).
203 * @warning Triggers assertion if `(pos + count) > other.Size()` or `count >
204 * StrCapacity`.
205 * @tparam OtherCapacity `StrCapacity` of source string (must be less than
206 * `StrCapacity`)
207 * @param other Source string with smaller capacity
208 * @param pos Starting position (default: 0)
209 * @param count Number of characters to copy (default: all remaining)
210 */
211 template <size_t OtherCapacity>
212 requires(OtherCapacity < StrCapacity)
214 BasicStaticString<OtherCapacity, CharT, Traits>&& other, size_type pos,
215 size_type count = npos) noexcept;
216
217 constexpr ~BasicStaticString() noexcept = default;
218
219 constexpr BasicStaticString& operator=(const BasicStaticString&) noexcept =
220 default;
221 constexpr BasicStaticString& operator=(BasicStaticString&&) noexcept =
222 default;
223
224 /**
225 * @brief Copy assignment from smaller capacity string.
226 * @warning Triggers assertion if `other.Size() > StrCapacity`.
227 * @tparam OtherCapacity `StrCapacity` of source string (must be less than
228 * `StrCapacity`)
229 * @param other Source string with smaller capacity
230 * @return Reference to this
231 */
232 template <size_t OtherCapacity>
233 requires(OtherCapacity < StrCapacity)
234 constexpr BasicStaticString& operator=(
235 const BasicStaticString<OtherCapacity, CharT, Traits>& other) noexcept;
236
237 /**
238 * @brief Move assignment from smaller capacity string.
239 * @warning Triggers assertion if `other.Size() > StrCapacity`.
240 * @tparam OtherCapacity `StrCapacity` of source string (must be less than
241 * `StrCapacity`)
242 * @param other Source string with smaller capacity
243 * @return Reference to this
244 */
245 template <size_t OtherCapacity>
246 requires(OtherCapacity < StrCapacity)
247 constexpr BasicStaticString& operator=(
248 BasicStaticString<OtherCapacity, CharT, Traits>&& other) noexcept;
249
250 /**
251 * @brief Assigns from a `std::basic_string_view`.
252 * @warning Triggers assertion if `sv.size() > StrCapacity`.
253 * @param sv Source string view
254 * @return Reference to this
255 */
256 constexpr BasicStaticString& operator=(
257 std::basic_string_view<CharT, Traits> sv) noexcept;
258
259 /**
260 * @brief Assigns from a null-terminated C string.
261 * @warning Triggers assertion if string length > `StrCapacity`.
262 * @param str Source C string
263 * @return Reference to this
264 */
265 constexpr BasicStaticString& operator=(const CharT* str) noexcept;
266
267 /**
268 * @brief Clears the string content.
269 */
270 constexpr void Clear() noexcept;
271
272 /**
273 * @brief Inserts a `std::basic_string_view` at position.
274 * @warning Triggers assertion if `pos > Size()` or resulting size >
275 * `Capacity()`.
276 * @param pos Position to insert at
277 * @param sv String view to insert
278 * @return Reference to this
279 */
281 size_type pos, std::basic_string_view<CharT, Traits> sv) noexcept;
282
283 /**
284 * @brief Inserts count copies of character at position.\
285 * @warning Triggers assertion if `pos > Size()` or resulting size >
286 * `Capacity()`
287 * @param pos Position to insert at
288 * @param count Number of characters
289 * @param ch Character to insert
290 * @return Reference to this
291 */
293 CharT ch) noexcept;
294
295 /**
296 * @brief Inserts characters from a range at position.
297 * @warning Triggers assertion if `pos > Size()` or resulting size >
298 * `Capacity()`.
299 * @tparam Range Range type
300 * @param pos Position to insert at
301 * @param range Range to insert
302 * @return Reference to this
303 */
304 template <std::ranges::input_range Range>
305 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
307 Range&& range) noexcept;
308
309 /**
310 * @brief Erases characters from `pos` to `pos + count`.
311 * @warning Triggers assertion if `pos > Size()`.
312 * @param pos Starting position
313 * @param count Number of characters to erase (default: all remaining)
314 * @return Reference to this
315 */
317 size_type count = npos) noexcept;
318
319 /**
320 * @brief Appends a character.
321 * @warning Triggers assertion if `Size() >= Capacity()`.
322 * @param ch Character to append
323 */
324 constexpr void PushBack(CharT ch) noexcept;
325
326 /**
327 * @brief Removes the last character.
328 * @warning Triggers assertion if string is empty.
329 */
330 constexpr void PopBack() noexcept;
331
332 /**
333 * @brief Appends a `std::basic_string_view`.
334 * @warning Triggers assertion if resulting size > `Capacity()`.
335 * @param sv String view to append
336 * @return Reference to this
337 */
339 std::basic_string_view<CharT, Traits> sv) noexcept;
340
341 /**
342 * @brief Appends count copies of character `ch`.
343 * @warning Triggers assertion if resulting size > `Capacity()`.
344 * @param count Number of characters
345 * @param ch Character to append
346 * @return Reference to this
347 */
348 constexpr BasicStaticString& Append(size_type count, CharT ch) noexcept;
349
350 /**
351 * @brief Appends a null-terminated C string.
352 * @warning Triggers assertion if resulting size > `Capacity()`.
353 * @param str C string to append
354 * @return Reference to this
355 */
356 constexpr BasicStaticString& Append(const CharT* str) noexcept {
357 return Append(std::basic_string_view<CharT, Traits>(str));
358 }
359
360 /**
361 * @brief Appends characters from a range.
362 * @warning Triggers assertion if resulting size > `Capacity()`.
363 * @tparam Range Range type
364 * @param range Range to append
365 * @return Reference to this
366 */
367 template <std::ranges::input_range Range>
368 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
369 constexpr BasicStaticString& AppendRange(Range&& range) noexcept;
370
371 /**
372 * @brief Replaces characters in range `[pos, pos + count)` with
373 * `std::basic_string_view`.
374 * @warning Triggers assertion if `pos > Size()` or resulting size >
375 * `Capacity()`.
376 * @param pos Starting position
377 * @param count Number of characters to replace
378 * @param sv Replacement string view
379 * @return Reference to this
380 */
382 size_type pos, size_type count,
383 std::basic_string_view<CharT, Traits> sv) noexcept;
384
385 /**
386 * @brief Replaces characters in range `[pos, pos + count)` with `count2`
387 * copies of `ch`.
388 * @warning Triggers assertion if `pos > Size()` or resulting size >
389 * `Capacity()`.
390 * @param pos Starting position
391 * @param count Number of characters to replace
392 * @param count2 Number of replacement characters
393 * @param ch Replacement character
394 * @return Reference to this
395 */
397 size_type count2, CharT ch) noexcept;
398
399 /**
400 * @brief Replaces characters in range `[pos, pos + count)` with characters
401 * from a range.
402 * @warning Triggers assertion if `pos > Size()` or resulting size >
403 * `Capacity()`.
404 * @tparam Range Range type
405 * @param pos Starting position
406 * @param count Number of characters to replace
407 * @param range Range of replacement characters
408 * @return Reference to this
409 */
410 template <std::ranges::input_range Range>
411 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
413 Range&& range) noexcept;
414
415 /**
416 * @brief Copies characters to a buffer.
417 * @warning Triggers assertion if `pos > Size()`.
418 * @param dest Destination buffer
419 * @param count Maximum number of characters to copy
420 * @param pos Starting position
421 * @return Number of characters copied
422 */
423 constexpr size_type Copy(CharT* dest, size_type count,
424 size_type pos = 0) const noexcept;
425
426 /**
427 * @brief Resizes the string.
428 * @warning Triggers assertion if `count > Capacity()`.
429 * @param count New size
430 * @param ch Character to fill if expanding
431 */
432 constexpr void Resize(size_type count, CharT ch = CharT{}) noexcept;
433
434 /**
435 * @brief Swaps contents with another `BasicStaticString`.
436 * @param other String to swap with
437 */
438 constexpr void Swap(BasicStaticString& other) noexcept;
439
440 /**
441 * @brief Assigns a `std::basic_string_view`.
442 * @warning Triggers assertion if `sv.size() > Capacity()`.
443 * @param sv String view to assign
444 * @return Reference to this
445 */
447 std::basic_string_view<CharT, Traits> sv) noexcept;
448
449 /**
450 * @brief Assigns a null-terminated C string.
451 * @warning Triggers assertion if string length > `Capacity()`.
452 * @param str C string to assign
453 * @return Reference to this
454 */
455 constexpr BasicStaticString& Assign(const CharT* str) noexcept {
456 return Assign(std::basic_string_view<CharT, Traits>(str));
457 }
458
459 /**
460 * @brief Assigns count copies of character ch.
461 * @warning Triggers assertion if `count > Capacity()`.
462 * @param count Number of characters
463 * @param ch Character to assign
464 * @return Reference to this
465 */
466 constexpr BasicStaticString& Assign(size_type count, CharT ch) noexcept;
467
468 /**
469 * @brief Assigns characters from a range.
470 * @warning Triggers assertion if range size > `Capacity()`.
471 * @tparam Range Range type
472 * @param range Range to assign from
473 * @return Reference to this
474 */
475 template <std::ranges::input_range Range>
476 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
477 constexpr BasicStaticString& AssignRange(Range&& range) noexcept;
478
479 /**
480 * @brief Returns a substring.
481 * @warning Triggers assertion if `pos > Size()`.
482 * @param pos Starting position
483 * @param count Number of characters (default: all remaining)
484 * @return Substring as StaticString with same capacity
485 */
486 [[nodiscard]] constexpr BasicStaticString Substr(
487 size_type pos = 0, size_type count = npos) const noexcept;
488
489 /**
490 * @brief Compares with another string.
491 * @param other String to compare with
492 * @return Negative if less, zero if equal, positive if greater
493 */
494 [[nodiscard]] constexpr int Compare(
495 std::basic_string_view<CharT, Traits> other) const noexcept {
496 return View().compare(other);
497 }
498
499 /**
500 * @brief Compares with another `BasicStaticString`.
501 * @tparam OtherCapacity `StrCapacity` of the other string
502 * @param other String to compare with
503 * @return Negative if less, zero if equal, positive if greater
504 */
505 template <size_t OtherCapacity>
506 [[nodiscard]] constexpr int Compare(
508 const noexcept {
509 return View().compare(other.View());
510 }
511
512 /**
513 * @brief Finds first occurrence of substring.
514 * @param sv Substring to search for
515 * @param pos Starting position
516 * @return Position of first occurrence, or `npos` if not found
517 */
518 [[nodiscard]] constexpr size_type Find(
519 std::basic_string_view<CharT, Traits> sv,
520 size_type pos = 0) const noexcept {
521 return View().find(sv, pos);
522 }
523
524 /**
525 * @brief Finds first occurrence of character.
526 * @param ch Character to search for
527 * @param pos Starting position
528 * @return Position of first occurrence, or `npos` if not found
529 */
530 [[nodiscard]] constexpr size_type Find(CharT ch,
531 size_type pos = 0) const noexcept {
532 return View().find(ch, pos);
533 }
534
535 /**
536 * @brief Finds last occurrence of substring.
537 * @param sv Substring to search for
538 * @param pos Starting position (searches backwards from here)
539 * @return Position of last occurrence, or `npos` if not found
540 */
541 [[nodiscard]] constexpr size_type RFind(
542 std::basic_string_view<CharT, Traits> sv,
543 size_type pos = npos) const noexcept {
544 return View().rfind(sv, pos);
545 }
546
547 /**
548 * @brief Finds last occurrence of character.
549 * @param ch Character to search for
550 * @param pos Starting position (searches backwards from here)
551 * @return Position of last occurrence, or `npos` if not found
552 */
553 [[nodiscard]] constexpr size_type RFind(CharT ch,
554 size_type pos = npos) const noexcept {
555 return View().rfind(ch, pos);
556 }
557
558 /**
559 * @brief Finds first occurrence of any character in sv.
560 * @param sv Characters to search for
561 * @param pos Starting position
562 * @return Position of first occurrence, or `npos` if not found
563 */
564 [[nodiscard]] constexpr size_type FindFirstOf(
565 std::basic_string_view<CharT, Traits> sv,
566 size_type pos = 0) const noexcept {
567 return View().find_first_of(sv, pos);
568 }
569
570 /**
571 * @brief Finds last occurrence of any character in sv.
572 * @param sv Characters to search for
573 * @param pos Starting position (searches backwards from here)
574 * @return Position of last occurrence, or `npos` if not found
575 */
576 [[nodiscard]] constexpr size_type FindLastOf(
577 std::basic_string_view<CharT, Traits> sv,
578 size_type pos = npos) const noexcept {
579 return View().find_last_of(sv, pos);
580 }
581
582 /**
583 * @brief Finds first character not in sv.
584 * @param sv Characters to exclude
585 * @param pos Starting position
586 * @return Position of first non-matching character, or `npos` if not found
587 */
588 [[nodiscard]] constexpr size_type FindFirstNotOf(
589 std::basic_string_view<CharT, Traits> sv,
590 size_type pos = 0) const noexcept {
591 return View().find_first_not_of(sv, pos);
592 }
593
594 /**
595 * @brief Finds last character not in sv.
596 * @param sv Characters to exclude
597 * @param pos Starting position (searches backwards from here)
598 * @return Position of last non-matching character, or `npos` if not found
599 */
600 [[nodiscard]] constexpr size_type FindLastNotOf(
601 std::basic_string_view<CharT, Traits> sv,
602 size_type pos = npos) const noexcept {
603 return View().find_last_not_of(sv, pos);
604 }
605
606 /**
607 * @brief Appends a `std::basic_string_view`.
608 * @warning Triggers assertion if resulting size > `Capacity()`.
609 * @param sv String view to append
610 * @return Reference to this
611 */
613 std::basic_string_view<CharT, Traits> sv) noexcept {
614 return Append(sv);
615 }
616
617 /**
618 * @brief Appends a character.
619 * @warning Triggers assertion if resulting size > `Capacity()`.
620 * @param ch Character to append
621 * @return Reference to this
622 */
623 constexpr BasicStaticString& operator+=(CharT ch) noexcept;
624
625 /**
626 * @brief Appends a null-terminated C string.
627 * @warning Triggers assertion if resulting size > `Capacity()`.
628 * @param str C string to append
629 * @return Reference to this
630 */
631 constexpr BasicStaticString& operator+=(const CharT* str) noexcept {
632 return Append(str);
633 }
634
635 /**
636 * @brief Accesses character at specified position.
637 * @warning Triggers assertion if `pos >= Size()`.
638 * @param pos Position of the character
639 * @return Reference to the character
640 */
641 [[nodiscard]] constexpr reference operator[](size_type pos) noexcept;
642
643 /**
644 * @brief Accesses character at specified position (const).
645 * @warning Triggers assertion if `pos >= Size()`.
646 * @param pos Position of the character
647 * @return Const reference to the character
648 */
649 [[nodiscard]] constexpr const_reference operator[](
650 size_type pos) const noexcept;
651
652 /**
653 * @brief Converts to `std::basic_string_view`.
654 * @return String view of the content
655 */
656 [[nodiscard]] constexpr operator std::basic_string_view<CharT, Traits>()
657 const noexcept {
658 return std::basic_string_view<CharT, Traits>(data_.data(), size_);
659 }
660
661 template <size_t OtherCapacity>
662 [[nodiscard]] constexpr bool operator==(
664 const noexcept {
665 return View() == other.View();
666 }
667
668 [[nodiscard]] constexpr bool operator==(
669 std::basic_string_view<CharT, Traits> other) const noexcept {
670 return View() == other;
671 }
672
673 [[nodiscard]] constexpr bool operator==(const CharT* other) const noexcept {
674 return View() == std::basic_string_view<CharT, Traits>(other);
675 }
676
677 template <size_t OtherCapacity>
678 [[nodiscard]] constexpr auto operator<=>(
680 const noexcept -> std::strong_ordering;
681
682 [[nodiscard]] constexpr auto operator<=>(
683 std::basic_string_view<CharT, Traits> other) const noexcept
684 -> std::strong_ordering;
685
686 [[nodiscard]] constexpr auto operator<=>(const CharT* other) const noexcept
687 -> std::strong_ordering {
688 return *this <=> std::basic_string_view<CharT, Traits>(other);
689 }
690
691 /**
692 * @brief Checks if the string is empty.
693 * @return True if `Size() == 0`
694 */
695 [[nodiscard]] constexpr bool Empty() const noexcept { return size_ == 0; }
696
697 /**
698 * @brief Checks if string starts with prefix.
699 * @param sv Prefix to check
700 * @return True if string starts with sv
701 */
702 [[nodiscard]] constexpr bool StartsWith(
703 std::basic_string_view<CharT, Traits> sv) const noexcept {
704 return View().starts_with(sv);
705 }
706
707 /**
708 * @brief Checks if string starts with character.
709 * @param ch Character to check
710 * @return True if string starts with ch
711 */
712 [[nodiscard]] constexpr bool StartsWith(CharT ch) const noexcept {
713 return !Empty() && Front() == ch;
714 }
715
716 /**
717 * @brief Checks if string ends with suffix.
718 * @param sv Suffix to check
719 * @return True if string ends with sv
720 */
721 [[nodiscard]] constexpr bool EndsWith(
722 std::basic_string_view<CharT, Traits> sv) const noexcept {
723 return View().ends_with(sv);
724 }
725
726 /**
727 * @brief Checks if string ends with character.
728 * @param ch Character to check
729 * @return True if string ends with ch
730 */
731 [[nodiscard]] constexpr bool EndsWith(CharT ch) const noexcept {
732 return !Empty() && Back() == ch;
733 }
734
735 /**
736 * @brief Checks if string contains substring.
737 * @param sv Substring to search for
738 * @return True if string contains sv
739 */
740 [[nodiscard]] constexpr bool Contains(
741 std::basic_string_view<CharT, Traits> sv) const noexcept {
742 return View().find(sv) != npos;
743 }
744
745 /**
746 * @brief Checks if string contains character.
747 * @param ch Character to search for
748 * @return True if string contains ch
749 */
750 [[nodiscard]] constexpr bool Contains(CharT ch) const noexcept {
751 return View().find(ch) != npos;
752 }
753
754 /**
755 * @brief Returns the number of characters.
756 * @return Number of characters (excluding null terminator)
757 */
758 [[nodiscard]] constexpr size_type Size() const noexcept { return size_; }
759
760 /**
761 * @brief Returns the number of characters.
762 * @return Number of characters (excluding null terminator)
763 */
764 [[nodiscard]] constexpr size_type Length() const noexcept { return size_; }
765
766 /**
767 * @brief Returns the maximum possible number of characters.
768 * @return StrCapacity
769 */
770 [[nodiscard]] static constexpr size_type MaxSize() noexcept {
771 return StrCapacity;
772 }
773
774 /**
775 * @brief Returns the capacity.
776 * @return StrCapacity
777 */
778 [[nodiscard]] static constexpr size_type Capacity() noexcept {
779 return StrCapacity;
780 }
781
782 /**
783 * @brief Returns the remaining capacity.
784 * @return `StrCapacity - Size()`
785 */
786 [[nodiscard]] constexpr size_type RemainingCapacity() const noexcept {
787 return StrCapacity - size_;
788 }
789
790 /**
791 * @brief Accesses character at specified position with bounds checking.
792 * @warning Triggers assertion if pos >= size().
793 * @param pos Position of the character
794 * @return Reference to the character
795 */
796 [[nodiscard]] constexpr reference At(size_type pos) noexcept;
797
798 /**
799 * @brief Accesses character at specified position with bounds checking
800 * (const).
801 * @warning Triggers assertion if `pos >= Size()`.
802 * @param pos Position of the character
803 * @return Const reference to the character
804 *
805 */
806 [[nodiscard]] constexpr const_reference At(size_type pos) const noexcept;
807
808 /**
809 * @brief Accesses the first character.
810 * @warning Triggers assertion if string is empty.
811 * @return Reference to the first character
812 */
813 [[nodiscard]] constexpr reference Front() noexcept;
814
815 /**
816 * @brief Accesses the first character (const).
817 * @warning Triggers assertion if string is empty.
818 * @return Const reference to the first character
819 */
820 [[nodiscard]] constexpr const_reference Front() const noexcept;
821
822 /**
823 * @brief Accesses the last character.
824 * @warning Triggers assertion if string is empty.
825 * @return Reference to the last character
826 */
827 [[nodiscard]] constexpr reference Back() noexcept;
828
829 /**
830 * @brief Accesses the last character (const).
831 * @warning Triggers assertion if string is empty.
832 * @return Const reference to the last character
833 */
834 [[nodiscard]] constexpr const_reference Back() const noexcept;
835
836 /**
837 * @brief Returns pointer to the underlying character array.
838 * @return Pointer to the character array
839 */
840 [[nodiscard]] constexpr pointer Data() noexcept { return data_.data(); }
841
842 /**
843 * @brief Returns pointer to the underlying character array (const).
844 * @return Const pointer to the character array
845 */
846 [[nodiscard]] constexpr const_pointer Data() const noexcept {
847 return data_.data();
848 }
849
850 /**
851 * @brief Returns null-terminated C string.
852 * @return Null-terminated character array
853 */
854 [[nodiscard]] constexpr const_pointer CStr() const noexcept {
855 return data_.data();
856 }
857
858 /**
859 * @brief Returns a `std::basic_string_view` of the content.
860 * @return String view of the content
861 */
862 [[nodiscard]] constexpr std::basic_string_view<CharT, Traits> View()
863 const noexcept {
864 return std::basic_string_view<CharT, Traits>(data_.data(), size_);
865 }
866
867 [[nodiscard]] constexpr iterator begin() noexcept { return data_.data(); }
868 [[nodiscard]] constexpr const_iterator begin() const noexcept {
869 return data_.data();
870 }
871 [[nodiscard]] constexpr const_iterator cbegin() const noexcept {
872 return data_.data();
873 }
874
875 [[nodiscard]] constexpr iterator end() noexcept {
876 return data_.data() + size_;
877 }
878 [[nodiscard]] constexpr const_iterator end() const noexcept {
879 return data_.data() + size_;
880 }
881 [[nodiscard]] constexpr const_iterator cend() const noexcept {
882 return data_.data() + size_;
883 }
884
885 [[nodiscard]] constexpr reverse_iterator rbegin() noexcept {
886 return reverse_iterator(end());
887 }
888 [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept {
889 return const_reverse_iterator(end());
890 }
891 [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept {
892 return const_reverse_iterator(end());
893 }
894
895 [[nodiscard]] constexpr reverse_iterator rend() noexcept {
896 return reverse_iterator(begin());
897 }
898 [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept {
900 }
901 [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept {
903 }
904
905private:
906 std::array<CharT, StrCapacity + 1>
907 data_{}; ///< Character storage (+ 1 for null terminator)
908 size_type size_ = 0; ///< Current string length
909};
910
911template <size_t StrCapacity, typename CharT, typename Traits>
912 requires(StrCapacity > 0)
914 std::basic_string_view<CharT, Traits> sv) noexcept {
915 HELIOS_ASSERT(sv.size() <= StrCapacity, "String view size exceeds capacity!");
916 const size_type copy_len = std::min(sv.size(), StrCapacity);
917 Traits::copy(data_.data(), sv.data(), copy_len);
918 size_ = copy_len;
919 data_[size_] = CharT{};
920}
921
922template <size_t StrCapacity, typename CharT, typename Traits>
923 requires(StrCapacity > 0)
925 std::basic_string_view<CharT, Traits> sv, size_type pos,
926 size_type count) noexcept {
927 HELIOS_ASSERT(pos <= sv.size(), "Position out of range!");
928 const size_type substr_len = std::min(count, sv.size() - pos);
929 HELIOS_ASSERT(substr_len <= StrCapacity, "Substring size exceeds capacity!");
930 Traits::copy(data_.data(), sv.data() + pos, substr_len);
931 size_ = substr_len;
932 data_[size_] = CharT{};
933}
934
935template <size_t StrCapacity, typename CharT, typename Traits>
936 requires(StrCapacity > 0)
937template <size_t N>
938 requires(N <= StrCapacity + 1)
939constexpr BasicStaticString<StrCapacity, CharT, Traits>::BasicStaticString(
940 const CharT (&str)[N]) noexcept {
941 // N includes null terminator for string literals
942 const size_type copy_len = (N > 0 && str[N - 1] == CharT{}) ? N - 1 : N;
943 HELIOS_ASSERT(copy_len <= StrCapacity,
944 "String literal size exceeds capacity!");
945 Traits::copy(data_.data(), str, copy_len);
946 size_ = copy_len;
947 data_[size_] = CharT{};
948}
949
950template <size_t StrCapacity, typename CharT, typename Traits>
951 requires(StrCapacity > 0)
953 size_type count, CharT ch) noexcept {
954 HELIOS_ASSERT(count <= StrCapacity, "Count exceeds capacity!");
955 std::ranges::fill_n(data_.begin(), static_cast<ptrdiff_t>(count), ch);
956 size_ = count;
957 data_[size_] = CharT{};
958}
959
960template <size_t StrCapacity, typename CharT, typename Traits>
961 requires(StrCapacity > 0)
963 const CharT* str, size_type len) noexcept {
964 HELIOS_ASSERT(len <= StrCapacity, "Length exceeds capacity!");
965 Traits::copy(data_.data(), str, len);
966 size_ = len;
967 data_[size_] = CharT{};
968}
969
970template <size_t StrCapacity, typename CharT, typename Traits>
971 requires(StrCapacity > 0)
972template <std::input_iterator InputIt>
974 InputIt first, InputIt last) noexcept {
975 size_type count = 0;
976 for (auto it = first; it != last && count < StrCapacity; ++it, ++count) {
977 data_[count] = *it;
978 }
979 size_ = count;
980 data_[size_] = CharT{};
981}
982
983template <size_t StrCapacity, typename CharT, typename Traits>
984 requires(StrCapacity > 0)
985template <std::ranges::input_range Range>
986 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
988 std::from_range_t /*tag*/, Range&& range) noexcept {
989 size_type count = 0;
990 for (auto&& ch : std::forward<Range>(range)) {
991 if (count >= StrCapacity) {
992 break;
993 }
994 data_[count++] = static_cast<CharT>(ch);
995 }
996 size_ = count;
997 data_[size_] = CharT{};
998}
999
1000template <size_t StrCapacity, typename CharT, typename Traits>
1001 requires(StrCapacity > 0)
1003 std::initializer_list<CharT> ilist) noexcept {
1004 HELIOS_ASSERT(ilist.size() <= StrCapacity,
1005 "Initializer list size exceeds capacity!");
1006 Traits::copy(data_.data(), ilist.begin(), ilist.size());
1007 size_ = ilist.size();
1008 data_[size_] = CharT{};
1009}
1010
1011template <size_t StrCapacity, typename CharT, typename Traits>
1012 requires(StrCapacity > 0)
1014 std::basic_string_view<CharT, Traits> sv) noexcept -> BasicStaticString& {
1015 Assign(sv);
1016 return *this;
1017}
1018
1019template <size_t StrCapacity, typename CharT, typename Traits>
1020 requires(StrCapacity > 0)
1022 const CharT* str) noexcept -> BasicStaticString& {
1023 Assign(str);
1024 return *this;
1025}
1026
1027template <size_t StrCapacity, typename CharT, typename Traits>
1028 requires(StrCapacity > 0)
1030 size_ = 0;
1031 data_[0] = CharT{};
1032}
1033
1034template <size_t StrCapacity, typename CharT, typename Traits>
1035 requires(StrCapacity > 0)
1037 size_type pos, std::basic_string_view<CharT, Traits> sv) noexcept
1038 -> BasicStaticString& {
1039 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1040 HELIOS_ASSERT(size_ + sv.size() <= StrCapacity,
1041 "Insert would exceed capacity!");
1042
1043 // Move existing characters to make room
1044 if (pos < size_) {
1045 Traits::move(data_.data() + pos + sv.size(), data_.data() + pos,
1046 size_ - pos);
1047 }
1048
1049 // Copy new characters
1050 Traits::copy(data_.data() + pos, sv.data(), sv.size());
1051 size_ += sv.size();
1052 data_[size_] = CharT{};
1053 return *this;
1054}
1055
1056template <size_t StrCapacity, typename CharT, typename Traits>
1057 requires(StrCapacity > 0)
1059 size_type pos, size_type count, CharT ch) noexcept -> BasicStaticString& {
1060 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1061 HELIOS_ASSERT(size_ + count <= StrCapacity, "Insert would exceed capacity!");
1062
1063 if (pos < size_) {
1064 Traits::move(data_.data() + pos + count, data_.data() + pos, size_ - pos);
1065 }
1066
1067 std::ranges::fill_n(data_.begin() + pos, static_cast<ptrdiff_t>(count), ch);
1068 size_ += count;
1069 data_[size_] = CharT{};
1070 return *this;
1071}
1072
1073template <size_t StrCapacity, typename CharT, typename Traits>
1074 requires(StrCapacity > 0)
1075template <std::ranges::input_range Range>
1076 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
1078 size_type pos, Range&& range) noexcept -> BasicStaticString& {
1079 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1080
1081 // Calculate range size if possible
1082 size_type range_size = 0;
1083 if constexpr (std::ranges::sized_range<Range>) {
1084 range_size = static_cast<size_type>(std::ranges::size(range));
1085 HELIOS_ASSERT(size_ + range_size <= StrCapacity,
1086 "Insert would exceed capacity!");
1087
1088 // Move existing characters
1089 if (pos < size_) {
1090 Traits::move(data_.data() + pos + range_size, data_.data() + pos,
1091 size_ - pos);
1092 }
1093
1094 // Copy from range
1095 auto dest = data_.begin() + pos;
1096 for (auto&& ch : std::forward<Range>(range)) {
1097 *dest++ = static_cast<CharT>(ch);
1098 }
1099 size_ += range_size;
1100 } else {
1101 // For non-sized ranges, insert one by one
1102 auto insert_pos = pos;
1103 for (auto&& ch : std::forward<Range>(range)) {
1104 HELIOS_ASSERT(size_ < StrCapacity, "Insert would exceed capacity!");
1105 if (insert_pos < size_) {
1106 Traits::move(data_.data() + insert_pos + 1, data_.data() + insert_pos,
1107 size_ - insert_pos);
1108 }
1109 data_[insert_pos++] = static_cast<CharT>(ch);
1110 ++size_;
1111 }
1112 }
1113
1114 data_[size_] = CharT{};
1115 return *this;
1116}
1117
1118template <size_t StrCapacity, typename CharT, typename Traits>
1119 requires(StrCapacity > 0)
1121 size_type pos, size_type count) noexcept -> BasicStaticString& {
1122 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1123 const size_type erase_count = std::min(count, size_ - pos);
1124 const size_type remaining = size_ - pos - erase_count;
1125 if (remaining > 0) {
1126 Traits::move(data_.data() + pos, data_.data() + pos + erase_count,
1127 remaining);
1128 }
1129 size_ -= erase_count;
1130 data_[size_] = CharT{};
1131 return *this;
1132}
1133
1134template <size_t StrCapacity, typename CharT, typename Traits>
1135 requires(StrCapacity > 0)
1137 CharT ch) noexcept {
1138 HELIOS_ASSERT(size_ < StrCapacity, "Cannot PushBack: string is at capacity!");
1139 data_[size_++] = ch;
1140 data_[size_] = CharT{};
1141}
1142
1143template <size_t StrCapacity, typename CharT, typename Traits>
1144 requires(StrCapacity > 0)
1145constexpr void
1147 HELIOS_ASSERT(!Empty(), "Cannot PopBack: string is empty!");
1148 data_[--size_] = CharT{};
1149}
1150
1151template <size_t StrCapacity, typename CharT, typename Traits>
1152 requires(StrCapacity > 0)
1154 std::basic_string_view<CharT, Traits> sv) noexcept -> BasicStaticString& {
1155 HELIOS_ASSERT(size_ + sv.size() <= StrCapacity,
1156 "Append would exceed capacity!");
1157 Traits::copy(data_.data() + size_, sv.data(), sv.size());
1158 size_ += sv.size();
1159 data_[size_] = CharT{};
1160 return *this;
1161}
1162
1163template <size_t StrCapacity, typename CharT, typename Traits>
1164 requires(StrCapacity > 0)
1166 size_type count, CharT ch) noexcept -> BasicStaticString& {
1167 HELIOS_ASSERT(size_ + count <= StrCapacity, "Append would exceed capacity!");
1168 std::ranges::fill_n(data_.begin() + size_, static_cast<ptrdiff_t>(count), ch);
1169 size_ += count;
1170 data_[size_] = CharT{};
1171 return *this;
1172}
1173
1174template <size_t StrCapacity, typename CharT, typename Traits>
1175 requires(StrCapacity > 0)
1176template <std::ranges::input_range Range>
1177 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
1179 Range&& range) noexcept -> BasicStaticString& {
1180 for (auto&& ch : std::forward<Range>(range)) {
1181 PushBack(static_cast<CharT>(ch));
1182 }
1183 return *this;
1184}
1185
1186template <size_t StrCapacity, typename CharT, typename Traits>
1187 requires(StrCapacity > 0)
1189 size_type pos, size_type count,
1190 std::basic_string_view<CharT, Traits> sv) noexcept -> BasicStaticString& {
1191 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1192 const size_type replace_count = std::min(count, size_ - pos);
1193 const size_type new_size = size_ - replace_count + sv.size();
1194 HELIOS_ASSERT(new_size <= StrCapacity, "Replace would exceed capacity!");
1195
1196 // Move tail
1197 const size_type tail_pos = pos + replace_count;
1198 const size_type tail_len = size_ - tail_pos;
1199 if (tail_len > 0 && sv.size() != replace_count) {
1200 Traits::move(data_.data() + pos + sv.size(), data_.data() + tail_pos,
1201 tail_len);
1202 }
1203
1204 // Copy replacement
1205 Traits::copy(data_.data() + pos, sv.data(), sv.size());
1206 size_ = new_size;
1207 data_[size_] = CharT{};
1208 return *this;
1209}
1210
1211template <size_t StrCapacity, typename CharT, typename Traits>
1212 requires(StrCapacity > 0)
1214 size_type pos, size_type count, size_type count2, CharT ch) noexcept
1215 -> BasicStaticString& {
1216 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1217 const size_type replace_count = std::min(count, size_ - pos);
1218 const size_type new_size = size_ - replace_count + count2;
1219 HELIOS_ASSERT(new_size <= StrCapacity, "Replace would exceed capacity!");
1220
1221 const size_type tail_pos = pos + replace_count;
1222 const size_type tail_len = size_ - tail_pos;
1223 if (tail_len > 0 && count2 != replace_count) {
1224 Traits::move(data_.data() + pos + count2, data_.data() + tail_pos,
1225 tail_len);
1226 }
1227
1228 std::ranges::fill_n(data_.begin() + pos, static_cast<ptrdiff_t>(count2), ch);
1229 size_ = new_size;
1230 data_[size_] = CharT{};
1231 return *this;
1232}
1233
1234template <size_t StrCapacity, typename CharT, typename Traits>
1235 requires(StrCapacity > 0)
1236template <std::ranges::input_range Range>
1237 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
1239 size_type pos, size_type count, Range&& range) noexcept
1240 -> BasicStaticString& {
1241 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1242
1243 const size_type replace_count = std::min(count, size_ - pos);
1244
1245 if constexpr (std::ranges::sized_range<Range>) {
1246 const auto range_size = static_cast<size_type>(std::ranges::size(range));
1247 const size_type new_size = size_ - replace_count + range_size;
1248 HELIOS_ASSERT(new_size <= StrCapacity, "Replace would exceed capacity!");
1249
1250 const size_type tail_pos = pos + replace_count;
1251 const size_type tail_len = size_ - tail_pos;
1252 if (tail_len > 0 && range_size != replace_count) {
1253 Traits::move(data_.data() + pos + range_size, data_.data() + tail_pos,
1254 tail_len);
1255 }
1256
1257 auto dest = data_.begin() + pos;
1258 for (auto&& ch : std::forward<Range>(range)) {
1259 *dest++ = static_cast<CharT>(ch);
1260 }
1261 size_ = new_size;
1262 } else {
1263 // For non-sized ranges, use temporary storage
1264 BasicStaticString temp;
1265 temp.Assign(View().substr(0, pos));
1266 temp.AppendRange(std::forward<Range>(range));
1267 if (pos + replace_count < size_) {
1268 temp.Append(View().substr(pos + replace_count));
1269 }
1270 *this = std::move(temp);
1271 }
1272
1273 data_[size_] = CharT{};
1274 return *this;
1275}
1276
1277template <size_t StrCapacity, typename CharT, typename Traits>
1278 requires(StrCapacity > 0)
1280 CharT* dest, size_type count, size_type pos) const noexcept -> size_type {
1281 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1282 const size_type copy_count = std::min(count, size_ - pos);
1283 Traits::copy(dest, data_.data() + pos, copy_count);
1284 return copy_count;
1285}
1286
1287template <size_t StrCapacity, typename CharT, typename Traits>
1288 requires(StrCapacity > 0)
1290 size_type count, CharT ch) noexcept {
1291 HELIOS_ASSERT(count <= StrCapacity, "Resize count exceeds capacity!");
1292 if (count > size_) {
1293 std::ranges::fill_n(data_.begin() + size_,
1294 static_cast<ptrdiff_t>(count - size_), ch);
1295 }
1296 size_ = count;
1297 data_[size_] = CharT{};
1298}
1299
1300template <size_t StrCapacity, typename CharT, typename Traits>
1301 requires(StrCapacity > 0)
1303 BasicStaticString& other) noexcept {
1304 std::swap(data_, other.data_);
1305 std::swap(size_, other.size_);
1306}
1307
1308template <size_t StrCapacity, typename CharT, typename Traits>
1309 requires(StrCapacity > 0)
1311 std::basic_string_view<CharT, Traits> sv) noexcept -> BasicStaticString& {
1312 HELIOS_ASSERT(sv.size() <= StrCapacity, "String view size exceeds capacity!");
1313 Traits::copy(data_.data(), sv.data(), sv.size());
1314 size_ = sv.size();
1315 data_[size_] = CharT{};
1316 return *this;
1317}
1318
1319template <size_t StrCapacity, typename CharT, typename Traits>
1320 requires(StrCapacity > 0)
1322 size_type count, CharT ch) noexcept -> BasicStaticString& {
1323 HELIOS_ASSERT(count <= StrCapacity, "Count exceeds capacity!");
1324 std::ranges::fill_n(data_.begin(), static_cast<ptrdiff_t>(count), ch);
1325 size_ = count;
1326 data_[size_] = CharT{};
1327 return *this;
1328}
1329
1330template <size_t StrCapacity, typename CharT, typename Traits>
1331 requires(StrCapacity > 0)
1332template <std::ranges::input_range Range>
1333 requires std::convertible_to<std::ranges::range_value_t<Range>, CharT>
1335 Range&& range) noexcept -> BasicStaticString& {
1336 Clear();
1337 return AppendRange(std::forward<Range>(range));
1338}
1339
1340template <size_t StrCapacity, typename CharT, typename Traits>
1341 requires(StrCapacity > 0)
1343 CharT ch) noexcept -> BasicStaticString& {
1344 PushBack(ch);
1345 return *this;
1346}
1347
1348template <size_t StrCapacity, typename CharT, typename Traits>
1349 requires(StrCapacity > 0)
1351 size_type pos) noexcept -> reference {
1352 HELIOS_ASSERT(pos < size_, "Position out of range!");
1353 return data_[pos];
1354}
1355
1356template <size_t StrCapacity, typename CharT, typename Traits>
1357 requires(StrCapacity > 0)
1359 size_type pos) const noexcept -> const_reference {
1360 HELIOS_ASSERT(pos < size_, "Position out of range!");
1361 return data_[pos];
1362}
1363
1364template <size_t StrCapacity, typename CharT, typename Traits>
1365 requires(StrCapacity > 0)
1367 size_type pos) noexcept -> reference {
1368 HELIOS_ASSERT(pos < size_, "Position out of range!");
1369 return data_[pos];
1370}
1371
1372template <size_t StrCapacity, typename CharT, typename Traits>
1373 requires(StrCapacity > 0)
1375 size_type pos) const noexcept -> const_reference {
1376 HELIOS_ASSERT(pos < size_, "Position out of range!");
1377 return data_[pos];
1378}
1379
1380template <size_t StrCapacity, typename CharT, typename Traits>
1381 requires(StrCapacity > 0)
1383 -> reference {
1384 HELIOS_ASSERT(!Empty(), "String is empty!");
1385 return data_[0];
1386}
1387
1388template <size_t StrCapacity, typename CharT, typename Traits>
1389 requires(StrCapacity > 0)
1391 const noexcept -> const_reference {
1392 HELIOS_ASSERT(!Empty(), "String is empty!");
1393 return data_[0];
1394}
1395
1396template <size_t StrCapacity, typename CharT, typename Traits>
1397 requires(StrCapacity > 0)
1399 -> reference {
1400 HELIOS_ASSERT(!Empty(), "String is empty!");
1401 return data_[size_ - 1];
1402}
1403
1404template <size_t StrCapacity, typename CharT, typename Traits>
1405 requires(StrCapacity > 0)
1407 const noexcept -> const_reference {
1408 HELIOS_ASSERT(!Empty(), "String is empty!");
1409 return data_[size_ - 1];
1410}
1411
1412template <size_t StrCapacity, typename CharT, typename Traits>
1413 requires(StrCapacity > 0)
1415 size_type pos, size_type count) const noexcept -> BasicStaticString {
1416 HELIOS_ASSERT(pos <= size_, "Position out of range!");
1417 const size_type substr_len = std::min(count, size_ - pos);
1418 return BasicStaticString(data_.data() + pos, substr_len);
1419}
1420
1421template <size_t StrCapacity, typename CharT, typename Traits>
1422 requires(StrCapacity > 0)
1423template <size_t OtherCapacity>
1425 const BasicStaticString<OtherCapacity, CharT, Traits>& other) const noexcept
1426 -> std::strong_ordering {
1427 const auto result = View().compare(other.View());
1428 if (result < 0) {
1429 return std::strong_ordering::less;
1430 }
1431 if (result > 0) {
1432 return std::strong_ordering::greater;
1433 }
1434 return std::strong_ordering::equal;
1435}
1436
1437template <size_t StrCapacity, typename CharT, typename Traits>
1438 requires(StrCapacity > 0)
1440 std::basic_string_view<CharT, Traits> other) const noexcept
1441 -> std::strong_ordering {
1442 const auto result = View().compare(other);
1443 if (result < 0) {
1444 return std::strong_ordering::less;
1445 }
1446 if (result > 0) {
1447 return std::strong_ordering::greater;
1448 }
1449 return std::strong_ordering::equal;
1450}
1451
1452template <size_t StrCapacity, typename CharT, typename Traits>
1453 requires(StrCapacity > 0)
1455 const BasicStaticString& other, size_type pos, size_type count) noexcept {
1456 HELIOS_ASSERT(pos <= other.Size(), "Position out of range!");
1457 const size_type substr_len = std::min(count, other.Size() - pos);
1458 HELIOS_ASSERT(substr_len <= StrCapacity, "Substring size exceeds capacity!");
1459 Traits::copy(data_.data(), other.Data() + pos, substr_len);
1460 size_ = substr_len;
1461 data_[size_] = CharT{};
1462}
1463
1464template <size_t StrCapacity, typename CharT, typename Traits>
1465 requires(StrCapacity > 0)
1467 BasicStaticString&& other, size_type pos, size_type count) noexcept {
1468 HELIOS_ASSERT(pos <= other.Size(), "Position out of range!");
1469 const size_type substr_len = std::min(count, other.Size() - pos);
1470 HELIOS_ASSERT(substr_len <= StrCapacity, "Substring size exceeds capacity!");
1471 Traits::copy(data_.data(), other.Data() + pos, substr_len);
1472 size_ = substr_len;
1473 data_[size_] = CharT{};
1474}
1475
1476template <size_t StrCapacity, typename CharT, typename Traits>
1477 requires(StrCapacity > 0)
1478template <size_t OtherCapacity>
1479 requires(OtherCapacity < StrCapacity)
1480constexpr BasicStaticString<StrCapacity, CharT, Traits>::BasicStaticString(
1481 const BasicStaticString<OtherCapacity, CharT, Traits>& other) noexcept {
1482 HELIOS_ASSERT(other.Size() <= StrCapacity,
1483 "Source string size exceeds capacity!");
1484 Traits::copy(data_.data(), other.Data(), other.Size());
1485 size_ = other.Size();
1486 data_[size_] = CharT{};
1487}
1488
1489template <size_t StrCapacity, typename CharT, typename Traits>
1490 requires(StrCapacity > 0)
1491template <size_t OtherCapacity>
1492 requires(OtherCapacity < StrCapacity)
1493constexpr BasicStaticString<StrCapacity, CharT, Traits>::BasicStaticString(
1494 BasicStaticString<OtherCapacity, CharT, Traits>&& other) noexcept {
1495 HELIOS_ASSERT(other.Size() <= StrCapacity,
1496 "Source string size exceeds capacity!");
1497 Traits::copy(data_.data(), other.Data(), other.Size());
1498 size_ = other.Size();
1499 data_[size_] = CharT{};
1500}
1501
1502template <size_t StrCapacity, typename CharT, typename Traits>
1503 requires(StrCapacity > 0)
1504template <size_t OtherCapacity>
1505 requires(OtherCapacity < StrCapacity)
1506constexpr BasicStaticString<StrCapacity, CharT, Traits>::BasicStaticString(
1507 const BasicStaticString<OtherCapacity, CharT, Traits>& other, size_type pos,
1508 size_type count) noexcept {
1509 HELIOS_ASSERT(pos <= other.Size(), "Position out of range!");
1510 const size_type substr_len = std::min(count, other.Size() - pos);
1511 HELIOS_ASSERT(substr_len <= StrCapacity, "Substring size exceeds capacity!");
1512 Traits::copy(data_.data(), other.Data() + pos, substr_len);
1513 size_ = substr_len;
1514 data_[size_] = CharT{};
1515}
1516
1517template <size_t StrCapacity, typename CharT, typename Traits>
1518 requires(StrCapacity > 0)
1519template <size_t OtherCapacity>
1520 requires(OtherCapacity < StrCapacity)
1521constexpr BasicStaticString<StrCapacity, CharT, Traits>::BasicStaticString(
1522 BasicStaticString<OtherCapacity, CharT, Traits>&& other, size_type pos,
1523 size_type count) noexcept {
1524 HELIOS_ASSERT(pos <= other.Size(), "Position out of range!");
1525 const size_type substr_len = std::min(count, other.Size() - pos);
1526 HELIOS_ASSERT(substr_len <= StrCapacity, "Substring size exceeds capacity!");
1527 Traits::copy(data_.data(), other.Data() + pos, substr_len);
1528 size_ = substr_len;
1529 data_[size_] = CharT{};
1530}
1531
1532template <size_t StrCapacity, typename CharT, typename Traits>
1533 requires(StrCapacity > 0)
1534template <size_t OtherCapacity>
1535 requires(OtherCapacity < StrCapacity)
1536constexpr auto BasicStaticString<StrCapacity, CharT, Traits>::operator=(
1537 const BasicStaticString<OtherCapacity, CharT, Traits>& other) noexcept
1538 -> BasicStaticString& {
1539 HELIOS_ASSERT(other.Size() <= StrCapacity,
1540 "Source string size exceeds capacity!");
1541 Traits::copy(data_.data(), other.Data(), other.Size());
1542 size_ = other.Size();
1543 data_[size_] = CharT{};
1544 return *this;
1545}
1546
1547template <size_t StrCapacity, typename CharT, typename Traits>
1548 requires(StrCapacity > 0)
1549template <size_t OtherCapacity>
1550 requires(OtherCapacity < StrCapacity)
1551constexpr auto BasicStaticString<StrCapacity, CharT, Traits>::operator=(
1552 BasicStaticString<OtherCapacity, CharT, Traits>&& other) noexcept
1553 -> BasicStaticString& {
1554 HELIOS_ASSERT(other.Size() <= StrCapacity,
1555 "Source string size exceeds capacity!");
1556 Traits::copy(data_.data(), other.Data(), other.Size());
1557 size_ = other.Size();
1558 data_[size_] = CharT{};
1559 return *this;
1560}
1561
1562/**
1563 * @brief Fixed-capacity string of `char`.
1564 * @tparam N Maximum capacity
1565 */
1566template <size_t N>
1568
1569/**
1570 * @brief Fixed-capacity string of `wchar_t`.
1571 * @tparam N Maximum capacity
1572 */
1573template <size_t N>
1575
1576/**
1577 * @brief Fixed-capacity string of `char8_t`.
1578 * @tparam N Maximum capacity
1579 */
1580template <size_t N>
1582
1583/**
1584 * @brief Fixed-capacity string of `char16_t`.
1585 * @tparam N Maximum capacity
1586 */
1587template <size_t N>
1589
1590/**
1591 * @brief Fixed-capacity string of `char32_t`.
1592 * @tparam N Maximum capacity
1593 */
1594template <size_t N>
1596
1597/**
1598 * @brief Concatenates two StaticStrings.
1599 * @tparam N1 `StrCapacity` of first string
1600 * @tparam N2 `StrCapacity` of second string
1601 * @tparam CharT Character type
1602 * @tparam Traits Character traits
1603 * @param lhs First string
1604 * @param rhs Second string
1605 * @return Concatenated string with capacity `N1 + N2`
1606 */
1607template <size_t N1, size_t N2, typename CharT, typename Traits>
1608[[nodiscard]] constexpr auto operator+(
1610 const BasicStaticString<N2, CharT, Traits>& rhs) noexcept
1613 result.Append(lhs.View());
1614 result.Append(rhs.View());
1615 return result;
1616}
1617
1618/**
1619 * @brief Concatenates `StaticString` with `std::basic_string_view`.
1620 * @warning Triggers assertion if combined length > `N`.
1621 * @tparam N `StrCapacity` of the static string
1622 * @tparam CharT Character type
1623 * @tparam Traits Character traits
1624 * @param lhs Static string
1625 * @param rhs String view
1626 * @return Concatenated string (same capacity as lhs)
1627 */
1628template <size_t N, typename CharT, typename Traits>
1629[[nodiscard]] constexpr auto operator+(
1631 std::basic_string_view<CharT, Traits> rhs) noexcept
1634 result.Append(rhs);
1635 return result;
1636}
1637
1638/**
1639 * @brief Concatenates `std::basic_string_view` with `StaticString`.
1640 * @warning Triggers assertion if combined length > `N`.
1641 * @tparam N `StrCapacity` of the static string
1642 * @tparam CharT Character type
1643 * @tparam Traits Character traits
1644 * @param lhs String view
1645 * @param rhs Static string
1646 * @return Concatenated string (same capacity as rhs)
1647 */
1648template <size_t N, typename CharT, typename Traits>
1649[[nodiscard]] constexpr auto operator+(
1650 std::basic_string_view<CharT, Traits> lhs,
1651 const BasicStaticString<N, CharT, Traits>& rhs) noexcept
1654 result.Append(rhs.View());
1655 return result;
1656}
1657
1658/**
1659 * @brief Concatenates StaticString with character.
1660 * @warning Triggers assertion if `lhs.Size() >= N`.
1661 * @tparam N `StrCapacity` of the static string
1662 * @tparam CharT Character type
1663 * @tparam Traits Character traits
1664 * @param lhs Static string
1665 * @param rhs Character
1666 * @return Concatenated string (same capacity as lhs)
1667 */
1668template <size_t N, typename CharT, typename Traits>
1669[[nodiscard]] constexpr auto operator+(
1670 const BasicStaticString<N, CharT, Traits>& lhs, CharT rhs) noexcept
1673 result.PushBack(rhs);
1674 return result;
1675}
1676
1677/**
1678 * @brief Concatenates character with StaticString.
1679 * @warning Triggers assertion if `rhs.Size() >= N`.
1680 * @tparam N `StrCapacity` of the static string
1681 * @tparam CharT Character type
1682 * @tparam Traits Character traits
1683 * @param lhs Character
1684 * @param rhs Static string
1685 * @return Concatenated string (same capacity as rhs)
1686 */
1687template <size_t N, typename CharT, typename Traits>
1688[[nodiscard]] constexpr auto operator+(
1689 CharT lhs, const BasicStaticString<N, CharT, Traits>& rhs) noexcept
1692 result.Append(rhs.View());
1693 return result;
1694}
1695
1696/**
1697 * @brief Swaps two BasicStaticStrings.
1698 * @tparam StrCapacity `StrCapacity` of the strings
1699 * @tparam CharT Character type
1700 * @tparam Traits Character traits
1701 * @param lhs First string
1702 * @param rhs Second string
1703 */
1704template <size_t StrCapacity, typename CharT, typename Traits>
1705constexpr void swap(
1708 lhs.Swap(rhs);
1709}
1710
1711/**
1712 * @brief Erases all elements equal to value.
1713 * @tparam StrCapacity `StrCapacity` of the string
1714 * @tparam CharT Character type
1715 * @tparam Traits Character traits
1716 * @param str String to modify
1717 * @param value Value to erase
1718 * @return Number of elements erased
1719 */
1720template <size_t StrCapacity, typename CharT, typename Traits>
1722 CharT value) noexcept ->
1724 const auto original_size = str.Size();
1725 auto* new_end = std::remove(str.begin(), str.end(), value);
1726 str.Resize(static_cast<
1728 new_end - str.begin()));
1729 return original_size - str.Size();
1730}
1731
1732/**
1733 * @brief Erases all elements satisfying predicate.
1734 * @tparam StrCapacity `StrCapacity` of the string
1735 * @tparam CharT Character type
1736 * @tparam Traits Character traits
1737 * @tparam Pred Predicate type
1738 * @param str String to modify
1739 * @param pred Unary predicate
1740 * @return Number of elements erased
1741 */
1742template <size_t StrCapacity, typename CharT, typename Traits, typename Pred>
1744 Pred pred) noexcept ->
1746 const auto original_size = str.Size();
1747 auto* new_end = std::remove_if(str.begin(), str.end(), pred);
1748 str.Resize(static_cast<
1750 new_end - str.begin()));
1751 return original_size - str.Size();
1752}
1753
1754/**
1755 * @brief Outputs a `BasicStaticString` to an output stream.
1756 * @tparam StrCapacity `StrCapacity` of the string
1757 * @tparam CharT Character type
1758 * @tparam Traits Character traits
1759 * @param os Output stream
1760 * @param str String to output
1761 * @return Reference to the output stream
1762 */
1763template <size_t StrCapacity, typename CharT, typename Traits>
1764inline auto operator<<(std::basic_ostream<CharT, Traits>& os,
1766 -> std::basic_ostream<CharT, Traits>& {
1767 return os << str.View();
1768}
1769
1770/**
1771 * @brief Inputs a `BasicStaticString` from an input stream.
1772 * @tparam StrCapacity `StrCapacity` of the string
1773 * @tparam CharT Character type
1774 * @tparam Traits Character traits
1775 * @param is Input stream
1776 * @param str String to input
1777 * @return Reference to the input stream
1778 */
1779template <size_t StrCapacity, typename CharT, typename Traits>
1780inline auto operator>>(std::basic_istream<CharT, Traits>& is,
1782 -> std::basic_istream<CharT, Traits>& {
1783 std::basic_string<CharT, Traits> temp;
1784 is >> temp;
1785 if (temp.size() <= StrCapacity) {
1786 str.Assign(temp);
1787 } else {
1788 is.setstate(std::ios_base::failbit);
1789 }
1790 return is;
1791}
1792
1793} // namespace helios::container
1794
1795namespace std {
1796
1797/**
1798 * @brief Hash support for `BasicStaticString`.
1799 * @tparam StrCapacity `StrCapacity` of the string
1800 * @tparam CharT Character type
1801 * @tparam Traits Character traits
1802 */
1803template <size_t StrCapacity, typename CharT, typename Traits>
1804struct hash<helios::container::BasicStaticString<StrCapacity, CharT, Traits>> {
1805 [[nodiscard]] constexpr size_t operator()(
1807 str) const noexcept {
1808 return hash<basic_string_view<CharT, Traits>>{}(str.View());
1809 }
1810};
1811
1812/**
1813 * @brief `std::format` support for BasicStaticString.
1814 * @details Enables formatting `BasicStaticString` using `std::format`
1815 * by delegating to `std::basic_string_view` formatter.
1816 * @tparam StrCapacity `StrCapacity` of the string
1817 * @tparam CharT Character type
1818 * @tparam Traits Character traits
1819 */
1820template <size_t StrCapacity, typename CharT, typename Traits>
1821struct formatter<
1822 helios::container::BasicStaticString<StrCapacity, CharT, Traits>>
1823 : formatter<basic_string_view<CharT, Traits>> {
1824 /// @brief Format the BasicStaticString by delegating to
1825 /// `std::basic_string_view` formatter.
1826 auto format(const helios::container::BasicStaticString<StrCapacity, CharT,
1827 Traits>& str,
1828 format_context& ctx) const {
1829 return formatter<basic_string_view<CharT, Traits>>::format(str.View(), ctx);
1830 }
1831};
1832
1833} // namespace std
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:259
A fixed-capacity string class that owns its storage.
constexpr const_iterator cbegin() const noexcept
constexpr BasicStaticString & operator+=(std::basic_string_view< char, std::char_traits< char > > sv) noexcept
constexpr auto operator<=>(std::basic_string_view< char, std::char_traits< char > > other) const noexcept -> std::strong_ordering
constexpr BasicStaticString(std::initializer_list< char > ilist) noexcept
constexpr BasicStaticString(std::basic_string_view< char, std::char_traits< char > > sv, size_type pos, size_type count=npos) noexcept
constexpr const_pointer CStr() const noexcept
constexpr const_reverse_iterator crbegin() const noexcept
constexpr bool StartsWith(std::basic_string_view< char, std::char_traits< char > > sv) const noexcept
constexpr int Compare(std::basic_string_view< char, std::char_traits< char > > other) const noexcept
constexpr size_type Copy(char *dest, size_type count, size_type pos=0) const noexcept
constexpr const_iterator cend() const noexcept
constexpr size_type RFind(std::basic_string_view< char, std::char_traits< char > > sv, size_type pos=npos) const noexcept
constexpr void Swap(BasicStaticString &other) noexcept
constexpr size_type Length() const noexcept
constexpr bool operator==(const char *other) const noexcept
constexpr reverse_iterator rend() noexcept
constexpr int Compare(const BasicStaticString< OtherCapacity, char, std::char_traits< char > > &other) const noexcept
constexpr const_reference operator[](size_type pos) const noexcept
static constexpr size_type MaxSize() noexcept
constexpr bool Contains(std::basic_string_view< char, std::char_traits< char > > sv) const noexcept
constexpr size_type FindFirstOf(std::basic_string_view< char, std::char_traits< char > > sv, size_type pos=0) const noexcept
constexpr void Resize(size_type count, char ch=char{}) noexcept
constexpr BasicStaticString & Erase(size_type pos=0, size_type count=npos) noexcept
constexpr size_type Find(std::basic_string_view< char, std::char_traits< char > > sv, size_type pos=0) const noexcept
constexpr BasicStaticString & Assign(const char *str) noexcept
constexpr size_type FindLastNotOf(std::basic_string_view< char, std::char_traits< char > > sv, size_type pos=npos) const noexcept
static constexpr size_type Capacity() noexcept
constexpr bool EndsWith(std::basic_string_view< char, std::char_traits< char > > sv) const noexcept
constexpr BasicStaticString() noexcept
Default constructor. Creates an empty string.
constexpr size_type Size() const noexcept
constexpr reference At(size_type pos) noexcept
constexpr BasicStaticString & Insert(size_type pos, std::basic_string_view< char, std::char_traits< char > > sv) noexcept
constexpr BasicStaticString(BasicStaticString &&) noexcept=default
constexpr const_iterator end() const noexcept
constexpr BasicStaticString Substr(size_type pos=0, size_type count=npos) const noexcept
constexpr size_type FindLastOf(std::basic_string_view< char, std::char_traits< char > > sv, size_type pos=npos) const noexcept
constexpr const_iterator begin() const noexcept
constexpr BasicStaticString & operator+=(char ch) noexcept
constexpr auto operator<=>(const BasicStaticString< OtherCapacity, char, std::char_traits< char > > &other) const noexcept -> std::strong_ordering
constexpr BasicStaticString(std::from_range_t tag, Range &&range) noexcept
constexpr size_type RFind(char ch, size_type pos=npos) const noexcept
constexpr bool operator==(const BasicStaticString< OtherCapacity, char, std::char_traits< char > > &other) const noexcept
constexpr BasicStaticString & Assign(std::basic_string_view< char, std::char_traits< char > > sv) noexcept
constexpr const_reverse_iterator rend() const noexcept
constexpr bool Contains(char ch) const noexcept
constexpr BasicStaticString & AssignRange(Range &&range) noexcept
constexpr BasicStaticString & ReplaceWithRange(size_type pos, size_type count, Range &&range) noexcept
constexpr BasicStaticString & Append(std::basic_string_view< char, std::char_traits< char > > sv) noexcept
constexpr BasicStaticString & operator+=(const char *str) noexcept
constexpr reverse_iterator rbegin() noexcept
constexpr size_type Find(char ch, size_type pos=0) const noexcept
constexpr std::basic_string_view< char, std::char_traits< char > > View() const noexcept
std::reverse_iterator< iterator > reverse_iterator
constexpr BasicStaticString(const char *str, size_type len) noexcept
constexpr BasicStaticString(const char *str) noexcept
constexpr const_reference At(size_type pos) const noexcept
constexpr size_type FindFirstNotOf(std::basic_string_view< char, std::char_traits< char > > sv, size_type pos=0) const noexcept
constexpr BasicStaticString(size_type count, char ch) noexcept
constexpr explicit(false) BasicStaticString(const char(&str)[N]) noexcept
constexpr const_pointer Data() const noexcept
constexpr const_reverse_iterator rbegin() const noexcept
constexpr const_reverse_iterator crend() const noexcept
constexpr auto operator<=>(const char *other) const noexcept -> std::strong_ordering
std::reverse_iterator< const_iterator > const_reverse_iterator
constexpr BasicStaticString & Assign(size_type count, char ch) noexcept
constexpr BasicStaticString & AppendRange(Range &&range) noexcept
constexpr bool EndsWith(char ch) const noexcept
constexpr BasicStaticString(std::basic_string_view< char, std::char_traits< char > > sv) noexcept
constexpr bool StartsWith(char ch) const noexcept
constexpr size_type RemainingCapacity() const noexcept
constexpr BasicStaticString(const BasicStaticString &) noexcept=default
constexpr BasicStaticString & Replace(size_type pos, size_type count, std::basic_string_view< char, std::char_traits< char > > sv) noexcept
constexpr reference operator[](size_type pos) noexcept
constexpr BasicStaticString & Replace(size_type pos, size_type count, size_type count2, char ch) noexcept
constexpr BasicStaticString(InputIt first, InputIt last) noexcept
constexpr bool operator==(std::basic_string_view< char, std::char_traits< char > > other) const noexcept
constexpr BasicStaticString & InsertRange(size_type pos, Range &&range) noexcept
constexpr auto operator+(const BasicStaticString< N1, CharT, Traits > &lhs, const BasicStaticString< N2, CharT, Traits > &rhs) noexcept -> BasicStaticString< N1+N2, CharT, Traits >
Concatenates two StaticStrings.
BasicStaticString< N, char16_t > StaticU16String
Fixed-capacity string of char16_t.
auto operator<<(std::basic_ostream< CharT, Traits > &os, const BasicStaticString< StrCapacity, CharT, Traits > &str) -> std::basic_ostream< CharT, Traits > &
Outputs a BasicStaticString to an output stream.
BasicStaticString< N, char > StaticString
Fixed-capacity string of char.
BasicStaticString< N, char32_t > StaticU32String
Fixed-capacity string of char32_t.
constexpr void swap(BasicStaticString< StrCapacity, CharT, Traits > &lhs, BasicStaticString< StrCapacity, CharT, Traits > &rhs) noexcept
Swaps two BasicStaticStrings.
auto operator>>(std::basic_istream< CharT, Traits > &is, BasicStaticString< StrCapacity, CharT, Traits > &str) -> std::basic_istream< CharT, Traits > &
Inputs a BasicStaticString from an input stream.
constexpr auto erase(BasicStaticString< StrCapacity, CharT, Traits > &str, CharT value) noexcept -> typename BasicStaticString< StrCapacity, CharT, Traits >::size_type
Erases all elements equal to value.
BasicStaticString< N, wchar_t > StaticWString
Fixed-capacity string of wchar_t.
BasicStaticString< N, char8_t > StaticU8String
Fixed-capacity string of char8_t.
constexpr auto erase_if(BasicStaticString< StrCapacity, CharT, Traits > &str, Pred pred) noexcept -> typename BasicStaticString< StrCapacity, CharT, Traits >::size_type
Erases all elements satisfying predicate.
STL namespace.
auto format(const helios::container::BasicStaticString< StrCapacity, CharT, Traits > &str, format_context &ctx) const
Format the BasicStaticString by delegating to std::basic_string_view formatter.
constexpr size_t operator()(const helios::container::BasicStaticString< StrCapacity, CharT, Traits > &str) const noexcept