From e660b9dc18e7e0de8025bc9c09c96373079a047e Mon Sep 17 00:00:00 2001 From: Christopher Di Bella Date: Sat, 26 Apr 2025 01:05:50 +0000 Subject: [PATCH 1/5] makes most operators hidden friends This ensures that they're not placed in their function names' respecitve overload sets, which has a considerable impact on build times and on compiler diagnostics (as they're not listed as failed candidates when overload resolution fails). --- sus/boxed/box.h | 6 +- sus/choice/choice.h | 14 +- sus/collections/array.h | 275 +++++---- sus/collections/slice.h | 12 +- sus/collections/vec.h | 6 +- sus/env/var.h | 2 +- sus/iter/generator.h | 4 +- sus/iter/iterator_loop.h | 4 +- sus/iter/size_hint.h | 16 + sus/iter/size_hint_impl.h | 14 +- sus/marker/empty.h | 40 +- sus/marker/unsafe.h | 40 +- sus/num/__private/float_methods.inc | 3 + sus/num/__private/float_methods_impl.inc | 3 - sus/num/__private/signed_integer_methods.inc | 3 + .../__private/signed_integer_methods_impl.inc | 3 - .../__private/unsigned_integer_methods.inc | 45 +- .../unsigned_integer_methods_impl.inc | 45 +- sus/num/signed_integer.h | 520 ++++++++--------- sus/num/try_from_int_error.h | 4 +- sus/num/try_from_int_error_impl.h | 5 - sus/num/unsigned_integer.h | 533 +++++++++--------- sus/num/unsigned_integer_consts.h | 56 ++ sus/num/unsigned_integer_impl.h | 2 + sus/ops/range.h | 38 +- sus/option/option.h | 8 +- sus/ptr/nonnull.h | 40 +- sus/result/result.h | 7 +- sus/string/__private/format_to_stream.h | 71 +-- .../__private/format_to_stream_unittest.cc | 6 +- sus/tuple/tuple.h | 54 +- 31 files changed, 963 insertions(+), 916 deletions(-) create mode 100644 sus/num/unsigned_integer_consts.h diff --git a/sus/boxed/box.h b/sus/boxed/box.h index 3109f5cc7..310e97418 100644 --- a/sus/boxed/box.h +++ b/sus/boxed/box.h @@ -656,6 +656,9 @@ class [[_sus_trivial_abi]] Box final : public __private::BoxBase, T> { return {}; } + // Stream support. + _sus_format_to_stream(Box) + private: enum FromPointer { FROM_POINTER }; constexpr explicit Box(FromPointer, T* t) noexcept : t_(t) {} @@ -708,9 +711,6 @@ struct fmt::formatter<::sus::boxed::Box, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::boxed, Box, T); - // Promote `Box` into the `sus` namespace. namespace sus { using ::sus::boxed::Box; diff --git a/sus/choice/choice.h b/sus/choice/choice.h index cb45dbda6..4aeb27cbe 100644 --- a/sus/choice/choice.h +++ b/sus/choice/choice.h @@ -910,6 +910,8 @@ class Choice<__private::TypeList, Tags...> final { const Choice<__private::TypeList, RhsTag, RhsTags...>& r) = delete; + // Stream support + _sus_format_to_stream(Choice) private: constexpr explicit Choice(IndexType i) noexcept : index_(i) {} @@ -1001,18 +1003,6 @@ struct fmt::formatter< } }; -// Stream support (written out manually due to use of template specialization). -namespace sus::choice_type { -template StreamType> -inline StreamType& operator<<( - StreamType& stream, - const Choice<__private::TypeList, 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; diff --git a/sus/collections/array.h b/sus/collections/array.h index 7b267c1bc..ec12820aa 100644 --- a/sus/collections/array.h +++ b/sus/collections/array.h @@ -63,6 +63,28 @@ struct Storage final {}; } // namespace __private +namespace __private { +template +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 +constexpr auto array_cmp(sus::cmp::Ordering auto equal, const auto& l, + const auto& r, + std::index_sequence) noexcept { + auto val = equal; + (true && ... && (array_cmp_impl(val, l, r))); + return val; +} +} + /// 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 @@ -335,10 +357,10 @@ class Array final { /// Satisfies the [`Eq, Array>`]($sus::cmp::Eq) concept. template requires(::sus::cmp::Eq) - constexpr bool operator==(const Array& r) const& noexcept + friend constexpr bool operator==(const Array& l, const Array& r) noexcept requires(::sus::cmp::Eq) { - return eq_impl(r, std::make_index_sequence()); + return l.eq_impl(r, std::make_index_sequence()); } /// Satisfies the [`Eq, Slice>`]($sus::cmp::Eq) concept. @@ -405,6 +427,114 @@ class Array final { sus::iter::IterRefCounter::empty_for_view(), storage_.data_, N); } + /// Compares two Arrays. + /// + /// Satisfies sus::cmp::StrongOrd> if sus::cmp::StrongOrd. + /// + /// Satisfies sus::cmp::Ord> if sus::cmp::Ord. + /// + /// Satisfies sus::cmp::PartialOrd> if sus::cmp::PartialOrd. + /// #[doc.overloads=array.cmp.array] + template + requires(::sus::cmp::ExclusiveStrongOrd) + constexpr friend std::strong_ordering operator<=>( + const Array& l, const Array& r) noexcept { + return __private::array_cmp(std::strong_ordering::equivalent, l, r, + std::make_index_sequence()); + } + /// #[doc.overloads=array.cmp.array] + template + requires(::sus::cmp::ExclusiveOrd) + constexpr friend std::weak_ordering operator<=>(const Array& l, + const Array& r) noexcept { + return __private::array_cmp(std::weak_ordering::equivalent, l, r, + std::make_index_sequence()); + } + /// #[doc.overloads=array.cmp.array] + template + requires(::sus::cmp::ExclusivePartialOrd) + constexpr friend std::partial_ordering operator<=>( + const Array& l, const Array& r) noexcept { + return __private::array_cmp(std::partial_ordering::equivalent, l, r, + std::make_index_sequence()); + } + + /// Compares an Array and a Slice. + /// + /// Satisfies sus::cmp::StrongOrd, Slice> if + /// sus::cmp::StrongOrd. + /// + /// Satisfies sus::cmp::Ord, Slice> if sus::cmp::Ord. + /// + /// Satisfies sus::cmp::PartialOrd, Slice> if + /// sus::cmp::PartialOrd. + /// #[doc.overloads=array.cmp.slice] + template + requires(::sus::cmp::ExclusiveStrongOrd) + constexpr friend std::strong_ordering operator<=>(const Array& l, + const Slice& r) noexcept { + if (r.len() != N) return r.len() <=> N; + return __private::array_cmp(std::strong_ordering::equivalent, l, r, + std::make_index_sequence()); + } + /// #[doc.overloads=array.cmp.slice] + template + requires(::sus::cmp::ExclusiveOrd) + constexpr friend std::weak_ordering operator<=>(const Array& l, + const Slice& r) noexcept { + if (r.len() != N) return r.len() <=> N; + return __private::array_cmp(std::weak_ordering::equivalent, l, r, + std::make_index_sequence()); + } + /// #[doc.overloads=array.cmp.slice] + template + requires(::sus::cmp::ExclusivePartialOrd) + constexpr friend std::partial_ordering operator<=>(const Array& l, + const Slice& r) noexcept { + if (r.len() != N) return r.len() <=> N; + return __private::array_cmp(std::partial_ordering::equivalent, l, r, + std::make_index_sequence()); + } + + /// Compares an Array and a SliceMut. + /// + /// Satisfies sus::cmp::StrongOrd, SliceMut> if + /// sus::cmp::StrongOrd. + /// + /// Satisfies sus::cmp::Ord, SliceMut> if sus::cmp::Ord. + /// + /// Satisfies sus::cmp::PartialOrd, SliceMut> if + /// sus::cmp::PartialOrd. + /// #[doc.overloads=array.cmp.slicemut] + template + requires(::sus::cmp::ExclusiveStrongOrd) + constexpr friend std::strong_ordering operator<=>( + const Array& l, const SliceMut& r) noexcept { + if (r.len() != N) return r.len() <=> N; + return __private::array_cmp(std::strong_ordering::equivalent, l, r, + std::make_index_sequence()); + } + /// #[doc.overloads=array.cmp.slicemut] + template + requires(::sus::cmp::ExclusiveOrd) + constexpr friend std::weak_ordering operator<=>(const Array& l, + const SliceMut& r) noexcept { + if (r.len() != N) return r.len() <=> N; + return __private::array_cmp(std::weak_ordering::equivalent, l, r, + std::make_index_sequence()); + } + /// #[doc.overloads=array.cmp.slicemut] + template + requires(::sus::cmp::ExclusivePartialOrd) + constexpr friend std::partial_ordering operator<=>( + const Array& l, const SliceMut& r) noexcept { + if (r.len() != N) return r.len() <=> N; + return __private::array_cmp(std::partial_ordering::equivalent, l, r, + std::make_index_sequence()); + } + + // Stream support + _sus_format_to_stream(Array) private: enum WithDefault { WITH_DEFAULT }; template @@ -467,136 +597,6 @@ template std::same_as, std::remove_cvref_t>)) Array(T&&, Ts&&...) -> Array, 1u + sizeof...(Ts)>; -namespace __private { - -template -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 -constexpr inline auto array_cmp(sus::cmp::Ordering auto equal, const auto& l, - const auto& r, - std::index_sequence) noexcept { - auto val = equal; - (true && ... && (array_cmp_impl(val, l, r))); - return val; -}; - -} // namespace __private - -/// Compares two Arrays. -/// -/// Satisfies sus::cmp::StrongOrd> if sus::cmp::StrongOrd. -/// -/// Satisfies sus::cmp::Ord> if sus::cmp::Ord. -/// -/// Satisfies sus::cmp::PartialOrd> if sus::cmp::PartialOrd. -/// #[doc.overloads=array.cmp.array] -template - requires(::sus::cmp::ExclusiveStrongOrd) -constexpr inline std::strong_ordering operator<=>( - const Array& l, const Array& r) noexcept { - return __private::array_cmp(std::strong_ordering::equivalent, l, r, - std::make_index_sequence()); -} -/// #[doc.overloads=array.cmp.array] -template - requires(::sus::cmp::ExclusiveOrd) -constexpr inline std::weak_ordering operator<=>(const Array& l, - const Array& r) noexcept { - return __private::array_cmp(std::weak_ordering::equivalent, l, r, - std::make_index_sequence()); -} -/// #[doc.overloads=array.cmp.array] -template - requires(::sus::cmp::ExclusivePartialOrd) -constexpr inline std::partial_ordering operator<=>( - const Array& l, const Array& r) noexcept { - return __private::array_cmp(std::partial_ordering::equivalent, l, r, - std::make_index_sequence()); -} - -/// Compares an Array and a Slice. -/// -/// Satisfies sus::cmp::StrongOrd, Slice> if -/// sus::cmp::StrongOrd. -/// -/// Satisfies sus::cmp::Ord, Slice> if sus::cmp::Ord. -/// -/// Satisfies sus::cmp::PartialOrd, Slice> if -/// sus::cmp::PartialOrd. -/// #[doc.overloads=array.cmp.slice] -template - requires(::sus::cmp::ExclusiveStrongOrd) -constexpr inline std::strong_ordering operator<=>(const Array& l, - const Slice& r) noexcept { - if (r.len() != N) return r.len() <=> N; - return __private::array_cmp(std::strong_ordering::equivalent, l, r, - std::make_index_sequence()); -} -/// #[doc.overloads=array.cmp.slice] -template - requires(::sus::cmp::ExclusiveOrd) -constexpr inline std::weak_ordering operator<=>(const Array& l, - const Slice& r) noexcept { - if (r.len() != N) return r.len() <=> N; - return __private::array_cmp(std::weak_ordering::equivalent, l, r, - std::make_index_sequence()); -} -/// #[doc.overloads=array.cmp.slice] -template - requires(::sus::cmp::ExclusivePartialOrd) -constexpr inline std::partial_ordering operator<=>(const Array& l, - const Slice& r) noexcept { - if (r.len() != N) return r.len() <=> N; - return __private::array_cmp(std::partial_ordering::equivalent, l, r, - std::make_index_sequence()); -} - -/// Compares an Array and a SliceMut. -/// -/// Satisfies sus::cmp::StrongOrd, SliceMut> if -/// sus::cmp::StrongOrd. -/// -/// Satisfies sus::cmp::Ord, SliceMut> if sus::cmp::Ord. -/// -/// Satisfies sus::cmp::PartialOrd, SliceMut> if -/// sus::cmp::PartialOrd. -/// #[doc.overloads=array.cmp.slicemut] -template - requires(::sus::cmp::ExclusiveStrongOrd) -constexpr inline std::strong_ordering operator<=>( - const Array& l, const SliceMut& r) noexcept { - if (r.len() != N) return r.len() <=> N; - return __private::array_cmp(std::strong_ordering::equivalent, l, r, - std::make_index_sequence()); -} -/// #[doc.overloads=array.cmp.slicemut] -template - requires(::sus::cmp::ExclusiveOrd) -constexpr inline std::weak_ordering operator<=>(const Array& l, - const SliceMut& r) noexcept { - if (r.len() != N) return r.len() <=> N; - return __private::array_cmp(std::weak_ordering::equivalent, l, r, - std::make_index_sequence()); -} -/// #[doc.overloads=array.cmp.slicemut] -template - requires(::sus::cmp::ExclusivePartialOrd) -constexpr inline std::partial_ordering operator<=>( - const Array& l, const SliceMut& r) noexcept { - if (r.len() != N) return r.len() <=> N; - return __private::array_cmp(std::partial_ordering::equivalent, l, r, - std::make_index_sequence()); -} - /// Support for using structured bindings with `Array`. /// #[doc.overloads=array.structured.bindings] template @@ -664,17 +664,6 @@ struct fmt::formatter<::sus::collections::Array, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support (written out manually due to size_t template param). -namespace sus::collections { -template StreamType> -inline StreamType& operator<<(StreamType& stream, const Array& 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; diff --git a/sus/collections/slice.h b/sus/collections/slice.h index 29663192d..6725aeca4 100644 --- a/sus/collections/slice.h +++ b/sus/collections/slice.h @@ -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() @@ -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() @@ -540,9 +546,6 @@ struct fmt::formatter<::sus::collections::Slice, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::collections, Slice, T); - // fmt support. template struct fmt::formatter<::sus::collections::SliceMut, Char> { @@ -568,9 +571,6 @@ struct fmt::formatter<::sus::collections::SliceMut, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::collections, SliceMut, T); - // Promote Slice into the `sus` namespace. namespace sus { using ::sus::collections::Slice; diff --git a/sus/collections/vec.h b/sus/collections/vec.h index d28e0e3fa..82054160d 100644 --- a/sus/collections/vec.h +++ b/sus/collections/vec.h @@ -829,6 +829,9 @@ class Vec final { ::sus::marker::unsafe_fn, iter_refs_.to_view_from_owner(), data_, len_); } + // Stream support. + _sus_format_to_stream(Vec) + #define _ptr_expr data_ #define _len_expr len_ #define _iter_refs_expr iter_refs_.to_iter_from_owner() @@ -1094,9 +1097,6 @@ struct fmt::formatter<::sus::collections::Vec, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::collections, Vec, T); - namespace sus::collections { /// Implicit for-ranged loop iteration for all collections via the `iter` /// method. diff --git a/sus/env/var.h b/sus/env/var.h index fc6a9c87b..46e5da020 100644 --- a/sus/env/var.h +++ b/sus/env/var.h @@ -36,7 +36,7 @@ struct VarError { Reason reason; /// Satisfies the [`Eq`]($sus::cmp::Eq) concept. - constexpr bool operator==(const VarError& rhs) const noexcept = default; + constexpr friend bool operator==(const VarError& lhs, const VarError& rhs) noexcept = default; }; /// Fetches the environment variable `key` from the current process. diff --git a/sus/iter/generator.h b/sus/iter/generator.h index abc98159b..d15fb1d93 100644 --- a/sus/iter/generator.h +++ b/sus/iter/generator.h @@ -122,9 +122,9 @@ class [[nodiscard]] [[_sus_trivial_abi]] GeneratorLoop { constexpr GeneratorLoop(Generator& generator sus_lifetimebound) noexcept : generator_(generator) {} - constexpr bool operator==( + constexpr friend bool operator==(const GeneratorLoop& l, const ::sus::iter::__private::IteratorEnd&) noexcept { - return generator_.co_handle_.done(); + return l.generator_.co_handle_.done(); } constexpr GeneratorLoop& operator++() & noexcept { // UB occurs if this is called after GeneratorLoop == IteratorEnd. This diff --git a/sus/iter/iterator_loop.h b/sus/iter/iterator_loop.h index 2fac60fea..65762f929 100644 --- a/sus/iter/iterator_loop.h +++ b/sus/iter/iterator_loop.h @@ -31,8 +31,8 @@ class [[nodiscard]] IteratorLoop final { constexpr IteratorLoop(Iter&& iter) noexcept : iter_(::sus::forward(iter)), item_(iter_.next()) {} - constexpr inline bool operator==(__private::IteratorEnd) const noexcept { - return item_.is_none(); + constexpr friend bool operator==(const IteratorLoop& x, __private::IteratorEnd) noexcept { + return x.item_.is_none(); } constexpr inline void operator++() & noexcept { item_ = iter_.next(); } constexpr inline Item operator*() & noexcept { diff --git a/sus/iter/size_hint.h b/sus/iter/size_hint.h index 859cba1e4..6e82c1bb2 100644 --- a/sus/iter/size_hint.h +++ b/sus/iter/size_hint.h @@ -18,6 +18,7 @@ #include "sus/num/unsigned_integer.h" #include "sus/option/option.h" +#include "sus/string/__private/format_to_stream.h" namespace sus::iter { @@ -27,6 +28,21 @@ struct SizeHint { friend constexpr bool operator==(const SizeHint& lhs, const SizeHint& rhs) noexcept = default; + + // Stream support. + _sus_format_to_stream(SizeHint) }; } // namespace sus::iter + +// fmt support. +template +struct fmt::formatter<::sus::iter::SizeHint, Char> { + template + constexpr auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + FormatContext::iterator format(const ::sus::iter::SizeHint& t, FormatContext& ctx) const; +}; diff --git a/sus/iter/size_hint_impl.h b/sus/iter/size_hint_impl.h index d4abd230e..212b33bcb 100644 --- a/sus/iter/size_hint_impl.h +++ b/sus/iter/size_hint_impl.h @@ -24,18 +24,8 @@ // fmt support. template -struct fmt::formatter<::sus::iter::SizeHint, Char> { - template - constexpr auto parse(ParseContext& ctx) { - return ctx.begin(); - } - - template - constexpr auto format(const ::sus::iter::SizeHint& t, +template + FormatContext::iterator fmt::formatter<::sus::iter::SizeHint, Char>::format(const ::sus::iter::SizeHint& t, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "SizeHint({}, {})", t.lower, t.upper); } -}; - -// Stream support. -_sus_format_to_stream(sus::iter, SizeHint); diff --git a/sus/marker/empty.h b/sus/marker/empty.h index 3f307231b..4e546e26e 100644 --- a/sus/marker/empty.h +++ b/sus/marker/empty.h @@ -19,6 +19,25 @@ #include "fmt/core.h" #include "sus/string/__private/format_to_stream.h" +namespace sus::marker { + struct EmptyMarker; +} + +// fmt support. +template +struct fmt::formatter<::sus::marker::EmptyMarker, Char> { + template + constexpr auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + constexpr auto format(const ::sus::marker::EmptyMarker&, + FormatContext& ctx) const { + return fmt::format_to(ctx.out(), "empty"); + } +}; + namespace sus::marker { /// A marker that designates emptinesss, for constructing an empty collection. @@ -31,6 +50,9 @@ struct EmptyMarker { /// $sus::marker::empty). /// #[doc.hidden] explicit consteval EmptyMarker() {} + + // Stream support. + _sus_format_to_stream(EmptyMarker) }; /// The global [`EmptyMarker`]($sus::marker::EmptyMarker) which can be passed to @@ -40,24 +62,6 @@ constexpr inline auto empty = EmptyMarker(); } // namespace sus::marker -// fmt support. -template -struct fmt::formatter<::sus::marker::EmptyMarker, Char> { - template - constexpr auto parse(ParseContext& ctx) { - return ctx.begin(); - } - - template - constexpr auto format(const ::sus::marker::EmptyMarker&, - FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "empty"); - } -}; - -// Stream support. -_sus_format_to_stream(sus::marker, EmptyMarker); - // Promote `empty` into the `sus` namespace. namespace sus { using sus::marker::empty; diff --git a/sus/marker/unsafe.h b/sus/marker/unsafe.h index c71ff59f2..075417f5d 100644 --- a/sus/marker/unsafe.h +++ b/sus/marker/unsafe.h @@ -22,9 +22,26 @@ namespace sus { /// Marker types, such as for accessing unsafe APIs, for overload resolution, /// or type elision. -namespace marker {} +namespace marker { + struct UnsafeFnMarker; +} } // namespace sus +// fmt support. +template +struct fmt::formatter<::sus::marker::UnsafeFnMarker, Char> { + template + constexpr auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + constexpr auto format(const ::sus::marker::UnsafeFnMarker&, + FormatContext& ctx) const { + return fmt::format_to(ctx.out(), "unsafe_fn"); + } +}; + namespace sus::marker { /// A marker that designates a function as unsafe, or containing Undefined @@ -51,6 +68,9 @@ struct UnsafeFnMarker { /// $sus::marker::unsafe_fn). /// #[doc.hidden] explicit consteval UnsafeFnMarker() {} + + // Stream support. + _sus_format_to_stream(UnsafeFnMarker) }; /// The global [`UnsafeFnMarker`]($sus::marker::UnsafeFnMarker) which can be @@ -59,21 +79,3 @@ struct UnsafeFnMarker { constexpr inline auto unsafe_fn = UnsafeFnMarker(); } // namespace sus::marker - -// fmt support. -template -struct fmt::formatter<::sus::marker::UnsafeFnMarker, Char> { - template - constexpr auto parse(ParseContext& ctx) { - return ctx.begin(); - } - - template - constexpr auto format(const ::sus::marker::UnsafeFnMarker&, - FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "unsafe_fn"); - } -}; - -// Stream support. -_sus_format_to_stream(sus::marker, UnsafeFnMarker); diff --git a/sus/num/__private/float_methods.inc b/sus/num/__private/float_methods.inc index 06e611dfa..9ac195503 100644 --- a/sus/num/__private/float_methods.inc +++ b/sus/num/__private/float_methods.inc @@ -1157,6 +1157,9 @@ _sus_pure static _self from_ne_bytes( const ::sus::collections::Array()>& bytes) noexcept; +// Stream support. +_sus_format_to_stream(_self) + #undef _self #undef _primitive #undef _unsigned diff --git a/sus/num/__private/float_methods_impl.inc b/sus/num/__private/float_methods_impl.inc index 039d81e23..7553d73a6 100644 --- a/sus/num/__private/float_methods_impl.inc +++ b/sus/num/__private/float_methods_impl.inc @@ -95,9 +95,6 @@ struct fmt::formatter<::sus::num::_self, Char> { formatter<_primitive, Char> underlying_; }; -// Stream support. -_sus_format_to_stream(sus::num, _self); - #undef _self #undef _primitive #undef _unsigned diff --git a/sus/num/__private/signed_integer_methods.inc b/sus/num/__private/signed_integer_methods.inc index 8c4a6f506..f27b1b4c8 100644 --- a/sus/num/__private/signed_integer_methods.inc +++ b/sus/num/__private/signed_integer_methods.inc @@ -2083,6 +2083,9 @@ _sus_pure static constexpr _self from_ne_bytes( const ::sus::collections::Array()>& bytes) noexcept; +// Stream support. +_sus_format_to_stream(_self) + #undef _self #undef _primitive #undef _unsigned diff --git a/sus/num/__private/signed_integer_methods_impl.inc b/sus/num/__private/signed_integer_methods_impl.inc index 2486aea43..5e341af61 100644 --- a/sus/num/__private/signed_integer_methods_impl.inc +++ b/sus/num/__private/signed_integer_methods_impl.inc @@ -265,9 +265,6 @@ struct fmt::formatter<::sus::num::_self, Char> { formatter<_primitive, Char> underlying_; }; -// Stream support. -_sus_format_to_stream(sus::num, _self); - #undef _self #undef _primitive #undef _unsigned diff --git a/sus/num/__private/unsigned_integer_methods.inc b/sus/num/__private/unsigned_integer_methods.inc index 0ee1408d6..9ba668c1c 100644 --- a/sus/num/__private/unsigned_integer_methods.inc +++ b/sus/num/__private/unsigned_integer_methods.inc @@ -2114,39 +2114,27 @@ _sus_pure constexpr _self wrapping_sub(U rhs) const& noexcept { /// Returns the number of ones in the binary representation of the current /// value. -_sus_pure constexpr u32 count_ones() const& noexcept { - return __private::count_ones(primitive_value); -} +_sus_pure constexpr u32 count_ones() const& noexcept; /// Returns the number of zeros in the binary representation of the current /// value. -_sus_pure constexpr u32 count_zeros() const& noexcept { - return (~(*this)).count_ones(); -} +_sus_pure constexpr u32 count_zeros() const& noexcept; /// Returns the number of leading ones in the binary representation of the /// current value. -_sus_pure constexpr u32 leading_ones() const& noexcept { - return (~(*this)).leading_zeros(); -} +_sus_pure constexpr u32 leading_ones() const& noexcept; /// Returns the number of leading zeros in the binary representation of the /// current value. -_sus_pure constexpr u32 leading_zeros() const& noexcept { - return __private::leading_zeros(primitive_value); -} +_sus_pure constexpr u32 leading_zeros() const& noexcept; /// Returns the number of trailing ones in the binary representation of the /// current value. -_sus_pure constexpr u32 trailing_ones() const& noexcept { - return (~(*this)).trailing_zeros(); -} +_sus_pure constexpr u32 trailing_ones() const& noexcept; /// Returns the number of trailing zeros in the binary representation of the /// current value. -_sus_pure constexpr u32 trailing_zeros() const& noexcept { - return __private::trailing_zeros(primitive_value); -} +_sus_pure constexpr u32 trailing_zeros() const& noexcept; /// Reverses the order of bits in the integer. The least significant bit becomes /// the most significant bit, second least-significant bit becomes second @@ -2181,15 +2169,7 @@ _sus_pure constexpr _self swap_bytes() const& noexcept { /// /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this /// behaviour. -_sus_pure constexpr _self pow(u32 rhs) const& noexcept { - const auto out = - __private::pow_with_overflow(primitive_value, rhs.primitive_value); - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(!out.overflow, - "attempt to multiply with overflow"); - } - return _self(out.value); -} +_sus_pure constexpr _self pow(u32 rhs) const& noexcept; /// Checked exponentiation. Computes [`pow`]($sus::num::@doc.self::pow), /// returning `None` if overflow occurred. @@ -2205,9 +2185,7 @@ _sus_pure constexpr ::sus::tuple_type::Tuple<_self, bool> overflowing_pow( /// Wrapping (modular) exponentiation. Computes [`pow`]( /// $sus::num::@doc.self::pow), wrapping around at the boundary of the type. -_sus_pure constexpr _self wrapping_pow(u32 exp) const& noexcept { - return _self(__private::wrapping_pow(primitive_value, exp.primitive_value)); -} +_sus_pure constexpr _self wrapping_pow(u32 exp) const& noexcept; /// Returns the base 2 logarithm of the number, rounded down. /// @@ -2273,9 +2251,7 @@ _sus_pure constexpr u32 log(U rhs) const& noexcept; #endif /// Returns `true` if and only if `self == 2^k` for some `k`. -_sus_pure constexpr bool is_power_of_two() const& noexcept { - return count_ones() == _self(_primitive{1u}); -} +_sus_pure constexpr bool is_power_of_two() const& noexcept; /// Calculates the smallest value greater than or equal to itself that is a /// multiple of `rhs`. @@ -2445,6 +2421,9 @@ to_ne_bytes() const& noexcept; const ::sus::collections::Array()>& bytes) noexcept; +// Stream support. +_sus_format_to_stream(_self) + #if _pointer /// Returns the address portion of the pointer. diff --git a/sus/num/__private/unsigned_integer_methods_impl.inc b/sus/num/__private/unsigned_integer_methods_impl.inc index 504f916fd..0f1507e57 100644 --- a/sus/num/__private/unsigned_integer_methods_impl.inc +++ b/sus/num/__private/unsigned_integer_methods_impl.inc @@ -748,6 +748,48 @@ _sus_pure constexpr _self _self::from_ne_bytes( return _self(val); } +_sus_pure constexpr u32 _self::count_ones() const& noexcept { + return __private::count_ones(primitive_value); +} + +_sus_pure constexpr u32 _self::count_zeros() const& noexcept { + return (~(*this)).count_ones(); +} + +_sus_pure constexpr u32 _self::leading_ones() const& noexcept { + return (~(*this)).leading_zeros(); +} + +_sus_pure constexpr u32 _self::leading_zeros() const& noexcept { + return __private::leading_zeros(primitive_value); +} + +_sus_pure constexpr u32 _self::trailing_ones() const& noexcept { + return (~(*this)).trailing_zeros(); +} + +_sus_pure constexpr u32 _self::trailing_zeros() const& noexcept { + return __private::trailing_zeros(primitive_value); +} + +_sus_pure constexpr _self _self::pow(u32 rhs) const& noexcept { + const auto out = + __private::pow_with_overflow(primitive_value, rhs.primitive_value); + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(!out.overflow, + "attempt to multiply with overflow"); + } + return _self(out.value); +} + +_sus_pure constexpr _self _self::wrapping_pow(u32 exp) const& noexcept { + return _self(__private::wrapping_pow(primitive_value, exp.primitive_value)); +} + +_sus_pure constexpr bool _self::is_power_of_two() const& noexcept { + return count_ones() == _self(_primitive{1u}); +} + } // namespace sus::num // std hash support. @@ -782,9 +824,6 @@ struct fmt::formatter<::sus::num::_self, Char> { formatter<_primitive, Char> underlying_; }; -// Stream support. -_sus_format_to_stream(sus::num, _self); - #undef _self #undef _primitive #undef _signed diff --git a/sus/num/signed_integer.h b/sus/num/signed_integer.h index a1cc1343a..8db569d2b 100644 --- a/sus/num/signed_integer.h +++ b/sus/num/signed_integer.h @@ -38,6 +38,7 @@ #include "sus/num/integer_concepts.h" #include "sus/num/try_from_int_error.h" #include "sus/num/unsigned_integer.h" +#include "sus/num/unsigned_integer_consts.h" #include "sus/option/option.h" #include "sus/ptr/copy.h" #include "sus/result/result.h" @@ -58,6 +59,43 @@ struct [[_sus_trivial_abi]] i32 final { #define _primitive int32_t #define _unsigned u32 #include "sus/num/__private/signed_integer_methods.inc" + + /// #[doc.overloads=signedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend i32 operator<<( + i32 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift left with overflow"); + return out.value; + } else { + return l.wrapping_shl(u64(r).primitive_value); + } + } + + /// #[doc.overloads=signedint.<<] + template + requires(!std::convertible_to) + constexpr friend i32 operator<<(i32 l, U r) noexcept = delete; + + /// #[doc.overloads=signedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend i32 operator>>( + i32 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift right with overflow"); + return out.value; + } else { + return l.wrapping_shr(u64(r).primitive_value); + } + } + /// #[doc.overloads=signedint.>>] + template + requires(!std::convertible_to) + constexpr friend i32 operator>>(i32 l, U r) noexcept = delete; }; #define _self i32 #define _primitive int32_t @@ -71,6 +109,74 @@ struct [[_sus_trivial_abi]] i8 final { #define _primitive int8_t #define _unsigned u8 #include "sus/num/__private/signed_integer_methods.inc" + + /// Satisfies the [`Shl`]($sus::num::Shl) concept for signed integers. + /// + /// This operation supports shifting with primitive signed or unsigned integers + /// that convert to the safe numeric, as well as enums. + /// However enum class is excluded as they require an explicit conversion to an + /// integer. + /// + /// Thus the bound is `std::convertible_to` (implicit conversion) instead of + /// `sus::construct::From` (explicit conversion). + /// + /// # Panics + /// This function will panic when `r` is not less than the number of bits in `l` + /// if overflow checks are enabled (they are by default) and will perform a + /// wrapping shift if overflow checks are disabled (not the default). + /// + /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this + /// behaviour. + /// + /// #[doc.overloads=signedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend i8 operator<<( + i8 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift left with overflow"); + return out.value; + } else { + return l.wrapping_shl(u64(r).primitive_value); + } + } + + /// #[doc.overloads=signedint.<<] + template + requires(!std::convertible_to) + constexpr friend i8 operator<<(i8 l, U r) noexcept = delete; + + /// Satisfies the [`Shr`]($sus::num::Shr) concept for signed integers. + /// + /// Performs sign extension, copying the sign bit to the right if its set. + /// + /// # Panics + /// This function will panic when `r` is not less than the number of bits in `l` + /// if overflow checks are enabled (they are by default) and will perform a + /// wrapping shift if overflow checks are disabled (not the default). + /// + /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this + /// behaviour. + /// + /// #[doc.overloads=signedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend i8 operator>>( + i8 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift right with overflow"); + return out.value; + } else { + return l.wrapping_shr(u64(r).primitive_value); + } + } + + /// #[doc.overloads=signedint.>>] + template + requires(!std::convertible_to) + constexpr friend i8 operator>>(i8 l, U r) noexcept = delete; }; #define _self i8 #define _primitive int8_t @@ -84,6 +190,41 @@ struct [[_sus_trivial_abi]] i16 final { #define _primitive int16_t #define _unsigned u16 #include "sus/num/__private/signed_integer_methods.inc" + + /// #[doc.overloads=signedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend i16 operator<<( + i16 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift left with overflow"); + return out.value; + } else { + return l.wrapping_shl(u64(r).primitive_value); + } + } + /// #[doc.overloads=signedint.<<] + template + requires(!std::convertible_to) + constexpr friend i16 operator<<(i16 l, U r) noexcept = delete; + /// #[doc.overloads=signedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend i16 operator>>( + i16 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift right with overflow"); + return out.value; + } else { + return l.wrapping_shr(u64(r).primitive_value); + } + } + /// #[doc.overloads=signedint.>>] + template + requires(!std::convertible_to) + constexpr friend i16 operator>>(i16 l, U r) noexcept = delete; }; #define _self i16 #define _primitive int16_t @@ -97,6 +238,44 @@ struct [[_sus_trivial_abi]] i64 final { #define _primitive int64_t #define _unsigned u64 #include "sus/num/__private/signed_integer_methods.inc" + + /// #[doc.overloads=signedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend i64 operator<<( + i64 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift left with overflow"); + return out.value; + } else { + return l.wrapping_shl(u64(r).primitive_value); + } + } + + /// #[doc.overloads=signedint.<<] + template + requires(!std::convertible_to) + constexpr friend i64 operator<<(i64 l, U r) noexcept = delete; + + /// #[doc.overloads=signedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend i64 operator>>( + i64 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift right with overflow"); + return out.value; + } else { + return l.wrapping_shr(u64(r).primitive_value); + } + } + + /// #[doc.overloads=signedint.>>] + template + requires(!std::convertible_to) + constexpr friend i64 operator>>(i64 l, U r) noexcept = delete; }; #define _self i64 #define _primitive int64_t @@ -121,61 +300,98 @@ struct [[_sus_trivial_abi]] isize final { #define _primitive ::sus::num::__private::addr_type<>::signed_type #define _unsigned usize #include "sus/num/__private/signed_integer_methods.inc" -}; -#define _self isize -#define _primitive ::sus::num::__private::addr_type<>::signed_type -#include "sus/num/__private/signed_integer_consts.inc" -/// Satisfies the [`Add`]($sus::num::Add) concept for pointers -/// (`T*`) with [`isize`]($sus::num::isize). -/// -/// Adds a [`isize`]($sus::num::isize) to a pointer, returning the resulting -/// pointer. -/// -/// #[doc.overloads=ptr.add.isize] -template - requires(std::constructible_from) -__sus_pure_const constexpr inline T* operator+(T* t, S offset) { - return t + ptrdiff_t{offset}; -} + /// #[doc.overloads=signedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend isize operator<<( + isize l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift left with overflow"); + return out.value; + } else { + return l.wrapping_shl(u64(r).primitive_value); + } + } -/// Satisfies the [`AddAssign`]($sus::num::AddAssign) concept for pointers -/// (`T*`) with [`isize`]($sus::num::isize). -/// -/// Adds a [`isize`]($sus::num::isize) to a referenced pointer, and returns -/// the input reference. -/// -/// #[doc.overloads=ptr.add.isize] -template -constexpr inline T*& operator+=(T*& t, isize offset) { - t += ptrdiff_t{offset}; - return t; -} + /// #[doc.overloads=signedint.<<] + template + requires(!std::convertible_to) + constexpr friend isize operator<<(isize l, U r) noexcept = delete; -/// Satisfies the [`Sub`]($sus::num::Sub) concept for pointers -/// (`T*`) with [`isize`]($sus::num::isize). -/// -/// Subtracts a [`isize`]($sus::num::isize) from a pointer, returning the -/// resulting pointer. -/// -/// #[doc.overloads=ptr.sub.isize] -template -__sus_pure_const constexpr inline T* operator-(T* t, isize offset) { - return t - ptrdiff_t{offset}; -} + /// #[doc.overloads=signedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend isize operator>>( + isize l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift right with overflow"); + return out.value; + } else { + return l.wrapping_shr(u64(r).primitive_value); + } + } -/// Satisfies the [`SubAssign`]($sus::num::SubAssign) concept for pointers -/// (`T*`) with [`isize`]($sus::num::isize). -/// -/// Subtracts a [`isize`]($sus::num::isize) from a referenced pointer, and -/// returns the input reference. -/// -/// #[doc.overloads=ptr.sub.isize] -template -constexpr inline T*& operator-=(T*& t, isize offset) { - t -= ptrdiff_t{offset}; - return t; -} + /// #[doc.overloads=signedint.>>] + template + requires(!std::convertible_to) + constexpr friend isize operator>>(isize l, U r) noexcept = delete; + + /// Satisfies the [`AddAssign`]($sus::num::AddAssign) concept for pointers + /// (`T*`) with [`isize`]($sus::num::isize). + /// + /// Adds a [`isize`]($sus::num::isize) to a referenced pointer, and returns + /// the input reference. + /// + /// #[doc.overloads=ptr.add.isize] + template + constexpr friend T*& operator+=(T*& t, isize offset) { + t += ptrdiff_t{offset}; + return t; + } + + /// Satisfies the [`Sub`]($sus::num::Sub) concept for pointers + /// (`T*`) with [`isize`]($sus::num::isize). + /// + /// Subtracts a [`isize`]($sus::num::isize) from a pointer, returning the + /// resulting pointer. + /// + /// #[doc.overloads=ptr.sub.isize] + template + __sus_pure_const constexpr friend T* operator-(T* t, isize offset) { + return t - ptrdiff_t{offset}; + } + + /// Satisfies the [`SubAssign`]($sus::num::SubAssign) concept for pointers + /// (`T*`) with [`isize`]($sus::num::isize). + /// + /// Subtracts a [`isize`]($sus::num::isize) from a referenced pointer, and + /// returns the input reference. + /// + /// #[doc.overloads=ptr.sub.isize] + template + constexpr friend T*& operator-=(T*& t, isize offset) { + t -= ptrdiff_t{offset}; + return t; + } + + /// Satisfies the [`Add`]($sus::num::Add) concept for pointers + /// (`T*`) with [`isize`]($sus::num::isize). + /// + /// Adds a [`isize`]($sus::num::isize) to a pointer, returning the resulting + /// pointer. + /// + /// #[doc.overloads=ptr.add.isize] + template + __sus_pure_const constexpr friend T* operator+(T* t, isize offset) { + return t + ptrdiff_t{offset}; + } +}; +#define _self isize +#define _primitive ::sus::num::__private::addr_type<>::signed_type +#include "sus/num/__private/signed_integer_consts.inc" /// Satisfies the [`Shl`]($sus::num::Shl) concept for signed primitive integers /// shifted by [`u64`]($sus::num::u64). @@ -212,208 +428,6 @@ template requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && !std::convertible_to) constexpr inline P operator>>(P l, U r) noexcept = delete; - -/// Satisfies the [`Shl`]($sus::num::Shl) concept for signed integers. -/// -/// This operation supports shifting with primitive signed or unsigned integers -/// that convert to the safe numeric, as well as enums. -/// However enum class is excluded as they require an explicit conversion to an -/// integer. -/// -/// Thus the bound is `std::convertible_to` (implicit conversion) instead of -/// `sus::construct::From` (explicit conversion). -/// -/// # Panics -/// This function will panic when `r` is not less than the number of bits in `l` -/// if overflow checks are enabled (they are by default) and will perform a -/// wrapping shift if overflow checks are disabled (not the default). -/// -/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this -/// behaviour. -/// -/// #[doc.overloads=signedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline i8 operator<<( - i8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.<<] -template - requires(!std::convertible_to) -constexpr inline i8 operator<<(i8 l, U r) noexcept = delete; -/// Satisfies the [`Shr`]($sus::num::Shr) concept for signed integers. -/// -/// Performs sign extension, copying the sign bit to the right if its set. -/// -/// # Panics -/// This function will panic when `r` is not less than the number of bits in `l` -/// if overflow checks are enabled (they are by default) and will perform a -/// wrapping shift if overflow checks are disabled (not the default). -/// -/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this -/// behaviour. -/// -/// #[doc.overloads=signedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline i8 operator>>( - i8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.>>] -template - requires(!std::convertible_to) -constexpr inline i8 operator>>(i8 l, U r) noexcept = delete; -/// #[doc.overloads=signedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline i16 operator<<( - i16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.<<] -template - requires(!std::convertible_to) -constexpr inline i16 operator<<(i16 l, U r) noexcept = delete; -/// #[doc.overloads=signedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline i16 operator>>( - i16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.>>] -template - requires(!std::convertible_to) -constexpr inline i16 operator>>(i16 l, U r) noexcept = delete; -/// #[doc.overloads=signedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline i32 operator<<( - i32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.<<] -template - requires(!std::convertible_to) -constexpr inline i32 operator<<(i32 l, U r) noexcept = delete; -/// #[doc.overloads=signedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline i32 operator>>( - i32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.>>] -template - requires(!std::convertible_to) -constexpr inline i32 operator>>(i32 l, U r) noexcept = delete; -/// #[doc.overloads=signedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline i64 operator<<( - i64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.<<] -template - requires(!std::convertible_to) -constexpr inline i64 operator<<(i64 l, U r) noexcept = delete; -/// #[doc.overloads=signedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline i64 operator>>( - i64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.>>] -template - requires(!std::convertible_to) -constexpr inline i64 operator>>(i64 l, U r) noexcept = delete; -/// #[doc.overloads=signedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline isize operator<<( - isize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.<<] -template - requires(!std::convertible_to) -constexpr inline isize operator<<(isize l, U r) noexcept = delete; -/// #[doc.overloads=signedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline isize operator>>( - isize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } -} -/// #[doc.overloads=signedint.>>] -template - requires(!std::convertible_to) -constexpr inline isize operator>>(isize l, U r) noexcept = delete; - } // namespace sus::num /// For writing [`i8`]($sus::num::i8) literals. diff --git a/sus/num/try_from_int_error.h b/sus/num/try_from_int_error.h index 01f5ae887..1c201aa9e 100644 --- a/sus/num/try_from_int_error.h +++ b/sus/num/try_from_int_error.h @@ -35,7 +35,9 @@ class TryFromIntError { _sus_pure constexpr Kind kind() const noexcept; /// Satisfies the [`Eq`]($sus::cmp::Eq) concept. - _sus_pure constexpr bool operator==(TryFromIntError rhs) const noexcept; + _sus_pure friend constexpr bool operator==(TryFromIntError lhs, TryFromIntError rhs) noexcept{ + return lhs.kind_ == rhs.kind_; +} private: enum Construct { CONSTRUCT }; diff --git a/sus/num/try_from_int_error_impl.h b/sus/num/try_from_int_error_impl.h index 092aed851..4d162acaa 100644 --- a/sus/num/try_from_int_error_impl.h +++ b/sus/num/try_from_int_error_impl.h @@ -35,11 +35,6 @@ _sus_pure constexpr TryFromIntError::Kind TryFromIntError::kind() return kind_; } -_sus_pure constexpr bool TryFromIntError::operator==( - TryFromIntError rhs) const noexcept { - return kind_ == rhs.kind_; -} - constexpr TryFromIntError::TryFromIntError(Construct, Kind k) noexcept : kind_(k) {} diff --git a/sus/num/unsigned_integer.h b/sus/num/unsigned_integer.h index 2aedc3721..f566460c5 100644 --- a/sus/num/unsigned_integer.h +++ b/sus/num/unsigned_integer.h @@ -46,6 +46,57 @@ namespace sus::num { // TODO: from_str_radix(). Need Result typ`e and Errors. +/// A 64-bit unsigned integer. +/// +/// See the [namespace level documentation]($sus::num) for more. +struct [[_sus_trivial_abi]] u64 final { +#define _self u64 +#define _pointer false +#define _pointer_sized +#define _primitive uint64_t +#define _signed i64 +#include "sus/num/__private/unsigned_integer_methods.inc" + + /// #[doc.overloads=unsignedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend u64 operator<<( + u64 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u64::BITS, "attempt to shift left with overflow"); + return u64( + __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); + } else { + return u64( + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.<<] + template + requires(!std::convertible_to) + constexpr friend u64 operator<<(u64 l, U r) noexcept = delete; + + /// #[doc.overloads=unsignedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend u64 operator>>( + u64 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u64::BITS, + "attempt to shift right with overflow"); + return u64( + __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); + } else { + return u64( + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.>>] + template + requires(!std::convertible_to) + constexpr friend u64 operator>>(u64 l, U r) noexcept = delete; +}; + /// A 32-bit unsigned integer. /// /// See the [namespace level documentation]($sus::num) for more. @@ -56,11 +107,46 @@ struct [[_sus_trivial_abi]] u32 final { #define _primitive uint32_t #define _signed i32 #include "sus/num/__private/unsigned_integer_methods.inc" + + /// #[doc.overloads=unsignedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend u32 operator<<( + u32 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u32::BITS, "attempt to shift left with overflow"); + return u32( + __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); + } else { + return u32( + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.<<] + template + requires(!std::convertible_to) + constexpr friend u32 operator<<(u32 l, U r) noexcept = delete; + + /// #[doc.overloads=unsignedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend u32 operator>>( + u32 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u32::BITS, + "attempt to shift right with overflow"); + return u32( + __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); + } else { + return u32( + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.>>] + template + requires(!std::convertible_to) + constexpr friend u32 operator>>(u32 l, U r) noexcept = delete; }; -#define _self u32 -#define _pointer false -#define _primitive uint32_t -#include "sus/num/__private/unsigned_integer_consts.inc" /// An 8-bit unsigned integer. /// @@ -72,11 +158,65 @@ struct [[_sus_trivial_abi]] u8 final { #define _primitive uint8_t #define _signed i8 #include "sus/num/__private/unsigned_integer_methods.inc" + + /// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned integers. + /// + /// # Panics + /// This function will panic when `r` is not less than the number of bits in `l` + /// if overflow checks are enabled (they are by default) and will perform a + /// wrapping shift if overflow checks are disabled (not the default). + /// + /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this + /// behaviour. + /// + /// #[doc.overloads=unsignedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend u8 operator<<( + u8 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u8::BITS, + "attempt to shift left with overflow"); + return u8( + __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); + } else { + return u8( + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + /// #[doc.overloads=unsignedint.<<] + template + requires(!std::convertible_to) + constexpr friend u8 operator<<(u8 l, U r) noexcept = delete; + + /// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned integers. + /// + /// # Panics + /// This function will panic when `r` is not less than the number of bits in `l` + /// if overflow checks are enabled (they are by default) and will perform a + /// wrapping shift if overflow checks are disabled (not the default). + /// + /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this + /// behaviour. + /// + /// #[doc.overloads=unsignedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend u8 operator>>( + u8 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u8::BITS, + "attempt to shift right with overflow"); + return u8( + __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); + } else { + return u8( + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + /// #[doc.overloads=unsignedint.>>] + template + requires(!std::convertible_to) + constexpr friend u8 operator>>(u8 l, U r) noexcept = delete; }; -#define _self u8 -#define _pointer false -#define _primitive uint8_t -#include "sus/num/__private/unsigned_integer_consts.inc" /// A 16-bit unsigned integer. /// @@ -88,27 +228,47 @@ struct [[_sus_trivial_abi]] u16 final { #define _primitive uint16_t #define _signed i16 #include "sus/num/__private/unsigned_integer_methods.inc" -}; -#define _self u16 -#define _pointer false -#define _primitive uint16_t -#include "sus/num/__private/unsigned_integer_consts.inc" -/// A 64-bit unsigned integer. -/// -/// See the [namespace level documentation]($sus::num) for more. -struct [[_sus_trivial_abi]] u64 final { -#define _self u64 -#define _pointer false -#define _pointer_sized -#define _primitive uint64_t -#define _signed i64 -#include "sus/num/__private/unsigned_integer_methods.inc" + /// #[doc.overloads=unsignedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend u16 operator<<( + u16 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u16::BITS, + "attempt to shift left with overflow"); + return u16( + __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); + } else { + return u16( + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.<<] + template + requires(!std::convertible_to) + constexpr friend u16 operator<<(u16 l, U r) noexcept = delete; + + /// #[doc.overloads=unsignedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend u16 operator>>( + u16 l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < u16::BITS, + "attempt to shift right with overflow"); + return u16( + __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); + } else { + return u16( + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.>>] + template + requires(!std::convertible_to) + constexpr friend u16 operator>>(u16 l, U r) noexcept = delete; }; -#define _self u64 -#define _pointer false -#define _primitive uint64_t -#include "sus/num/__private/unsigned_integer_consts.inc" /// An address-sized unsigned integer. /// @@ -135,12 +295,45 @@ struct [[_sus_trivial_abi]] usize final { ::sus::num::__private::ptr_type<::sus::mem::size_of()>::unsigned_type #define _signed isize #include "sus/num/__private/unsigned_integer_methods.inc" + + /// #[doc.overloads=unsignedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend usize operator<<( + usize l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < usize::BITS, "attempt to shift left with overflow"); + return usize( + __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); + } else { + return usize( + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.<<] + template + requires(!std::convertible_to) + constexpr friend usize operator<<(usize l, U r) noexcept = delete; + + /// #[doc.overloads=unsignedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend usize operator>>( + usize l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < usize::BITS, "attempt to shift right with overflow"); + return usize( + __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); + } else { + return usize( + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.>>] + template + requires(!std::convertible_to) + constexpr friend usize operator>>(usize l, U r) noexcept = delete; }; -#define _self usize -#define _pointer false -#define _primitive \ - ::sus::num::__private::ptr_type<::sus::mem::size_of()>::unsigned_type -#include "sus/num/__private/unsigned_integer_consts.inc" /// A pointer-sized unsigned integer. /// @@ -174,13 +367,45 @@ struct [[_sus_trivial_abi]] uptr final { ::sus::num::__private::ptr_type< \ ::sus::mem::size_of()>::unsigned_type #include "sus/num/__private/unsigned_integer_methods.inc" + + /// #[doc.overloads=unsignedint.<<] + [[nodiscard]] __sus_pure_const constexpr friend uptr operator<<( + uptr l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < uptr::BITS, "attempt to shift left with overflow"); + return uptr( + __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); + } else { + return uptr( + __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.<<] + template + requires(!std::convertible_to) + constexpr friend uptr operator<<(uptr l, U r) noexcept = delete; + + /// #[doc.overloads=unsignedint.>>] + [[nodiscard]] __sus_pure_const constexpr friend uptr operator>>( + uptr l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < uptr::BITS, "attempt to shift right with overflow"); + return uptr( + __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); + } else { + return uptr( + __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) + .value); + } + } + + /// #[doc.overloads=unsignedint.>>] + template + requires(!std::convertible_to) + constexpr friend uptr operator>>(uptr l, U r) noexcept = delete; }; -#define _self uptr -#define _pointer true -#define _primitive \ - ::sus::num::__private::ptr_type< \ - ::sus::mem::size_of()>::unsigned_type -#include "sus/num/__private/unsigned_integer_consts.inc" /// Satisfies the [`Add`]($sus::num::Add) concept for pointers /// (`T*`) with [`usize`]($sus::num::usize). @@ -267,238 +492,6 @@ template requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && !std::convertible_to) constexpr inline P operator>>(P l, U r) noexcept = delete; - -/// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned integers. -/// -/// # Panics -/// This function will panic when `r` is not less than the number of bits in `l` -/// if overflow checks are enabled (they are by default) and will perform a -/// wrapping shift if overflow checks are disabled (not the default). -/// -/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this -/// behaviour. -/// -/// #[doc.overloads=unsignedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline u8 operator<<( - u8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u8::BITS, - "attempt to shift left with overflow"); - return u8( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u8( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.<<] -template - requires(!std::convertible_to) -constexpr inline u8 operator<<(u8 l, U r) noexcept = delete; -/// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned integers. -/// -/// # Panics -/// This function will panic when `r` is not less than the number of bits in `l` -/// if overflow checks are enabled (they are by default) and will perform a -/// wrapping shift if overflow checks are disabled (not the default). -/// -/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this -/// behaviour. -/// -/// #[doc.overloads=unsignedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline u8 operator>>( - u8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u8::BITS, - "attempt to shift right with overflow"); - return u8( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u8( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.>>] -template - requires(!std::convertible_to) -constexpr inline u8 operator>>(u8 l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline u16 operator<<( - u16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u16::BITS, - "attempt to shift left with overflow"); - return u16( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u16( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.<<] -template - requires(!std::convertible_to) -constexpr inline u16 operator<<(u16 l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline u16 operator>>( - u16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u16::BITS, - "attempt to shift right with overflow"); - return u16( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u16( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.>>] -template - requires(!std::convertible_to) -constexpr inline u16 operator>>(u16 l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline u32 operator<<( - u32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u32::BITS, "attempt to shift left with overflow"); - return u32( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u32( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.<<] -template - requires(!std::convertible_to) -constexpr inline u32 operator<<(u32 l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline u32 operator>>( - u32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u32::BITS, - "attempt to shift right with overflow"); - return u32( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u32( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.>>] -template - requires(!std::convertible_to) -constexpr inline u32 operator>>(u32 l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline u64 operator<<( - u64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u64::BITS, "attempt to shift left with overflow"); - return u64( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u64( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.<<] -template - requires(!std::convertible_to) -constexpr inline u64 operator<<(u64 l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline u64 operator>>( - u64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u64::BITS, - "attempt to shift right with overflow"); - return u64( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u64( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.>>] -template - requires(!std::convertible_to) -constexpr inline u64 operator>>(u64 l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline usize operator<<( - usize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < usize::BITS, "attempt to shift left with overflow"); - return usize( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return usize( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.<<] -template - requires(!std::convertible_to) -constexpr inline usize operator<<(usize l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline usize operator>>( - usize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < usize::BITS, "attempt to shift right with overflow"); - return usize( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return usize( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.>>] -template - requires(!std::convertible_to) -constexpr inline usize operator>>(usize l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.<<] -[[nodiscard]] __sus_pure_const constexpr inline uptr operator<<( - uptr l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < uptr::BITS, "attempt to shift left with overflow"); - return uptr( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return uptr( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.<<] -template - requires(!std::convertible_to) -constexpr inline uptr operator<<(uptr l, U r) noexcept = delete; -/// #[doc.overloads=unsignedint.>>] -[[nodiscard]] __sus_pure_const constexpr inline uptr operator>>( - uptr l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < uptr::BITS, "attempt to shift right with overflow"); - return uptr( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return uptr( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); - } -} -/// #[doc.overloads=unsignedint.>>] -template - requires(!std::convertible_to) -constexpr inline uptr operator>>(uptr l, U r) noexcept = delete; - } // namespace sus::num /// For writing [`u8`]($sus::num::u8) literals. diff --git a/sus/num/unsigned_integer_consts.h b/sus/num/unsigned_integer_consts.h new file mode 100644 index 000000000..f431a3abb --- /dev/null +++ b/sus/num/unsigned_integer_consts.h @@ -0,0 +1,56 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// IWYU pragma: private, include "sus/num/types.h" +// IWYU pragma: friend "sus/.*" +#pragma once + +#include "sus/num/unsigned_integer.h" + +namespace sus::num { + +#define _self u32 +#define _pointer false +#define _primitive uint32_t +#include "sus/num/__private/unsigned_integer_consts.inc" + +#define _self u8 +#define _pointer false +#define _primitive uint8_t +#include "sus/num/__private/unsigned_integer_consts.inc" + +#define _self u16 +#define _pointer false +#define _primitive uint16_t +#include "sus/num/__private/unsigned_integer_consts.inc" + +#define _self u64 +#define _pointer false +#define _primitive uint64_t +#include "sus/num/__private/unsigned_integer_consts.inc" + +#define _self usize +#define _pointer false +#define _primitive \ + ::sus::num::__private::ptr_type<::sus::mem::size_of()>::unsigned_type +#include "sus/num/__private/unsigned_integer_consts.inc" + +#define _self uptr +#define _pointer true +#define _primitive \ + ::sus::num::__private::ptr_type< \ + ::sus::mem::size_of()>::unsigned_type +#include "sus/num/__private/unsigned_integer_consts.inc" + +} // namespace sus::num diff --git a/sus/num/unsigned_integer_impl.h b/sus/num/unsigned_integer_impl.h index bf0d718c7..79f27c4d5 100644 --- a/sus/num/unsigned_integer_impl.h +++ b/sus/num/unsigned_integer_impl.h @@ -60,3 +60,5 @@ #define _pointer 1 #define _primitive ::sus::num::__private::ptr_type<::sus::mem::size_of()>::unsigned_type #include "sus/num/__private/unsigned_integer_methods_impl.inc" + +#include "sus/num/unsigned_integer_consts.h" diff --git a/sus/ops/range.h b/sus/ops/range.h index 5de01c114..f50dd48b6 100644 --- a/sus/ops/range.h +++ b/sus/ops/range.h @@ -218,14 +218,17 @@ class Range final : public __private::RangeIter, T> { /// Compares two `Range` for equality, satisfying the [`Eq`]($sus::cmp::Eq) /// concept if `T` satisfies [`Eq`]($sus::cmp::Eq). - constexpr bool operator==(const Range& rhs) const noexcept + constexpr friend bool operator==(const Range& lhs, const Range& rhs) noexcept requires(::sus::cmp::Eq) { - return start == rhs.start && finish == rhs.finish; + return lhs.start == rhs.start && lhs.finish == rhs.finish; } sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn, decltype(start), decltype(finish)); + + // Stream support. + _sus_format_to_stream(Range) }; /// A range only bounded inclusively below (`start..`). @@ -299,14 +302,17 @@ class RangeFrom final : public __private::RangeFromIter, T> { } // sus::cmp::Eq trait - constexpr bool operator==(const RangeFrom& rhs) const noexcept + constexpr friend bool operator==(const RangeFrom& lhs, const RangeFrom& rhs) noexcept requires(::sus::cmp::Eq) { - return start == rhs.start; + return lhs.start == rhs.start; } sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn, decltype(start)); + + // Stream support. + _sus_format_to_stream(RangeFrom) }; /// A range only bounded exclusively above (`..end`). @@ -370,14 +376,17 @@ class RangeTo final { constexpr RangeTo end_at(T t) && noexcept { return RangeTo(::sus::move(t)); } // sus::cmp::Eq trait - constexpr bool operator==(const RangeTo& rhs) const noexcept + constexpr friend bool operator==(const RangeTo& lhs, const RangeTo& rhs) noexcept requires(::sus::cmp::Eq) { - return finish == rhs.finish; + return lhs.finish == rhs.finish; } sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn, decltype(finish)); + + // Stream support. + _sus_format_to_stream(RangeTo) }; /// An unbounded range (`..`). @@ -435,13 +444,16 @@ class [[_sus_trivial_abi]] RangeFull final { } // sus::cmp::Eq trait - constexpr bool operator==(const RangeFull& rhs) const noexcept + constexpr friend bool operator==(const RangeFull&, const RangeFull&) noexcept requires(::sus::cmp::Eq) { return true; } sus_class_trivially_relocatable(::sus::marker::unsafe_fn); + + // Stream support. + _sus_format_to_stream(RangeFull) }; /// Return a new Range that starts at `start` and ends at `end`. @@ -487,9 +499,6 @@ struct fmt::formatter<::sus::ops::Range, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::ops, Range, T); - // fmt support. template struct fmt::formatter<::sus::ops::RangeFrom, Char> { @@ -512,9 +521,6 @@ struct fmt::formatter<::sus::ops::RangeFrom, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::ops, RangeFrom, T); - // fmt support. template struct fmt::formatter<::sus::ops::RangeTo, Char> { @@ -537,9 +543,6 @@ struct fmt::formatter<::sus::ops::RangeTo, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::ops, RangeTo, T); - // fmt support. template struct fmt::formatter<::sus::ops::RangeFull, Char> { @@ -560,6 +563,3 @@ struct fmt::formatter<::sus::ops::RangeFull, Char> { private: ::sus::string::__private::AnyFormatter underlying_; }; - -// Stream support. -_sus_format_to_stream(sus::ops, RangeFull, T); diff --git a/sus/option/option.h b/sus/option/option.h index d60201395..bd0c136f4 100644 --- a/sus/option/option.h +++ b/sus/option/option.h @@ -365,7 +365,7 @@ namespace sus { /// another [`Option`]($sus::option::Option) as input, and produce an /// [`Option`]($sus::option::Option) as output. /// Only the [`and_that`]($sus::option::Option::and_that) -/// method can produce an [`Option`]($sus::option::Option) value having a +/// method can produce an [`Option`]($sus::option::Option) value having a /// different inner type `U` than [`Option`]($sus::option::Option). /// /// | method | self | input | output | @@ -1933,6 +1933,9 @@ class Option final { } } + // Stream support. + _sus_format_to_stream(Option) + private: template friend class Option; @@ -2097,9 +2100,6 @@ struct fmt::formatter<::sus::option::Option, Char> { ::sus::string::__private::AnyFormatter underlying_; }; -// Stream support. -_sus_format_to_stream(sus::option, Option, T); - // Promote Option and its enum values into the `sus` namespace. namespace sus { using ::sus::option::none; diff --git a/sus/ptr/nonnull.h b/sus/ptr/nonnull.h index 9b2316298..7f1d31c57 100644 --- a/sus/ptr/nonnull.h +++ b/sus/ptr/nonnull.h @@ -151,6 +151,25 @@ class [[_sus_trivial_abi]] NonNull { static_cast(ptr_)); } + /// Satisfies the [`Eq, NonNull>`]($sus::cmp::Eq) concept if the + /// pointers are comparable and thus satisfy `Eq` as well. + template + requires(::sus::cmp::Eq) + constexpr friend bool operator==(const NonNull& l, const NonNull& r) noexcept { + return l.as_ptr() == r.as_ptr(); + } + + /// Satisfies the [`StrongOrd>`]($sus::cmp::StrongOrd) concept if the + /// pointers are comparable and thus satisfy `StrongOrd` as well. + template + requires(::sus::cmp::StrongOrd) + constexpr friend std::strong_ordering operator<=>(const NonNull& l, const NonNull& r) noexcept { + return l.as_ptr() <=> r.as_ptr(); + } + + // Stream support. + _sus_format_to_stream(NonNull) + private: T* ptr_; @@ -166,24 +185,6 @@ class [[_sus_trivial_abi]] NonNull { : ptr_(nullptr) {} }; -/// Satisfies the [`Eq, NonNull>`]($sus::cmp::Eq) concept if the -/// pointers are comparable and thus satisfy `Eq` as well. -template - requires(::sus::cmp::Eq) -constexpr inline bool operator==(const NonNull& l, - const NonNull& r) noexcept { - return l.as_ptr() == r.as_ptr(); -} - -/// Satisfies the [`StrongOrd>`]($sus::cmp::StrongOrd) concept if the -/// pointers are comparable and thus satisfy `StrongOrd` as well. -template - requires(::sus::cmp::StrongOrd) -constexpr inline std::strong_ordering operator<=>( - const NonNull& l, const NonNull& r) noexcept { - return l.as_ptr() <=> r.as_ptr(); -} - } // namespace sus::ptr // fmt support. @@ -203,6 +204,3 @@ struct fmt::formatter<::sus::ptr::NonNull, Char> { private: formatter underlying_; }; - -// Stream support. -_sus_format_to_stream(sus::ptr, NonNull, T); diff --git a/sus/result/result.h b/sus/result/result.h index f120937b5..b452a1023 100644 --- a/sus/result/result.h +++ b/sus/result/result.h @@ -775,6 +775,7 @@ class [[nodiscard]] Result final { { return eq(l, r); } + template requires(VoidOrEq && ::sus::cmp::Eq) friend constexpr bool operator==(const Result& l, @@ -848,6 +849,9 @@ class [[nodiscard]] Result final { friend constexpr auto operator<=>(const Result& l, const Result& r) noexcept = delete; + // Stream support. + _sus_format_to_stream(Result) + private: template friend class Result; @@ -1141,9 +1145,6 @@ struct fmt::formatter<::sus::result::Result, Char> { ::sus::string::__private::AnyFormatter underlying_err_; }; -// Stream support. -_sus_format_to_stream(sus::result, Result, T, E); - namespace sus { using ::sus::result::Err; using ::sus::result::err; diff --git a/sus/string/__private/format_to_stream.h b/sus/string/__private/format_to_stream.h index 2a2fb3eb7..7a7e1cc23 100644 --- a/sus/string/__private/format_to_stream.h +++ b/sus/string/__private/format_to_stream.h @@ -16,6 +16,7 @@ // IWYU pragma: friend "sus/.*" #pragma once +#include #include #include @@ -23,25 +24,24 @@ #include "sus/macros/compiler.h" #include "sus/macros/for_each.h" -#if SUS_COMPILER_IS_GCC -#include -#endif namespace sus::string::__private { template concept ConvertibleFrom = std::convertible_to; -template -concept StreamCanReceiveString = requires(T& t, std::basic_string s) { - // Check ConvertibleFrom as std streams return std::basic_ostream&, which the - // input type `T&` is convertible to. The concept ordering means we want - // `ConvertibleFrom<..the output type.., T&>` to be true then. - { t << s } -> ConvertibleFrom; -}; +template +concept StreamCanReceiveString = + !std::same_as, std::remove_cvref_t> && + requires(T& t, const std::basic_string s) { + // Check ConvertibleFrom as std streams return std::basic_ostream&, which the + // input type `T&` is convertible to. The concept ordering means we want + // `ConvertibleFrom<..the output type.., T&>` to be true then. + { t << s } -> ConvertibleFrom; + }; /// Consumes the string `s` and streams it to the output stream `os`. -template S> +template S> S& format_to_stream(S& os, const std::basic_string& s) { os << s; return os; @@ -79,37 +79,20 @@ S& format_to_stream(S& os, const std::basic_string& s) { /// match. So we can revert back to the usual incantation then. // // clang-format off -#define _sus_format_to_stream(Namespace, Type, ...) \ - namespace Namespace { \ - using namespace ::sus::string::__private; \ - template< \ - _sus_for_each(_sus_format_to_stream_add_class, _sus_for_each_sep_comma, \ - __VA_ARGS__) __VA_OPT__(,) \ - /* Inserts `std::same_as Sus_ValueType` if required for GCC. */ \ - sus_if_gcc( \ - _sus_format_to_stream_parameter_concept##__VA_OPT__(_with_template)( \ - Type __VA_OPT__(<__VA_ARGS__>) \ - ) \ - ) \ - StreamCanReceiveString Sus_StreamType \ - > \ - /** Adaptor from fmt to streams. \ - * #[doc.hidden] */ \ - inline Sus_StreamType& operator<<( \ - Sus_StreamType& stream, \ - /* Uses `Sus_ValueType` as the type if required for GCC, or `Type`. */ \ - sus_if_gcc( \ - const \ - _sus_format_to_stream_parameter##__VA_OPT__(_with_template)( \ - Type __VA_OPT__(<__VA_ARGS__>) \ - ) \ - & value \ - ) \ - /* Uses `Type` unconditionally for non-GCC. */ \ - sus_if_not_gcc(const Type __VA_OPT__(<__VA_ARGS__>)& value) \ - ) { \ - static_assert(fmt::is_formattable)>::value); \ - return format_to_stream(stream, fmt::to_string(value)); \ - } \ - } +#define _sus_format_to_stream(Type) \ + template< \ + /* Inserts `std::same_as Sus_ValueType` if required for GCC. */ \ + sus_if_gcc( \ + _sus_format_to_stream_parameter_concept(Type) \ + ) \ + sus::string::__private::StreamCanReceiveString Sus_StreamType, \ + std::same_as U = Type \ + > \ + /** Adaptor from fmt to streams. \ + * #[doc.hidden] */ \ + friend Sus_StreamType& operator<<( \ + Sus_StreamType& stream, const U& value) { \ + static_assert(fmt::is_formattable::value); \ + return ::sus::string::__private::format_to_stream(stream, fmt::to_string(value)); \ + } \ // clang-format on diff --git a/sus/string/__private/format_to_stream_unittest.cc b/sus/string/__private/format_to_stream_unittest.cc index 279a8c4e8..21466f6af 100644 --- a/sus/string/__private/format_to_stream_unittest.cc +++ b/sus/string/__private/format_to_stream_unittest.cc @@ -25,7 +25,9 @@ #include "sus/tuple/tuple.h" namespace { -struct Streamable {}; +struct Streamable { + _sus_format_to_stream(Streamable) +}; } // namespace template <> @@ -41,8 +43,6 @@ struct fmt::formatter { } }; -_sus_format_to_stream(, Streamable); - namespace { TEST(FormatToStream, ToStringStream) { diff --git a/sus/tuple/tuple.h b/sus/tuple/tuple.h index 71654dee9..ef19d7927 100644 --- a/sus/tuple/tuple.h +++ b/sus/tuple/tuple.h @@ -252,18 +252,18 @@ class Tuple final { /// # Implementation Note /// The non-template overload allows tuple() marker types to convert to /// Tuple for comparison. - constexpr bool operator==(const Tuple& r) const& noexcept + constexpr friend bool operator==(const Tuple& l, const Tuple& r) noexcept requires((::sus::cmp::Eq && ... && ::sus::cmp::Eq)) { return __private::storage_eq( - storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); + l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } template requires(sizeof...(Us) == sizeof...(Ts) && (::sus::cmp::Eq && ... && ::sus::cmp::Eq)) - constexpr bool operator==(const Tuple& r) const& noexcept { + constexpr friend bool operator==(const Tuple& l, const Tuple& r) noexcept { return __private::storage_eq( - storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); + l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } /// Compares two Tuples. @@ -276,31 +276,32 @@ class Tuple final { /// Tuple for comparison. // // sus::cmp::StrongOrd> trait. - constexpr std::strong_ordering operator<=>(const Tuple& r) const& noexcept + constexpr friend std::strong_ordering operator<=>(const Tuple& l, const Tuple& r) noexcept requires((::sus::cmp::StrongOrd && ... && ::sus::cmp::StrongOrd)) { return __private::storage_cmp( - std::strong_ordering::equal, storage_, r.storage_, + std::strong_ordering::equal, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } template requires(sizeof...(Us) == sizeof...(Ts) && (::sus::cmp::StrongOrd && ... && ::sus::cmp::StrongOrd)) - constexpr std::strong_ordering operator<=>( - const Tuple& r) const& noexcept { + constexpr friend std::strong_ordering operator<=>( + const Tuple& l, + const Tuple& r) noexcept { return __private::storage_cmp( - std::strong_ordering::equal, storage_, r.storage_, + std::strong_ordering::equal, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } // sus::cmp::Ord> trait. - constexpr std::weak_ordering operator<=>(const Tuple& r) const& noexcept + constexpr friend std::weak_ordering operator<=>(const Tuple& l, const Tuple& r) noexcept requires(!(::sus::cmp::StrongOrd && ... && ::sus::cmp::StrongOrd) && (::sus::cmp::Ord && ... && ::sus::cmp::Ord)) { return __private::storage_cmp( - std::weak_ordering::equivalent, storage_, r.storage_, + std::weak_ordering::equivalent, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } template @@ -308,20 +309,21 @@ class Tuple final { !(::sus::cmp::StrongOrd && ... && ::sus::cmp::StrongOrd) && (::sus::cmp::Ord && ... && ::sus::cmp::Ord)) - constexpr std::weak_ordering operator<=>( - const Tuple& r) const& noexcept { + constexpr friend std::weak_ordering operator<=>( + const Tuple& l, + const Tuple& r) noexcept { return __private::storage_cmp( - std::weak_ordering::equivalent, storage_, r.storage_, + std::weak_ordering::equivalent, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } // sus::cmp::PartialOrd> trait. - constexpr std::partial_ordering operator<=>(const Tuple& r) const& noexcept + constexpr friend std::partial_ordering operator<=>(const Tuple& l, const Tuple& r) noexcept requires(!(::sus::cmp::Ord && ... && ::sus::cmp::Ord) && (::sus::cmp::PartialOrd && ... && ::sus::cmp::PartialOrd)) { return __private::storage_cmp( - std::partial_ordering::equivalent, storage_, r.storage_, + std::partial_ordering::equivalent, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } template @@ -329,10 +331,11 @@ class Tuple final { !(::sus::cmp::Ord && ... && ::sus::cmp::Ord) && (::sus::cmp::PartialOrd && ... && ::sus::cmp::PartialOrd)) - constexpr std::partial_ordering operator<=>( - const Tuple& r) const& noexcept { + constexpr friend std::partial_ordering operator<=>( + const Tuple& l, + const Tuple& r) noexcept { return __private::storage_cmp( - std::partial_ordering::equivalent, storage_, r.storage_, + std::partial_ordering::equivalent, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } @@ -374,6 +377,8 @@ class Tuple final { } } + _sus_format_to_stream(Tuple) + private: template friend class Tuple; @@ -578,17 +583,6 @@ struct fmt::formatter<::sus::tuple_type::Tuple, Char> { } }; -// Stream support (written out manually due to use of template pack). -namespace sus::tuple_type { -template StreamType> -inline StreamType& operator<<(StreamType& stream, - const Tuple& value) { - return ::sus::string::__private::format_to_stream(stream, - fmt::to_string(value)); -} -} // namespace sus::tuple_type - // Promote Tuple into the `sus` namespace. namespace sus { using ::sus::tuple_type::Tuple; From 2a0342c4cf0dcd4bd9a01f5606b68a789bbeb9dc Mon Sep 17 00:00:00 2001 From: Christopher Di Bella Date: Wed, 30 Apr 2025 20:05:01 +0000 Subject: [PATCH 2/5] applies clang-format --- sus/boxed/box.h | 2 +- sus/choice/choice.h | 3 +- sus/collections/array.h | 31 +++--- sus/collections/slice.h | 2 +- sus/collections/vec.h | 2 +- sus/env/var.h | 3 +- sus/iter/generator.h | 3 +- sus/iter/iterator_loop.h | 3 +- sus/iter/size_hint.h | 5 +- sus/iter/size_hint_impl.h | 8 +- sus/marker/empty.h | 4 +- sus/marker/unsafe.h | 4 +- sus/num/__private/float_methods.inc | 2 +- sus/num/__private/signed_integer_methods.inc | 2 +- .../__private/unsigned_integer_methods.inc | 2 +- .../unsigned_integer_methods_impl.inc | 3 +- sus/num/signed_integer.h | 60 +++++------ sus/num/try_from_int_error.h | 7 +- sus/num/unsigned_integer.h | 102 +++++++++--------- sus/num/unsigned_integer_impl.h | 2 +- sus/ops/range.h | 14 +-- sus/option/option.h | 2 +- sus/ptr/nonnull.h | 8 +- sus/result/result.h | 2 +- sus/string/__private/format_to_stream.h | 16 +-- .../__private/format_to_stream_unittest.cc | 2 +- sus/tuple/tuple.h | 23 ++-- 27 files changed, 167 insertions(+), 150 deletions(-) diff --git a/sus/boxed/box.h b/sus/boxed/box.h index 310e97418..bdd62ef3c 100644 --- a/sus/boxed/box.h +++ b/sus/boxed/box.h @@ -657,7 +657,7 @@ class [[_sus_trivial_abi]] Box final : public __private::BoxBase, T> { } // Stream support. - _sus_format_to_stream(Box) + _sus_format_to_stream(Box); private: enum FromPointer { FROM_POINTER }; diff --git a/sus/choice/choice.h b/sus/choice/choice.h index 4aeb27cbe..941af0605 100644 --- a/sus/choice/choice.h +++ b/sus/choice/choice.h @@ -911,7 +911,8 @@ class Choice<__private::TypeList, Tags...> final { delete; // Stream support - _sus_format_to_stream(Choice) + _sus_format_to_stream(Choice); + private: constexpr explicit Choice(IndexType i) noexcept : index_(i) {} diff --git a/sus/collections/array.h b/sus/collections/array.h index ec12820aa..a0ab9b93c 100644 --- a/sus/collections/array.h +++ b/sus/collections/array.h @@ -65,8 +65,8 @@ struct Storage final {}; namespace __private { template -constexpr bool array_cmp_impl(sus::cmp::Ordering auto& val, - const auto& l, const auto& r) noexcept { +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. @@ -77,13 +77,12 @@ constexpr bool array_cmp_impl(sus::cmp::Ordering auto& val, template constexpr auto array_cmp(sus::cmp::Ordering auto equal, const auto& l, - const auto& r, - std::index_sequence) noexcept { + const auto& r, std::index_sequence) noexcept { auto val = equal; (true && ... && (array_cmp_impl(val, l, r))); return val; } -} +} // namespace __private /// A collection of objects of type `T`, with a fixed size `N`. /// @@ -357,7 +356,8 @@ class Array final { /// Satisfies the [`Eq, Array>`]($sus::cmp::Eq) concept. template requires(::sus::cmp::Eq) - friend constexpr bool operator==(const Array& l, const Array& r) noexcept + friend constexpr bool operator==(const Array& l, + const Array& r) noexcept requires(::sus::cmp::Eq) { return l.eq_impl(r, std::make_index_sequence()); @@ -445,8 +445,8 @@ class Array final { /// #[doc.overloads=array.cmp.array] template requires(::sus::cmp::ExclusiveOrd) - constexpr friend std::weak_ordering operator<=>(const Array& l, - const Array& r) noexcept { + constexpr friend std::weak_ordering operator<=>( + const Array& l, const Array& r) noexcept { return __private::array_cmp(std::weak_ordering::equivalent, l, r, std::make_index_sequence()); } @@ -471,8 +471,8 @@ class Array final { /// #[doc.overloads=array.cmp.slice] template requires(::sus::cmp::ExclusiveStrongOrd) - constexpr friend std::strong_ordering operator<=>(const Array& l, - const Slice& r) noexcept { + constexpr friend std::strong_ordering operator<=>( + const Array& l, const Slice& r) noexcept { if (r.len() != N) return r.len() <=> N; return __private::array_cmp(std::strong_ordering::equivalent, l, r, std::make_index_sequence()); @@ -489,8 +489,8 @@ class Array final { /// #[doc.overloads=array.cmp.slice] template requires(::sus::cmp::ExclusivePartialOrd) - constexpr friend std::partial_ordering operator<=>(const Array& l, - const Slice& r) noexcept { + constexpr friend std::partial_ordering operator<=>( + const Array& l, const Slice& r) noexcept { if (r.len() != N) return r.len() <=> N; return __private::array_cmp(std::partial_ordering::equivalent, l, r, std::make_index_sequence()); @@ -517,8 +517,8 @@ class Array final { /// #[doc.overloads=array.cmp.slicemut] template requires(::sus::cmp::ExclusiveOrd) - constexpr friend std::weak_ordering operator<=>(const Array& l, - const SliceMut& r) noexcept { + constexpr friend std::weak_ordering operator<=>( + const Array& l, const SliceMut& r) noexcept { if (r.len() != N) return r.len() <=> N; return __private::array_cmp(std::weak_ordering::equivalent, l, r, std::make_index_sequence()); @@ -534,7 +534,8 @@ class Array final { } // Stream support - _sus_format_to_stream(Array) + _sus_format_to_stream(Array); + private: enum WithDefault { WITH_DEFAULT }; template diff --git a/sus/collections/slice.h b/sus/collections/slice.h index 6725aeca4..3da6943f3 100644 --- a/sus/collections/slice.h +++ b/sus/collections/slice.h @@ -249,7 +249,7 @@ class [[_sus_trivial_abi]] Slice final { } // Stream support. - _sus_format_to_stream(Slice) + _sus_format_to_stream(Slice); #define _ptr_expr data_ #define _len_expr len_ diff --git a/sus/collections/vec.h b/sus/collections/vec.h index 82054160d..90dd202c0 100644 --- a/sus/collections/vec.h +++ b/sus/collections/vec.h @@ -830,7 +830,7 @@ class Vec final { } // Stream support. - _sus_format_to_stream(Vec) + _sus_format_to_stream(Vec); #define _ptr_expr data_ #define _len_expr len_ diff --git a/sus/env/var.h b/sus/env/var.h index 46e5da020..193f0df38 100644 --- a/sus/env/var.h +++ b/sus/env/var.h @@ -36,7 +36,8 @@ struct VarError { Reason reason; /// Satisfies the [`Eq`]($sus::cmp::Eq) concept. - constexpr friend bool operator==(const VarError& lhs, const VarError& rhs) noexcept = default; + constexpr friend bool operator==(const VarError& lhs, + const VarError& rhs) noexcept = default; }; /// Fetches the environment variable `key` from the current process. diff --git a/sus/iter/generator.h b/sus/iter/generator.h index d15fb1d93..f267bd718 100644 --- a/sus/iter/generator.h +++ b/sus/iter/generator.h @@ -122,7 +122,8 @@ class [[nodiscard]] [[_sus_trivial_abi]] GeneratorLoop { constexpr GeneratorLoop(Generator& generator sus_lifetimebound) noexcept : generator_(generator) {} - constexpr friend bool operator==(const GeneratorLoop& l, + constexpr friend bool operator==( + const GeneratorLoop& l, const ::sus::iter::__private::IteratorEnd&) noexcept { return l.generator_.co_handle_.done(); } diff --git a/sus/iter/iterator_loop.h b/sus/iter/iterator_loop.h index 65762f929..9ff8c3cea 100644 --- a/sus/iter/iterator_loop.h +++ b/sus/iter/iterator_loop.h @@ -31,7 +31,8 @@ class [[nodiscard]] IteratorLoop final { constexpr IteratorLoop(Iter&& iter) noexcept : iter_(::sus::forward(iter)), item_(iter_.next()) {} - constexpr friend bool operator==(const IteratorLoop& x, __private::IteratorEnd) noexcept { + constexpr friend bool operator==(const IteratorLoop& x, + __private::IteratorEnd) noexcept { return x.item_.is_none(); } constexpr inline void operator++() & noexcept { item_ = iter_.next(); } diff --git a/sus/iter/size_hint.h b/sus/iter/size_hint.h index 6e82c1bb2..4ce4f1968 100644 --- a/sus/iter/size_hint.h +++ b/sus/iter/size_hint.h @@ -30,7 +30,7 @@ struct SizeHint { const SizeHint& rhs) noexcept = default; // Stream support. - _sus_format_to_stream(SizeHint) + _sus_format_to_stream(SizeHint); }; } // namespace sus::iter @@ -44,5 +44,6 @@ struct fmt::formatter<::sus::iter::SizeHint, Char> { } template - FormatContext::iterator format(const ::sus::iter::SizeHint& t, FormatContext& ctx) const; + FormatContext::iterator format(const ::sus::iter::SizeHint& t, + FormatContext& ctx) const; }; diff --git a/sus/iter/size_hint_impl.h b/sus/iter/size_hint_impl.h index 212b33bcb..9d6be1ae9 100644 --- a/sus/iter/size_hint_impl.h +++ b/sus/iter/size_hint_impl.h @@ -25,7 +25,7 @@ // fmt support. template template - FormatContext::iterator fmt::formatter<::sus::iter::SizeHint, Char>::format(const ::sus::iter::SizeHint& t, - FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "SizeHint({}, {})", t.lower, t.upper); - } +FormatContext::iterator fmt::formatter<::sus::iter::SizeHint, Char>::format( + const ::sus::iter::SizeHint& t, FormatContext& ctx) const { + return fmt::format_to(ctx.out(), "SizeHint({}, {})", t.lower, t.upper); +} diff --git a/sus/marker/empty.h b/sus/marker/empty.h index 4e546e26e..89445710c 100644 --- a/sus/marker/empty.h +++ b/sus/marker/empty.h @@ -20,7 +20,7 @@ #include "sus/string/__private/format_to_stream.h" namespace sus::marker { - struct EmptyMarker; +struct EmptyMarker; } // fmt support. @@ -52,7 +52,7 @@ struct EmptyMarker { explicit consteval EmptyMarker() {} // Stream support. - _sus_format_to_stream(EmptyMarker) + _sus_format_to_stream(EmptyMarker); }; /// The global [`EmptyMarker`]($sus::marker::EmptyMarker) which can be passed to diff --git a/sus/marker/unsafe.h b/sus/marker/unsafe.h index 075417f5d..9fe452240 100644 --- a/sus/marker/unsafe.h +++ b/sus/marker/unsafe.h @@ -23,7 +23,7 @@ namespace sus { /// Marker types, such as for accessing unsafe APIs, for overload resolution, /// or type elision. namespace marker { - struct UnsafeFnMarker; +struct UnsafeFnMarker; } } // namespace sus @@ -70,7 +70,7 @@ struct UnsafeFnMarker { explicit consteval UnsafeFnMarker() {} // Stream support. - _sus_format_to_stream(UnsafeFnMarker) + _sus_format_to_stream(UnsafeFnMarker); }; /// The global [`UnsafeFnMarker`]($sus::marker::UnsafeFnMarker) which can be diff --git a/sus/num/__private/float_methods.inc b/sus/num/__private/float_methods.inc index 9ac195503..33c007d42 100644 --- a/sus/num/__private/float_methods.inc +++ b/sus/num/__private/float_methods.inc @@ -1158,7 +1158,7 @@ _sus_pure static _self from_ne_bytes( bytes) noexcept; // Stream support. -_sus_format_to_stream(_self) +_sus_format_to_stream(_self); #undef _self #undef _primitive diff --git a/sus/num/__private/signed_integer_methods.inc b/sus/num/__private/signed_integer_methods.inc index f27b1b4c8..ebdbeffae 100644 --- a/sus/num/__private/signed_integer_methods.inc +++ b/sus/num/__private/signed_integer_methods.inc @@ -2084,7 +2084,7 @@ _sus_pure static constexpr _self from_ne_bytes( bytes) noexcept; // Stream support. -_sus_format_to_stream(_self) +_sus_format_to_stream(_self); #undef _self #undef _primitive diff --git a/sus/num/__private/unsigned_integer_methods.inc b/sus/num/__private/unsigned_integer_methods.inc index 9ba668c1c..2552742f5 100644 --- a/sus/num/__private/unsigned_integer_methods.inc +++ b/sus/num/__private/unsigned_integer_methods.inc @@ -2422,7 +2422,7 @@ to_ne_bytes() const& noexcept; bytes) noexcept; // Stream support. -_sus_format_to_stream(_self) +_sus_format_to_stream(_self); #if _pointer diff --git a/sus/num/__private/unsigned_integer_methods_impl.inc b/sus/num/__private/unsigned_integer_methods_impl.inc index 0f1507e57..d32c0492e 100644 --- a/sus/num/__private/unsigned_integer_methods_impl.inc +++ b/sus/num/__private/unsigned_integer_methods_impl.inc @@ -776,8 +776,7 @@ _sus_pure constexpr _self _self::pow(u32 rhs) const& noexcept { const auto out = __private::pow_with_overflow(primitive_value, rhs.primitive_value); if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(!out.overflow, - "attempt to multiply with overflow"); + sus_check_with_message(!out.overflow, "attempt to multiply with overflow"); } return _self(out.value); } diff --git a/sus/num/signed_integer.h b/sus/num/signed_integer.h index 8db569d2b..737b37cd5 100644 --- a/sus/num/signed_integer.h +++ b/sus/num/signed_integer.h @@ -64,10 +64,10 @@ struct [[_sus_trivial_abi]] i32 final { [[nodiscard]] __sus_pure_const constexpr friend i32 operator<<( i32 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); + "attempt to shift left with overflow"); return out.value; } else { return l.wrapping_shl(u64(r).primitive_value); @@ -83,10 +83,10 @@ struct [[_sus_trivial_abi]] i32 final { [[nodiscard]] __sus_pure_const constexpr friend i32 operator>>( i32 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return out.value; } else { return l.wrapping_shr(u64(r).primitive_value); @@ -132,10 +132,10 @@ struct [[_sus_trivial_abi]] i8 final { [[nodiscard]] __sus_pure_const constexpr friend i8 operator<<( i8 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); + "attempt to shift left with overflow"); return out.value; } else { return l.wrapping_shl(u64(r).primitive_value); @@ -163,10 +163,10 @@ struct [[_sus_trivial_abi]] i8 final { [[nodiscard]] __sus_pure_const constexpr friend i8 operator>>( i8 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return out.value; } else { return l.wrapping_shr(u64(r).primitive_value); @@ -195,10 +195,10 @@ struct [[_sus_trivial_abi]] i16 final { [[nodiscard]] __sus_pure_const constexpr friend i16 operator<<( i16 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); + "attempt to shift left with overflow"); return out.value; } else { return l.wrapping_shl(u64(r).primitive_value); @@ -212,10 +212,10 @@ struct [[_sus_trivial_abi]] i16 final { [[nodiscard]] __sus_pure_const constexpr friend i16 operator>>( i16 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return out.value; } else { return l.wrapping_shr(u64(r).primitive_value); @@ -243,10 +243,10 @@ struct [[_sus_trivial_abi]] i64 final { [[nodiscard]] __sus_pure_const constexpr friend i64 operator<<( i64 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); + "attempt to shift left with overflow"); return out.value; } else { return l.wrapping_shl(u64(r).primitive_value); @@ -262,10 +262,10 @@ struct [[_sus_trivial_abi]] i64 final { [[nodiscard]] __sus_pure_const constexpr friend i64 operator>>( i64 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return out.value; } else { return l.wrapping_shr(u64(r).primitive_value); @@ -305,10 +305,10 @@ struct [[_sus_trivial_abi]] isize final { [[nodiscard]] __sus_pure_const constexpr friend isize operator<<( isize l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); + "attempt to shift left with overflow"); return out.value; } else { return l.wrapping_shl(u64(r).primitive_value); @@ -324,10 +324,10 @@ struct [[_sus_trivial_abi]] isize final { [[nodiscard]] __sus_pure_const constexpr friend isize operator>>( isize l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value); + const auto out = __private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value); sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return out.value; } else { return l.wrapping_shr(u64(r).primitive_value); diff --git a/sus/num/try_from_int_error.h b/sus/num/try_from_int_error.h index 1c201aa9e..c1275c477 100644 --- a/sus/num/try_from_int_error.h +++ b/sus/num/try_from_int_error.h @@ -35,9 +35,10 @@ class TryFromIntError { _sus_pure constexpr Kind kind() const noexcept; /// Satisfies the [`Eq`]($sus::cmp::Eq) concept. - _sus_pure friend constexpr bool operator==(TryFromIntError lhs, TryFromIntError rhs) noexcept{ - return lhs.kind_ == rhs.kind_; -} + _sus_pure friend constexpr bool operator==(TryFromIntError lhs, + TryFromIntError rhs) noexcept { + return lhs.kind_ == rhs.kind_; + } private: enum Construct { CONSTRUCT }; diff --git a/sus/num/unsigned_integer.h b/sus/num/unsigned_integer.h index f566460c5..c2b853511 100644 --- a/sus/num/unsigned_integer.h +++ b/sus/num/unsigned_integer.h @@ -61,13 +61,14 @@ struct [[_sus_trivial_abi]] u64 final { [[nodiscard]] __sus_pure_const constexpr friend u64 operator<<( u64 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u64::BITS, "attempt to shift left with overflow"); + sus_check_with_message(r < u64::BITS, + "attempt to shift left with overflow"); return u64( __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); } else { - return u64( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u64(__private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -81,13 +82,13 @@ struct [[_sus_trivial_abi]] u64 final { u64 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { sus_check_with_message(r < u64::BITS, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return u64( __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); } else { - return u64( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u64(__private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -112,13 +113,14 @@ struct [[_sus_trivial_abi]] u32 final { [[nodiscard]] __sus_pure_const constexpr friend u32 operator<<( u32 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u32::BITS, "attempt to shift left with overflow"); + sus_check_with_message(r < u32::BITS, + "attempt to shift left with overflow"); return u32( __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); } else { - return u32( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u32(__private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -132,13 +134,13 @@ struct [[_sus_trivial_abi]] u32 final { u32 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { sus_check_with_message(r < u32::BITS, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return u32( __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); } else { - return u32( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u32(__private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -174,13 +176,13 @@ struct [[_sus_trivial_abi]] u8 final { u8 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { sus_check_with_message(r < u8::BITS, - "attempt to shift left with overflow"); + "attempt to shift left with overflow"); return u8( __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); } else { - return u8( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u8(__private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } /// #[doc.overloads=unsignedint.<<] @@ -203,13 +205,13 @@ struct [[_sus_trivial_abi]] u8 final { u8 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { sus_check_with_message(r < u8::BITS, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return u8( __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); } else { - return u8( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u8(__private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } /// #[doc.overloads=unsignedint.>>] @@ -234,13 +236,13 @@ struct [[_sus_trivial_abi]] u16 final { u16 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { sus_check_with_message(r < u16::BITS, - "attempt to shift left with overflow"); + "attempt to shift left with overflow"); return u16( __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); } else { - return u16( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u16(__private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -254,13 +256,13 @@ struct [[_sus_trivial_abi]] u16 final { u16 l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { sus_check_with_message(r < u16::BITS, - "attempt to shift right with overflow"); + "attempt to shift right with overflow"); return u16( __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); } else { - return u16( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return u16(__private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -300,13 +302,14 @@ struct [[_sus_trivial_abi]] usize final { [[nodiscard]] __sus_pure_const constexpr friend usize operator<<( usize l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < usize::BITS, "attempt to shift left with overflow"); + sus_check_with_message(r < usize::BITS, + "attempt to shift left with overflow"); return usize( __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); } else { - return usize( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return usize(__private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -319,13 +322,14 @@ struct [[_sus_trivial_abi]] usize final { [[nodiscard]] __sus_pure_const constexpr friend usize operator>>( usize l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < usize::BITS, "attempt to shift right with overflow"); + sus_check_with_message(r < usize::BITS, + "attempt to shift right with overflow"); return usize( __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); } else { - return usize( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return usize(__private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -372,13 +376,14 @@ struct [[_sus_trivial_abi]] uptr final { [[nodiscard]] __sus_pure_const constexpr friend uptr operator<<( uptr l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < uptr::BITS, "attempt to shift left with overflow"); + sus_check_with_message(r < uptr::BITS, + "attempt to shift left with overflow"); return uptr( __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); } else { - return uptr( - __private::shl_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return uptr(__private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } @@ -391,13 +396,14 @@ struct [[_sus_trivial_abi]] uptr final { [[nodiscard]] __sus_pure_const constexpr friend uptr operator>>( uptr l, std::convertible_to auto r) noexcept { if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < uptr::BITS, "attempt to shift right with overflow"); + sus_check_with_message(r < uptr::BITS, + "attempt to shift right with overflow"); return uptr( __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); } else { - return uptr( - __private::shr_with_overflow(l.primitive_value, u64(r).primitive_value) - .value); + return uptr(__private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); } } diff --git a/sus/num/unsigned_integer_impl.h b/sus/num/unsigned_integer_impl.h index 79f27c4d5..6c6a38f70 100644 --- a/sus/num/unsigned_integer_impl.h +++ b/sus/num/unsigned_integer_impl.h @@ -60,5 +60,5 @@ #define _pointer 1 #define _primitive ::sus::num::__private::ptr_type<::sus::mem::size_of()>::unsigned_type #include "sus/num/__private/unsigned_integer_methods_impl.inc" - +// Comment to prevent clang-format from deleting this line and sorting includes #include "sus/num/unsigned_integer_consts.h" diff --git a/sus/ops/range.h b/sus/ops/range.h index f50dd48b6..d0f25b474 100644 --- a/sus/ops/range.h +++ b/sus/ops/range.h @@ -228,7 +228,7 @@ class Range final : public __private::RangeIter, T> { decltype(start), decltype(finish)); // Stream support. - _sus_format_to_stream(Range) + _sus_format_to_stream(Range); }; /// A range only bounded inclusively below (`start..`). @@ -302,7 +302,8 @@ class RangeFrom final : public __private::RangeFromIter, T> { } // sus::cmp::Eq trait - constexpr friend bool operator==(const RangeFrom& lhs, const RangeFrom& rhs) noexcept + constexpr friend bool operator==(const RangeFrom& lhs, + const RangeFrom& rhs) noexcept requires(::sus::cmp::Eq) { return lhs.start == rhs.start; @@ -312,7 +313,7 @@ class RangeFrom final : public __private::RangeFromIter, T> { decltype(start)); // Stream support. - _sus_format_to_stream(RangeFrom) + _sus_format_to_stream(RangeFrom); }; /// A range only bounded exclusively above (`..end`). @@ -376,7 +377,8 @@ class RangeTo final { constexpr RangeTo end_at(T t) && noexcept { return RangeTo(::sus::move(t)); } // sus::cmp::Eq trait - constexpr friend bool operator==(const RangeTo& lhs, const RangeTo& rhs) noexcept + constexpr friend bool operator==(const RangeTo& lhs, + const RangeTo& rhs) noexcept requires(::sus::cmp::Eq) { return lhs.finish == rhs.finish; @@ -386,7 +388,7 @@ class RangeTo final { decltype(finish)); // Stream support. - _sus_format_to_stream(RangeTo) + _sus_format_to_stream(RangeTo); }; /// An unbounded range (`..`). @@ -453,7 +455,7 @@ class [[_sus_trivial_abi]] RangeFull final { sus_class_trivially_relocatable(::sus::marker::unsafe_fn); // Stream support. - _sus_format_to_stream(RangeFull) + _sus_format_to_stream(RangeFull); }; /// Return a new Range that starts at `start` and ends at `end`. diff --git a/sus/option/option.h b/sus/option/option.h index bd0c136f4..259908162 100644 --- a/sus/option/option.h +++ b/sus/option/option.h @@ -1934,7 +1934,7 @@ class Option final { } // Stream support. - _sus_format_to_stream(Option) + _sus_format_to_stream(Option); private: template diff --git a/sus/ptr/nonnull.h b/sus/ptr/nonnull.h index 7f1d31c57..ac4196050 100644 --- a/sus/ptr/nonnull.h +++ b/sus/ptr/nonnull.h @@ -155,7 +155,8 @@ class [[_sus_trivial_abi]] NonNull { /// pointers are comparable and thus satisfy `Eq` as well. template requires(::sus::cmp::Eq) - constexpr friend bool operator==(const NonNull& l, const NonNull& r) noexcept { + constexpr friend bool operator==(const NonNull& l, + const NonNull& r) noexcept { return l.as_ptr() == r.as_ptr(); } @@ -163,12 +164,13 @@ class [[_sus_trivial_abi]] NonNull { /// pointers are comparable and thus satisfy `StrongOrd` as well. template requires(::sus::cmp::StrongOrd) - constexpr friend std::strong_ordering operator<=>(const NonNull& l, const NonNull& r) noexcept { + constexpr friend std::strong_ordering operator<=>( + const NonNull& l, const NonNull& r) noexcept { return l.as_ptr() <=> r.as_ptr(); } // Stream support. - _sus_format_to_stream(NonNull) + _sus_format_to_stream(NonNull); private: T* ptr_; diff --git a/sus/result/result.h b/sus/result/result.h index b452a1023..445ea77fc 100644 --- a/sus/result/result.h +++ b/sus/result/result.h @@ -850,7 +850,7 @@ class [[nodiscard]] Result final { const Result& r) noexcept = delete; // Stream support. - _sus_format_to_stream(Result) + _sus_format_to_stream(Result); private: template diff --git a/sus/string/__private/format_to_stream.h b/sus/string/__private/format_to_stream.h index 7a7e1cc23..1cb59504d 100644 --- a/sus/string/__private/format_to_stream.h +++ b/sus/string/__private/format_to_stream.h @@ -24,7 +24,6 @@ #include "sus/macros/compiler.h" #include "sus/macros/for_each.h" - namespace sus::string::__private { template @@ -32,13 +31,13 @@ concept ConvertibleFrom = std::convertible_to; template concept StreamCanReceiveString = - !std::same_as, std::remove_cvref_t> && - requires(T& t, const std::basic_string s) { - // Check ConvertibleFrom as std streams return std::basic_ostream&, which the - // input type `T&` is convertible to. The concept ordering means we want - // `ConvertibleFrom<..the output type.., T&>` to be true then. - { t << s } -> ConvertibleFrom; - }; + !std::same_as, std::remove_cvref_t> && + requires(T& t, const std::basic_string s) { + // Check ConvertibleFrom as std streams return std::basic_ostream&, which the + // input type `T&` is convertible to. The concept ordering means we want + // `ConvertibleFrom<..the output type.., T&>` to be true then. + { t << s } -> ConvertibleFrom; + }; /// Consumes the string `s` and streams it to the output stream `os`. template S> @@ -95,4 +94,5 @@ S& format_to_stream(S& os, const std::basic_string& s) { static_assert(fmt::is_formattable::value); \ return ::sus::string::__private::format_to_stream(stream, fmt::to_string(value)); \ } \ + static_assert(true) // clang-format on diff --git a/sus/string/__private/format_to_stream_unittest.cc b/sus/string/__private/format_to_stream_unittest.cc index 21466f6af..1765a38a5 100644 --- a/sus/string/__private/format_to_stream_unittest.cc +++ b/sus/string/__private/format_to_stream_unittest.cc @@ -26,7 +26,7 @@ namespace { struct Streamable { - _sus_format_to_stream(Streamable) + _sus_format_to_stream(Streamable); }; } // namespace diff --git a/sus/tuple/tuple.h b/sus/tuple/tuple.h index ef19d7927..9188bd5a3 100644 --- a/sus/tuple/tuple.h +++ b/sus/tuple/tuple.h @@ -261,7 +261,8 @@ class Tuple final { template requires(sizeof...(Us) == sizeof...(Ts) && (::sus::cmp::Eq && ... && ::sus::cmp::Eq)) - constexpr friend bool operator==(const Tuple& l, const Tuple& r) noexcept { + constexpr friend bool operator==(const Tuple& l, + const Tuple& r) noexcept { return __private::storage_eq( l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } @@ -276,7 +277,8 @@ class Tuple final { /// Tuple for comparison. // // sus::cmp::StrongOrd> trait. - constexpr friend std::strong_ordering operator<=>(const Tuple& l, const Tuple& r) noexcept + constexpr friend std::strong_ordering operator<=>(const Tuple& l, + const Tuple& r) noexcept requires((::sus::cmp::StrongOrd && ... && ::sus::cmp::StrongOrd)) { return __private::storage_cmp( @@ -288,15 +290,15 @@ class Tuple final { (::sus::cmp::StrongOrd && ... && ::sus::cmp::StrongOrd)) constexpr friend std::strong_ordering operator<=>( - const Tuple& l, - const Tuple& r) noexcept { + const Tuple& l, const Tuple& r) noexcept { return __private::storage_cmp( std::strong_ordering::equal, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } // sus::cmp::Ord> trait. - constexpr friend std::weak_ordering operator<=>(const Tuple& l, const Tuple& r) noexcept + constexpr friend std::weak_ordering operator<=>(const Tuple& l, + const Tuple& r) noexcept requires(!(::sus::cmp::StrongOrd && ... && ::sus::cmp::StrongOrd) && (::sus::cmp::Ord && ... && ::sus::cmp::Ord)) { @@ -310,15 +312,15 @@ class Tuple final { ::sus::cmp::StrongOrd) && (::sus::cmp::Ord && ... && ::sus::cmp::Ord)) constexpr friend std::weak_ordering operator<=>( - const Tuple& l, - const Tuple& r) noexcept { + const Tuple& l, const Tuple& r) noexcept { return __private::storage_cmp( std::weak_ordering::equivalent, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); } // sus::cmp::PartialOrd> trait. - constexpr friend std::partial_ordering operator<=>(const Tuple& l, const Tuple& r) noexcept + constexpr friend std::partial_ordering operator<=>(const Tuple& l, + const Tuple& r) noexcept requires(!(::sus::cmp::Ord && ... && ::sus::cmp::Ord) && (::sus::cmp::PartialOrd && ... && ::sus::cmp::PartialOrd)) { @@ -332,8 +334,7 @@ class Tuple final { (::sus::cmp::PartialOrd && ... && ::sus::cmp::PartialOrd)) constexpr friend std::partial_ordering operator<=>( - const Tuple& l, - const Tuple& r) noexcept { + const Tuple& l, const Tuple& r) noexcept { return __private::storage_cmp( std::partial_ordering::equivalent, l.storage_, r.storage_, std::make_index_sequence<1u + sizeof...(Ts)>()); @@ -377,7 +378,7 @@ class Tuple final { } } - _sus_format_to_stream(Tuple) + _sus_format_to_stream(Tuple); private: template From ea928609def4bc23ef104d2f8decc4218d59382e Mon Sep 17 00:00:00 2001 From: Christopher Di Bella Date: Wed, 30 Apr 2025 22:07:04 +0000 Subject: [PATCH 3/5] should hopefully fix GCC CI --- sus/string/__private/format_to_stream.h | 32 +++++++++---------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/sus/string/__private/format_to_stream.h b/sus/string/__private/format_to_stream.h index 1cb59504d..5dc4b83ce 100644 --- a/sus/string/__private/format_to_stream.h +++ b/sus/string/__private/format_to_stream.h @@ -31,6 +31,7 @@ concept ConvertibleFrom = std::convertible_to; template concept StreamCanReceiveString = + /// Ensure that we don't accidentally recursively check `U`. !std::same_as, std::remove_cvref_t> && requires(T& t, const std::basic_string s) { // Check ConvertibleFrom as std streams return std::basic_ostream&, which the @@ -60,30 +61,19 @@ S& format_to_stream(S& os, const std::basic_string& s) { /// /// # Implementation Notes /// -/// The `Type` argument is encoded as a template argument for the GCC compiler -/// because it does not reject the overload when the `Type` does not match -/// otherwise, and then ends up recursively trying to solve -/// `StreamCanReceiveString`. On the first attempt to solve -/// `StreamCanReceiveString`, it tries to call this overload with -/// `std::string` which is *not* `Type` and yet it considers it a valid -/// overload, so it tries to again solve `StreamCanReceiveString` which -/// is now recursive. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99599. -/// -/// Actually it gets worse. If the `Type` has template parameters, we can't use -/// `std::same_as> Sus_ValueType` as the compiler can't -/// infer the `Params...` there, even though `Sus_ValueType` appears in the -/// parameter list. So we _have_ to put the real type in the parameter list. -/// But also in this case GCC does the same thing as the others and does not -/// include the function in the overload set if the non-concept type doesn't -/// match. So we can revert back to the usual incantation then. -// +/// The `U` template type parameter allows `_sus_format_to_stream` to be a +/// hidden friend when `Type` is not a class template. Directly using `Type` +/// means that the function is immediately instantiated, and we'll get a +/// compile-time error unless `fmt::formatter` is specialised before `Type`'s +/// definition, since `fmt::is_formattable` doesn't know it's a formattable type +/// at this point in the code. This isn't a problem for primary class templates, +/// but it is problematic for regular classes and full specialisations. Using a +/// dependent type `U` defers instantiation until `operator<<` is first used. +/// We need to constrain `U` to be the same type as `Type`, otherwise it will +/// be ambiguous as to which overload we want. // clang-format off #define _sus_format_to_stream(Type) \ template< \ - /* Inserts `std::same_as Sus_ValueType` if required for GCC. */ \ - sus_if_gcc( \ - _sus_format_to_stream_parameter_concept(Type) \ - ) \ sus::string::__private::StreamCanReceiveString Sus_StreamType, \ std::same_as U = Type \ > \ From 13c863d88594b5eb04ed12efbe5a2416a31191f0 Mon Sep 17 00:00:00 2001 From: Christopher Di Bella Date: Thu, 1 May 2025 22:18:00 +0000 Subject: [PATCH 4/5] includes `sus/iter/size_hint_impl.h` from `sus/num/types.h` Running an include tracer indicated that placing `size_hint_impl.h` in this header should prevent link-time errors when attempting to incidentally format `SizeHint`. --- sus/num/types.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sus/num/types.h b/sus/num/types.h index 3928916b8..849f80551 100644 --- a/sus/num/types.h +++ b/sus/num/types.h @@ -115,4 +115,8 @@ namespace num {} #include "sus/num/try_from_int_error_impl.h" #include "sus/num/unsigned_integer.h" #include "sus/num/unsigned_integer_impl.h" + +// Running an include tracer indicated that placing size_hint_impl.h in this +// header should fix link-time errors when attempting to format `SizeHint`. +#include "sus/iter/size_hint_impl.h" // IWYU pragma: end_exports From 438c0235c7d8181219b5a04488cbe476ff736327 Mon Sep 17 00:00:00 2001 From: Christopher Di Bella Date: Thu, 1 May 2025 23:20:08 +0000 Subject: [PATCH 5/5] makes all operators hidden friends --- sus/num/__private/signed_integer_methods.inc | 136 +++++++ .../__private/unsigned_integer_methods.inc | 112 ++++++ sus/num/signed_integer.h | 252 ------------ sus/num/unsigned_integer.h | 372 ++---------------- 4 files changed, 282 insertions(+), 590 deletions(-) diff --git a/sus/num/__private/signed_integer_methods.inc b/sus/num/__private/signed_integer_methods.inc index ebdbeffae..dc49cf938 100644 --- a/sus/num/__private/signed_integer_methods.inc +++ b/sus/num/__private/signed_integer_methods.inc @@ -2083,6 +2083,142 @@ _sus_pure static constexpr _self from_ne_bytes( const ::sus::collections::Array()>& bytes) noexcept; +/// Satisfies the [`Shl`]($sus::num::Shl) concept for signed integers. +/// +/// This operation supports shifting with primitive signed or unsigned integers +/// that convert to the safe numeric, as well as enums. +/// However enum class is excluded as they require an explicit conversion to an +/// integer. +/// +/// Thus the bound is `std::convertible_to` (implicit conversion) instead of +/// `sus::construct::From` (explicit conversion). +/// +/// # Panics +/// This function will panic when `r` is not less than the number of bits in `l` +/// if overflow checks are enabled (they are by default) and will perform a +/// wrapping shift if overflow checks are disabled (not the default). +/// +/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this +/// behaviour. +/// +/// #[doc.overloads=signedint.<<] +[[nodiscard]] __sus_pure_const constexpr friend _self operator<<( + _self l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = __private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift left with overflow"); + return out.value; + } else { + return l.wrapping_shl(u64(r).primitive_value); + } +} + +/// #[doc.overloads=signedint.<<] +template + requires(!std::convertible_to) +constexpr friend _self operator<<(_self l, U r) noexcept = delete; + +/// Satisfies the [`Shr`]($sus::num::Shr) concept for signed integers. +/// +/// Performs sign extension, copying the sign bit to the right if its set. +/// +/// # Panics +/// This function will panic when `r` is not less than the number of bits in `l` +/// if overflow checks are enabled (they are by default) and will perform a +/// wrapping shift if overflow checks are disabled (not the default). +/// +/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this +/// behaviour. +/// +/// #[doc.overloads=signedint.>>] +[[nodiscard]] __sus_pure_const constexpr friend _self operator>>( + _self l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + const auto out = __private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value); + sus_check_with_message(!out.overflow, + "attempt to shift right with overflow"); + return out.value; + } else { + return l.wrapping_shr(u64(r).primitive_value); + } +} + +/// #[doc.overloads=signedint.>>] +template + requires(!std::convertible_to) +constexpr friend _self operator>>(_self l, U r) noexcept = delete; + +/// Satisfies the [`Shl`]($sus::num::Shl) concept for signed primitive integers +/// shifted by [`u64`]($sus::num::u64). +/// #[doc.overloads=signed.prim.< + requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && + std::same_as && std::convertible_to) +[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, U r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l << u64(r).primitive_value; +} +/// #[doc.overloads=signed.prim.< + requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && + std::same_as && !std::convertible_to) +constexpr friend P operator<<(P l, U r) noexcept = delete; + +/// Satisfies the [`Shr`]($sus::num::Shr) concept for signed primitive integers +/// shifted by [`u64`]($sus::num::u64). +/// +/// Performs sign extension, copying the sign bit to the right if its set. +/// #[doc.overloads=signed.prim.>>u64] +template + requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && + std::same_as && std::convertible_to) +[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, U r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l >> u64(r).primitive_value; +} +/// #[doc.overloads=signed.prim.>>u64] +template + requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && + std::same_as && !std::convertible_to) +constexpr friend P operator>>(P l, U r) noexcept = delete; + +/// #[doc.overloads=unsigned.prim.< + requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && + std::same_as && std::convertible_to) +[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, U r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l << u64(r).primitive_value; +} + +/// #[doc.overloads=unsigned.prim.< + requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && + std::same_as && !std::convertible_to) +constexpr friend P operator<<(P l, U r) noexcept = delete; + +/// #[doc.overloads=unsigned.prim.>>u64] +template + requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && + std::same_as && std::convertible_to) +[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, U r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l >> u64(r).primitive_value; +} + +/// #[doc.overloads=unsigned.prim.>>u64] +template + requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && + std::same_as && !std::convertible_to) +constexpr friend P operator>>(P l, U r) noexcept = delete; + // Stream support. _sus_format_to_stream(_self); diff --git a/sus/num/__private/unsigned_integer_methods.inc b/sus/num/__private/unsigned_integer_methods.inc index 2552742f5..6643a74f0 100644 --- a/sus/num/__private/unsigned_integer_methods.inc +++ b/sus/num/__private/unsigned_integer_methods.inc @@ -2424,6 +2424,118 @@ to_ne_bytes() const& noexcept; // Stream support. _sus_format_to_stream(_self); +/// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned integers. +/// +/// # Panics +/// This function will panic when `r` is not less than the number of bits in `l` +/// if overflow checks are enabled (they are by default) and will perform a +/// wrapping shift if overflow checks are disabled (not the default). +/// +/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this +/// behaviour. +/// +/// #[doc.overloads=unsignedint.<<] +[[nodiscard]] __sus_pure_const constexpr friend _self operator<<( + _self l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < _self::BITS, + "attempt to shift left with overflow"); + return _self( + __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); + } else { + return _self(__private::shl_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); + } +} + +/// #[doc.overloads=unsignedint.<<] +template + requires(!std::convertible_to) +constexpr friend _self operator<<(_self l, U r) noexcept = delete; + +/// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned integers. +/// +/// # Panics +/// This function will panic when `r` is not less than the number of bits in `l` +/// if overflow checks are enabled (they are by default) and will perform a +/// wrapping shift if overflow checks are disabled (not the default). +/// +/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this +/// behaviour. +/// +/// #[doc.overloads=unsignedint.>>] +[[nodiscard]] __sus_pure_const constexpr friend _self operator>>( + _self l, std::convertible_to auto r) noexcept { + if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { + sus_check_with_message(r < _self::BITS, + "attempt to shift right with overflow"); + return _self( + __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); + } else { + return _self(__private::shr_with_overflow(l.primitive_value, + u64(r).primitive_value) + .value); + } +} + +/// #[doc.overloads=unsignedint.>>] +template + requires(!std::convertible_to) +constexpr friend _self operator>>(_self l, U r) noexcept = delete; + +/// Satisfies the [`Add`]($sus::num::Add) concept for pointers +/// (`T*`) with [`usize`]($sus::num::usize). +/// +/// Adds a [`usize`]($sus::num::usize) to a pointer, returning the resulting +/// pointer. +/// +/// #[doc.overloads=ptr.add.usize] +template +__sus_pure_const constexpr friend T* operator+(T* t, _self offset) { + return t + size_t{offset}; +} + +/// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned primitive +/// integers shifted by [`u64`]($sus::num::u64). +/// #[doc.overloads=unsigned.prim.< + requires(UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) +[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, _self r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l << u64(r).primitive_value; +} + +/// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned primitive +/// integers shifted by [`u64`]($sus::num::u64). +/// #[doc.overloads=unsigned.prim.>>u64] +template + requires(UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) +[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, _self r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l >> u64(r).primitive_value; +} + +/// #[doc.overloads=signed.prim.< + requires(SignedPrimitiveInteger

|| SignedPrimitiveEnum

) +[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, _self r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l << u64(r).primitive_value; +} + +/// #[doc.overloads=signed.prim.>>u64] +template + requires(SignedPrimitiveInteger

|| SignedPrimitiveEnum

) +[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, _self r) noexcept { + // No UB checks on primitive types, since there's no promotion to a Subspace + // return type? + return l >> u64(r).primitive_value; +} + #if _pointer /// Returns the address portion of the pointer. diff --git a/sus/num/signed_integer.h b/sus/num/signed_integer.h index 737b37cd5..1be3d2857 100644 --- a/sus/num/signed_integer.h +++ b/sus/num/signed_integer.h @@ -59,43 +59,6 @@ struct [[_sus_trivial_abi]] i32 final { #define _primitive int32_t #define _unsigned u32 #include "sus/num/__private/signed_integer_methods.inc" - - /// #[doc.overloads=signedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend i32 operator<<( - i32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } - } - - /// #[doc.overloads=signedint.<<] - template - requires(!std::convertible_to) - constexpr friend i32 operator<<(i32 l, U r) noexcept = delete; - - /// #[doc.overloads=signedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend i32 operator>>( - i32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } - } - /// #[doc.overloads=signedint.>>] - template - requires(!std::convertible_to) - constexpr friend i32 operator>>(i32 l, U r) noexcept = delete; }; #define _self i32 #define _primitive int32_t @@ -109,74 +72,6 @@ struct [[_sus_trivial_abi]] i8 final { #define _primitive int8_t #define _unsigned u8 #include "sus/num/__private/signed_integer_methods.inc" - - /// Satisfies the [`Shl`]($sus::num::Shl) concept for signed integers. - /// - /// This operation supports shifting with primitive signed or unsigned integers - /// that convert to the safe numeric, as well as enums. - /// However enum class is excluded as they require an explicit conversion to an - /// integer. - /// - /// Thus the bound is `std::convertible_to` (implicit conversion) instead of - /// `sus::construct::From` (explicit conversion). - /// - /// # Panics - /// This function will panic when `r` is not less than the number of bits in `l` - /// if overflow checks are enabled (they are by default) and will perform a - /// wrapping shift if overflow checks are disabled (not the default). - /// - /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this - /// behaviour. - /// - /// #[doc.overloads=signedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend i8 operator<<( - i8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } - } - - /// #[doc.overloads=signedint.<<] - template - requires(!std::convertible_to) - constexpr friend i8 operator<<(i8 l, U r) noexcept = delete; - - /// Satisfies the [`Shr`]($sus::num::Shr) concept for signed integers. - /// - /// Performs sign extension, copying the sign bit to the right if its set. - /// - /// # Panics - /// This function will panic when `r` is not less than the number of bits in `l` - /// if overflow checks are enabled (they are by default) and will perform a - /// wrapping shift if overflow checks are disabled (not the default). - /// - /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this - /// behaviour. - /// - /// #[doc.overloads=signedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend i8 operator>>( - i8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } - } - - /// #[doc.overloads=signedint.>>] - template - requires(!std::convertible_to) - constexpr friend i8 operator>>(i8 l, U r) noexcept = delete; }; #define _self i8 #define _primitive int8_t @@ -190,41 +85,6 @@ struct [[_sus_trivial_abi]] i16 final { #define _primitive int16_t #define _unsigned u16 #include "sus/num/__private/signed_integer_methods.inc" - - /// #[doc.overloads=signedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend i16 operator<<( - i16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } - } - /// #[doc.overloads=signedint.<<] - template - requires(!std::convertible_to) - constexpr friend i16 operator<<(i16 l, U r) noexcept = delete; - /// #[doc.overloads=signedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend i16 operator>>( - i16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } - } - /// #[doc.overloads=signedint.>>] - template - requires(!std::convertible_to) - constexpr friend i16 operator>>(i16 l, U r) noexcept = delete; }; #define _self i16 #define _primitive int16_t @@ -238,44 +98,6 @@ struct [[_sus_trivial_abi]] i64 final { #define _primitive int64_t #define _unsigned u64 #include "sus/num/__private/signed_integer_methods.inc" - - /// #[doc.overloads=signedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend i64 operator<<( - i64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } - } - - /// #[doc.overloads=signedint.<<] - template - requires(!std::convertible_to) - constexpr friend i64 operator<<(i64 l, U r) noexcept = delete; - - /// #[doc.overloads=signedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend i64 operator>>( - i64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } - } - - /// #[doc.overloads=signedint.>>] - template - requires(!std::convertible_to) - constexpr friend i64 operator>>(i64 l, U r) noexcept = delete; }; #define _self i64 #define _primitive int64_t @@ -301,44 +123,6 @@ struct [[_sus_trivial_abi]] isize final { #define _unsigned usize #include "sus/num/__private/signed_integer_methods.inc" - /// #[doc.overloads=signedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend isize operator<<( - isize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift left with overflow"); - return out.value; - } else { - return l.wrapping_shl(u64(r).primitive_value); - } - } - - /// #[doc.overloads=signedint.<<] - template - requires(!std::convertible_to) - constexpr friend isize operator<<(isize l, U r) noexcept = delete; - - /// #[doc.overloads=signedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend isize operator>>( - isize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - const auto out = __private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value); - sus_check_with_message(!out.overflow, - "attempt to shift right with overflow"); - return out.value; - } else { - return l.wrapping_shr(u64(r).primitive_value); - } - } - - /// #[doc.overloads=signedint.>>] - template - requires(!std::convertible_to) - constexpr friend isize operator>>(isize l, U r) noexcept = delete; - /// Satisfies the [`AddAssign`]($sus::num::AddAssign) concept for pointers /// (`T*`) with [`isize`]($sus::num::isize). /// @@ -392,42 +176,6 @@ struct [[_sus_trivial_abi]] isize final { #define _self isize #define _primitive ::sus::num::__private::addr_type<>::signed_type #include "sus/num/__private/signed_integer_consts.inc" - -/// Satisfies the [`Shl`]($sus::num::Shl) concept for signed primitive integers -/// shifted by [`u64`]($sus::num::u64). -/// #[doc.overloads=signed.prim.< - requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && - std::convertible_to) -[[nodiscard]] __sus_pure_const constexpr inline P operator<<(P l, U r) noexcept { - // No UB checks on primitive types, since there's no promotion to a Subspace - // return type? - return l << u64(r).primitive_value; -} -/// #[doc.overloads=signed.prim.< - requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && - !std::convertible_to) -constexpr inline P operator<<(P l, U r) noexcept = delete; - -/// Satisfies the [`Shr`]($sus::num::Shr) concept for signed primitive integers -/// shifted by [`u64`]($sus::num::u64). -/// -/// Performs sign extension, copying the sign bit to the right if its set. -/// #[doc.overloads=signed.prim.>>u64] -template - requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && - std::convertible_to) -[[nodiscard]] __sus_pure_const constexpr inline P operator>>(P l, U r) noexcept { - // No UB checks on primitive types, since there's no promotion to a Subspace - // return type? - return l >> u64(r).primitive_value; -} -/// #[doc.overloads=signed.prim.>>u64] -template - requires((SignedPrimitiveInteger

|| SignedPrimitiveEnum

) && - !std::convertible_to) -constexpr inline P operator>>(P l, U r) noexcept = delete; } // namespace sus::num /// For writing [`i8`]($sus::num::i8) literals. diff --git a/sus/num/unsigned_integer.h b/sus/num/unsigned_integer.h index c2b853511..62b7d6b1e 100644 --- a/sus/num/unsigned_integer.h +++ b/sus/num/unsigned_integer.h @@ -56,46 +56,6 @@ struct [[_sus_trivial_abi]] u64 final { #define _primitive uint64_t #define _signed i64 #include "sus/num/__private/unsigned_integer_methods.inc" - - /// #[doc.overloads=unsignedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend u64 operator<<( - u64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u64::BITS, - "attempt to shift left with overflow"); - return u64( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u64(__private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.<<] - template - requires(!std::convertible_to) - constexpr friend u64 operator<<(u64 l, U r) noexcept = delete; - - /// #[doc.overloads=unsignedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend u64 operator>>( - u64 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u64::BITS, - "attempt to shift right with overflow"); - return u64( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u64(__private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.>>] - template - requires(!std::convertible_to) - constexpr friend u64 operator>>(u64 l, U r) noexcept = delete; }; /// A 32-bit unsigned integer. @@ -108,46 +68,6 @@ struct [[_sus_trivial_abi]] u32 final { #define _primitive uint32_t #define _signed i32 #include "sus/num/__private/unsigned_integer_methods.inc" - - /// #[doc.overloads=unsignedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend u32 operator<<( - u32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u32::BITS, - "attempt to shift left with overflow"); - return u32( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u32(__private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.<<] - template - requires(!std::convertible_to) - constexpr friend u32 operator<<(u32 l, U r) noexcept = delete; - - /// #[doc.overloads=unsignedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend u32 operator>>( - u32 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u32::BITS, - "attempt to shift right with overflow"); - return u32( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u32(__private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.>>] - template - requires(!std::convertible_to) - constexpr friend u32 operator>>(u32 l, U r) noexcept = delete; }; /// An 8-bit unsigned integer. @@ -160,64 +80,6 @@ struct [[_sus_trivial_abi]] u8 final { #define _primitive uint8_t #define _signed i8 #include "sus/num/__private/unsigned_integer_methods.inc" - - /// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned integers. - /// - /// # Panics - /// This function will panic when `r` is not less than the number of bits in `l` - /// if overflow checks are enabled (they are by default) and will perform a - /// wrapping shift if overflow checks are disabled (not the default). - /// - /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this - /// behaviour. - /// - /// #[doc.overloads=unsignedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend u8 operator<<( - u8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u8::BITS, - "attempt to shift left with overflow"); - return u8( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u8(__private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - /// #[doc.overloads=unsignedint.<<] - template - requires(!std::convertible_to) - constexpr friend u8 operator<<(u8 l, U r) noexcept = delete; - - /// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned integers. - /// - /// # Panics - /// This function will panic when `r` is not less than the number of bits in `l` - /// if overflow checks are enabled (they are by default) and will perform a - /// wrapping shift if overflow checks are disabled (not the default). - /// - /// See [overflow checks]($sus::num#overflow-behaviour) for controlling this - /// behaviour. - /// - /// #[doc.overloads=unsignedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend u8 operator>>( - u8 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u8::BITS, - "attempt to shift right with overflow"); - return u8( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u8(__private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - /// #[doc.overloads=unsignedint.>>] - template - requires(!std::convertible_to) - constexpr friend u8 operator>>(u8 l, U r) noexcept = delete; }; /// A 16-bit unsigned integer. @@ -230,46 +92,6 @@ struct [[_sus_trivial_abi]] u16 final { #define _primitive uint16_t #define _signed i16 #include "sus/num/__private/unsigned_integer_methods.inc" - - /// #[doc.overloads=unsignedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend u16 operator<<( - u16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u16::BITS, - "attempt to shift left with overflow"); - return u16( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return u16(__private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.<<] - template - requires(!std::convertible_to) - constexpr friend u16 operator<<(u16 l, U r) noexcept = delete; - - /// #[doc.overloads=unsignedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend u16 operator>>( - u16 l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < u16::BITS, - "attempt to shift right with overflow"); - return u16( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return u16(__private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.>>] - template - requires(!std::convertible_to) - constexpr friend u16 operator>>(u16 l, U r) noexcept = delete; }; /// An address-sized unsigned integer. @@ -298,45 +120,44 @@ struct [[_sus_trivial_abi]] usize final { #define _signed isize #include "sus/num/__private/unsigned_integer_methods.inc" - /// #[doc.overloads=unsignedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend usize operator<<( - usize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < usize::BITS, - "attempt to shift left with overflow"); - return usize( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return usize(__private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } + /// Satisfies the [`AddAssign`]($sus::num::AddAssign) concept for pointers + /// (`T*`) with [`usize`]($sus::num::usize). + /// + /// Adds a [`usize`]($sus::num::usize) to a referenced pointer, and returns the + /// input reference. + /// + /// #[doc.overloads=ptr.add.usize] + template + constexpr friend T*& operator+=(T*& t, usize offset) { + t += size_t{offset}; + return t; } - /// #[doc.overloads=unsignedint.<<] - template - requires(!std::convertible_to) - constexpr friend usize operator<<(usize l, U r) noexcept = delete; - - /// #[doc.overloads=unsignedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend usize operator>>( - usize l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < usize::BITS, - "attempt to shift right with overflow"); - return usize( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return usize(__private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } + /// Satisfies the [`Sub`]($sus::num::Sub) concept for pointers + /// (`T*`) with [`usize`]($sus::num::usize). + /// + /// Subtracts a [`usize`]($sus::num::usize) from a pointer, returning the + /// resulting pointer. + /// + /// #[doc.overloads=ptr.sub.usize] + template + __sus_pure_const constexpr friend T* operator-(T* t, usize offset) { + return t - size_t{offset}; } - /// #[doc.overloads=unsignedint.>>] - template - requires(!std::convertible_to) - constexpr friend usize operator>>(usize l, U r) noexcept = delete; + /// Satisfies the [`SubAssign`]($sus::num::SubAssign) concept for pointers + /// (`T*`) with [`usize`]($sus::num::usize). + /// + /// Subtracts a [`usize`]($sus::num::usize) from a referenced pointer, and + /// returns the input + /// reference. + /// + /// #[doc.overloads=ptr.sub.usize] + template + constexpr friend T*& operator-=(T*& t, usize offset) { + t -= size_t{offset}; + return t; + } }; /// A pointer-sized unsigned integer. @@ -371,133 +192,8 @@ struct [[_sus_trivial_abi]] uptr final { ::sus::num::__private::ptr_type< \ ::sus::mem::size_of()>::unsigned_type #include "sus/num/__private/unsigned_integer_methods.inc" - - /// #[doc.overloads=unsignedint.<<] - [[nodiscard]] __sus_pure_const constexpr friend uptr operator<<( - uptr l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < uptr::BITS, - "attempt to shift left with overflow"); - return uptr( - __private::unchecked_shl(l.primitive_value, u64(r).primitive_value)); - } else { - return uptr(__private::shl_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.<<] - template - requires(!std::convertible_to) - constexpr friend uptr operator<<(uptr l, U r) noexcept = delete; - - /// #[doc.overloads=unsignedint.>>] - [[nodiscard]] __sus_pure_const constexpr friend uptr operator>>( - uptr l, std::convertible_to auto r) noexcept { - if constexpr (SUS_CHECK_INTEGER_OVERFLOW) { - sus_check_with_message(r < uptr::BITS, - "attempt to shift right with overflow"); - return uptr( - __private::unchecked_shr(l.primitive_value, u64(r).primitive_value)); - } else { - return uptr(__private::shr_with_overflow(l.primitive_value, - u64(r).primitive_value) - .value); - } - } - - /// #[doc.overloads=unsignedint.>>] - template - requires(!std::convertible_to) - constexpr friend uptr operator>>(uptr l, U r) noexcept = delete; }; -/// Satisfies the [`Add`]($sus::num::Add) concept for pointers -/// (`T*`) with [`usize`]($sus::num::usize). -/// -/// Adds a [`usize`]($sus::num::usize) to a pointer, returning the resulting -/// pointer. -/// -/// #[doc.overloads=ptr.add.usize] -template - requires(std::constructible_from) -__sus_pure_const constexpr inline T* operator+(T* t, U offset) { - return t + size_t{offset}; -} - -/// Satisfies the [`AddAssign`]($sus::num::AddAssign) concept for pointers -/// (`T*`) with [`usize`]($sus::num::usize). -/// -/// Adds a [`usize`]($sus::num::usize) to a referenced pointer, and returns the -/// input reference. -/// -/// #[doc.overloads=ptr.add.usize] -template -constexpr inline T*& operator+=(T*& t, usize offset) { - t += size_t{offset}; - return t; -} - -/// Satisfies the [`Sub`]($sus::num::Sub) concept for pointers -/// (`T*`) with [`usize`]($sus::num::usize). -/// -/// Subtracts a [`usize`]($sus::num::usize) from a pointer, returning the -/// resulting pointer. -/// -/// #[doc.overloads=ptr.sub.usize] -template -__sus_pure_const constexpr inline T* operator-(T* t, usize offset) { - return t - size_t{offset}; -} - -/// Satisfies the [`SubAssign`]($sus::num::SubAssign) concept for pointers -/// (`T*`) with [`usize`]($sus::num::usize). -/// -/// Subtracts a [`usize`]($sus::num::usize) from a referenced pointer, and -/// returns the input -/// reference. -/// -/// #[doc.overloads=ptr.sub.usize] -template -constexpr inline T*& operator-=(T*& t, usize offset) { - t -= size_t{offset}; - return t; -} - -/// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned primitive -/// integers shifted by [`u64`]($sus::num::u64). -/// #[doc.overloads=unsigned.prim.< - requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && - std::convertible_to) -[[nodiscard]] __sus_pure_const constexpr inline P operator<<(P l, U r) noexcept { - // No UB checks on primitive types, since there's no promotion to a Subspace - // return type? - return l << u64(r).primitive_value; -} -/// #[doc.overloads=unsigned.prim.< - requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && - !std::convertible_to) -constexpr inline P operator<<(P l, U r) noexcept = delete; - -/// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned primitive -/// integers shifted by [`u64`]($sus::num::u64). -/// #[doc.overloads=unsigned.prim.>>u64] -template - requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && - std::convertible_to) -[[nodiscard]] __sus_pure_const constexpr inline P operator>>(P l, U r) noexcept { - // No UB checks on primitive types, since there's no promotion to a Subspace - // return type? - return l >> u64(r).primitive_value; -} -/// #[doc.overloads=unsigned.prim.>>u64] -template - requires((UnsignedPrimitiveInteger

|| UnsignedPrimitiveEnum

) && - !std::convertible_to) -constexpr inline P operator>>(P l, U r) noexcept = delete; } // namespace sus::num /// For writing [`u8`]($sus::num::u8) literals.