37#ifndef HYBSTR_DYNAMIC_EXPAND_CAPACITY
38#define HYBSTR_DYNAMIC_EXPAND_CAPACITY 1000
42# define HYBSTR_CPP_STD _MSVC_LANG
44# define HYBSTR_CPP_STD __cplusplus
47#if HYBSTR_CPP_STD >= 202002L
48 #define HYBSTR_CPP_20_OR_ABOVE true
50 #define HYBSTR_CPP_20_OR_ABOVE false
53#if !HYBSTR_CPP_20_OR_ABOVE
55 #define consteval constexpr
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()
69 #define HYBSTR_IS_CONSTANT_EVALUATED false
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,
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,
89 [[nodiscard]]
constexpr auto string(_Iter start, _Iter end)
noexcept;
140 template <std::
size_t BufferCapacity = 0, std::
size_t DynamicExpandCapacity = HYBSTR_DYNAMIC_EXPAND_CAPACITY>
143 template <std::
size_t, std::
size_t>
144 friend class string_impl;
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;
170 template <std::
size_t N>
173 static_assert(N > 0 && N - 1 <= BufferCapacity,
"string literal too long");
174 for (std::size_t i = 0; i < N - 1; ++i)
189 const std::size_t len = std::min(n, BufferCapacity);
190 for (std::size_t i = 0; i < len; ++i)
204 const std::size_t len = std::min(sv.size(), BufferCapacity);
205 for (std::size_t i = 0; i < len; ++i)
217 template<
typename _Iter>
222 while (i < BufferCapacity && start != end)
224 _data[i++] = *(start++);
237 [[nodiscard]] constexpr auto
size() const noexcept -> size_type
242 [[nodiscard]]
constexpr auto capacity() const noexcept -> size_type
244 return BufferCapacity;
247 [[nodiscard]]
constexpr auto empty() const noexcept ->
bool
253 [[nodiscard]]
constexpr auto data() noexcept -> pointer
258 [[nodiscard]]
constexpr auto data() const noexcept -> const_pointer
263 [[nodiscard]]
constexpr auto c_str() const noexcept -> const_pointer
268 [[nodiscard]]
constexpr auto view() const noexcept -> view_type
273 [[nodiscard]]
auto str() const -> std::
string
275 return std::string(begin(), end());
280 [[nodiscard]]
constexpr auto operator[](size_type i)
noexcept -> reference
285 [[nodiscard]]
constexpr auto operator[](size_type i)
const noexcept -> const_reference
290 [[nodiscard]]
constexpr auto begin() noexcept -> iterator
292 return _data.begin();
294 [[nodiscard]]
constexpr auto begin() const noexcept -> const_iterator
296 return _data.begin();
298 [[nodiscard]]
constexpr auto cbegin() const noexcept -> const_iterator
300 return _data.cbegin();
302 [[nodiscard]]
constexpr auto end() noexcept -> iterator
306 [[nodiscard]]
constexpr auto end() const noexcept -> const_iterator
310 [[nodiscard]]
constexpr auto cend() const noexcept -> const_iterator
314 [[nodiscard]]
constexpr auto rbegin() noexcept -> reverse_iterator
316 return _data.rbegin() + 1;
318 [[nodiscard]]
constexpr auto rbegin() const noexcept -> const_reverse_iterator
320 return _data.rbegin() + 1;
322 [[nodiscard]]
constexpr auto crbegin() const noexcept -> const_reverse_iterator
324 return _data.crbegin() + 1;
326 [[nodiscard]]
constexpr auto rend() noexcept -> reverse_iterator
330 [[nodiscard]]
constexpr auto rend() const noexcept -> const_reverse_iterator
334 [[nodiscard]]
constexpr auto crend() const noexcept -> const_reverse_iterator
336 return _data.crend();
345 template <std::
size_t N>
346 [[nodiscard]]
constexpr auto set(
char c)
const noexcept
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)
366 template <std::
size_t N>
367 [[nodiscard]]
constexpr auto append(
const char(&
str)[N])
const noexcept
369 string_impl<BufferCapacity + N - 1, DynamicExpandCapacity> result{};
371 for (std::size_t i = 0; i <
_size; ++i)
373 result._data[i] =
_data[i];
375 for (std::size_t i = 0; i < N - 1; ++i)
380 result._size =
_size + (N - 1);
381 result._data[result._size] =
'\0';
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
397 BufferCapacity + TargetSize,
398 std::max(DynamicExpandCapacity, ExpandCapacity)
401 for (std::size_t i = 0; i <
_size; ++i)
403 result._data[i] =
_data[i];
405 for (std::size_t i = 0; i < other.size(); ++i)
407 result._data[
_size + i] = other._data[i];
410 result._size =
_size + other.size();
411 result._data[result._size] =
'\0';
418 template<std::
size_t TargetSize = DynamicExpandCapacity>
419 [[nodiscard]]
constexpr auto append(std::string_view sv)
const noexcept
421 if (HYBSTR_IS_CONSTANT_EVALUATED)
423 string_impl<BufferCapacity + TargetSize, DynamicExpandCapacity> result{};
424 for (std::size_t i = 0; i <
_size; ++i)
428 for (std::size_t i = 0; i < sv.size(); ++i)
439 assert(sv.size() < TargetSize);
441 string_impl<BufferCapacity + TargetSize, DynamicExpandCapacity> result{};
444 std::copy_n(sv.data(), sv.size(), result.
_data.data() +
_size);
454 template<std::
size_t N = 1>
455 [[nodiscard]]
constexpr auto append(
char c)
const noexcept
457 string_impl<BufferCapacity + N, DynamicExpandCapacity> result{};
458 for (std::size_t i = 0; i <
_size; ++i)
462 for (std::size_t i = 0; i < N; ++i)
472 [[nodiscard]]
constexpr auto push_back(
char c)
const noexcept
483 template<std::
size_t N>
484 [[nodiscard]]
constexpr auto resize(
char c =
' ') const noexcept
486 string_impl<N, DynamicExpandCapacity> result{};
488 const std::size_t len = std::min(
_size, N);
490 for (std::size_t i = 0; i < len; ++i)
494 for (std::size_t i = len; i < N; ++i)
508 template<std::
size_t N>
509 [[nodiscard]]
constexpr auto reserve() const noexcept
511 if constexpr (BufferCapacity < N)
513 string_impl<N, DynamicExpandCapacity> result{};
516 for (std::size_t i = 0; i < result.
_size; ++i)
526 return string_impl<N, DynamicExpandCapacity> { *
this };
530 std::array<char, BufferCapacity + 1>
_data{};
534 template<std::
size_t N>
535 string_impl(
const char(&)[N]) -> string_impl<N>;
552 std::size_t B1, std::size_t DynamicExpandCapacity1,
553 std::size_t B2, std::size_t DynamicExpandCapacity2
562 std::max(DynamicExpandCapacity1, DynamicExpandCapacity2)
565 for (std::size_t i = 0; i < s1.size(); ++i)
567 result._data[i] = s1._data[i];
569 for (std::size_t i = 0; i < s2.size(); ++i)
571 result._data[s1.size() + i] = s2._data[i];
574 result.
_size = s1._size + s2._size;
575 result._data[result._size] =
'\0';
583 std::size_t BufferCapacity,
584 std::size_t DynamicExpandCapacity,
594 for (std::size_t i = 0; i < s.
size(); ++i)
598 for (std::size_t i = 0; i < N - 1; ++i)
614 std::size_t BufferCapacity,
615 std::size_t DynamicExpandCapacity,
625 for (std::size_t i = 0; i < N - 1; ++i)
627 result.
_data[i] = str[i];
629 for (std::size_t i = 0; i < s.
size(); ++i)
645 std::size_t BufferCapacity,
646 std::size_t DynamicExpandCapacity
655 for (std::size_t i = 0; i < s.
size(); ++i)
670 std::size_t BufferCapacity,
671 std::size_t DynamicExpandCapacity
681 for (std::size_t i = 0; i < s.
size(); ++i)
695 std::size_t BufferCapacity,
696 std::size_t DynamicExpandCapacity
705 for (std::size_t i = 0; i < s.
size(); ++i)
709 for (std::size_t i = 0; i < sv.size(); ++i)
724 std::size_t BufferCapacity,
725 std::size_t DynamicExpandCapacity
744 std::size_t B1, std::size_t D1,
745 std::size_t B2, std::size_t D2
752 if (s1._size != s2._size)
757 for (std::size_t i = 0; i < s1._size; ++i)
759 if (s1._data[i] != s2._data[i])
772 std::size_t B1, std::size_t D1,
773 std::size_t B2, std::size_t D2
783#if HYBSTR_CPP_20_OR_ABOVE
788 std::size_t B1, std::size_t D1,
789 std::size_t B2, std::size_t D2
796 const std::size_t min_size = std::min(s1._size, s2._size);
798 for (std::size_t i = 0; i < min_size; ++i)
800 if (
auto cmp = s1._data[i] <=> s2._data[i]; cmp != 0)
805 return s1._size <=> s2._size;
813 std::size_t B1, std::size_t D1,
814 std::size_t B2, std::size_t D2
821 const std::size_t min_size = std::min(s1._size, s2._size);
823 for (std::size_t i = 0; i < min_size; ++i)
825 if (s1._data[i] < s2._data[i])
return true;
828 return s1._size < s2._size;
835 std::size_t B1, std::size_t D1,
836 std::size_t B2, std::size_t D2
850 std::size_t B1, std::size_t D1,
851 std::size_t B2, std::size_t D2
865 std::size_t B1, std::size_t D1,
866 std::size_t B2, std::size_t D2
886 template <std::
size_t BufferCapacity, std::
size_t DynamicExpandCapacity>
890 template <
typename T>
893#if HYBSTR_CPP_20_OR_ABOVE
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()>();
908#if HYBSTR_CPP_20_OR_ABOVE
919 #define HYBSTR_FIT_STRING(str)\
920 hybstr::fit_string<(str)>()
933 #define HYBSTR_FIT_STRING(str) \
934 ([&]() constexpr noexcept { return (str).template resize<(str).size()>(); })()
944 template<std::
size_t DynamicExpandCapacity>
953 template<std::
size_t DynamicExpandCapacity, std::
size_t N>
954 [[nodiscard]]
constexpr auto string(
const char(&str)[N])
965 template<std::
size_t ViewSize, std::
size_t DynamicExpandCapacity>
966 [[nodiscard]]
constexpr auto string(std::string_view sv)
noexcept
978 template<std::
size_t RangeSize, std::
size_t DynamicExpandCapacity,
typename _Iter>
979 [[nodiscard]]
constexpr auto string(_Iter start, _Iter end)
noexcept
991#if HYBSTR_CPP_20_OR_ABOVE
1000 template<hybstr::
string_impl str>
1001 [[nodiscard]]
consteval auto operator""_hyb() noexcept
1014 [[nodiscard]]
consteval auto operator""_hyb(
const char* str, std::size_t len)
noexcept
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.
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