diff --git a/src/core/include/mp-units/bits/hacks.h b/src/core/include/mp-units/bits/hacks.h index f1d9b837..f8522059 100644 --- a/src/core/include/mp-units/bits/hacks.h +++ b/src/core/include/mp-units/bits/hacks.h @@ -90,6 +90,20 @@ #endif + +#if !defined __cpp_lib_ranges_to_container + +namespace std { + +struct from_range_t { + explicit from_range_t() = default; +}; +inline constexpr from_range_t from_range{}; + +} // namespace std + +#endif + #if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17 #define MP_UNITS_CONSTEVAL constexpr diff --git a/src/core/include/mp-units/ext/algorithm.h b/src/core/include/mp-units/ext/algorithm.h index 1d5a7d67..3aa460b8 100644 --- a/src/core/include/mp-units/ext/algorithm.h +++ b/src/core/include/mp-units/ext/algorithm.h @@ -72,45 +72,6 @@ constexpr bool all_of(InputIt first, InputIt last, UnaryPred p) return find_if_not(first, last, p) == last; } -template -constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) -{ - for (; first1 != last1; ++first1, ++first2) { - if (!(*first1 == *first2)) { - return false; - } - } - return true; -} - -template -constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2, Cmp comp) - -> decltype(comp(*first1, *first2)) -{ - using ret_t = decltype(comp(*first1, *first2)); - static_assert(std::disjunction_v, std::is_same, - std::is_same>, - "The return type must be a comparison category type."); - - bool exhaust1 = (first1 == last1); - bool exhaust2 = (first2 == last2); - MP_UNITS_DIAGNOSTIC_PUSH - MP_UNITS_DIAGNOSTIC_IGNORE_ZERO_AS_NULLPOINTER_CONSTANT - for (; !exhaust1 && !exhaust2; exhaust1 = (++first1 == last1), exhaust2 = (++first2 == last2)) - if (auto c = comp(*first1, *first2); c != 0) return c; - MP_UNITS_DIAGNOSTIC_POP - - if (!exhaust1) return std::strong_ordering::greater; - if (!exhaust2) return std::strong_ordering::less; - return std::strong_ordering::equal; -} - -template -constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2) -{ - return ::mp_units::detail::lexicographical_compare_three_way(first1, last1, first2, last2, std::compare_three_way()); -} - template constexpr ForwardIt max_element(ForwardIt first, ForwardIt last) { diff --git a/src/core/include/mp-units/ext/fixed_string.h b/src/core/include/mp-units/ext/fixed_string.h index 8dac2822..80165c3f 100644 --- a/src/core/include/mp-units/ext/fixed_string.h +++ b/src/core/include/mp-units/ext/fixed_string.h @@ -26,10 +26,10 @@ // NOLINTBEGIN(*-avoid-c-arrays) #pragma once -// TODO use when moved to C++20 modules (parsing takes too long for each translation unit) +#include // IWYU pragma: keep #include #include // IWYU pragma: keep -#include +#include #ifndef MP_UNITS_IN_MODULE_INTERFACE #include @@ -49,22 +49,34 @@ namespace mp_units { * @tparam CharT Character type to be used by the string * @tparam N The size of the string */ -template -struct basic_fixed_string { - CharT data_[N + 1] = {}; +template> +class basic_fixed_string { +public: + CharT data_[N + 1] = {}; // exposition only + // types + using traits_type = Traits; using value_type = CharT; - using pointer = CharT*; - using const_pointer = const CharT*; - using reference = CharT&; - using const_reference = const CharT&; - using const_iterator = const CharT*; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using const_iterator = const value_type*; using iterator = const_iterator; + using const_reverse_iterator = std::reverse_iterator; + using reverse_iterator = const_reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; + // construction and assignment + template... Chars> + requires(sizeof...(Chars) == N) && (... && !std::is_pointer_v) + constexpr explicit basic_fixed_string(Chars... chars) noexcept : data_{chars..., CharT{}} + { + } + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept + consteval explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) { gsl_Expects(txt[N] == CharT{}); for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i]; @@ -72,98 +84,195 @@ struct basic_fixed_string { template S> requires std::convertible_to, CharT> - constexpr explicit basic_fixed_string(It first, S last) noexcept + constexpr explicit basic_fixed_string(It begin, S end) { - gsl_Expects(std::distance(first, last) == N); - for (auto it = data_; first != last; ++first, ++it) *it = *first; + gsl_Expects(std::distance(begin, end) == N); + for (auto it = data_; begin != end; ++begin, ++it) *it = *begin; } - template... Rest> - requires(1 + sizeof...(Rest) == N) - constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT{}} + template + requires std::convertible_to, CharT> + constexpr explicit basic_fixed_string(std::from_range_t, R&& r) { + gsl_Expects(std::ranges::size(r) == N); + for (auto it = data_; auto&& v : std::forward(r)) *it++ = std::forward(v); } - [[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 static_cast(data_); } - [[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); } - [[nodiscard]] constexpr value_type operator[](size_type index) const noexcept - { - gsl_Expects(index < N); - return data()[index]; - } + constexpr basic_fixed_string(const basic_fixed_string&) noexcept = default; + constexpr basic_fixed_string& operator=(const basic_fixed_string&) noexcept = default; + // iterator support [[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 const_iterator cbegin() const noexcept { return begin(); } + [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); } + [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } + [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); } - // NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor) - [[nodiscard]] constexpr explicit(false) operator std::basic_string_view() const noexcept + // capacity + [[nodiscard]] constexpr size_type size() const noexcept { return N; } + [[nodiscard]] constexpr size_type length() const noexcept { return size(); } + [[nodiscard]] constexpr size_type max_size() const noexcept { return size(); } + [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } + + // element access + [[nodiscard]] constexpr const_reference operator[](size_type pos) const { - return std::basic_string_view(cbegin(), cend()); + gsl_Expects(pos < N); + return data()[pos]; + } + + [[nodiscard]] constexpr const_reference at(size_type pos) const + { + if (pos >= size()) throw std::out_of_range("basic_fixed_string::at"); + return (*this)[pos]; + } + [[nodiscard]] constexpr const_reference front() const + { + gsl_Expects(!empty()); + return (*this)[0]; + } + [[nodiscard]] constexpr const_reference back() const + { + gsl_Expects(!empty()); + return (*this)[N - 1]; + } + [[nodiscard]] constexpr const_pointer data() const noexcept { return static_cast(data_); } + + // modifiers + constexpr void swap(basic_fixed_string& s) noexcept { std::swap_ranges(begin(), end(), s.begin()); } + + // string operations + [[nodiscard]] constexpr const_pointer c_str() const noexcept { return data(); } + [[nodiscard]] constexpr std::basic_string_view view() const noexcept + { + return std::basic_string_view(cbegin(), cend()); + } + // NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor) + [[nodiscard]] constexpr explicit(false) operator std::basic_string_view() const noexcept + { + return view(); } template - [[nodiscard]] constexpr friend basic_fixed_string operator+( - const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept + [[nodiscard]] constexpr friend basic_fixed_string operator+( + const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept { - CharT txt[N + N2 + 1] = {}; - + CharT txt[N + N2] = {}; for (size_t i = 0; i != N; ++i) txt[i] = lhs[i]; for (size_t i = 0; i != N2; ++i) txt[N + i] = rhs[i]; - - return basic_fixed_string(txt); + return basic_fixed_string(std::begin(txt), std::end(txt)); } - [[nodiscard]] constexpr bool operator==(const basic_fixed_string&) const = default; - - template - [[nodiscard]] friend constexpr bool operator==(const basic_fixed_string&, const basic_fixed_string&) + [[nodiscard]] constexpr friend basic_fixed_string operator+(const basic_fixed_string& lhs, + CharT rhs) noexcept { - return false; + CharT txt[N + 1] = {}; + for (size_t i = 0; i != N; ++i) txt[i] = lhs[i]; + txt[N] = rhs; + return basic_fixed_string(std::begin(txt), std::end(txt)); + } + + [[nodiscard]] constexpr friend basic_fixed_string operator+( + const CharT lhs, const basic_fixed_string& rhs) noexcept + { + CharT txt[1 + N] = {lhs}; + for (size_t i = 0; i != N; ++i) txt[1 + i] = rhs[i]; + return basic_fixed_string(std::begin(txt), std::end(txt)); } template + [[nodiscard]] consteval friend basic_fixed_string operator+( + const basic_fixed_string& lhs, const CharT (&rhs)[N2]) noexcept + { + CharT txt[N + N2 - 1] = {}; + for (size_t i = 0; i != N; ++i) txt[i] = lhs[i]; + for (size_t i = 0; i != N2 - 1; ++i) txt[N + i] = rhs[i]; + return basic_fixed_string(std::begin(txt), std::end(txt)); + } + + template + [[nodiscard]] consteval friend basic_fixed_string operator+( + const CharT (&lhs)[N1], const basic_fixed_string& rhs) noexcept + { + CharT txt[N1 + N - 1] = {}; + for (size_t i = 0; i != N1 - 1; ++i) txt[i] = lhs[i]; + for (size_t i = 0; i != N; ++i) txt[N1 - 1 + i] = rhs[i]; + return basic_fixed_string(std::begin(txt), std::end(txt)); + } + + // non-member comparison functions + template + [[nodiscard]] friend constexpr bool operator==(const basic_fixed_string& lhs, + const basic_fixed_string& rhs) + { + return lhs.view() == rhs.view(); + } + template + [[nodiscard]] friend consteval bool operator==(const basic_fixed_string& lhs, const CharT (&rhs)[N2]) + { + return lhs.view() == std::basic_string_view(std::cbegin(rhs), std::cend(rhs) - 1); + } + + template [[nodiscard]] friend constexpr auto operator<=>(const basic_fixed_string& lhs, - const basic_fixed_string& rhs) + const basic_fixed_string& rhs) { - // TODO std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); - return detail::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + return lhs.view() <=> rhs.view(); + } + template + [[nodiscard]] friend consteval auto operator<=>(const basic_fixed_string& lhs, const CharT (&rhs)[N2]) + { + return lhs.view() <=> std::basic_string_view(std::cbegin(rhs), std::cend(rhs) - 1); } - template + // inserters and extractors friend std::basic_ostream& operator<<(std::basic_ostream& os, - const basic_fixed_string& str) + const basic_fixed_string& str) { return os << str.c_str(); } }; +// deduction guides +template CharT, std::convertible_to... Rest> +basic_fixed_string(CharT, Rest...) -> basic_fixed_string; + template basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string; -template... Rest> -basic_fixed_string(CharT, Rest...) -> basic_fixed_string; +template CharT, std::size_t N> +basic_fixed_string(std::from_range_t, std::array) -> basic_fixed_string; +// typedef-names template using fixed_string = basic_fixed_string; - +template +using fixed_u8string = basic_fixed_string; +template +using fixed_u16string = basic_fixed_string; +template +using fixed_u32string = 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 +// hash support +template +struct std::hash> : std::hash {}; +template +struct std::hash> : std::hash {}; +template +struct std::hash> : std::hash {}; +template +struct std::hash> : std::hash {}; +template +struct std::hash> : std::hash {}; + +// formatting support template struct MP_UNITS_STD_FMT::formatter> : formatter> { template diff --git a/src/core/include/mp-units/framework/dimension.h b/src/core/include/mp-units/framework/dimension.h index 770194b9..a708afc2 100644 --- a/src/core/include/mp-units/framework/dimension.h +++ b/src/core/include/mp-units/framework/dimension.h @@ -328,8 +328,7 @@ MP_UNITS_EXPORT template(D{}); - return basic_fixed_string(buffer.begin(), buffer.end()); + return basic_fixed_string(std::from_range, detail::get_symbol_buffer(D{})); #endif } diff --git a/src/core/include/mp-units/framework/symbol_text.h b/src/core/include/mp-units/framework/symbol_text.h index d36aa082..f7c3efaa 100644 --- a/src/core/include/mp-units/framework/symbol_text.h +++ b/src/core/include/mp-units/framework/symbol_text.h @@ -24,8 +24,10 @@ #pragma once // IWYU pragma: private, include +// TODO use when moved to C++20 modules (parsing takes too long for each translation unit) #include #include +#include #include #ifndef MP_UNITS_IN_MODULE_INTERFACE @@ -85,7 +87,8 @@ constexpr fixed_u8string to_u8string(fixed_string txt) * @tparam M The size of the ASCII-only symbol */ MP_UNITS_EXPORT template -struct symbol_text { +class symbol_text { +public: fixed_u8string unicode_; fixed_string ascii_; @@ -96,7 +99,7 @@ struct symbol_text { } // NOLINTNEXTLINE(*-avoid-c-arrays, google-explicit-constructor, hicpp-explicit-conversions) - constexpr explicit(false) symbol_text(const char (&txt)[N + 1]) : + consteval explicit(false) symbol_text(const char (&txt)[N + 1]) : unicode_(detail::to_u8string(basic_fixed_string{txt})), ascii_(txt) { gsl_Expects(txt[N] == char{}); @@ -110,7 +113,7 @@ struct symbol_text { } // NOLINTNEXTLINE(*-avoid-c-arrays) - constexpr symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a) + consteval symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a) { gsl_Expects(u[N] == char8_t{}); gsl_Expects(a[M] == char{}); diff --git a/src/core/include/mp-units/framework/unit.h b/src/core/include/mp-units/framework/unit.h index ce9484a2..8e8ad5df 100644 --- a/src/core/include/mp-units/framework/unit.h +++ b/src/core/include/mp-units/framework/unit.h @@ -854,8 +854,7 @@ MP_UNITS_EXPORT template(U{}); - return basic_fixed_string(buffer.begin(), buffer.end()); + return basic_fixed_string(std::from_range, detail::get_symbol_buffer(U{})); #endif } diff --git a/test/runtime/CMakeLists.txt b/test/runtime/CMakeLists.txt index f78c0ad4..fcd2cca8 100644 --- a/test/runtime/CMakeLists.txt +++ b/test/runtime/CMakeLists.txt @@ -24,7 +24,9 @@ cmake_minimum_required(VERSION 3.5) find_package(Catch2 3 REQUIRED) -add_executable(unit_tests_runtime distribution_test.cpp fmt_test.cpp math_test.cpp atomic_test.cpp) +add_executable( + unit_tests_runtime distribution_test.cpp fixed_string_test.cpp fmt_test.cpp math_test.cpp atomic_test.cpp +) if(${projectPrefix}BUILD_CXX_MODULES) target_compile_definitions(unit_tests_runtime PUBLIC ${projectPrefix}MODULES) endif() diff --git a/test/runtime/fixed_string_test.cpp b/test/runtime/fixed_string_test.cpp new file mode 100644 index 00000000..706e8b17 --- /dev/null +++ b/test/runtime/fixed_string_test.cpp @@ -0,0 +1,67 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include +#ifdef MP_UNITS_MODULES +import mp_units; +#else +#include +#endif + +using namespace mp_units; + +TEST_CASE("fixed_string::at", "[fixed_string]") +{ + basic_fixed_string txt = "abc"; + SECTION("in range") + { + CHECK(txt.at(0) == 'a'); + CHECK(txt.at(1) == 'b'); + CHECK(txt.at(2) == 'c'); + } + SECTION("out of range") + { + REQUIRE_THROWS_MATCHES(txt.at(3), std::out_of_range, Catch::Matchers::Message("basic_fixed_string::at")); + REQUIRE_THROWS_MATCHES(txt.at(1024), std::out_of_range, Catch::Matchers::Message("basic_fixed_string::at")); + } +} + +TEST_CASE("fixed_string text output", "[fixed_string][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("fixed_string hash", "[fixed_string][hash]") +{ + basic_fixed_string txt = "units"; + CHECK(std::hash>{}(txt) == std::hash{}("units")); +} diff --git a/test/runtime/fmt_test.cpp b/test/runtime/fmt_test.cpp index e8437438..8c26ee28 100644 --- a/test/runtime/fmt_test.cpp +++ b/test/runtime/fmt_test.cpp @@ -34,7 +34,6 @@ #ifdef MP_UNITS_MODULES import mp_units; #else -#include #include #include // IWYU pragma: keep #include @@ -51,18 +50,6 @@ 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 93890a98..87ca7660 100644 --- a/test/static/fixed_string_test.cpp +++ b/test/static/fixed_string_test.cpp @@ -27,36 +27,152 @@ using namespace mp_units; namespace { +constexpr std::array array = {'a', 'b', 'c'}; + +auto from_string = [] { + std::string txt = "abc"; + return fixed_string<3>(std::from_range, txt); +}; + +auto from_string_iter = [] { + std::string txt = "abc"; + return fixed_string<3>(txt.begin(), txt.end()); +}; + +constexpr fixed_string<0> txt0; constexpr basic_fixed_string txt1('a'); +constexpr basic_fixed_string txt2('a', 'b', 'c'); +constexpr basic_fixed_string txt3 = "abc"; +constexpr fixed_string<3> txt4(array.begin(), array.end()); +constexpr basic_fixed_string txt5(std::from_range, array); +constexpr basic_fixed_string txt6(from_string()); +constexpr basic_fixed_string txt7(from_string_iter()); + +constexpr fixed_string<3> txt8(txt2.begin(), txt2.end()); +constexpr fixed_string<3> txt9(txt2.rbegin(), txt2.rend()); + +static_assert(txt0.size() == 0); static_assert(txt1.size() == 1); +static_assert(txt2.size() == 3); +static_assert(txt3.size() == 3); +static_assert(txt4.size() == 3); +static_assert(txt5.size() == 3); +static_assert(txt6.size() == 3); +static_assert(txt7.size() == 3); +static_assert(txt8.size() == 3); +static_assert(txt9.size() == 3); + +static_assert(txt0.length() == 0); +static_assert(txt1.length() == 1); +static_assert(txt2.length() == 3); + +static_assert(txt0.max_size() == 0); +static_assert(txt1.max_size() == 1); +static_assert(txt2.max_size() == 3); + +static_assert(txt0.empty() == true); +static_assert(txt1.empty() == false); +static_assert(txt2.empty() == false); +static_assert(txt3.empty() == false); +static_assert(txt4.empty() == false); +static_assert(txt5.empty() == false); +static_assert(txt6.empty() == false); +static_assert(txt7.empty() == false); +static_assert(txt8.empty() == false); +static_assert(txt9.empty() == false); + static_assert(txt1[0] == 'a'); +static_assert(txt2[0] == 'a'); +static_assert(txt2[1] == 'b'); +static_assert(txt2[2] == 'c'); +static_assert(txt9[0] == 'c'); +static_assert(txt9[1] == 'b'); +static_assert(txt9[2] == 'a'); + +static_assert(txt1.at(0) == 'a'); +static_assert(txt2.at(0) == 'a'); +static_assert(txt2.at(1) == 'b'); +static_assert(txt2.at(2) == 'c'); +static_assert(txt9.at(0) == 'c'); +static_assert(txt9.at(1) == 'b'); +static_assert(txt9.at(2) == 'a'); + +static_assert(txt1.front() == 'a'); +static_assert(txt1.back() == 'a'); +static_assert(txt2.front() == 'a'); +static_assert(txt2.back() == 'c'); +static_assert(txt5.front() == 'a'); +static_assert(txt5.back() == 'c'); +static_assert(txt6.front() == 'a'); +static_assert(txt6.back() == 'c'); +static_assert(txt7.front() == 'a'); +static_assert(txt7.back() == 'c'); +static_assert(txt8.front() == 'a'); +static_assert(txt8.back() == 'c'); +static_assert(txt9.front() == 'c'); +static_assert(txt9.back() == 'a'); + +static_assert(std::string_view(txt0.data()) == ""); +static_assert(std::string_view(txt0.c_str()) == ""); +static_assert(std::string_view(txt1.data()) == "a"); +static_assert(std::string_view(txt1.c_str()) == "a"); +static_assert(std::string_view(txt2.data()) == "abc"); +static_assert(std::string_view(txt2.c_str()) == "abc"); + +static_assert(txt0 == ""); +static_assert("a" == txt1); +static_assert(txt2 == "abc"); +static_assert(txt3 == "abc"); +static_assert(txt4 == "abc"); +static_assert(txt5 == "abc"); +static_assert(txt6 == "abc"); +static_assert(txt7 == "abc"); +static_assert(txt8 == "abc"); +static_assert(txt9 == "cba"); + 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")); -static_assert(basic_fixed_string('b') + txt1 == basic_fixed_string("ba")); -static_assert(txt1 + basic_fixed_string("bc") == basic_fixed_string("abc")); -static_assert(basic_fixed_string("bc") + txt1 == basic_fixed_string("bca")); +static_assert(txt1 == "a"); +static_assert(txt1 != "b"); +static_assert(txt1 != "aa"); +static_assert(txt1 < "b"); +static_assert(txt1 < "aa"); + +static_assert(txt1 + basic_fixed_string('b') == "ab"); +static_assert(basic_fixed_string('b') + txt1 == "ba"); +static_assert(txt1 + basic_fixed_string("bc") == "abc"); +static_assert(basic_fixed_string("bc") + txt1 == "bca"); +static_assert(txt1 + 'b' == "ab"); +static_assert('b' + txt1 == "ba"); +static_assert(txt1 + "bc" == "abc"); +static_assert("bc" + txt1 == "bca"); -constexpr basic_fixed_string txt2("abc"); -static_assert(txt2.size() == 3); -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")); -static_assert(basic_fixed_string('d') + txt2 == basic_fixed_string("dabc")); -static_assert(txt2 + basic_fixed_string("def") == basic_fixed_string("abcdef")); -static_assert(basic_fixed_string("def") + txt2 == basic_fixed_string("defabc")); +static_assert(txt2 == "abc"); +static_assert(txt2 != "cba"); +static_assert(txt2 != "abcd"); +static_assert(txt2 < "b"); +static_assert(txt2 > "aa"); -#ifndef MP_UNITS_COMP_GCC -static_assert(std::string_view(basic_fixed_string("abcd")).find('c') == 2); -#endif +static_assert(txt2 + basic_fixed_string('d') == "abcd"); +static_assert(basic_fixed_string('d') + txt2 == "dabc"); +static_assert(txt2 + basic_fixed_string("def") == "abcdef"); +static_assert(basic_fixed_string("def") + txt2 == "defabc"); +static_assert(txt2 + 'd' == "abcd"); +static_assert('d' + txt2 == "dabc"); +static_assert(txt2 + "def" == "abcdef"); +static_assert("def" + txt2 == "defabc"); + +static_assert(std::string_view(txt2) == "abc"); +static_assert(txt2.view() == "abc"); +static_assert(std::string_view(txt2).find('b') == 1); +static_assert(txt2.view().find('b') == 1); } // namespace