Skip to content

Commit 438c023

Browse files
committed
makes all operators hidden friends
1 parent 13c863d commit 438c023

File tree

4 files changed

+282
-590
lines changed

4 files changed

+282
-590
lines changed

sus/num/__private/signed_integer_methods.inc

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,142 @@ _sus_pure static constexpr _self from_ne_bytes(
20832083
const ::sus::collections::Array<u8, ::sus::mem::size_of<_primitive>()>&
20842084
bytes) noexcept;
20852085

2086+
/// Satisfies the [`Shl`]($sus::num::Shl) concept for signed integers.
2087+
///
2088+
/// This operation supports shifting with primitive signed or unsigned integers
2089+
/// that convert to the safe numeric, as well as enums.
2090+
/// However enum class is excluded as they require an explicit conversion to an
2091+
/// integer.
2092+
///
2093+
/// Thus the bound is `std::convertible_to` (implicit conversion) instead of
2094+
/// `sus::construct::From` (explicit conversion).
2095+
///
2096+
/// # Panics
2097+
/// This function will panic when `r` is not less than the number of bits in `l`
2098+
/// if overflow checks are enabled (they are by default) and will perform a
2099+
/// wrapping shift if overflow checks are disabled (not the default).
2100+
///
2101+
/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this
2102+
/// behaviour.
2103+
///
2104+
/// #[doc.overloads=signedint.<<]
2105+
[[nodiscard]] __sus_pure_const constexpr friend _self operator<<(
2106+
_self l, std::convertible_to<u64> auto r) noexcept {
2107+
if constexpr (SUS_CHECK_INTEGER_OVERFLOW) {
2108+
const auto out = __private::shl_with_overflow(l.primitive_value,
2109+
u64(r).primitive_value);
2110+
sus_check_with_message(!out.overflow,
2111+
"attempt to shift left with overflow");
2112+
return out.value;
2113+
} else {
2114+
return l.wrapping_shl(u64(r).primitive_value);
2115+
}
2116+
}
2117+
2118+
/// #[doc.overloads=signedint.<<]
2119+
template <class U>
2120+
requires(!std::convertible_to<U, u64>)
2121+
constexpr friend _self operator<<(_self l, U r) noexcept = delete;
2122+
2123+
/// Satisfies the [`Shr`]($sus::num::Shr) concept for signed integers.
2124+
///
2125+
/// Performs sign extension, copying the sign bit to the right if its set.
2126+
///
2127+
/// # Panics
2128+
/// This function will panic when `r` is not less than the number of bits in `l`
2129+
/// if overflow checks are enabled (they are by default) and will perform a
2130+
/// wrapping shift if overflow checks are disabled (not the default).
2131+
///
2132+
/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this
2133+
/// behaviour.
2134+
///
2135+
/// #[doc.overloads=signedint.>>]
2136+
[[nodiscard]] __sus_pure_const constexpr friend _self operator>>(
2137+
_self l, std::convertible_to<u64> auto r) noexcept {
2138+
if constexpr (SUS_CHECK_INTEGER_OVERFLOW) {
2139+
const auto out = __private::shr_with_overflow(l.primitive_value,
2140+
u64(r).primitive_value);
2141+
sus_check_with_message(!out.overflow,
2142+
"attempt to shift right with overflow");
2143+
return out.value;
2144+
} else {
2145+
return l.wrapping_shr(u64(r).primitive_value);
2146+
}
2147+
}
2148+
2149+
/// #[doc.overloads=signedint.>>]
2150+
template <class U>
2151+
requires(!std::convertible_to<U, u64>)
2152+
constexpr friend _self operator>>(_self l, U r) noexcept = delete;
2153+
2154+
/// Satisfies the [`Shl`]($sus::num::Shl) concept for signed primitive integers
2155+
/// shifted by [`u64`]($sus::num::u64).
2156+
/// #[doc.overloads=signed.prim.<<u64]
2157+
template <class P, class U>
2158+
requires((SignedPrimitiveInteger<P> || SignedPrimitiveEnum<P>) &&
2159+
std::same_as<U, _self> && std::convertible_to<U, u64>)
2160+
[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, U r) noexcept {
2161+
// No UB checks on primitive types, since there's no promotion to a Subspace
2162+
// return type?
2163+
return l << u64(r).primitive_value;
2164+
}
2165+
/// #[doc.overloads=signed.prim.<<u64]
2166+
template <class P, class U>
2167+
requires((SignedPrimitiveInteger<P> || SignedPrimitiveEnum<P>) &&
2168+
std::same_as<U, _self> && !std::convertible_to<U, u64>)
2169+
constexpr friend P operator<<(P l, U r) noexcept = delete;
2170+
2171+
/// Satisfies the [`Shr`]($sus::num::Shr) concept for signed primitive integers
2172+
/// shifted by [`u64`]($sus::num::u64).
2173+
///
2174+
/// Performs sign extension, copying the sign bit to the right if its set.
2175+
/// #[doc.overloads=signed.prim.>>u64]
2176+
template <class P, class U>
2177+
requires((SignedPrimitiveInteger<P> || SignedPrimitiveEnum<P>) &&
2178+
std::same_as<U, _self> && std::convertible_to<U, u64>)
2179+
[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, U r) noexcept {
2180+
// No UB checks on primitive types, since there's no promotion to a Subspace
2181+
// return type?
2182+
return l >> u64(r).primitive_value;
2183+
}
2184+
/// #[doc.overloads=signed.prim.>>u64]
2185+
template <class P, class U>
2186+
requires((SignedPrimitiveInteger<P> || SignedPrimitiveEnum<P>) &&
2187+
std::same_as<U, _self> && !std::convertible_to<U, u64>)
2188+
constexpr friend P operator>>(P l, U r) noexcept = delete;
2189+
2190+
/// #[doc.overloads=unsigned.prim.<<u64]
2191+
template <class P, class U>
2192+
requires((UnsignedPrimitiveInteger<P> || UnsignedPrimitiveEnum<P>) &&
2193+
std::same_as<U, _self> && std::convertible_to<U, u64>)
2194+
[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, U r) noexcept {
2195+
// No UB checks on primitive types, since there's no promotion to a Subspace
2196+
// return type?
2197+
return l << u64(r).primitive_value;
2198+
}
2199+
2200+
/// #[doc.overloads=unsigned.prim.<<u64]
2201+
template <class P, class U>
2202+
requires((UnsignedPrimitiveInteger<P> || UnsignedPrimitiveEnum<P>) &&
2203+
std::same_as<U, _self> && !std::convertible_to<U, u64>)
2204+
constexpr friend P operator<<(P l, U r) noexcept = delete;
2205+
2206+
/// #[doc.overloads=unsigned.prim.>>u64]
2207+
template <class P, class U>
2208+
requires((UnsignedPrimitiveInteger<P> || UnsignedPrimitiveEnum<P>) &&
2209+
std::same_as<U, _self> && std::convertible_to<U, u64>)
2210+
[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, U r) noexcept {
2211+
// No UB checks on primitive types, since there's no promotion to a Subspace
2212+
// return type?
2213+
return l >> u64(r).primitive_value;
2214+
}
2215+
2216+
/// #[doc.overloads=unsigned.prim.>>u64]
2217+
template <class P, class U>
2218+
requires((UnsignedPrimitiveInteger<P> || UnsignedPrimitiveEnum<P>) &&
2219+
std::same_as<U, _self> && !std::convertible_to<U, u64>)
2220+
constexpr friend P operator>>(P l, U r) noexcept = delete;
2221+
20862222
// Stream support.
20872223
_sus_format_to_stream(_self);
20882224

sus/num/__private/unsigned_integer_methods.inc

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,6 +2424,118 @@ to_ne_bytes() const& noexcept;
24242424
// Stream support.
24252425
_sus_format_to_stream(_self);
24262426

2427+
/// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned integers.
2428+
///
2429+
/// # Panics
2430+
/// This function will panic when `r` is not less than the number of bits in `l`
2431+
/// if overflow checks are enabled (they are by default) and will perform a
2432+
/// wrapping shift if overflow checks are disabled (not the default).
2433+
///
2434+
/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this
2435+
/// behaviour.
2436+
///
2437+
/// #[doc.overloads=unsignedint.<<]
2438+
[[nodiscard]] __sus_pure_const constexpr friend _self operator<<(
2439+
_self l, std::convertible_to<u64> auto r) noexcept {
2440+
if constexpr (SUS_CHECK_INTEGER_OVERFLOW) {
2441+
sus_check_with_message(r < _self::BITS,
2442+
"attempt to shift left with overflow");
2443+
return _self(
2444+
__private::unchecked_shl(l.primitive_value, u64(r).primitive_value));
2445+
} else {
2446+
return _self(__private::shl_with_overflow(l.primitive_value,
2447+
u64(r).primitive_value)
2448+
.value);
2449+
}
2450+
}
2451+
2452+
/// #[doc.overloads=unsignedint.<<]
2453+
template <class U>
2454+
requires(!std::convertible_to<U, u64>)
2455+
constexpr friend _self operator<<(_self l, U r) noexcept = delete;
2456+
2457+
/// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned integers.
2458+
///
2459+
/// # Panics
2460+
/// This function will panic when `r` is not less than the number of bits in `l`
2461+
/// if overflow checks are enabled (they are by default) and will perform a
2462+
/// wrapping shift if overflow checks are disabled (not the default).
2463+
///
2464+
/// See [overflow checks]($sus::num#overflow-behaviour) for controlling this
2465+
/// behaviour.
2466+
///
2467+
/// #[doc.overloads=unsignedint.>>]
2468+
[[nodiscard]] __sus_pure_const constexpr friend _self operator>>(
2469+
_self l, std::convertible_to<u64> auto r) noexcept {
2470+
if constexpr (SUS_CHECK_INTEGER_OVERFLOW) {
2471+
sus_check_with_message(r < _self::BITS,
2472+
"attempt to shift right with overflow");
2473+
return _self(
2474+
__private::unchecked_shr(l.primitive_value, u64(r).primitive_value));
2475+
} else {
2476+
return _self(__private::shr_with_overflow(l.primitive_value,
2477+
u64(r).primitive_value)
2478+
.value);
2479+
}
2480+
}
2481+
2482+
/// #[doc.overloads=unsignedint.>>]
2483+
template <class U>
2484+
requires(!std::convertible_to<U, u64>)
2485+
constexpr friend _self operator>>(_self l, U r) noexcept = delete;
2486+
2487+
/// Satisfies the [`Add`]($sus::num::Add) concept for pointers
2488+
/// (`T*`) with [`usize`]($sus::num::usize).
2489+
///
2490+
/// Adds a [`usize`]($sus::num::usize) to a pointer, returning the resulting
2491+
/// pointer.
2492+
///
2493+
/// #[doc.overloads=ptr.add.usize]
2494+
template <class T>
2495+
__sus_pure_const constexpr friend T* operator+(T* t, _self offset) {
2496+
return t + size_t{offset};
2497+
}
2498+
2499+
/// Satisfies the [`Shl`]($sus::num::Shl) concept for unsigned primitive
2500+
/// integers shifted by [`u64`]($sus::num::u64).
2501+
/// #[doc.overloads=unsigned.prim.<<u64]
2502+
template <class P>
2503+
requires(UnsignedPrimitiveInteger<P> || UnsignedPrimitiveEnum<P>)
2504+
[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, _self r) noexcept {
2505+
// No UB checks on primitive types, since there's no promotion to a Subspace
2506+
// return type?
2507+
return l << u64(r).primitive_value;
2508+
}
2509+
2510+
/// Satisfies the [`Shr`]($sus::num::Shr) concept for unsigned primitive
2511+
/// integers shifted by [`u64`]($sus::num::u64).
2512+
/// #[doc.overloads=unsigned.prim.>>u64]
2513+
template <class P>
2514+
requires(UnsignedPrimitiveInteger<P> || UnsignedPrimitiveEnum<P>)
2515+
[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, _self r) noexcept {
2516+
// No UB checks on primitive types, since there's no promotion to a Subspace
2517+
// return type?
2518+
return l >> u64(r).primitive_value;
2519+
}
2520+
2521+
/// #[doc.overloads=signed.prim.<<u64]
2522+
template <class P>
2523+
requires(SignedPrimitiveInteger<P> || SignedPrimitiveEnum<P>)
2524+
[[nodiscard]] __sus_pure_const constexpr friend P operator<<(P l, _self r) noexcept {
2525+
// No UB checks on primitive types, since there's no promotion to a Subspace
2526+
// return type?
2527+
return l << u64(r).primitive_value;
2528+
}
2529+
2530+
/// #[doc.overloads=signed.prim.>>u64]
2531+
template <class P>
2532+
requires(SignedPrimitiveInteger<P> || SignedPrimitiveEnum<P>)
2533+
[[nodiscard]] __sus_pure_const constexpr friend P operator>>(P l, _self r) noexcept {
2534+
// No UB checks on primitive types, since there's no promotion to a Subspace
2535+
// return type?
2536+
return l >> u64(r).primitive_value;
2537+
}
2538+
24272539
#if _pointer
24282540

24292541
/// Returns the address portion of the pointer.

0 commit comments

Comments
 (0)