Skip to content

makes most operators hidden friends #471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Stream support
// 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
276 changes: 133 additions & 143 deletions sus/collections/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,27 @@ struct Storage<T, 0> final {};

} // namespace __private

namespace __private {
Comment on lines 64 to +66
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can avoid closing and opening the namespace here

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`.
///
/// An Array can not be larger than [`isize::MAX`]($sus::num::isize::MAX), as
Expand Down Expand Up @@ -335,10 +356,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 +427,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>)
constexpr friend std::strong_ordering operator<=>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we write friend constexpr as the order for these keywords consistently (the one above is in that order)?

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>)
constexpr friend 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>)
constexpr friend 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>)
constexpr friend 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>)
constexpr friend 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>)
constexpr friend 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>)
constexpr friend 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>)
constexpr friend 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>)
constexpr friend 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Stream support
// Stream support.

_sus_format_to_stream(Array);

private:
enum WithDefault { WITH_DEFAULT };
template <size_t... Is>
Expand Down Expand Up @@ -467,136 +598,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 +665,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
Loading