diff --git a/src/core/include/mp-units/bits/external/fixed_string.h b/src/core/include/mp-units/bits/external/fixed_string.h index 64e1172d..8eff4aa9 100644 --- a/src/core/include/mp-units/bits/external/fixed_string.h +++ b/src/core/include/mp-units/bits/external/fixed_string.h @@ -33,6 +33,7 @@ #include #include #include +#include #endif MP_UNITS_EXPORT @@ -60,34 +61,40 @@ struct basic_fixed_string { constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept { - if constexpr (N != 0) - for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i]; + gsl_ExpectsAudit(txt[N] == CharT{}); + for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i]; + } + + template S> + requires std::convertible_to, CharT> + constexpr explicit basic_fixed_string(It first, S last) noexcept + { + gsl_ExpectsAudit(std::distance(last, first) == N); + for (auto it = data_; first != last; ++first, ++it) *it = *first; } template... Rest> requires(1 + sizeof...(Rest) == N) - constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT('\0')} + constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT{}} { } - constexpr basic_fixed_string(const CharT* ptr, std::integral_constant) noexcept - { - if constexpr (N != 0) - for (std::size_t i = 0; i < N; ++i) data_[i] = *ptr++; - } - [[nodiscard]] constexpr bool empty() const noexcept { return N == 0; } [[nodiscard]] constexpr size_type size() const noexcept { return N; } [[nodiscard]] constexpr const_pointer data() const noexcept { return data_; } [[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); } - [[nodiscard]] constexpr value_type operator[](size_type index) const noexcept { return data()[index]; } + [[nodiscard]] constexpr value_type operator[](size_type index) const noexcept + { + gsl_ExpectsAudit(index < N); + return data()[index]; + } [[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); } [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return data(); } [[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); } [[nodiscard]] constexpr const_iterator cend() const noexcept { return data() + size(); } - [[nodiscard]] constexpr std::basic_string_view view() const noexcept + [[nodiscard]] constexpr operator std::basic_string_view() const noexcept { return std::basic_string_view(cbegin(), cend()); } @@ -104,11 +111,7 @@ struct basic_fixed_string { return basic_fixed_string(txt); } - [[nodiscard]] constexpr bool operator==(const basic_fixed_string& other) const - { - if (size() != other.size()) return false; - return detail::equal(begin(), end(), other.begin()); // TODO std::ranges::equal(*this, other) - } + [[nodiscard]] constexpr bool operator==(const basic_fixed_string&) const = default; template [[nodiscard]] friend constexpr bool operator==(const basic_fixed_string&, const basic_fixed_string&) @@ -138,22 +141,28 @@ basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string; template... Rest> basic_fixed_string(CharT, Rest...) -> basic_fixed_string; -template -basic_fixed_string(const CharT* ptr, std::integral_constant) -> basic_fixed_string; - template using fixed_string = basic_fixed_string; +template +using fixed_wstring = basic_fixed_string; + template using fixed_u8string = basic_fixed_string; +template +using fixed_u16string = basic_fixed_string; + +template +using fixed_u32string = basic_fixed_string; + } // namespace mp_units template struct MP_UNITS_STD_FMT::formatter> : formatter> { template - auto format(const mp_units::basic_fixed_string& str, FormatContext& ctx) + auto format(const mp_units::basic_fixed_string& str, FormatContext& ctx) const -> decltype(ctx.out()) { - return formatter>::format(str.view(), ctx); + return formatter>::format(std::basic_string_view(str), ctx); } }; diff --git a/src/core/include/mp-units/dimension.h b/src/core/include/mp-units/dimension.h index bef17e10..25f032df 100644 --- a/src/core/include/mp-units/dimension.h +++ b/src/core/include/mp-units/dimension.h @@ -294,9 +294,9 @@ constexpr Out dimension_symbol_to(Out out, D d, dimension_symbol_formatting fmt namespace detail { template -[[nodiscard]] consteval std::array get_symbol_buffer(D) +[[nodiscard]] consteval std::array get_symbol_buffer(D) { - std::array buffer{}; + std::array buffer{}; dimension_symbol_to(buffer.begin(), D{}, fmt); return buffer; } @@ -326,7 +326,7 @@ MP_UNITS_EXPORT template(D{}); - return basic_fixed_string(buffer.data(), std::integral_constant{}); + return basic_fixed_string(buffer.begin(), buffer.end()); #endif } diff --git a/src/core/include/mp-units/unit.h b/src/core/include/mp-units/unit.h index 7ef58e03..6bcbd96a 100644 --- a/src/core/include/mp-units/unit.h +++ b/src/core/include/mp-units/unit.h @@ -816,9 +816,9 @@ constexpr Out unit_symbol_to(Out out, U u, unit_symbol_formatting fmt = unit_sym namespace detail { template -[[nodiscard]] consteval std::array get_symbol_buffer(U) +[[nodiscard]] consteval std::array get_symbol_buffer(U) { - std::array buffer{}; + std::array buffer; unit_symbol_to(buffer.begin(), U{}, fmt); return buffer; } @@ -847,7 +847,7 @@ MP_UNITS_EXPORT template(U{}); - return basic_fixed_string(buffer.data(), std::integral_constant{}); + return basic_fixed_string(buffer.begin(), buffer.end()); #endif } diff --git a/test/runtime/fmt_test.cpp b/test/runtime/fmt_test.cpp index 5c1c0ad8..840cdda9 100644 --- a/test/runtime/fmt_test.cpp +++ b/test/runtime/fmt_test.cpp @@ -46,6 +46,18 @@ inline constexpr bool mp_units::is_vector = true; using namespace mp_units; using namespace mp_units::si::unit_symbols; +TEST_CASE("fixed_string", "[text][ostream][fmt]") +{ + basic_fixed_string txt = "units"; + SECTION("iostream") + { + std::ostringstream os; + os << txt; + CHECK(os.str() == "units"); + } + SECTION("fmt") { CHECK(MP_UNITS_STD_FMT::format("{}", txt) == "units"); } +} + TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") { std::ostringstream os; diff --git a/test/static/fixed_string_test.cpp b/test/static/fixed_string_test.cpp index a5d6769c..97f1c15f 100644 --- a/test/static/fixed_string_test.cpp +++ b/test/static/fixed_string_test.cpp @@ -30,6 +30,8 @@ constexpr basic_fixed_string txt1('a'); static_assert(txt1.size() == 1); static_assert(txt1[0] == 'a'); static_assert(txt1 == basic_fixed_string("a")); +static_assert(txt1 != basic_fixed_string("b")); +static_assert(txt1 != basic_fixed_string("aa")); static_assert(txt1 < basic_fixed_string("b")); static_assert(txt1 < basic_fixed_string("aa")); static_assert(txt1 + basic_fixed_string('b') == basic_fixed_string("ab")); @@ -43,6 +45,8 @@ static_assert(txt2[0] == 'a'); static_assert(txt2[1] == 'b'); static_assert(txt2[2] == 'c'); static_assert(txt2 == basic_fixed_string("abc")); +static_assert(txt2 != basic_fixed_string("cba")); +static_assert(txt2 != basic_fixed_string("abcd")); static_assert(txt2 < basic_fixed_string("b")); static_assert(txt2 > basic_fixed_string("aa")); static_assert(txt2 + basic_fixed_string('d') == basic_fixed_string("abcd")); @@ -51,7 +55,7 @@ static_assert(txt2 + basic_fixed_string("def") == basic_fixed_string("abcdef")); static_assert(basic_fixed_string("def") + txt2 == basic_fixed_string("defabc")); #ifndef MP_UNITS_COMP_GCC -static_assert(basic_fixed_string("abcd").view().find('c') == 2); +static_assert(std::string_view(basic_fixed_string("abcd")).find('c') == 2); #endif } // namespace