Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify common unit if label has just one unit #338

Merged
merged 3 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions au/code/au/unit_of_measure.hh
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,11 @@ struct CommonUnit {
template <typename A, typename B>
struct InOrderFor<CommonUnit, A, B> : InOrderFor<UnitProduct, A, B> {};

template <typename... Us>
struct UnitList {};
template <typename A, typename B>
struct InOrderFor<UnitList, A, B> : InOrderFor<UnitProduct, A, B> {};

namespace detail {
// This machinery searches a unit list for one that "matches" a target unit.
//
Expand All @@ -524,7 +529,7 @@ namespace detail {
// Generic template.
template <template <class, class> class Matcher,
typename TargetUnit,
typename UnitList = TargetUnit>
typename UnitListT = TargetUnit>
struct FirstMatchingUnit;

// Base case for an empty list: the target unit is the best match.
Expand Down Expand Up @@ -612,6 +617,32 @@ constexpr typename CommonUnitLabelImpl<Us...>::LabelT CommonUnitLabelImpl<Us...>
template <typename U>
struct CommonUnitLabelImpl<U> : UnitLabel<U> {};

template <typename U>
struct UnscaledUnitImpl : stdx::type_identity<U> {};
template <typename U, typename M>
struct UnscaledUnitImpl<ScaledUnit<U, M>> : stdx::type_identity<U> {};
template <typename U>
using UnscaledUnit = typename UnscaledUnitImpl<U>::type;

template <typename U>
struct DistinctUnscaledUnitsImpl : stdx::type_identity<UnitList<UnscaledUnit<U>>> {};
template <typename U>
using DistinctUnscaledUnits = typename DistinctUnscaledUnitsImpl<U>::type;
template <typename... Us>
struct DistinctUnscaledUnitsImpl<CommonUnit<Us...>>
: stdx::type_identity<FlatDedupedTypeListT<UnitList, UnscaledUnit<Us>...>> {};

template <typename U, typename DistinctUnits>
struct SimplifyIfOnlyOneUnscaledUnitImpl;
template <typename U>
using SimplifyIfOnlyOneUnscaledUnit =
typename SimplifyIfOnlyOneUnscaledUnitImpl<U, DistinctUnscaledUnits<U>>::type;
template <typename U, typename SoleUnscaledUnit>
struct SimplifyIfOnlyOneUnscaledUnitImpl<U, UnitList<SoleUnscaledUnit>>
: stdx::type_identity<decltype(SoleUnscaledUnit{} * UnitRatioT<U, SoleUnscaledUnit>{})> {};
template <typename U, typename... Us>
struct SimplifyIfOnlyOneUnscaledUnitImpl<U, UnitList<Us...>> : stdx::type_identity<U> {};

} // namespace detail

template <typename A, typename B>
Expand All @@ -626,7 +657,9 @@ using ComputeCommonUnitImpl =

template <typename... Us>
struct ComputeCommonUnit
: detail::FirstMatchingUnit<AreUnitsQuantityEquivalent, ComputeCommonUnitImpl<Us...>> {};
: stdx::type_identity<detail::SimplifyIfOnlyOneUnscaledUnit<
typename detail::FirstMatchingUnit<AreUnitsQuantityEquivalent,
ComputeCommonUnitImpl<Us...>>::type>> {};

////////////////////////////////////////////////////////////////////////////////////////////////////
// `CommonPointUnitT` helper implementation.
Expand Down
35 changes: 35 additions & 0 deletions au/code/au/unit_of_measure_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,11 @@ TEST(CommonUnit, DownranksAnonymousScaledUnits) {
StaticAssertTypeEq<CommonUnitT<Yards, decltype(Feet{} * mag<3>())>, Yards>();
}

TEST(CommonUnit, WhenCommonUnitLabelWouldBeIdenticalToSomeUnitJustUsesThatUnit) {
StaticAssertTypeEq<CommonUnitT<decltype(Feet{} * mag<6>()), decltype(Feet{} * mag<10>())>,
decltype(Feet{} * mag<2>())>();
}

// Four coprime units of the same dimension.
struct W : decltype(Inches{} * mag<2>()) {};
struct X : decltype(Inches{} * mag<3>()) {};
Expand Down Expand Up @@ -701,5 +706,35 @@ TEST(EliminateRedundantUnits, AlwaysRemovesSameUnitAmongQuantityEquivalentChoice
EliminateRedundantUnits<SomePack<Twelvinch, Feet>>>();
}

TEST(UnscaledUnit, IdentityForGeneralUnits) {
StaticAssertTypeEq<UnscaledUnit<Feet>, Feet>();
StaticAssertTypeEq<UnscaledUnit<Celsius>, Celsius>();
}

TEST(UnscaledUnit, RemovesScaleFactorFromScaledUnit) {
StaticAssertTypeEq<UnscaledUnit<decltype(Feet{} * mag<3>())>, Feet>();
StaticAssertTypeEq<UnscaledUnit<decltype(Celsius{} / mag<2>())>, Celsius>();
}

TEST(DistinctUnscaledUnits, UnitListOfOneElementForNonCommonUnit) {
StaticAssertTypeEq<DistinctUnscaledUnits<Feet>, UnitList<Feet>>();
StaticAssertTypeEq<DistinctUnscaledUnits<decltype(Feet{} / mag<12>())>, UnitList<Feet>>();
}

TEST(DistinctUnscaledUnits, RemovesDupesFromCommonUnit) {
StaticAssertTypeEq<
DistinctUnscaledUnits<decltype(common_unit(Feet{} * mag<3>(), Feet{} / mag<12>()))>,
UnitList<Feet>>();
StaticAssertTypeEq<DistinctUnscaledUnits<decltype(common_unit(
Feet{} * mag<3>(), Inches{} * mag<48>(), Feet{} * mag<5>()))>,
UnitList<Inches, Feet>>();
}

TEST(SimplifyIfOnlyOneUnscaledUnit, IdentityForNonCommonUnit) {
StaticAssertTypeEq<SimplifyIfOnlyOneUnscaledUnit<Feet>, Feet>();
StaticAssertTypeEq<SimplifyIfOnlyOneUnscaledUnit<decltype(Feet{} * mag<3>())>,
decltype(Feet{} * mag<3>())>();
}

} // namespace detail
} // namespace au
Loading