Skip to content
6 changes: 3 additions & 3 deletions sus/boxed/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,9 @@ class [[_sus_trivial_abi]] Box final : public __private::BoxBase<Box<T>, T> {
return {};
}

// Stream support.
_sus_format_to_stream(Box);

private:
enum FromPointer { FROM_POINTER };
constexpr explicit Box(FromPointer, T* t) noexcept : t_(t) {}
Expand Down Expand Up @@ -708,9 +711,6 @@ struct fmt::formatter<::sus::boxed::Box<T>, Char> {
::sus::string::__private::AnyFormatter<T, Char> underlying_;
};

// Stream support.
_sus_format_to_stream(sus::boxed, Box, T);

// Promote `Box` into the `sus` namespace.
namespace sus {
using ::sus::boxed::Box;
Expand Down
15 changes: 3 additions & 12 deletions sus/choice/choice.h
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,9 @@ class Choice<__private::TypeList<Ts...>, Tags...> final {
const Choice<__private::TypeList<RhsTs...>, RhsTag, RhsTags...>& r) =
delete;

// Stream support.
_sus_format_to_stream(Choice);

private:
constexpr explicit Choice(IndexType i) noexcept : index_(i) {}

Expand Down Expand Up @@ -1001,18 +1004,6 @@ struct fmt::formatter<
}
};

// Stream support (written out manually due to use of template specialization).
namespace sus::choice_type {
template <class... Ts, auto... Tags,
::sus::string::__private::StreamCanReceiveString<char> StreamType>
inline StreamType& operator<<(
StreamType& stream,
const Choice<__private::TypeList<Ts...>, Tags...>& value) {
return ::sus::string::__private::format_to_stream(stream,
fmt::to_string(value));
}
} // namespace sus::choice_type

// Promote Choice into the `sus` namespace.
namespace sus {
using ::sus::choice_type::Choice;
Expand Down
273 changes: 130 additions & 143 deletions sus/collections/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ struct Storage final {
template <class T>
struct Storage<T, 0> final {};

template <size_t I>
constexpr bool array_cmp_impl(sus::cmp::Ordering auto& val, const auto& l,
const auto& r) noexcept {
auto cmp = l.get_unchecked(::sus::marker::unsafe_fn, I) <=>
r.get_unchecked(::sus::marker::unsafe_fn, I);
// Allow downgrading from equal to equivalent, but not the inverse.
if (cmp != 0) val = cmp;
// Short circuit by returning true when we find a difference.
return val == 0;
}

template <size_t... Is>
constexpr auto array_cmp(sus::cmp::Ordering auto equal, const auto& l,
const auto& r, std::index_sequence<Is...>) noexcept {
auto val = equal;
(true && ... && (array_cmp_impl<Is>(val, l, r)));
return val;
}
} // namespace __private

/// A collection of objects of type `T`, with a fixed size `N`.
Expand Down Expand Up @@ -335,10 +353,11 @@ class Array final {
/// Satisfies the [`Eq<Array<T, N>, Array<U, N>>`]($sus::cmp::Eq) concept.
template <class U>
requires(::sus::cmp::Eq<T, U>)
constexpr bool operator==(const Array<U, N>& r) const& noexcept
friend constexpr bool operator==(const Array& l,
const Array<U, N>& r) noexcept
requires(::sus::cmp::Eq<T>)
{
return eq_impl(r, std::make_index_sequence<N>());
return l.eq_impl(r, std::make_index_sequence<N>());
}

/// Satisfies the [`Eq<Array<T, N>, Slice<U>>`]($sus::cmp::Eq) concept.
Expand Down Expand Up @@ -405,6 +424,115 @@ class Array final {
sus::iter::IterRefCounter::empty_for_view(), storage_.data_, N);
}

/// Compares two Arrays.
///
/// Satisfies sus::cmp::StrongOrd<Array<T, N>> if sus::cmp::StrongOrd<T>.
///
/// Satisfies sus::cmp::Ord<Array<T, N>> if sus::cmp::Ord<T>.
///
/// Satisfies sus::cmp::PartialOrd<Array<T, N>> if sus::cmp::PartialOrd<T>.
/// #[doc.overloads=array.cmp.array]
template <class U>
requires(::sus::cmp::ExclusiveStrongOrd<T, U>)
friend constexpr std::strong_ordering operator<=>(
const Array& l, const Array<U, N>& r) noexcept {
return __private::array_cmp(std::strong_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.array]
template <class U>
requires(::sus::cmp::ExclusiveOrd<T, U>)
friend constexpr std::weak_ordering operator<=>(
const Array& l, const Array<U, N>& r) noexcept {
return __private::array_cmp(std::weak_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.array]
template <class U>
requires(::sus::cmp::ExclusivePartialOrd<T, U>)
friend constexpr std::partial_ordering operator<=>(
const Array& l, const Array<U, N>& r) noexcept {
return __private::array_cmp(std::partial_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}

/// Compares an Array and a Slice.
///
/// Satisfies sus::cmp::StrongOrd<Array<T, N>, Slice<T>> if
/// sus::cmp::StrongOrd<T>.
///
/// Satisfies sus::cmp::Ord<Array<T, N>, Slice<T>> if sus::cmp::Ord<T>.
///
/// Satisfies sus::cmp::PartialOrd<Array<T, N>, Slice<T>> if
/// sus::cmp::PartialOrd<T>.
/// #[doc.overloads=array.cmp.slice]
template <class U>
requires(::sus::cmp::ExclusiveStrongOrd<T, U>)
friend constexpr std::strong_ordering operator<=>(
const Array& l, const Slice<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::strong_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slice]
template <class U>
requires(::sus::cmp::ExclusiveOrd<T, U>)
friend constexpr std::weak_ordering operator<=>(const Array& l,
const Slice<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::weak_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slice]
template <class U>
requires(::sus::cmp::ExclusivePartialOrd<T, U>)
friend constexpr std::partial_ordering operator<=>(
const Array& l, const Slice<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::partial_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}

/// Compares an Array and a SliceMut.
///
/// Satisfies sus::cmp::StrongOrd<Array<T, N>, SliceMut<T>> if
/// sus::cmp::StrongOrd<T>.
///
/// Satisfies sus::cmp::Ord<Array<T, N>, SliceMut<T>> if sus::cmp::Ord<T>.
///
/// Satisfies sus::cmp::PartialOrd<Array<T, N>, SliceMut<T>> if
/// sus::cmp::PartialOrd<T>.
/// #[doc.overloads=array.cmp.slicemut]
template <class U>
requires(::sus::cmp::ExclusiveStrongOrd<T, U>)
friend constexpr std::strong_ordering operator<=>(
const Array& l, const SliceMut<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::strong_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slicemut]
template <class U>
requires(::sus::cmp::ExclusiveOrd<T, U>)
friend constexpr std::weak_ordering operator<=>(
const Array& l, const SliceMut<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::weak_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slicemut]
template <class U>
requires(::sus::cmp::ExclusivePartialOrd<T, U>)
friend constexpr std::partial_ordering operator<=>(
const Array& l, const SliceMut<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::partial_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}

// Stream support.
_sus_format_to_stream(Array);

private:
enum WithDefault { WITH_DEFAULT };
template <size_t... Is>
Expand Down Expand Up @@ -467,136 +595,6 @@ template <class T, class... Ts>
std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<Ts>>))
Array(T&&, Ts&&...) -> Array<std::remove_cvref_t<T>, 1u + sizeof...(Ts)>;

namespace __private {

template <size_t I>
constexpr inline bool array_cmp_impl(sus::cmp::Ordering auto& val,
const auto& l, const auto& r) noexcept {
auto cmp = l.get_unchecked(::sus::marker::unsafe_fn, I) <=>
r.get_unchecked(::sus::marker::unsafe_fn, I);
// Allow downgrading from equal to equivalent, but not the inverse.
if (cmp != 0) val = cmp;
// Short circuit by returning true when we find a difference.
return val == 0;
};

template <size_t... Is>
constexpr inline auto array_cmp(sus::cmp::Ordering auto equal, const auto& l,
const auto& r,
std::index_sequence<Is...>) noexcept {
auto val = equal;
(true && ... && (array_cmp_impl<Is>(val, l, r)));
return val;
};

} // namespace __private

/// Compares two Arrays.
///
/// Satisfies sus::cmp::StrongOrd<Array<T, N>> if sus::cmp::StrongOrd<T>.
///
/// Satisfies sus::cmp::Ord<Array<T, N>> if sus::cmp::Ord<T>.
///
/// Satisfies sus::cmp::PartialOrd<Array<T, N>> if sus::cmp::PartialOrd<T>.
/// #[doc.overloads=array.cmp.array]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusiveStrongOrd<T, U>)
constexpr inline std::strong_ordering operator<=>(
const Array<T, N>& l, const Array<U, N>& r) noexcept {
return __private::array_cmp(std::strong_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.array]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusiveOrd<T, U>)
constexpr inline std::weak_ordering operator<=>(const Array<T, N>& l,
const Array<U, N>& r) noexcept {
return __private::array_cmp(std::weak_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.array]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusivePartialOrd<T, U>)
constexpr inline std::partial_ordering operator<=>(
const Array<T, N>& l, const Array<U, N>& r) noexcept {
return __private::array_cmp(std::partial_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}

/// Compares an Array and a Slice.
///
/// Satisfies sus::cmp::StrongOrd<Array<T, N>, Slice<T>> if
/// sus::cmp::StrongOrd<T>.
///
/// Satisfies sus::cmp::Ord<Array<T, N>, Slice<T>> if sus::cmp::Ord<T>.
///
/// Satisfies sus::cmp::PartialOrd<Array<T, N>, Slice<T>> if
/// sus::cmp::PartialOrd<T>.
/// #[doc.overloads=array.cmp.slice]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusiveStrongOrd<T, U>)
constexpr inline std::strong_ordering operator<=>(const Array<T, N>& l,
const Slice<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::strong_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slice]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusiveOrd<T, U>)
constexpr inline std::weak_ordering operator<=>(const Array<T, N>& l,
const Slice<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::weak_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slice]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusivePartialOrd<T, U>)
constexpr inline std::partial_ordering operator<=>(const Array<T, N>& l,
const Slice<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::partial_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}

/// Compares an Array and a SliceMut.
///
/// Satisfies sus::cmp::StrongOrd<Array<T, N>, SliceMut<T>> if
/// sus::cmp::StrongOrd<T>.
///
/// Satisfies sus::cmp::Ord<Array<T, N>, SliceMut<T>> if sus::cmp::Ord<T>.
///
/// Satisfies sus::cmp::PartialOrd<Array<T, N>, SliceMut<T>> if
/// sus::cmp::PartialOrd<T>.
/// #[doc.overloads=array.cmp.slicemut]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusiveStrongOrd<T, U>)
constexpr inline std::strong_ordering operator<=>(
const Array<T, N>& l, const SliceMut<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::strong_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slicemut]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusiveOrd<T, U>)
constexpr inline std::weak_ordering operator<=>(const Array<T, N>& l,
const SliceMut<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::weak_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}
/// #[doc.overloads=array.cmp.slicemut]
template <class T, class U, size_t N>
requires(::sus::cmp::ExclusivePartialOrd<T, U>)
constexpr inline std::partial_ordering operator<=>(
const Array<T, N>& l, const SliceMut<U>& r) noexcept {
if (r.len() != N) return r.len() <=> N;
return __private::array_cmp(std::partial_ordering::equivalent, l, r,
std::make_index_sequence<N>());
}

/// Support for using structured bindings with `Array`.
/// #[doc.overloads=array.structured.bindings]
template <size_t I, class T, size_t N>
Expand Down Expand Up @@ -664,17 +662,6 @@ struct fmt::formatter<::sus::collections::Array<T, N>, Char> {
::sus::string::__private::AnyFormatter<T, Char> underlying_;
};

// Stream support (written out manually due to size_t template param).
namespace sus::collections {
template <class T, size_t N,
::sus::string::__private::StreamCanReceiveString<char> StreamType>
inline StreamType& operator<<(StreamType& stream, const Array<T, N>& value) {
return ::sus::string::__private::format_to_stream(stream,
fmt::to_string(value));
}

} // namespace sus::collections

namespace sus::collections {
// Documented in vec.h
using ::sus::iter::begin;
Expand Down
12 changes: 6 additions & 6 deletions sus/collections/slice.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ class [[_sus_trivial_abi]] Slice final {
iter_refs_ = ::sus::iter::IterRefCounter::empty_for_view();
}

// Stream support.
_sus_format_to_stream(Slice);

#define _ptr_expr data_
#define _len_expr len_
#define _iter_refs_expr iter_refs_.to_iter_from_view()
Expand Down Expand Up @@ -471,6 +474,9 @@ class [[_sus_trivial_abi]] SliceMut final {
slice_.iter_refs_ = ::sus::iter::IterRefCounter::empty_for_view();
}

// Stream support.
_sus_format_to_stream(SliceMut);

#define _ptr_expr slice_.data_
#define _len_expr slice_.len_
#define _iter_refs_expr slice_.iter_refs_.to_iter_from_view()
Expand Down Expand Up @@ -540,9 +546,6 @@ struct fmt::formatter<::sus::collections::Slice<T>, Char> {
::sus::string::__private::AnyFormatter<T, Char> underlying_;
};

// Stream support.
_sus_format_to_stream(sus::collections, Slice, T);

// fmt support.
template <class T, class Char>
struct fmt::formatter<::sus::collections::SliceMut<T>, Char> {
Expand All @@ -568,9 +571,6 @@ struct fmt::formatter<::sus::collections::SliceMut<T>, Char> {
::sus::string::__private::AnyFormatter<T, Char> underlying_;
};

// Stream support.
_sus_format_to_stream(sus::collections, SliceMut, T);

// Promote Slice into the `sus` namespace.
namespace sus {
using ::sus::collections::Slice;
Expand Down
Loading