// A clock is four types, a flag and a now(). This one only moves when you tell
// it to, which makes it the clock to hand a test — and makes this output exact.
#include <chrono>
#include <concepts>
#include <iostream>
#include <ratio>

namespace sc = std::chrono;

struct manual_clock {
    using rep        = long long;                     // what counts the ticks
    using period     = std::milli;                    // one tick is 1/1000 of a second
    using duration   = sc::duration<rep, period>;     // a count of ticks
    using time_point = sc::time_point<manual_clock>;  // a duration since this clock's epoch
    static constexpr bool is_steady = false;          // advance() may be given a negative step

    static time_point now() noexcept { return current; }
    static void advance(duration step) noexcept { current += step; }

private:
    static inline time_point current{};               // starts at its own epoch
};

// The requirements, as a concept. C++20 ships this check as
// std::chrono::is_clock_v, but libc++ 21 does not have it yet, so it is spelled
// out here — which is also the clearest statement of what a clock is.
template <class C>
concept a_clock = requires {
    typename C::rep;
    typename C::period;
    typename C::duration;
    typename C::time_point;
    { C::is_steady } -> std::convertible_to<bool>;
    { C::now() } -> std::same_as<typename C::time_point>;
};

int main() {
    std::cout << std::boolalpha;
    std::cout << "a_clock<manual_clock>     = " << a_clock<manual_clock> << '\n';     // true
    std::cout << "a_clock<sc::steady_clock> = " << a_clock<sc::steady_clock> << '\n'; // true
    std::cout << "a_clock<int>              = " << a_clock<int> << '\n';              // false

    auto start = manual_clock::now();
    manual_clock::advance(sc::milliseconds{1500});
    auto stop = manual_clock::now();

    std::cout << "stop - start      = " << (stop - start) << '\n';                    // 1500ms
    std::cout << "since the epoch   = " << stop.time_since_epoch() << '\n';           // 1500ms
    std::cout << "one tick          = " << manual_clock::period::num << '/'
              << manual_clock::period::den << " s\n";                                 // 1/1000 s

    // The clock is part of the time point's type: this is not a steady_clock one.
    std::cout << "same type as steady_clock's time_point = "
              << std::same_as<manual_clock::time_point, sc::steady_clock::time_point> << '\n';  // false
}
