Skip to content

Commit

Permalink
Convert optimizations backport (#222)
Browse files Browse the repository at this point in the history
* Fold overloads for same units

* Remove unused template parameters

* Add `normal_convert` optimization

* Use `normal_convert` in Pi overloads

* Use `normal_convert` in translation overload

* Use Pi optimized overload

* Restore template parameters for folded up overloads

* Deduce `T`

* Fix whitespace [skip ci]

Co-authored-by: Nic Holthaus <[email protected]>
  • Loading branch information
JohelEGP and nholthaus authored Oct 6, 2020
1 parent 865c261 commit 4550b90
Showing 1 changed file with 51 additions and 31 deletions.
82 changes: 51 additions & 31 deletions include/units.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
//--------------------

#include <chrono>
#include <cstddef>
#include <ratio>
#include <type_traits>
#include <cstdint>
Expand Down Expand Up @@ -1517,82 +1518,101 @@ namespace units
}

/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::false_type) noexcept
template<class Ratio, class PiRatio, class Translation, bool piRequired, bool translationRequired, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::integral_constant<bool, piRequired>, std::integral_constant<bool, translationRequired>) noexcept
{
return value;
}

/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::true_type) noexcept
template<std::size_t Ratio_num, std::size_t Ratio_den>
struct normal_convert
{
return value;
}
template<typename T>
inline constexpr T operator()(const T& value) const noexcept
{
return value * Ratio_num / Ratio_den;
}
};

/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::false_type) noexcept
template<std::size_t Ratio_num>
struct normal_convert<Ratio_num, 1>
{
return value;
}
template<typename T>
inline constexpr T operator()(const T& value) const noexcept
{
return value * Ratio_num;
}
};

/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::true_type) noexcept
template<std::size_t Ratio_den>
struct normal_convert<1, Ratio_den>
{
return value;
}
template<typename T>
inline constexpr T operator()(const T& value) const noexcept
{
return value / Ratio_den;
}
};

template<>
struct normal_convert<1, 1>
{
template<typename T>
inline constexpr T operator()(const T& value) const noexcept
{
return value;
}
};

/// convert dispatch for units of different types w/ no translation and no PI
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
template<class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::false_type) noexcept
{
return ((value * Ratio::num) / Ratio::den);
return normal_convert<Ratio::num, Ratio::den>{}(value);
}

/// convert dispatch for units of different types w/ no translation, but has PI in numerator
// constepxr with PI in numerator
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
template<class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr
std::enable_if_t<(PiRatio::num / PiRatio::den >= 1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
return ((value * pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den);
return normal_convert<Ratio::num, Ratio::den>{}(value) * pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den);
}

/// convert dispatch for units of different types w/ no translation, but has PI in denominator
// constexpr with PI in denominator
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
template<class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr
std::enable_if_t<(PiRatio::num / PiRatio::den <= -1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
return (value * Ratio::num) / (Ratio::den * pow(constants::detail::PI_VAL, -PiRatio::num / PiRatio::den));
return normal_convert<Ratio::num, Ratio::den>{}(value) / pow(constants::detail::PI_VAL, -PiRatio::num / PiRatio::den);
}

/// convert dispatch for units of different types w/ no translation, but has PI in numerator
// Not constexpr - uses std::pow
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
template<class Ratio, class PiRatio, class Translation, typename T>
static inline // sorry, this can't be constexpr!
std::enable_if_t<(PiRatio::num / PiRatio::den < 1 && PiRatio::num / PiRatio::den > -1), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den);
return normal_convert<Ratio::num, Ratio::den>{}(value) * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den);
}

/// convert dispatch for units of different types with a translation, but no PI
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
template<class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::true_type) noexcept
{
return ((value * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
return normal_convert<Ratio::num, Ratio::den>{}(value) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
}

/// convert dispatch for units of different types with a translation AND PI
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, const std::false_type, const std::true_type, const std::true_type) noexcept
template<class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::false_type isSame, std::true_type piRequired, std::true_type) noexcept
{
return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
return convert<Ratio, PiRatio, Translation>(value, isSame, piRequired, std::false_type()) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
}
}
/** @endcond */ // END DOXYGEN IGNORE
Expand Down Expand Up @@ -1627,7 +1647,7 @@ namespace units
using piRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, PiRatio>::value)>;
using translationRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, Translation>::value)>;

return units::detail::convert<UnitFrom, UnitTo, Ratio, PiRatio, Translation, T>
return units::detail::convert<Ratio, PiRatio, Translation>
(value, isSame{}, piRequired{}, translationRequired{});
}

Expand Down

0 comments on commit 4550b90

Please sign in to comment.