#pragma once #include "compat/assert.hpp" #include namespace floormat { struct Ns { explicit constexpr Ns(): stamp{0} {} explicit constexpr Ns(uint64_t x) : stamp{x} {} static Ns from_millis(uint64_t x); explicit operator uint64_t() const; explicit operator float() const; uint64_t operator*() const; friend Ns operator+(const Ns& lhs, const Ns& rhs); friend Ns operator-(const Ns& lhs, const Ns& rhs); friend Ns operator*(const Ns&, const Ns&) = delete; template requires (std::is_integral_v && std::is_unsigned_v) friend 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)) friend Ns operator*(const Ns& lhs, T rhs) { fm_assert(rhs >= T{0}); return lhs * uint64_t(rhs); } template friend Ns operator*(T lhs, const Ns& rhs) { return rhs * lhs; } template requires std::is_same_v friend Ns operator*(const Ns& lhs, T rhs) { auto a = lhs.stamp; auto x = float(a) * float{rhs}; fm_assert(x <= 1 << 24 && x >= 0); return Ns{uint64_t(x)}; } template requires std::is_same_v friend Ns operator*(T lhs, const Ns& rhs) { return rhs * lhs; } friend uint64_t operator/(const Ns& lhs, const Ns& rhs); friend Ns operator/(const Ns& lhs, uint64_t rhs); friend uint64_t operator%(const Ns& lhs, const Ns& rhs); friend Ns operator%(const Ns& lhs, uint64_t rhs); friend bool operator==(const Ns& lhs, const Ns& rhs); friend std::strong_ordering operator<=>(const Ns& lhs, const Ns& rhs); friend Debug& operator<<(Debug& dbg, const Ns& box); uint64_t stamp; }; constexpr inline Ns Second{1000000000}, Millisecond{1000000}; struct Time final { static Time now() noexcept; bool operator==(const Time&) const noexcept; std::strong_ordering operator<=>(const Time&) const noexcept; friend Ns operator-(const Time& lhs, const Time& rhs) noexcept; [[nodiscard]] Ns update(const Time& ts = now()) & noexcept; static float to_seconds(const Ns& ts) noexcept; static float to_milliseconds(const Ns& ts) noexcept; uint64_t stamp = init(); private: static uint64_t init() noexcept; }; constexpr inline size_t fm_DATETIME_BUF_SIZE = 32; const char* format_datetime_to_string(char(&buf)[fm_DATETIME_BUF_SIZE]); } // namespace floormat