hybstr
Hybrid constexpr string library for compile-time and runtime use
Loading...
Searching...
No Matches
hybstr.hpp
Go to the documentation of this file.
1
23
24#pragma once
25
26#include <array>
27#include <string>
28#include <cassert>
29#include <cstddef>
30#include <utility>
31#include <optional>
32#include <algorithm>
33#include <stdexcept>
34#include <string_view>
35#include <type_traits>
36
37#ifndef HYBSTR_DYNAMIC_EXPAND_CAPACITY
38#define HYBSTR_DYNAMIC_EXPAND_CAPACITY 1000
39#endif
40
41#if defined(_MSC_VER)
42# define HYBSTR_CPP_STD _MSVC_LANG
43#else
44# define HYBSTR_CPP_STD __cplusplus
45#endif
46
47#if HYBSTR_CPP_STD >= 202002L
48 #define HYBSTR_CPP_20_OR_ABOVE true
49#else
50 #define HYBSTR_CPP_20_OR_ABOVE false
51#endif
52
53#if !HYBSTR_CPP_20_OR_ABOVE
54 #ifndef consteval
55 #define consteval constexpr
56 #endif
57#endif
58
59#if HYBSTR_CPP_20_OR_ABOVE
60 #include <type_traits>
61 #define HYBSTR_IS_CONSTANT_EVALUATED std::is_constant_evaluated()
62#elif defined(__clang__) || defined(__GNUC__)
63 #define HYBSTR_IS_CONSTANT_EVALUATED __builtin_is_constant_evaluated()
64 #elif defined(_MSC_VER) && _MSC_VER >= 1928
65 #define HYBSTR_IS_CONSTANT_EVALUATED __builtin_is_constant_evaluated()
66#elif defined(__INTEL_LLVM_COMPILER)
67 #define HYBSTR_IS_CONSTANT_EVALUATED __builtin_is_constant_evaluated()
68#else
69 #define HYBSTR_IS_CONSTANT_EVALUATED false
70#endif
71
76namespace hybstr
77{
78 template<std::size_t DynamicExpandCapacity = HYBSTR_DYNAMIC_EXPAND_CAPACITY>
79 [[nodiscard]] constexpr auto string();
80 template<std::size_t DynamicExpandCapacity = HYBSTR_DYNAMIC_EXPAND_CAPACITY,
81 std::size_t N>
82 [[nodiscard]] constexpr auto string(const char(&str)[N]);
83 template<std::size_t ViewSize = HYBSTR_DYNAMIC_EXPAND_CAPACITY,
84 std::size_t DynamicExpandCapacity = HYBSTR_DYNAMIC_EXPAND_CAPACITY>
85 [[nodiscard]] constexpr auto string(std::string_view sv) noexcept;
86 template<std::size_t RangeSize = HYBSTR_DYNAMIC_EXPAND_CAPACITY,
87 std::size_t DynamicExpandCapacity = HYBSTR_DYNAMIC_EXPAND_CAPACITY,
88 typename _Iter>
89 [[nodiscard]] constexpr auto string(_Iter start, _Iter end) noexcept;
90
140 template <std::size_t BufferCapacity = 0, std::size_t DynamicExpandCapacity = HYBSTR_DYNAMIC_EXPAND_CAPACITY>
141 class string_impl
142 {
143 template <std::size_t, std::size_t>
144 friend class string_impl;
145 public:
146 using value_type = char;
147 using reference = value_type&;
148 using const_reference = const value_type&;
149 using size_type = std::size_t;
150 using view_type = std::string_view;
151 using pointer = char*;
152 using const_pointer = const char*;
153 using iterator = typename std::array<char, BufferCapacity + 1>::iterator;
154 using const_iterator = typename std::array<char, BufferCapacity + 1>::const_iterator;
155 using reverse_iterator = typename std::array<char, BufferCapacity + 1>::reverse_iterator;
156 using const_reverse_iterator = typename std::array<char, BufferCapacity + 1>::const_reverse_iterator;
157
159 constexpr string_impl() noexcept
160 : _size(0)
161 {
162 _data[0] = '\0';
163 }
164
170 template <std::size_t N>
171 constexpr string_impl(const char(&str)[N]) noexcept
172 {
173 static_assert(N > 0 && N - 1 <= BufferCapacity, "string literal too long");
174 for (std::size_t i = 0; i < N - 1; ++i)
175 {
176 _data[i] = str[i];
177 }
178 _data[N - 1] = '\0';
179 _size = N - 1;
180 }
181
187 constexpr string_impl(const std::size_t& n, char c) noexcept
188 {
189 const std::size_t len = std::min(n, BufferCapacity);
190 for (std::size_t i = 0; i < len; ++i)
191 {
192 _data[i] = c;
193 }
194 _data[len] = '\0';
195 _size = len;
196 }
197
202 constexpr string_impl(std::string_view sv) noexcept
203 {
204 const std::size_t len = std::min(sv.size(), BufferCapacity);
205 for (std::size_t i = 0; i < len; ++i)
206 {
207 _data[i] = sv[i];
208 }
209 _data[len] = '\0';
210 _size = len;
211 }
212
217 template<typename _Iter>
218 constexpr string_impl(_Iter start, _Iter end) noexcept
219 {
220 std::size_t i = 0;
221
222 while (i < BufferCapacity && start != end)
223 {
224 _data[i++] = *(start++);
225 }
226
227 _data[i] = '\0';
228 _size = i;
229 }
230
231 constexpr string_impl(const string_impl&) noexcept = default;
232 constexpr string_impl(string_impl&&) noexcept = default;
233 constexpr string_impl& operator=(const string_impl&) noexcept = default;
234 constexpr string_impl& operator=(string_impl&&) noexcept = default;
235
237 [[nodiscard]] constexpr auto size() const noexcept -> size_type
238 {
239 return _size;
240 }
241
242 [[nodiscard]] constexpr auto capacity() const noexcept -> size_type
243 {
244 return BufferCapacity;
245 }
246
247 [[nodiscard]] constexpr auto empty() const noexcept -> bool
248 {
249 return _size == 0;
250 }
251
253 [[nodiscard]] constexpr auto data() noexcept -> pointer
254 {
255 return _data.data();
256 }
257
258 [[nodiscard]] constexpr auto data() const noexcept -> const_pointer
259 {
260 return _data.data();
261 }
262
263 [[nodiscard]] constexpr auto c_str() const noexcept -> const_pointer
264 {
265 return _data.data();
266 }
267
268 [[nodiscard]] constexpr auto view() const noexcept -> view_type
269 {
270 return std::string_view(_data.data(), _size);
271 }
272
273 [[nodiscard]] auto str() const -> std::string
274 {
275 return std::string(begin(), end());
276 }
277
278
280 [[nodiscard]] constexpr auto operator[](size_type i) noexcept -> reference
281 {
282 return _data[i];
283 }
284
285 [[nodiscard]] constexpr auto operator[](size_type i) const noexcept -> const_reference
286 {
287 return _data[i];
288 }
289
290 [[nodiscard]] constexpr auto begin() noexcept -> iterator
291 {
292 return _data.begin();
293 }
294 [[nodiscard]] constexpr auto begin() const noexcept -> const_iterator
295 {
296 return _data.begin();
297 }
298 [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator
299 {
300 return _data.cbegin();
301 }
302 [[nodiscard]] constexpr auto end() noexcept -> iterator
303 {
304 return _data.begin() + _size;
305 }
306 [[nodiscard]] constexpr auto end() const noexcept -> const_iterator
307 {
308 return _data.begin() + _size;
309 }
310 [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator
311 {
312 return _data.begin() + _size;
313 }
314 [[nodiscard]] constexpr auto rbegin() noexcept -> reverse_iterator
315 {
316 return _data.rbegin() + 1;
317 }
318 [[nodiscard]] constexpr auto rbegin() const noexcept -> const_reverse_iterator
319 {
320 return _data.rbegin() + 1;
321 }
322 [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator
323 {
324 return _data.crbegin() + 1;
325 }
326 [[nodiscard]] constexpr auto rend() noexcept -> reverse_iterator
327 {
328 return _data.rend();
329 }
330 [[nodiscard]] constexpr auto rend() const noexcept -> const_reverse_iterator
331 {
332 return _data.rend();
333 }
334 [[nodiscard]] constexpr auto crend() const noexcept -> const_reverse_iterator
335 {
336 return _data.crend();
337 }
338
345 template <std::size_t N>
346 [[nodiscard]] constexpr auto set(char c) const noexcept
347 {
348 static_assert(N >= 0 && N < BufferCapacity, "index out of bound");
349 string_impl<BufferCapacity, DynamicExpandCapacity> result{};
350 for (std::size_t i = 0; i < _size; ++i)
351 {
352 result._data[i] = _data[i];
353 }
354 result._size = _size;
355 result._data[N] = c;
356 result._data[result._size] = '\0';
357
358 return result;
359 }
360
366 template <std::size_t N>
367 [[nodiscard]] constexpr auto append(const char(&str)[N]) const noexcept
368 {
369 string_impl<BufferCapacity + N - 1, DynamicExpandCapacity> result{};
370
371 for (std::size_t i = 0; i < _size; ++i)
372 {
373 result._data[i] = _data[i];
374 }
375 for (std::size_t i = 0; i < N - 1; ++i)
376 {
377 result._data[_size + i] = str[i];
378 }
379
380 result._size = _size + (N - 1);
381 result._data[result._size] = '\0';
382
383 return result;
384 }
385
393 template<std::size_t TargetSize = DynamicExpandCapacity, std::size_t N, std::size_t ExpandCapacity>
394 [[nodiscard]] constexpr auto append(const string_impl<N, ExpandCapacity>& other) const noexcept
395 {
396 string_impl<
397 BufferCapacity + TargetSize,
398 std::max(DynamicExpandCapacity, ExpandCapacity)
399 > result{};
400
401 for (std::size_t i = 0; i < _size; ++i)
402 {
403 result._data[i] = _data[i];
404 }
405 for (std::size_t i = 0; i < other.size(); ++i)
406 {
407 result._data[_size + i] = other._data[i];
408 }
409
410 result._size = _size + other.size();
411 result._data[result._size] = '\0';
412 return result;
413 }
414
418 template<std::size_t TargetSize = DynamicExpandCapacity>
419 [[nodiscard]] constexpr auto append(std::string_view sv) const noexcept
420 {
421 if (HYBSTR_IS_CONSTANT_EVALUATED)
422 {
423 string_impl<BufferCapacity + TargetSize, DynamicExpandCapacity> result{};
424 for (std::size_t i = 0; i < _size; ++i)
425 {
426 result._data[i] = _data[i];
427 }
428 for (std::size_t i = 0; i < sv.size(); ++i)
429 {
430 result._data[_size + i] = sv[i];
431 }
432 result._size = _size + sv.size();
433 result._data[result._size] = '\0';
434 return result;
435 }
436 else
437 {
438 // "string_impl overflow; increase the dynamic buffer size"
439 assert(sv.size() < TargetSize);
440
441 string_impl<BufferCapacity + TargetSize, DynamicExpandCapacity> result{};
442
443 std::copy_n(_data.data(), _size, result._data.data());
444 std::copy_n(sv.data(), sv.size(), result._data.data() + _size);
445 result._size = _size + sv.size();
446 result._data[result._size] = '\0';
447 return result;
448 }
449 }
450
454 template<std::size_t N = 1>
455 [[nodiscard]] constexpr auto append(char c) const noexcept
456 {
457 string_impl<BufferCapacity + N, DynamicExpandCapacity> result{};
458 for (std::size_t i = 0; i < _size; ++i)
459 {
460 result._data[i] = _data[i];
461 }
462 for (std::size_t i = 0; i < N; ++i)
463 {
464 result._data[_size + i] = c;
465 }
466 result._size = _size + N;
467 result._data[result._size] = '\0';
468 return result;
469 }
470
472 [[nodiscard]] constexpr auto push_back(char c) const noexcept
473 {
474 return append<1>(c);
475 }
476
483 template<std::size_t N>
484 [[nodiscard]] constexpr auto resize(char c = ' ') const noexcept
485 {
486 string_impl<N, DynamicExpandCapacity> result{};
487
488 const std::size_t len = std::min(_size, N);
489
490 for (std::size_t i = 0; i < len; ++i)
491 {
492 result._data[i] = _data[i];
493 }
494 for (std::size_t i = len; i < N; ++i)
495 {
496 result._data[i] = c;
497 }
498
499 result._size = N;
500 result._data[result._size] = '\0';
501
502 return result;
503 }
504
508 template<std::size_t N>
509 [[nodiscard]] constexpr auto reserve() const noexcept
510 {
511 if constexpr (BufferCapacity < N)
512 {
513 string_impl<N, DynamicExpandCapacity> result{};
514 result._size = std::min(_size, N);
515
516 for (std::size_t i = 0; i < result._size; ++i)
517 {
518 result._data[i] = _data[i];
519 }
520
521 result._data[result._size] = '\0';
522 return result;
523 }
524 else
525 {
526 return string_impl<N, DynamicExpandCapacity> { *this };
527 }
528 }
529
530 std::array<char, BufferCapacity + 1> _data{};
531 size_type _size{};
532 };
533
534 template<std::size_t N>
535 string_impl(const char(&)[N]) -> string_impl<N>;
536
537 // ======================================================================
538 // Operators
539 // ======================================================================
540
551 template<
552 std::size_t B1, std::size_t DynamicExpandCapacity1,
553 std::size_t B2, std::size_t DynamicExpandCapacity2
554 >
555 [[nodiscard]] constexpr auto operator+(
558 ) noexcept
559 {
561 B1 + B2,
562 std::max(DynamicExpandCapacity1, DynamicExpandCapacity2)
563 > result{};
564
565 for (std::size_t i = 0; i < s1.size(); ++i)
566 {
567 result._data[i] = s1._data[i];
568 }
569 for (std::size_t i = 0; i < s2.size(); ++i)
570 {
571 result._data[s1.size() + i] = s2._data[i];
572 }
573
574 result._size = s1._size + s2._size;
575 result._data[result._size] = '\0';
576 return result;
577 }
578
582 template<
583 std::size_t BufferCapacity,
584 std::size_t DynamicExpandCapacity,
585 std::size_t N
586 >
587 [[nodiscard]] constexpr auto operator+(
589 const char(&str)[N]
590 ) noexcept
591 {
593
594 for (std::size_t i = 0; i < s.size(); ++i)
595 {
596 result._data[i] = s._data[i];
597 }
598 for (std::size_t i = 0; i < N - 1; ++i)
599 {
600 result._data[s.size() + i] = str[i];
601 }
602
603 result._size = s.size() + N - 1;
604 result._data[result._size] = '\0';
605
606 return result;
607 }
608
609
613 template<
614 std::size_t BufferCapacity,
615 std::size_t DynamicExpandCapacity,
616 std::size_t N
617 >
618 [[nodiscard]] constexpr auto operator+(
619 const char(&str)[N],
621 ) noexcept
622 {
624
625 for (std::size_t i = 0; i < N - 1; ++i)
626 {
627 result._data[i] = str[i];
628 }
629 for (std::size_t i = 0; i < s.size(); ++i)
630 {
631 result._data[N + i - 1] = s._data[i];
632 }
633
634 result._size = s.size() + N - 1;
635 result._data[result._size] = '\0';
636
637 return result;
638 }
639
640
644 template<
645 std::size_t BufferCapacity,
646 std::size_t DynamicExpandCapacity
647 >
648 [[nodiscard]] constexpr auto operator+(
650 char c
651 ) noexcept
652 {
654
655 for (std::size_t i = 0; i < s.size(); ++i)
656 {
657 result._data[i] = s._data[i];
658 }
659 result._size = s.size() + 1;
660 result._data[result._size - 1] = c;
661 result._data[result._size] = '\0';
662
663 return result;
664 }
665
669 template<
670 std::size_t BufferCapacity,
671 std::size_t DynamicExpandCapacity
672 >
673 [[nodiscard]] constexpr auto operator+(
674 char c,
676 ) noexcept
677 {
679
680 result._data[0] = c;
681 for (std::size_t i = 0; i < s.size(); ++i)
682 {
683 result._data[i + 1] = s._data[i];
684 }
685 result._size = s.size() + 1;
686 result._data[result._size] = '\0';
687
688 return result;
689 }
690
694 template<
695 std::size_t BufferCapacity,
696 std::size_t DynamicExpandCapacity
697 >
698 [[nodiscard]] constexpr auto operator+(
700 std::string_view sv
701 ) noexcept
702 {
704
705 for (std::size_t i = 0; i < s.size(); ++i)
706 {
707 result._data[i] = s._data[i];
708 }
709 for (std::size_t i = 0; i < sv.size(); ++i)
710 {
711 result._data[s.size() + i] = sv[i];
712 }
713
714 result._size = s.size() + sv.size();
715 result._data[result._size] = '\0';
716
717 return result;
718 }
719
723 template<
724 std::size_t BufferCapacity,
725 std::size_t DynamicExpandCapacity
726 >
727 [[nodiscard]] constexpr auto operator+(
728 std::string_view sv,
730 ) noexcept
731 {
732 return s + sv;
733 }
734
735
736 // ======================================================================
737 // Comparisons
738 // =====================================================================
739
743 template<
744 std::size_t B1, std::size_t D1,
745 std::size_t B2, std::size_t D2
746 >
747 [[nodiscard]] constexpr bool operator==(
748 const string_impl<B1, D1>& s1,
749 const string_impl<B2, D2>& s2
750 ) noexcept
751 {
752 if (s1._size != s2._size)
753 {
754 return false;
755 }
756
757 for (std::size_t i = 0; i < s1._size; ++i)
758 {
759 if (s1._data[i] != s2._data[i])
760 {
761 return false;
762 }
763 }
764 return true;
765 }
766
767
771 template<
772 std::size_t B1, std::size_t D1,
773 std::size_t B2, std::size_t D2
774 >
775 [[nodiscard]] constexpr bool operator!=(
776 const string_impl<B1, D1>& s1,
777 const string_impl<B2, D2>& s2
778 ) noexcept
779 {
780 return !(s1 == s2);
781 }
782
783#if HYBSTR_CPP_20_OR_ABOVE
787 template<
788 std::size_t B1, std::size_t D1,
789 std::size_t B2, std::size_t D2
790 >
791 [[nodiscard]] constexpr auto operator<=>(
792 const string_impl<B1, D1>& s1,
793 const string_impl<B2, D2>& s2
794 ) noexcept
795 {
796 const std::size_t min_size = std::min(s1._size, s2._size);
797
798 for (std::size_t i = 0; i < min_size; ++i)
799 {
800 if (auto cmp = s1._data[i] <=> s2._data[i]; cmp != 0)
801 {
802 return cmp;
803 }
804 }
805 return s1._size <=> s2._size;
806 }
807
808#else
812 template<
813 std::size_t B1, std::size_t D1,
814 std::size_t B2, std::size_t D2
815 >
816 [[nodiscard]] constexpr bool operator<(
817 const string_impl<B1, D1>& s1,
818 const string_impl<B2, D2>& s2
819 ) noexcept
820 {
821 const std::size_t min_size = std::min(s1._size, s2._size);
822
823 for (std::size_t i = 0; i < min_size; ++i)
824 {
825 if (s1._data[i] < s2._data[i]) return true;
826 else return false;
827 }
828 return s1._size < s2._size;
829 }
830
834 template<
835 std::size_t B1, std::size_t D1,
836 std::size_t B2, std::size_t D2
837 >
838 [[nodiscard]] constexpr bool operator<=(
839 const string_impl<B1, D1>& s1,
840 const string_impl<B2, D2>& s2
841 ) noexcept
842 {
843 return !(s2 < s1);
844 }
845
849 template<
850 std::size_t B1, std::size_t D1,
851 std::size_t B2, std::size_t D2
852 >
853 [[nodiscard]] constexpr bool operator>(
854 const string_impl<B1, D1>& s1,
855 const string_impl<B2, D2>& s2
856 ) noexcept
857 {
858 return s2 < s1;
859 }
860
864 template<
865 std::size_t B1, std::size_t D1,
866 std::size_t B2, std::size_t D2
867 >
868 [[nodiscard]] constexpr bool operator>=(
869 const string_impl<B1, D1>& s1,
870 const string_impl<B2, D2>& s2
871 ) noexcept
872 {
873 return !(s1 < s2);
874 }
875#endif
876
877 // ======================================================================
878 // Traits and Utilities
879 // ======================================================================
880
884 template<typename T>
885 struct is_string_impl : std::false_type {};
886 template <std::size_t BufferCapacity, std::size_t DynamicExpandCapacity>
887 struct is_string_impl<string_impl<BufferCapacity, DynamicExpandCapacity>> : std::true_type {};
888
890 template <typename T>
892
893#if HYBSTR_CPP_20_OR_ABOVE
900 template <auto str>
901 [[nodiscard]] consteval auto fit_string() noexcept
902 {
903 static_assert(is_string_impl_v<std::remove_cvref_t<decltype(str)>>, "Expect a vre::string as input");
904 return str.template resize<str.size()>();
905 }
906#endif
907
908#if HYBSTR_CPP_20_OR_ABOVE
919 #define HYBSTR_FIT_STRING(str)\
920 hybstr::fit_string<(str)>()
921#else
933 #define HYBSTR_FIT_STRING(str) \
934 ([&]() constexpr noexcept { return (str).template resize<(str).size()>(); })()
935#endif
936
937 // ======================================================================
938 // Factory Functions
939 // ======================================================================
940
944 template<std::size_t DynamicExpandCapacity>
945 [[nodiscard]] constexpr auto string()
946 {
948 }
949
953 template<std::size_t DynamicExpandCapacity, std::size_t N>
954 [[nodiscard]] constexpr auto string(const char(&str)[N])
955 {
957 }
958
965 template<std::size_t ViewSize, std::size_t DynamicExpandCapacity>
966 [[nodiscard]] constexpr auto string(std::string_view sv) noexcept
967 {
969 }
970
978 template<std::size_t RangeSize, std::size_t DynamicExpandCapacity, typename _Iter>
979 [[nodiscard]] constexpr auto string(_Iter start, _Iter end) noexcept
980 {
982 }
983} // namespace hybstr
984
989namespace hybstr::literals
990{
991#if HYBSTR_CPP_20_OR_ABOVE
1000 template<hybstr::string_impl str>
1001 [[nodiscard]] consteval auto operator""_hyb() noexcept
1002 {
1003 return str;
1004 }
1005#else
1014 [[nodiscard]] consteval auto operator""_hyb(const char* str, std::size_t len) noexcept
1015 {
1016 return hybstr::string(str, str + len);
1017 }
1018 #endif
1019}
Fixed-capacity string that will expand on demand.
Definition hybstr.hpp:142
constexpr auto reserve() const noexcept
Ensures compile-time capacity is at least N. If current capacity is smaller, a new string_impl is cre...
Definition hybstr.hpp:509
constexpr string_impl(const char(&str)[N]) noexcept
Constructs from a string literal.
Definition hybstr.hpp:171
size_type _size
Number of characters currently stored.
Definition hybstr.hpp:531
constexpr string_impl() noexcept
Default constructor. Initializes an empty string.
Definition hybstr.hpp:159
constexpr auto empty() const noexcept -> bool
Definition hybstr.hpp:247
constexpr auto data() const noexcept -> const_pointer
Definition hybstr.hpp:258
constexpr auto push_back(char c) const noexcept
Appends a single character.
Definition hybstr.hpp:472
constexpr string_impl(const std::size_t &n, char c) noexcept
Fills the buffer with a repeated character.
Definition hybstr.hpp:187
constexpr string_impl(_Iter start, _Iter end) noexcept
Constructs from an iterator range. Copies until 'end' or until BufferCapacity is reached.
Definition hybstr.hpp:218
constexpr auto append(std::string_view sv) const noexcept
Appends a std::string_view.
Definition hybstr.hpp:419
constexpr auto operator[](size_type i) noexcept -> reference
Accesses a character by index (mutable).
Definition hybstr.hpp:280
constexpr auto set(char c) const noexcept
Replaces a character at compile time.
Definition hybstr.hpp:346
auto str() const -> std::string
Definition hybstr.hpp:273
constexpr auto append(char c) const noexcept
Appends one or more repeated characters.
Definition hybstr.hpp:455
constexpr auto view() const noexcept -> view_type
Definition hybstr.hpp:268
constexpr auto append(const char(&str)[N]) const noexcept
Appends a C-style string literal.
Definition hybstr.hpp:367
constexpr auto resize(char c=' ') const noexcept
Resizes the string to a new compile-time capacity.
Definition hybstr.hpp:484
constexpr auto operator[](size_type i) const noexcept -> const_reference
Accesses a character by index (const).
Definition hybstr.hpp:285
constexpr auto c_str() const noexcept -> const_pointer
Definition hybstr.hpp:263
constexpr auto capacity() const noexcept -> size_type
Definition hybstr.hpp:242
constexpr string_impl(std::string_view sv) noexcept
Constructs from a std::string_view. Copies up to BufferCapacity characters.
Definition hybstr.hpp:202
constexpr auto append(const string_impl< N, ExpandCapacity > &other) const noexcept
Appends another hybrid string.
Definition hybstr.hpp:394
constexpr auto data() noexcept -> pointer
Definition hybstr.hpp:253
std::array< char, BufferCapacity+1 > _data
Internal fixed buffer (+1 for null terminator).
Definition hybstr.hpp:530
constexpr auto size() const noexcept -> size_type
Definition hybstr.hpp:237
Contains user defined literal operators for creating 'hybstr::string_impl' objects.
Main interface.
constexpr bool operator>(const string_impl< B1, D1 > &s1, const string_impl< B2, D2 > &s2) noexcept
Greater than comparison for two hybrid strings.
Definition hybstr.hpp:853
constexpr bool operator>=(const string_impl< B1, D1 > &s1, const string_impl< B2, D2 > &s2) noexcept
Greater than or equal to comparison for two hybrid strings.
Definition hybstr.hpp:868
constexpr bool operator==(const string_impl< B1, D1 > &s1, const string_impl< B2, D2 > &s2) noexcept
Equality comparison for two hybrid strings.
Definition hybstr.hpp:747
consteval auto fit_string() noexcept
Adjusts the compile-time buffer size to exactly fit the string content. C++20 or above.
Definition hybstr.hpp:901
constexpr bool operator!=(const string_impl< B1, D1 > &s1, const string_impl< B2, D2 > &s2) noexcept
Inequality comparison for two hybrid strings.
Definition hybstr.hpp:775
constexpr bool operator<=(const string_impl< B1, D1 > &s1, const string_impl< B2, D2 > &s2) noexcept
Less than or equal to comparison for two hybrid strings.
Definition hybstr.hpp:838
constexpr auto string()
Creates an empty hybrid string.
Definition hybstr.hpp:945
constexpr bool is_string_impl_v
Shorthand boolean variable for is_string_impl.
Definition hybstr.hpp:891
constexpr auto operator<=>(const string_impl< B1, D1 > &s1, const string_impl< B2, D2 > &s2) noexcept
Lexicographical three-way comparison for hybrid strings. C++20 or above.
Definition hybstr.hpp:791
constexpr auto operator+(const string_impl< B1, DynamicExpandCapacity1 > &s1, const string_impl< B2, DynamicExpandCapacity2 > &s2) noexcept
Concatenates two hybrid strings.
Definition hybstr.hpp:555
constexpr bool operator<(const string_impl< B1, D1 > &s1, const string_impl< B2, D2 > &s2) noexcept
Less than comparison for two hybrid strings. C++17.
Definition hybstr.hpp:816
Type trait for detecting hybstr::string_impl.
Definition hybstr.hpp:885