#pragma once
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <cstdint>
#include <utility>


#define LOG(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
#define LOG_ERRNO(fmt, ...) LOG(fmt " - %d: %s", ##__VA_ARGS__, errno, strerror(errno))

#ifdef NDEBUG
#define INLINE inline __attribute__((always_inline))
#else
#define INLINE
#endif

#define PACKED __attribute__((packed))
#define UNUSED __attribute__((unused))
#if 0
#define ALIGN(b) __attribute__((aligned(b)))
#else
#define ALIGN(b) alignas(b) // should work for make_unique[]
#endif

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

#define MICRO_COORD (1.0e-6F)
#define MICRO_DIST (1.0e-3F)


typedef uint64_t msec_t;


/** @brief Monotonic game clock and timer with millisecond resolution. */
class Timer {
  private:
    msec_t start;

  public:
    Timer() : start{now()} {}

    static msec_t now() {
        struct timespec ts {};
        (void)clock_gettime(CLOCK_MONOTONIC, &ts);
        return (static_cast<msec_t>(ts.tv_sec) * 1000) + (static_cast<msec_t>(ts.tv_nsec) / 1000000);
    }

    /** @brief restart */
    void reset() {
        start = now();
    }

    /** @brief elapsed time since start */
    msec_t measure() const {
        return now() - start;
    }

    /** @brief elapsed time and immediately restart */
    msec_t measurement() {
        const msec_t ts = now();
        return ts - std::exchange(start, ts);
    }
};