Program Listing for File adm_time_extras.hpp

Return to documentation for file (include/eat/process/adm_time_extras.hpp)

#pragma once
#include <adm/elements/time.hpp>
#include <cmath>
#include <numeric>

namespace eat {
namespace admx {

inline adm::FractionalTime add_with_same_denominators(adm::FractionalTime const &lhs, adm::FractionalTime const &rhs) {
  return adm::FractionalTime{lhs.numerator() + rhs.numerator(), lhs.denominator()};
}

inline adm::FractionalTime add_with_different_denominators(adm::FractionalTime const &lhs,
                                                           adm::FractionalTime const &rhs) {
  auto const lhs_n = lhs.normalised();
  auto const rhs_n = rhs.normalised();
  auto const denominator = std::lcm(lhs_n.denominator(), rhs_n.denominator());
  auto const l_numerator = lhs_n.numerator() * denominator / lhs_n.denominator();
  auto const r_numerator = rhs_n.numerator() * denominator / rhs_n.denominator();
  return adm::FractionalTime{l_numerator + r_numerator, denominator}.normalised();
}

inline adm::FractionalTime plus(adm::FractionalTime const &lhs, adm::FractionalTime const &rhs) {
  if (lhs.denominator() == rhs.denominator()) {
    return add_with_same_denominators(lhs, rhs);
  } else {
    return add_with_different_denominators(lhs, rhs);
  }
}

inline adm::FractionalTime negate(adm::FractionalTime const &time) { return {-time.numerator(), time.denominator()}; }

inline adm::FractionalTime minus(adm::FractionalTime const &lhs, adm::FractionalTime const &rhs) {
  return plus(lhs, negate(rhs));
}

template <typename Rep, typename Period>
adm::FractionalTime roundToFractional(std::chrono::duration<Rep, Period> rhs, int64_t target_denominator) {
  auto multiplier = static_cast<double>(target_denominator) / Period::den;
  auto numerator = std::llround(multiplier * rhs.count());
  return adm::FractionalTime{numerator, target_denominator};
}

// Adds two times, preserving denominator if first is fractional and second is not
inline adm::Time plus(adm::Time const &first, adm::Time const &second) {
  if (first.isNanoseconds()) {
    return {first.asNanoseconds() + second.asNanoseconds()};
  } else if (second.isNanoseconds()) {
    return plus(first.asFractional(), roundToFractional(second.asNanoseconds(), first.asFractional().denominator()));
  } else {
    return plus(first.asFractional(), second.asFractional());
  }
}

// Subtracts second time from first, preserving denominator if first is fractional and second is not
inline adm::Time minus(adm::Time const &first, adm::Time const &second) {
  if (first.isNanoseconds()) {
    return first.asNanoseconds() - second.asNanoseconds();
  } else {
    if (second.isNanoseconds()) {
      return minus(first.asFractional(), roundToFractional(second.asNanoseconds(), first.asFractional().denominator()));
    } else {
      return minus(first.asFractional(), second.asFractional());
    }
  }
}

}  // namespace admx
}  // namespace eat