1#ifndef TREE_SITTER_CLOCK_H_
  2#define TREE_SITTER_CLOCK_H_
  3
  4#include <stdbool.h>
  5#include <stdint.h>
  6
  7typedef uint64_t TSDuration;
  8
  9#ifdef _WIN32
 10
 11// Windows:
 12// * Represent a time as a performance counter value.
 13// * Represent a duration as a number of performance counter ticks.
 14
 15#include <windows.h>
 16typedef uint64_t TSClock;
 17
 18static inline TSDuration duration_from_micros(uint64_t micros) {
 19  LARGE_INTEGER frequency;
 20  QueryPerformanceFrequency(&frequency);
 21  return micros * (uint64_t)frequency.QuadPart / 1000000;
 22}
 23
 24static inline uint64_t duration_to_micros(TSDuration self) {
 25  LARGE_INTEGER frequency;
 26  QueryPerformanceFrequency(&frequency);
 27  return self * 1000000 / (uint64_t)frequency.QuadPart;
 28}
 29
 30static inline TSClock clock_null(void) {
 31  return 0;
 32}
 33
 34static inline TSClock clock_now(void) {
 35  LARGE_INTEGER result;
 36  QueryPerformanceCounter(&result);
 37  return (uint64_t)result.QuadPart;
 38}
 39
 40static inline TSClock clock_after(TSClock base, TSDuration duration) {
 41  return base + duration;
 42}
 43
 44static inline bool clock_is_null(TSClock self) {
 45  return !self;
 46}
 47
 48static inline bool clock_is_gt(TSClock self, TSClock other) {
 49  return self > other;
 50}
 51
 52#elif defined(CLOCK_MONOTONIC) && !defined(__APPLE__)
 53
 54// POSIX with monotonic clock support (Linux)
 55// * Represent a time as a monotonic (seconds, nanoseconds) pair.
 56// * Represent a duration as a number of microseconds.
 57//
 58// On these platforms, parse timeouts will correspond accurately to
 59// real time, regardless of what other processes are running.
 60
 61#include <time.h>
 62typedef struct timespec TSClock;
 63
 64static inline TSDuration duration_from_micros(uint64_t micros) {
 65  return micros;
 66}
 67
 68static inline uint64_t duration_to_micros(TSDuration self) {
 69  return self;
 70}
 71
 72static inline TSClock clock_now(void) {
 73  TSClock result;
 74  clock_gettime(CLOCK_MONOTONIC, &result);
 75  return result;
 76}
 77
 78static inline TSClock clock_null(void) {
 79  return (TSClock) {0, 0};
 80}
 81
 82static inline TSClock clock_after(TSClock base, TSDuration duration) {
 83  TSClock result = base;
 84  result.tv_sec += duration / 1000000;
 85  result.tv_nsec += (duration % 1000000) * 1000;
 86  if (result.tv_nsec >= 1000000000) {
 87    result.tv_nsec -= 1000000000;
 88    ++(result.tv_sec);
 89  }
 90  return result;
 91}
 92
 93static inline bool clock_is_null(TSClock self) {
 94  return !self.tv_sec;
 95}
 96
 97static inline bool clock_is_gt(TSClock self, TSClock other) {
 98  if (self.tv_sec > other.tv_sec) return true;
 99  if (self.tv_sec < other.tv_sec) return false;
100  return self.tv_nsec > other.tv_nsec;
101}
102
103#else
104
105// macOS or POSIX without monotonic clock support
106// * Represent a time as a process clock value.
107// * Represent a duration as a number of process clock ticks.
108//
109// On these platforms, parse timeouts may be affected by other processes,
110// which is not ideal, but is better than using a non-monotonic time API
111// like `gettimeofday`.
112
113#include <time.h>
114typedef uint64_t TSClock;
115
116static inline TSDuration duration_from_micros(uint64_t micros) {
117  return micros * (uint64_t)CLOCKS_PER_SEC / 1000000;
118}
119
120static inline uint64_t duration_to_micros(TSDuration self) {
121  return self * 1000000 / (uint64_t)CLOCKS_PER_SEC;
122}
123
124static inline TSClock clock_null(void) {
125  return 0;
126}
127
128static inline TSClock clock_now(void) {
129  return (uint64_t)clock();
130}
131
132static inline TSClock clock_after(TSClock base, TSDuration duration) {
133  return base + duration;
134}
135
136static inline bool clock_is_null(TSClock self) {
137  return !self;
138}
139
140static inline bool clock_is_gt(TSClock self, TSClock other) {
141  return self > other;
142}
143
144#endif
145
146#endif  // TREE_SITTER_CLOCK_H_