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