#pragma once #include "compat/assert.hpp" #include "nanosecond.hpp" namespace floormat { template requires (std::is_same_v) Ns operator*(const Ns& lhs, T b) { constexpr double max{uint64_t{1} << 53}; auto a = lhs.stamp; fm_assert(b >= 0); fm_assert(b <= max); auto x = double(a) * b; fm_assert(x >= 0); fm_assert(x <= max); return Ns{(uint64_t)x}; } constexpr Ns operator+(const Ns& lhs, const Ns& rhs) { constexpr auto max = (uint64_t)-1; auto a = lhs.stamp, b = rhs.stamp; fm_assert(max - a >= b); return Ns{a + b}; } constexpr Ns operator-(const Ns& lhs, const Ns& rhs) { auto a = lhs.stamp, b = rhs.stamp; fm_assert(a >= b); return Ns{a - b}; } template requires (std::is_integral_v && std::is_unsigned_v) constexpr Ns operator*(const Ns& lhs, T rhs) { auto a = lhs.stamp, b = uint64_t{rhs}; auto x = a * b; fm_assert(b == 0 || x / b == a); return Ns{x}; } template requires (std::is_integral_v && std::is_signed_v && sizeof(T) < sizeof(uint64_t)) constexpr Ns operator*(const Ns& lhs, T rhs) { fm_assert(rhs >= T{0}); auto b = uint64_t(rhs); auto x = lhs.stamp * b; fm_assert(b == 0 || x / b == lhs.stamp); return Ns{x}; } template constexpr Ns operator*(T lhs, const Ns& rhs) { return rhs * lhs; } constexpr uint64_t operator/(const Ns& lhs, const Ns& rhs) { auto a = lhs.stamp, b = rhs.stamp; fm_assert(b != 0); return a / b; } constexpr Ns operator/(const Ns& lhs, uint64_t b) { auto a = lhs.stamp; fm_assert(b != 0); return Ns{a / b}; } constexpr uint64_t operator%(const Ns& lhs, const Ns& rhs) { auto a = lhs.stamp, b = rhs.stamp; fm_assert(b != 0); return a % b; } constexpr Ns operator%(const Ns& lhs, uint64_t b) { auto a = lhs.stamp; fm_assert(b != 0); return Ns{a % b}; } constexpr Ns& operator+=(Ns& lhs, const Ns& rhs) { constexpr auto max = (uint64_t)-1; auto b = rhs.stamp; fm_assert(max - lhs.stamp >= b); lhs.stamp += b; return lhs; } constexpr std::strong_ordering operator<=>(const Ns& lhs, const Ns& rhs) { auto a = lhs.stamp, b = rhs.stamp; return a <=> b; } } // namespace floormat