#ifndef CTL_NANO_TIMER_H #define CTL_NANO_TIMER_H #define CTL_NOEXCEPT throw() #if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) #if _MSC_VER >= 1900 #undef CTL_NOEXCEPT #define CTL_NOEXCEPT noexcept #endif #elif defined(__cplusplus) && __cplusplus >= 201103L #if defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__clang__) // If compiler is GCC/G++ #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 #undef CTL_NOEXCEPT #define CTL_NOEXCEPT noexcept #endif #elif defined(__clang__) #if __has_feature(cxx_noexcept) #undef CTL_NOEXCEPT #define CTL_NOEXCEPT noexcept #endif #else // Assume type traits and initializer support for other compilers and standard libraries #undef CTL_NOEXCEPT #define CTL_NOEXCEPT noexcept #endif #endif #if defined(__MACH__) #include #include namespace CTL { class nanotimer { private: clock_serv_t system_clock; mach_timespec_t time1, time2; public: nanotimer() CTL_NOEXCEPT { host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &system_clock); } ~nanotimer() CTL_NOEXCEPT { mach_port_deallocate(mach_task_self(), system_clock); } void start() CTL_NOEXCEPT { clock_get_time(system_clock, &time1); } double get_elapsed_ms() CTL_NOEXCEPT { return static_cast(get_elapsed_ns()) / 1000000.0; } double get_elapsed_us() CTL_NOEXCEPT { return static_cast(get_elapsed_ns()) / 1000.0; } double get_elapsed_ns() CTL_NOEXCEPT { clock_get_time(system_clock, &time2); return ((1000000000.0 * static_cast(time2.tv_sec - time1.tv_sec)) + static_cast(time2.tv_nsec - time1.tv_nsec)); } }; // Linux/BSD implementation: #elif (defined(linux) || defined(__linux__) || defined(__linux)) || (defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) || defined(__OHOS__) #include #include namespace CTL { class nanotimer { private: struct timespec time1, time2; public: nanotimer() CTL_NOEXCEPT {} void start() CTL_NOEXCEPT { clock_gettime(CLOCK_MONOTONIC, &time1); } double get_elapsed_ms() CTL_NOEXCEPT { return get_elapsed_ns() / 1000000.0; } double get_elapsed_us() CTL_NOEXCEPT { return get_elapsed_ns() / 1000.0; } double get_elapsed_ns() CTL_NOEXCEPT { clock_gettime(CLOCK_MONOTONIC, &time2); return ((1000000000.0 * static_cast(time2.tv_sec - time1.tv_sec)) + static_cast(time2.tv_nsec - time1.tv_nsec)); } }; // Windows implementation: #elif defined(_WIN32) #if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) && !defined(NOMINMAX) #define NOMINMAX // Otherwise MS compilers act like idiots when using std::numeric_limits<>::max() and including windows.h #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #else #include #endif namespace CTL { class nanotimer { private: LARGE_INTEGER ticks1, ticks2; double frequency; public: nanotimer() CTL_NOEXCEPT { LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); frequency = static_cast(freq.QuadPart); } void start() CTL_NOEXCEPT { QueryPerformanceCounter(&ticks1); } double get_elapsed_ms() CTL_NOEXCEPT { QueryPerformanceCounter(&ticks2); return (static_cast(ticks2.QuadPart - ticks1.QuadPart) * 1000.0) / frequency; } double get_elapsed_us() CTL_NOEXCEPT { return get_elapsed_ms() * 1000.0; } double get_elapsed_ns() CTL_NOEXCEPT { return get_elapsed_ms() * 1000000.0; } }; #endif #if defined(__MACH__) || (defined(linux) || defined(__linux__) || defined(__linux)) || (defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) || defined(_WIN32) || defined(__OHOS__) inline void nanosecond_delay(const double delay_ns) CTL_NOEXCEPT { nanotimer timer; timer.start(); while(timer.get_elapsed_ns() < delay_ns) {}; } inline void microsecond_delay(const double delay_us) CTL_NOEXCEPT { nanosecond_delay(delay_us * 1000.0); } inline void millisecond_delay(const double delay_ms) CTL_NOEXCEPT { nanosecond_delay(delay_ms * 1000000.0); } } #endif #undef CTL_NOEXCEPT #endif