#pragma once namespace nall { //attempt to keep Natural / Integer types when performing a math operation against another Natural / Integer or primitive type //try not to lose any data through truncation (eg Natural<32> + Natural<32> -> Natural<64>) //complex SFINAE is needed to prevent the creation of ambiguous operator overloads #define Type PrimitiveType #define Compatible PrimitiveCompatible #define CastExpand PrimitiveCastExpand #define CastShrink PrimitiveCastShrink #define CastDouble PrimitiveCastDouble #define CastLarger PrimitiveCastLarger #define CastLesser PrimitiveCastLesser template struct Type { using type = T; static inline constexpr uint bits = 8 * sizeof(T); }; template<> struct Type { using type = typename Boolean::type; static inline constexpr uint bits = Boolean::bits(); }; template struct Type> { using type = typename Natural::type; static inline constexpr uint bits = Natural::bits(); }; template struct Type> { using type = typename Integer::type; static inline constexpr uint bits = Integer::bits(); }; template struct Type> { using type = typename Real::type; static inline constexpr uint bits = Real::bits(); }; //compatible: SFINAE operator enable template struct Compatible { static const bool value = false; }; template struct Compatible, RHS, enable_if_t>> { static const bool value = true; }; template struct Compatible, enable_if_t>> { static const bool value = true; }; template struct Compatible, Natural> { static const bool value = true; }; template struct Compatible, RHS, enable_if_t>> { static const bool value = true; }; template struct Compatible, enable_if_t>> { static const bool value = true; }; template struct Compatible, Integer> { static const bool value = true; }; //expand: LHS+RHS bits template struct CastExpand { using type = void; }; template struct CastExpand, RHS, enable_if_t>> { using type = Natural::bits>; }; template struct CastExpand, enable_if_t>> { using type = Natural::bits + RHS>; }; template struct CastExpand, Natural> { using type = Natural; }; template struct CastExpand, RHS, enable_if_t>> { using type = Integer::bits>; }; template struct CastExpand, enable_if_t>> { using type = Integer::bits + RHS>; }; template struct CastExpand, Integer> { using type = Integer; }; //shrink: LHS-RHS bits template struct CastShrink { using type = void; }; template struct CastShrink, RHS, enable_if_t>> { using type = Natural::bits>; }; template struct CastShrink, enable_if_t>> { using type = Natural::bits - RHS>; }; template struct CastShrink, Natural> { using type = Natural; }; template struct CastShrink, RHS, enable_if_t>> { using type = Integer::bits>; }; template struct CastShrink, enable_if_t>> { using type = Integer::bits - RHS>; }; template struct CastShrink, Integer> { using type = Integer; }; //double: 1+max(LHS,RHS) bits template struct CastDouble { using type = void; }; template struct CastDouble, RHS, enable_if_t>> { using type = Natural<1 + (LHS >= Type::bits ? LHS : Type::bits)>; }; template struct CastDouble, enable_if_t>> { using type = Natural<1 + (Type::bits >= RHS ? Type::bits : RHS)>; }; template struct CastDouble, Natural> { using type = Natural<1 + (LHS >= RHS ? LHS : RHS)>; }; template struct CastDouble, RHS, enable_if_t>> { using type = Integer<1 + (LHS >= Type::bits ? LHS : Type::bits)>; }; template struct CastDouble, enable_if_t>> { using type = Integer<1 + (Type::bits >= RHS ? Type::bits : RHS)>; }; template struct CastDouble, Integer> { using type = Integer<1 + (LHS >= RHS ? LHS : RHS)>; }; //larger: max(LHS,RHS) bits template struct CastLarger { using type = void; }; template struct CastLarger, RHS, enable_if_t>> { using type = Natural= Type::bits ? LHS : Type::bits>; }; template struct CastLarger, enable_if_t>> { using type = Natural::bits >= RHS ? Type::bits : RHS>; }; template struct CastLarger, Natural> { using type = Natural= RHS ? LHS : RHS>; }; template struct CastLarger, RHS, enable_if_t>> { using type = Integer= Type::bits ? LHS : Type::bits>; }; template struct CastLarger, enable_if_t>> { using type = Integer::bits >= RHS ? Type::bits : RHS>; }; template struct CastLarger, Integer> { using type = Integer= RHS ? LHS : RHS>; }; //lesser: min(LHS,RHS) bits template struct CastLesser { using type = void; }; template struct CastLesser, RHS, enable_if_t>> { using type = Natural::bits ? LHS : Type::bits>; }; template struct CastLesser, enable_if_t>> { using type = Natural::bits <= RHS ? Type::bits : RHS>; }; template struct CastLesser, Natural> { using type = Natural; }; template struct CastLesser, RHS, enable_if_t>> { using type = Integer::bits ? LHS : Type::bits>; }; template struct CastLesser, enable_if_t>> { using type = Integer::bits <= RHS ? Type::bits : RHS>; }; template struct CastLesser, Integer> { using type = Integer; }; #define TP template::value>> #define Source typename Type::type #define Expand typename CastExpand::type #define Shrink typename CastShrink::type #define Double typename CastDouble::type #define Larger typename CastLarger::type #define Lesser typename CastLesser::type #define TLE typename Type::type>::type #define TLN typename Type::type #define TRN typename Type::type #if 1 TP inline auto operator *(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs * (TRN)rhs}; } TP inline auto operator /(const LHS& lhs, const RHS& rhs) -> Source { return {(TLN)lhs / (TRN)rhs}; } TP inline auto operator %(const LHS& lhs, const RHS& rhs) -> Source { return {(TLN)lhs % (TRN)rhs}; } TP inline auto operator +(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs + (TRN)rhs}; } TP inline auto operator -(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs - (TRN)rhs}; } TP inline auto operator<<(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs << (TRN)rhs}; } TP inline auto operator>>(const LHS& lhs, const RHS& rhs) -> Source { return {(TLN)lhs >> (TRN)rhs}; } TP inline auto operator &(const LHS& lhs, const RHS& rhs) -> Lesser { return {(TLN)lhs & (TRN)rhs}; } TP inline auto operator ^(const LHS& lhs, const RHS& rhs) -> Larger { return {(TLN)lhs ^ (TRN)rhs}; } TP inline auto operator |(const LHS& lhs, const RHS& rhs) -> Larger { return {(TLN)lhs | (TRN)rhs}; } #endif #if 0 TP inline auto operator *(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs * (TRN)rhs}; } TP inline auto operator /(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs / (TRN)rhs}; } TP inline auto operator %(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs % (TRN)rhs}; } TP inline auto operator +(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs + (TRN)rhs}; } TP inline auto operator -(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs - (TRN)rhs}; } TP inline auto operator<<(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs << (TRN)rhs}; } TP inline auto operator>>(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs >> (TRN)rhs}; } TP inline auto operator &(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs & (TRN)rhs}; } TP inline auto operator ^(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs ^ (TRN)rhs}; } TP inline auto operator |(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs | (TRN)rhs}; } #endif #undef TP #undef Source #undef Expand #undef Shrink #undef Double #undef Larger #undef Lesser #undef TLE #undef TLN #undef TRN #undef Type #undef Compatible #undef CastExpand #undef CastShrink #undef CastDouble #undef CastLarger #undef CastLesser }