refactor: fixed_string refactored to reflect the latest changes to P3094R1

This commit is contained in:
Mateusz Pusz
2024-03-18 22:50:35 +09:00
parent 02dc42738f
commit 16f4f5d4a8
5 changed files with 53 additions and 28 deletions

View File

@ -33,6 +33,7 @@
#include <cstddef>
#include <cstdlib>
#include <ostream>
#include <string_view>
#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<std::input_iterator It, std::sentinel_for<It> S>
requires std::convertible_to<std::iter_value_t<It>, 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<std::convertible_to<CharT>... 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<std::size_t, N>) 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<CharT> view() const noexcept
[[nodiscard]] constexpr operator std::basic_string_view<CharT>() const noexcept
{
return std::basic_string_view<CharT>(cbegin(), cend());
}
@ -104,11 +111,7 @@ struct basic_fixed_string {
return basic_fixed_string<CharT, N + N2>(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<std::size_t N2>
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string&, const basic_fixed_string<CharT, N2>&)
@ -138,22 +141,28 @@ basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>;
template<typename CharT, std::convertible_to<CharT>... Rest>
basic_fixed_string(CharT, Rest...) -> basic_fixed_string<CharT, 1 + sizeof...(Rest)>;
template<typename CharT, std::size_t N>
basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) -> basic_fixed_string<CharT, N>;
template<std::size_t N>
using fixed_string = basic_fixed_string<char, N>;
template<std::size_t N>
using fixed_wstring = basic_fixed_string<wchar_t, N>;
template<std::size_t N>
using fixed_u8string = basic_fixed_string<char8_t, N>;
template<std::size_t N>
using fixed_u16string = basic_fixed_string<char16_t, N>;
template<std::size_t N>
using fixed_u32string = basic_fixed_string<char32_t, N>;
} // namespace mp_units
template<typename CharT, std::size_t N>
struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : formatter<std::basic_string_view<CharT>> {
template<typename FormatContext>
auto format(const mp_units::basic_fixed_string<CharT, N>& str, FormatContext& ctx)
auto format(const mp_units::basic_fixed_string<CharT, N>& str, FormatContext& ctx) const -> decltype(ctx.out())
{
return formatter<std::basic_string_view<CharT>>::format(str.view(), ctx);
return formatter<std::basic_string_view<CharT>>::format(std::basic_string_view<CharT>(str), ctx);
}
};

View File

@ -294,9 +294,9 @@ constexpr Out dimension_symbol_to(Out out, D d, dimension_symbol_formatting fmt
namespace detail {
template<typename CharT, std::size_t N, dimension_symbol_formatting fmt, Dimension D>
[[nodiscard]] consteval std::array<CharT, N + 1> get_symbol_buffer(D)
[[nodiscard]] consteval std::array<CharT, N> get_symbol_buffer(D)
{
std::array<CharT, N + 1> buffer{};
std::array<CharT, N> buffer{};
dimension_symbol_to<CharT>(buffer.begin(), D{}, fmt);
return buffer;
}
@ -326,7 +326,7 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
#else
constexpr std::size_t size = get_size();
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(D{});
return basic_fixed_string(buffer.data(), std::integral_constant<std::size_t, size>{});
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
#endif
}

View File

@ -816,9 +816,9 @@ constexpr Out unit_symbol_to(Out out, U u, unit_symbol_formatting fmt = unit_sym
namespace detail {
template<typename CharT, std::size_t N, unit_symbol_formatting fmt, Unit U>
[[nodiscard]] consteval std::array<CharT, N + 1> get_symbol_buffer(U)
[[nodiscard]] consteval std::array<CharT, N> get_symbol_buffer(U)
{
std::array<CharT, N + 1> buffer{};
std::array<CharT, N> buffer;
unit_symbol_to<CharT>(buffer.begin(), U{}, fmt);
return buffer;
}
@ -847,7 +847,7 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
#else
constexpr std::size_t size = get_size();
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(U{});
return basic_fixed_string(buffer.data(), std::integral_constant<std::size_t, size>{});
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
#endif
}

View File

@ -46,6 +46,18 @@ inline constexpr bool mp_units::is_vector<T> = 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;

View File

@ -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