Skip to content

Commit

Permalink
chore: cleaned the CRTP implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRustifyer committed Sep 6, 2024
1 parent 1837fe9 commit b25786d
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 132 deletions.
63 changes: 50 additions & 13 deletions zero/ifc/math/numbers/detail.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@ import std;
import math.ops;
import math.symbols;

import :numbers.general;
import :numbers.naturals;
import :numbers.integers;
import :numbers.rationals;


#if defined(__clang__) // TODO: clang18 seems to be unable to resolve templates declared
// on internal partitions, so they must be 'exported' (even tho the module itself isn't being
// exported (module :numbers.detail), so this macro provisionally normalize the access of the
// template Number(s) operations to the implementation details internal module partition
export namespace zero::math {
#if defined(__clang__) // TODO: clang18 seems to be unable to resolve templates
// declared on internal partitions, so they must be
// 'exported' (even tho the module itself isn't being
// exported (module :numbers.detail), so this macro
// provisionally normalize the access of the template
// Number(s) operations to the implementation details
// internal module partition
export namespace zero::math {
#elif defined(_MSC_VER)
using namespace zero::math;
using namespace zero::math;
#endif

template <typename L, typename R>
concept EitherRational =
std::is_same_v<L, Rational> || std::is_same_v<R, Rational>;

// Helper to extract the inner value of a Number type or avoid the method
// call if it's a primitive (std::is_arithmetic_v).
template <typename T> constexpr auto normalize(const T &value) noexcept {
Expand All @@ -28,20 +33,52 @@ template <typename T> constexpr auto normalize(const T &value) noexcept {
return value.number();
}

// Generalized arithmetic operation helper using lambdas
template <typename L, typename R, typename Op>
constexpr auto arithmetic_op(const L &lhs, const R &rhs, Op op) noexcept {
// Handle Rational cases separately by calling the specialized logic
if constexpr (EitherRational<L, R>)
return op(lhs, rhs);
// Handle all other cases
else
return op(normalize(lhs), normalize(rhs));
}

// Specialized addition and subtraction for Rational types
template <typename L, typename R>
constexpr auto rational_add_or_subtract(const L &lhs, const R &rhs, int sign) noexcept {
constexpr auto rational_add_or_subtract(const L &lhs, const R &rhs,
int sign) noexcept {
// Ensure one of them is a Rational
if constexpr (std::is_same_v<L, Rational> && std::is_same_v<R, Rational>) {
return sum_or_subtract(lhs, rhs, sign);
} else if constexpr (std::is_same_v<L, Rational>) {
// LHS is Rational, RHS is a different numeric type
Rational normalized_rhs = Rational(rhs); // Convert rhs to Rational
return sum_or_subtract(lhs, normalized_rhs, sign);
return sum_or_subtract(lhs, Rational(rhs), sign);
} else if constexpr (std::is_same_v<R, Rational>) {
// RHS is Rational, LHS is a different numeric type
Rational normalized_lhs = Rational(lhs); // Convert lhs to Rational
return sum_or_subtract(normalized_lhs, rhs, sign);
return sum_or_subtract(Rational(lhs), rhs, sign);
}
}

// Helper function to sum or subtract two Rationals
[[nodiscard]] constexpr Rational
sum_or_subtract(const Rational &lhs, const Rational &rhs, int sign) noexcept {
const int lhs_numerator = lhs.numerator().number();
const int rhs_numerator = sign * rhs.numerator().number();
const int lhs_denominator = lhs.denominator().number();
const int rhs_denominator = rhs.denominator().number();

if (lhs_denominator == rhs_denominator) { // Like fractions
return {lhs_numerator + sign * rhs_numerator, lhs_denominator};
} else { // Unlike fractions
// Get their LCD by finding their LCM
const auto lcd = zero::math::lcm(lhs_denominator, rhs_denominator);

// Scale numerators to have the common denominator (LCM)
const int numerator = (lhs_numerator * (lcd / lhs_denominator)) +
(rhs_numerator * (lcd / rhs_denominator));

return {numerator, lcd};
}
}

Expand Down
67 changes: 0 additions & 67 deletions zero/ifc/math/numbers/general.cppm

This file was deleted.

1 change: 0 additions & 1 deletion zero/ifc/math/numbers/integers.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import math.ops;
import math.symbols;

import :general;
import :numbers.general;
import :numbers.naturals;

export namespace zero::math {
Expand Down
1 change: 0 additions & 1 deletion zero/ifc/math/numbers/naturals.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import std;
import math.symbols;

import :general;
import :numbers.general;

export namespace zero::math {
/// A positive integer number
Expand Down
44 changes: 3 additions & 41 deletions zero/ifc/math/numbers/numbers.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,11 @@ import :numbers.detail;
import math.ops;

export namespace zero::math {
// Generalized arithmetic operation helper using lambdas
template <typename L, typename R, typename Op>
constexpr auto arithmetic_op(const L &lhs, const R &rhs, Op op) noexcept {
if constexpr (std::is_same_v<L, Rational> || std::is_same_v<R, Rational>) {
// Handle Rational cases separately by calling the specialized logic
return op(lhs, rhs);
} else {
// Handle all other cases
return op(normalize(lhs), normalize(rhs));
}
}

// Operator overloads for mixed-type arithmetic involving Rational
template <Numerical L, Numerical R>
constexpr auto operator+(const L &lhs, const R &rhs) noexcept {
auto op = [](const auto &a, const auto &b) {
if constexpr (std::is_same_v<L, Rational> ||
std::is_same_v<R, Rational>) {
if constexpr (EitherRational<L, R>) {
return rational_add_or_subtract(a, b, 1); // Special logic for Rational addition
} else {
return a + b; // Generic addition
Expand All @@ -44,8 +31,7 @@ constexpr auto operator+(const L &lhs, const R &rhs) noexcept {
template <Numerical L, Numerical R>
constexpr auto operator-(const L &lhs, const R &rhs) noexcept {
auto op = [](const auto &a, const auto &b) {
if constexpr (std::is_same_v<std::decay_t<decltype(a)>, Rational> ||
std::is_same_v<std::decay_t<decltype(b)>, Rational>) {
if constexpr (EitherRational<L, R>) {
return rational_add_or_subtract(a, b, -1); // Special logic for Rational subtraction
} else {
return a - b; // Generic subtraction
Expand Down Expand Up @@ -76,8 +62,7 @@ constexpr auto operator*(const L &lhs, const R &rhs) noexcept {
template <Numerical L, Numerical R>
constexpr bool operator==(const L &lhs, const R &rhs) noexcept {
auto op = [](const auto &a, const auto &b) {
if constexpr (std::is_same_v<std::decay_t<decltype(a)>, Rational> &&
std::is_same_v<std::decay_t<decltype(b)>, Rational>) {
if constexpr (EitherRational<L, R>) {
// Equality check for Rational types
return a.numerator() == b.numerator() &&
a.denominator() == b.denominator();
Expand All @@ -91,27 +76,4 @@ constexpr bool operator==(const L &lhs, const R &rhs) noexcept {
};
return arithmetic_op(lhs, rhs, op);
}


// Helper function to sum or subtract two Rationals
[[nodiscard]] constexpr Rational
sum_or_subtract(const Rational &lhs, const Rational &rhs, int sign) noexcept {
if (lhs.denominator() == rhs.denominator()) { // Like fractions
return {lhs.numerator() + sign * rhs.numerator(), lhs.denominator()};
} else { // Unlike fractions
const int lhs_numerator = lhs.numerator().number();
const int rhs_numerator = sign * rhs.numerator();
const int lhs_denominator = lhs.denominator().number();
const int rhs_denominator = rhs.denominator().number();

// Get their LCD by finding their LCM
const auto lcd = zero::math::lcm(lhs_denominator, rhs_denominator);

// Scale numerators to have the common denominator (LCM)
const int numerator = (lhs_numerator * (lcd / lhs_denominator)) +
(rhs_numerator * (lcd / rhs_denominator));

return {numerator, lcd};
}
}
} // namespace zero::math
8 changes: 1 addition & 7 deletions zero/ifc/math/numbers/rationals.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import math.ops;
import math.symbols;

import :general;
import :numbers.general;
import :numbers.naturals;
import :numbers.integers;

Expand Down Expand Up @@ -35,7 +34,7 @@ export namespace zero::math {
public:
constexpr static MathSymbol symbol = MathSymbol::Rationals;

/* template<Numerical L, Numerical R>
/* template<Numerical L, Numerical R> // TODO: don't think that's work to have universal references over const l-value references
[[nodiscard]] constexpr Rational(L&& numerator, R&& denominator) noexcept
: _numerator(static_cast<Integer>(std::forward<L>(numerator))),
_denominator(static_cast<Integer>(std::forward<R>(denominator))) {}
Expand Down Expand Up @@ -72,8 +71,3 @@ export namespace zero::math {
}
};
}

// Equality



1 change: 0 additions & 1 deletion zork_config/zork_clang.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ interfaces = [
{ file = 'math/linear_algebra/matrix.cppm', partition = { module = 'math.linear_algebra', partition_name = 'matrix' } },
{ file = 'math/linear_algebra/root.cppm', module_name = 'math.linear_algebra' },
# Numbers - Core
{ file = 'math/numbers/general.cppm', partition = { module = 'math', partition_name = 'numbers.general' } },
{ file = 'math/numbers/naturals.cppm', partition = { module = 'math', partition_name = 'numbers.naturals' } },
{ file = 'math/numbers/integers.cppm', partition = { module = 'math', partition_name = 'numbers.integers' } },
{ file = 'math/numbers/rationals.cppm', partition = { module = 'math', partition_name = 'numbers.rationals' } },
Expand Down
1 change: 0 additions & 1 deletion zork_config/zork_windows_msvc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ interfaces = [
{ file = 'math/linear_algebra/matrix.cppm', partition = { module = 'math.linear_algebra', partition_name = 'matrix' } },
{ file = 'math/linear_algebra/root.cppm', module_name = 'math.linear_algebra' },
# Numbers - Core
{ file = 'math/numbers/general.cppm', partition = { module = 'math', partition_name = 'numbers.general' } },
{ file = 'math/numbers/naturals.cppm', partition = { module = 'math', partition_name = 'numbers.naturals' } },
{ file = 'math/numbers/integers.cppm', partition = { module = 'math', partition_name = 'numbers.integers' } },
{ file = 'math/numbers/rationals.cppm', partition = { module = 'math', partition_name = 'numbers.rationals' } },
Expand Down

0 comments on commit b25786d

Please sign in to comment.