Program Listing for File time.hpp#
↰ Return to documentation for file (librapid/include/librapid/utils/time.hpp)
#ifndef LIBRAPID_UTILS_TIME_HPP
#define LIBRAPID_UTILS_TIME_HPP
namespace librapid {
namespace time {
constexpr int64_t nanosecond = int64_t(1);
constexpr int64_t microsecond = nanosecond * 1000;
constexpr int64_t millisecond = microsecond * 1000;
constexpr int64_t second = millisecond * 1000;
constexpr int64_t minute = second * 60;
constexpr int64_t hour = minute * 60;
constexpr int64_t day = hour * 24;
} // namespace time
template<int64_t scale = time::second>
LIBRAPID_NODISCARD double now() {
using namespace std::chrono;
#if defined(LIBRAPID_OS_WINDOWS)
using rep = int64_t;
using period = std::nano;
using duration = std::chrono::duration<rep, period>;
static const int64_t clockFreq = []() -> int64_t {
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return frequency.QuadPart;
}();
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
return duration(count.QuadPart * static_cast<int64_t>(std::nano::den) / clockFreq).count() /
(double)scale;
#else
return (double)high_resolution_clock::now().time_since_epoch().count() / (double)scale;
#endif
}
constexpr static double sleepOffset = 0;
template<int64_t scale = time::second>
LIBRAPID_ALWAYS_INLINE void sleep(double time) {
using namespace std::chrono;
time *= scale;
auto start = now<time::nanosecond>();
while (now<time::nanosecond>() - start < time - sleepOffset) {}
}
template<int64_t scale = time::second>
std::string formatTime(double time, const std::string &format = "{:.3f}") {
double ns = time * scale;
int numUnits = 8;
static std::string prefix[] = {
"ns",
#if defined(LIBRAPID_OS_WINDOWS) && defined(LIBRAPID_NO_WINDOWS_H)
"µs",
#else
"us",
#endif
"ms",
"s",
"m",
"h",
"d",
"y"
};
static double divisor[] = {1000, 1000, 1000, 60, 60, 24, 365, 1e300};
for (int i = 0; i < numUnits; ++i) {
if (ns < divisor[i]) return std::operator+(fmt::format(format, ns), prefix[i]);
ns /= divisor[i];
}
return fmt::format("{}ns", time * ns);
}
class Timer {
public:
explicit Timer(std::string name = "") :
m_name(std::move(name)), m_start(now<time::nanosecond>()), m_end(-1) {}
Timer(const Timer &) = default;
Timer(Timer &&) = default;
Timer &operator=(const Timer &) = default;
Timer &operator=(Timer &&) = default;
~Timer() {
m_end = now<time::nanosecond>();
}
template<size_t scale = time::second>
Timer &setTargetTime(double time) {
m_iters = 0;
m_targetTime = time * (double)scale;
m_start = now<time::nanosecond>();
return *this;
}
void start() {
m_start = now<time::nanosecond>();
m_end = -1;
}
void stop() { m_end = now<time::nanosecond>(); }
void reset() {
m_start = now<time::nanosecond>();
m_end = -1;
}
template<int64_t scale = time::second>
LIBRAPID_NODISCARD double elapsed() const {
if (m_end == -1) return (now<time::nanosecond>() - m_start) / (double)scale;
return (m_end - m_start) / (double)scale;
}
template<int64_t scale = time::second>
LIBRAPID_NODISCARD double average() const {
return elapsed<scale>() / (double)m_iters;
}
bool isRunning() {
++m_iters;
return now<time::nanosecond>() - m_start < m_targetTime;
}
LIBRAPID_NODISCARD std::string str(const std::string &format = "{:.3f}") const {
double tmpEnd = m_end;
if (tmpEnd < 0) tmpEnd = now<time::nanosecond>();
return fmt::format(
"{}Elapsed: {} | Average: {}",
(m_name.empty() ? "" : m_name + ": "),
formatTime<time::nanosecond>(tmpEnd - m_start, format),
formatTime<time::nanosecond>((tmpEnd - m_start) / (double)m_iters, format));
}
private:
std::string m_name = "Timer";
double m_start = 0;
double m_end = 0;
size_t m_iters = 0;
double m_targetTime = 0;
};
} // namespace librapid
LIBRAPID_SIMPLE_IO_IMPL_NO_TEMPLATE(librapid::Timer);
#endif // LIBRAPID_UTILS_TIME_HPP