Skip to content

Commit

Permalink
Support powers and roots for unit wrappers
Browse files Browse the repository at this point in the history
This unlocks some basic missing functionality for `Constant` and
`SymbolFor`: namely, we should be able to pass instances of them to
`squared()`, `sqrt()`, `pow<N>()`, `root<N>()`, and so on.

Fixes #375.
  • Loading branch information
chiphogg committed Jan 15, 2025
1 parent 930394d commit 9665780
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 10 deletions.
1 change: 1 addition & 0 deletions au/code/au/constant.hh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct Constant : detail::MakesQuantityFromNumber<Constant, Unit>,
detail::ComposesWith<Constant, Unit, Constant, Constant>,
detail::ComposesWith<Constant, Unit, QuantityMaker, QuantityMaker>,
detail::ComposesWith<Constant, Unit, SingularNameFor, SingularNameFor>,
detail::SupportsRationalPowers<Constant, Unit>,
detail::CanScaleByMagnitude<Constant, Unit> {
// Convert this constant to a Quantity of the given rep.
template <typename T>
Expand Down
2 changes: 2 additions & 0 deletions au/code/au/constant_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ TEST(Constant, SupportsMultiplyingConstantByItself) {
StaticAssertTypeEq<decltype(c * c), Constant<decltype(squared(SpeedOfLight{}))>>();
}

TEST(Constant, CanTakePowers) { StaticAssertTypeEq<decltype(squared(c)), decltype(c * c)>(); }

TEST(Constant, ComposesViaDivision) {
StaticAssertTypeEq<decltype(c / h), Constant<decltype(SpeedOfLight{} / PlancksConstant{})>>();
}
Expand Down
1 change: 1 addition & 0 deletions au/code/au/unit_symbol.hh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ template <typename Unit>
struct SymbolFor : detail::MakesQuantityFromNumber<SymbolFor, Unit>,
detail::ScalesQuantity<SymbolFor, Unit>,
detail::ComposesWith<SymbolFor, Unit, SymbolFor, SymbolFor>,
detail::SupportsRationalPowers<SymbolFor, Unit>,
detail::CanScaleByMagnitude<SymbolFor, Unit> {};

//
Expand Down
4 changes: 4 additions & 0 deletions au/code/au/unit_symbol_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ TEST(SymbolFor, CanScaleByMagnitude) {
EXPECT_THAT(3.5f / u100_m, SameTypeAndValue(inverse(meters * mag<100>())(3.5f)));
}

TEST(SymbolFor, CanApplyNamedPowerFunctions) {
StaticAssertTypeEq<decltype(squared(m)), decltype(m * m)>();
}

} // namespace au
18 changes: 18 additions & 0 deletions au/code/au/wrapper_operations.hh
Original file line number Diff line number Diff line change
Expand Up @@ -217,5 +217,23 @@ struct CanScaleByMagnitude {
}
};

//
// A mixin to enable raising a unit wrapper to a rational power.
//
template <template <typename U> class UnitWrapper, typename Unit>
struct SupportsRationalPowers {
// (W^N), for wrapper W and integer N.
template <std::intmax_t N>
friend constexpr auto pow(UnitWrapper<Unit>) {
return UnitWrapper<UnitPowerT<Unit, N>>{};
}

// (W^(1/N)), for wrapper W and integer N.
template <std::intmax_t N>
friend constexpr auto root(UnitWrapper<Unit>) {
return UnitWrapper<UnitPowerT<Unit, 1, N>>{};
}
};

} // namespace detail
} // namespace au
25 changes: 15 additions & 10 deletions au/code/au/wrapper_operations_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct UnitWrapper : MakesQuantityFromNumber<UnitWrapper, Unit>,
ScalesQuantity<UnitWrapper, Unit>,
ComposesWith<UnitWrapper, Unit, UnitWrapper, UnitWrapper>,
ComposesWith<UnitWrapper, Unit, QuantityMaker, QuantityMaker>,
SupportsRationalPowers<UnitWrapper, Unit>,
CanScaleByMagnitude<UnitWrapper, Unit> {};

TEST(MakesQuantityFromNumber, MakesQuantityWhenPostMultiplyingNumericValue) {
Expand Down Expand Up @@ -144,18 +145,22 @@ TEST(CanScaleByMagnitude, MakesScaledWrapperWhenDividingByMagnitude) {
StaticAssertTypeEq<decltype(mol / PI), UnitWrapper<decltype(Moles{} / PI)>>();
}

TEST(ForbidsComposingWith, FailsToCompileWhenMultiplyingOrDividingWithForbiddenWrapper) {
// Uncomment each line below individually to verify.
TEST(SupportsRationalPowers, RaisesUnitToGivenPower) {
constexpr auto mol = UnitWrapper<Moles>{};
StaticAssertTypeEq<decltype(pow<3>(mol)), UnitWrapper<decltype(pow<3>(Moles{}))>>();
}

TEST(SupportsRationalPowers, EnablesTakingRoots) {
constexpr auto mol = UnitWrapper<Moles>{};
StaticAssertTypeEq<decltype(root<8>(mol)), UnitWrapper<decltype(root<8>(Moles{}))>>();
}

// UnitWrapper<Meters>{} * meters_pt;
// UnitWrapper<Meters>{} / meters_pt;
// meters_pt *UnitWrapper<Meters>{};
// meters_pt / UnitWrapper<Meters>{};
TEST(SupportsRationalPowers, UnlocksNamedPowerHelpers) {
constexpr auto mol = UnitWrapper<Moles>{};

// UnitWrapper<Meters>{} * meters_pt(1);
// UnitWrapper<Meters>{} / meters_pt(1);
// meters_pt(1) * UnitWrapper<Meters>{};
// meters_pt(1) / UnitWrapper<Meters>{};
StaticAssertTypeEq<decltype(cubed(mol)), decltype(pow<3>(mol))>();
StaticAssertTypeEq<decltype(squared(mol)), decltype(pow<2>(mol))>();
StaticAssertTypeEq<decltype(sqrt(mol)), decltype(root<2>(mol))>();
}

} // namespace
Expand Down

0 comments on commit 9665780

Please sign in to comment.