mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +02:00
feat: basic_fixed_string
implementation and testing improved
This commit is contained in:
@ -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
|
||||
|
@ -72,45 +72,6 @@ constexpr bool all_of(InputIt first, InputIt last, UnaryPred p)
|
||||
return find_if_not(first, last, p) == last;
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) {
|
||||
if (!(*first1 == *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class I1, class I2, class Cmp>
|
||||
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<ret_t, std::strong_ordering>, std::is_same<ret_t, std::weak_ordering>,
|
||||
std::is_same<ret_t, std::partial_ordering>>,
|
||||
"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<class I1, class I2>
|
||||
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<class ForwardIt>
|
||||
constexpr ForwardIt max_element(ForwardIt first, ForwardIt last)
|
||||
{
|
||||
|
@ -26,10 +26,10 @@
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
#pragma once
|
||||
|
||||
// TODO use <algorithm> when moved to C++20 modules (parsing takes too long for each translation unit)
|
||||
#include <mp-units/bits/hacks.h> // IWYU pragma: keep
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/compat_macros.h> // IWYU pragma: keep
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
#include <mp-units/ext/type_traits.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
@ -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<typename CharT, std::size_t N>
|
||||
struct basic_fixed_string {
|
||||
CharT data_[N + 1] = {};
|
||||
template<typename CharT, std::size_t N, typename Traits = std::char_traits<CharT>>
|
||||
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<const_iterator>;
|
||||
using reverse_iterator = const_reverse_iterator;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// construction and assignment
|
||||
template<std::convertible_to<CharT>... Chars>
|
||||
requires(sizeof...(Chars) == N) && (... && !std::is_pointer_v<Chars>)
|
||||
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<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
|
||||
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<std::convertible_to<CharT>... Rest>
|
||||
requires(1 + sizeof...(Rest) == N)
|
||||
constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT{}}
|
||||
template<std::ranges::input_range R>
|
||||
requires std::convertible_to<std::ranges::range_reference_t<R>, 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>(r)) *it++ = std::forward<decltype(v)>(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<const_pointer>(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<CharT>() 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<CharT>(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<const_pointer>(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<CharT, Traits> view() const noexcept
|
||||
{
|
||||
return std::basic_string_view<CharT, Traits>(cbegin(), cend());
|
||||
}
|
||||
// NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor)
|
||||
[[nodiscard]] constexpr explicit(false) operator std::basic_string_view<CharT, Traits>() const noexcept
|
||||
{
|
||||
return view();
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2> operator+(
|
||||
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2, Traits> operator+(
|
||||
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2, Traits>& 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<CharT, N + N2>(txt);
|
||||
return basic_fixed_string<CharT, N + N2, Traits>(std::begin(txt), std::end(txt));
|
||||
}
|
||||
|
||||
[[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>&)
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + 1, Traits> 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<CharT, N + 1, Traits>(std::begin(txt), std::end(txt));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, 1 + N, Traits> 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<CharT, 1 + N, Traits>(std::begin(txt), std::end(txt));
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] consteval friend basic_fixed_string<CharT, N + N2 - 1, Traits> 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<CharT, N + N2 - 1, Traits>(std::begin(txt), std::end(txt));
|
||||
}
|
||||
|
||||
template<std::size_t N1>
|
||||
[[nodiscard]] consteval friend basic_fixed_string<CharT, N1 + N - 1, Traits> 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<CharT, N1 + N - 1, Traits>(std::begin(txt), std::end(txt));
|
||||
}
|
||||
|
||||
// non-member comparison functions
|
||||
template<size_t N2>
|
||||
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string& lhs,
|
||||
const basic_fixed_string<CharT, N2, Traits>& rhs)
|
||||
{
|
||||
return lhs.view() == rhs.view();
|
||||
}
|
||||
template<size_t N2>
|
||||
[[nodiscard]] friend consteval bool operator==(const basic_fixed_string& lhs, const CharT (&rhs)[N2])
|
||||
{
|
||||
return lhs.view() == std::basic_string_view<CharT, Traits>(std::cbegin(rhs), std::cend(rhs) - 1);
|
||||
}
|
||||
|
||||
template<size_t N2>
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const basic_fixed_string& lhs,
|
||||
const basic_fixed_string<CharT, N2>& rhs)
|
||||
const basic_fixed_string<CharT, N2, Traits>& 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<size_t N2>
|
||||
[[nodiscard]] friend consteval auto operator<=>(const basic_fixed_string& lhs, const CharT (&rhs)[N2])
|
||||
{
|
||||
return lhs.view() <=> std::basic_string_view<CharT, Traits>(std::cbegin(rhs), std::cend(rhs) - 1);
|
||||
}
|
||||
|
||||
template<typename Traits>
|
||||
// inserters and extractors
|
||||
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
|
||||
const basic_fixed_string<CharT, N>& str)
|
||||
const basic_fixed_string& str)
|
||||
{
|
||||
return os << str.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
// deduction guides
|
||||
template<one_of<char, char8_t, char16_t, char32_t, wchar_t> 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 (&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<one_of<char, char8_t, char16_t, char32_t, wchar_t> CharT, std::size_t N>
|
||||
basic_fixed_string(std::from_range_t, std::array<CharT, N>) -> basic_fixed_string<CharT, N>;
|
||||
|
||||
// typedef-names
|
||||
template<std::size_t N>
|
||||
using fixed_string = basic_fixed_string<char, 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>;
|
||||
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
|
||||
|
||||
// hash support
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_string<N>> : std::hash<std::string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_u8string<N>> : std::hash<std::u8string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_u16string<N>> : std::hash<std::u16string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_u32string<N>> : std::hash<std::u32string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_wstring<N>> : std::hash<std::wstring_view> {};
|
||||
|
||||
// formatting support
|
||||
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>
|
||||
|
@ -328,8 +328,7 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
|
||||
return std::string_view(buffer.data(), size);
|
||||
#else
|
||||
constexpr std::size_t size = get_size();
|
||||
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(D{});
|
||||
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
|
||||
return basic_fixed_string(std::from_range, detail::get_symbol_buffer<CharT, size, fmt>(D{}));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,10 @@
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: private, include <mp-units/framework.h>
|
||||
// TODO use <algorithm> when moved to C++20 modules (parsing takes too long for each translation unit)
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
@ -85,7 +87,8 @@ constexpr fixed_u8string<N> to_u8string(fixed_string<N> txt)
|
||||
* @tparam M The size of the ASCII-only symbol
|
||||
*/
|
||||
MP_UNITS_EXPORT template<std::size_t N, std::size_t M>
|
||||
struct symbol_text {
|
||||
class symbol_text {
|
||||
public:
|
||||
fixed_u8string<N> unicode_;
|
||||
fixed_string<M> 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{});
|
||||
|
@ -854,8 +854,7 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
|
||||
return std::string_view(buffer.data(), size);
|
||||
#else
|
||||
constexpr std::size_t size = get_size();
|
||||
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(U{});
|
||||
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
|
||||
return basic_fixed_string(std::from_range, detail::get_symbol_buffer<CharT, size, fmt>(U{}));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
67
test/runtime/fixed_string_test.cpp
Normal file
67
test/runtime/fixed_string_test.cpp
Normal file
@ -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 <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_exception.hpp>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <string_view>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#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<fixed_string<5>>{}(txt) == std::hash<std::string_view>{}("units"));
|
||||
}
|
@ -34,7 +34,6 @@
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/ostream.h> // IWYU pragma: keep
|
||||
#include <mp-units/systems/cgs.h>
|
||||
@ -51,18 +50,6 @@ 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;
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user