#ifndef CTLL__FIXED_STRING__GPP #define CTLL__FIXED_STRING__GPP #ifndef CTLL_IN_A_MODULE #include #include #include #include #include #endif #include "utilities.hpp" namespace ctll { struct length_value_t { uint32_t value; uint8_t length; }; constexpr length_value_t length_and_value_of_utf8_code_point(uint8_t first_unit) noexcept { if ((first_unit & 0b1000'0000) == 0b0000'0000) return {static_cast(first_unit), 1}; else if ((first_unit & 0b1110'0000) == 0b1100'0000) return {static_cast(first_unit & 0b0001'1111), 2}; else if ((first_unit & 0b1111'0000) == 0b1110'0000) return {static_cast(first_unit & 0b0000'1111), 3}; else if ((first_unit & 0b1111'1000) == 0b1111'0000) return {static_cast(first_unit & 0b0000'0111), 4}; else if ((first_unit & 0b1111'1100) == 0b1111'1000) return {static_cast(first_unit & 0b0000'0011), 5}; else if ((first_unit & 0b1111'1100) == 0b1111'1100) return {static_cast(first_unit & 0b0000'0001), 6}; else return {0, 0}; } constexpr char32_t value_of_trailing_utf8_code_point(uint8_t unit, bool & correct) noexcept { if ((unit & 0b1100'0000) == 0b1000'0000) return unit & 0b0011'1111; else { correct = false; return 0; } } constexpr length_value_t length_and_value_of_utf16_code_point(uint16_t first_unit) noexcept { if ((first_unit & 0b1111110000000000) == 0b1101'1000'0000'0000) return {static_cast(first_unit & 0b0000001111111111), 2}; else return {first_unit, 1}; } struct construct_from_pointer_t { }; constexpr auto construct_from_pointer = construct_from_pointer_t{}; CTLL_EXPORT template struct fixed_string { char32_t content[N] = {}; size_t real_size{0}; bool correct_flag{true}; template constexpr fixed_string(construct_from_pointer_t, const T * input) noexcept { if constexpr (std::is_same_v) { #ifdef CTRE_STRING_IS_UTF8 size_t out{0}; for (size_t i{0}; i < N; ++i) { length_value_t info = length_and_value_of_utf8_code_point(input[i]); switch (info.length) { case 6: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 5: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 4: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 3: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 2: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 1: content[out++] = static_cast(info.value); real_size++; break; default: correct_flag = false; return; } } #else for (size_t i{0}; i < N; ++i) { content[i] = static_cast(input[i]); real_size++; } #endif #if __cpp_char8_t } else if constexpr (std::is_same_v) { size_t out{0}; for (size_t i{0}; i < N; ++i) { length_value_t info = length_and_value_of_utf8_code_point(input[i]); switch (info.length) { case 6: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 5: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 4: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 3: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 2: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 1: content[out++] = static_cast(info.value); real_size++; break; default: correct_flag = false; return; } } #endif } else if constexpr (std::is_same_v) { size_t out{0}; for (size_t i{0}; i < N; ++i) { length_value_t info = length_and_value_of_utf16_code_point(input[i]); if (info.length == 2) { if (++i < N) { if ((input[i] & 0b1111'1100'0000'0000) == 0b1101'1100'0000'0000) { content[out++] = ((info.value << 10) | (input[i] & 0b0000'0011'1111'1111)) + 0x10000; } else { correct_flag = false; break; } } } else { content[out++] = info.value; } } real_size = out; } else if constexpr (std::is_same_v || std::is_same_v) { for (size_t i{0}; i < N; ++i) { content[i] = static_cast(input[i]); real_size++; } } } template constexpr fixed_string(const std::array & in) noexcept: fixed_string{construct_from_pointer, in.data()} { } template constexpr fixed_string(const T (&input)[N+1]) noexcept: fixed_string{construct_from_pointer, input} { } constexpr fixed_string(const fixed_string & other) noexcept { for (size_t i{0}; i < N; ++i) { content[i] = other.content[i]; } real_size = other.real_size; correct_flag = other.correct_flag; } constexpr bool correct() const noexcept { return correct_flag; } constexpr size_t size() const noexcept { return real_size; } constexpr const char32_t * begin() const noexcept { return content; } constexpr const char32_t * end() const noexcept { return content + size(); } constexpr char32_t operator[](size_t i) const noexcept { return content[i]; } template constexpr bool is_same_as(const fixed_string & rhs) const noexcept { if (real_size != rhs.size()) return false; for (size_t i{0}; i != real_size; ++i) { if (content[i] != rhs[i]) return false; } return true; } constexpr operator std::basic_string_view() const noexcept { return std::basic_string_view{content, size()}; } }; template <> class fixed_string<0> { static constexpr char32_t empty[1] = {0}; public: template constexpr fixed_string(const T *) noexcept { } constexpr fixed_string(std::initializer_list) noexcept { } constexpr fixed_string(const fixed_string &) noexcept { } constexpr bool correct() const noexcept { return true; } constexpr size_t size() const noexcept { return 0; } constexpr const char32_t * begin() const noexcept { return empty; } constexpr const char32_t * end() const noexcept { return empty + size(); } constexpr char32_t operator[](size_t) const noexcept { return 0; } constexpr operator std::basic_string_view() const noexcept { return std::basic_string_view{empty, 0}; } }; template fixed_string(const CharT (&)[N]) -> fixed_string; template fixed_string(const std::array &) -> fixed_string; template fixed_string(fixed_string) -> fixed_string; } #endif