mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-29 18:07:16 +02:00
refactor: fixed_string
refactored to reflect the latest changes to P3094R1
This commit is contained in:
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user