#ifndef OB_TIMER_HH #define OB_TIMER_HH #include "ob/string.hh" #include #include #include #include #include #include namespace OB { class Timer { public: Timer() = default; operator bool() { return _is_running; } Timer& start() { _is_running = true; _start = std::chrono::high_resolution_clock::now(); return *this; } Timer& stop() { update(); _is_running = false; return *this; } Timer& reset() { _is_running = false; _total = {}; return *this; } Timer& toggle() { if (_is_running) { update(); _is_running = false; } else { _is_running = true; _start = std::chrono::high_resolution_clock::now(); } return *this; } template T time() { if (_is_running) { update(); } return std::chrono::duration_cast(_total); } std::tuple diff(long int const sec) { if (_is_running) { update(); } long int const now {static_cast(std::chrono::time_point_cast(_total).time_since_epoch().count())}; return seconds_to_hms(sec - now); } long int seconds() { if (_is_running) { update(); } return static_cast(std::chrono::time_point_cast(_total).time_since_epoch().count()); } std::tuple hms() { if (_is_running) { update(); } long int const diff {static_cast(std::chrono::time_point_cast(_total).time_since_epoch().count())}; return seconds_to_hms(diff); } std::string str() { if (_is_running) { update(); } long int const diff {static_cast(std::chrono::time_point_cast(_total).time_since_epoch().count())}; return seconds_to_string(diff); } void str(std::string const& str) { reset(); _total = std::chrono::time_point(string_to_seconds(str)); } static long int str_to_sec(std::string const& str) { return std::chrono::time_point(string_to_seconds(str)).time_since_epoch().count(); } static std::string sec_to_str(long int const sec) { return seconds_to_string(sec); } private: inline static long int constexpr t_second {1}; inline static long int constexpr t_minute {t_second * 60}; inline static long int constexpr t_hour {t_minute * 60}; inline static long int constexpr t_day {t_hour * 24}; inline static long int constexpr t_week {t_day * 7}; inline static long int constexpr t_month {static_cast(t_day * 30.4)}; inline static long int constexpr t_year {t_month * 12}; static std::chrono::seconds string_to_seconds(std::string const& str) { auto const pstr = OB::String::match(str, std::regex("^(?:(\\d+)Y)?:?(?:(\\d+)M)?:?(?:(\\d+)W)?:?(?:(\\d+)D)?:?(?:(\\d+)h)?:?(?:(\\d+)m)?:?(?:(\\d+)s)?$")); if (! pstr) { return static_cast(0); } auto const t = pstr.value(); long int sec {0}; if (! t.at(1).empty()) { sec += std::stol(t.at(1)) * t_year; } if (! t.at(2).empty()) { sec += std::stol(t.at(2)) * t_month; } if (! t.at(3).empty()) { sec += std::stol(t.at(3)) * t_week; } if (! t.at(4).empty()) { sec += std::stol(t.at(4)) * t_day; } if (! t.at(5).empty()) { sec += std::stol(t.at(5)) * t_hour; } if (! t.at(6).empty()) { sec += std::stol(t.at(6)) * t_minute; } if (! t.at(7).empty()) { sec += std::stol(t.at(7)) * t_second; } return static_cast(sec); } static std::string seconds_to_string(long int sec) { std::string res; auto const fuzzy_string = [&](long int const time_ref, std::string const time_str) { auto const t = (sec / time_ref); sec -= (t * time_ref); res += std::to_string(t) + time_str + ":"; }; if (sec >= t_year) { fuzzy_string(t_year, "Y"); } if (sec >= t_month) { fuzzy_string(t_month, "M"); } if (sec >= t_week) { fuzzy_string(t_week, "W"); } if (sec >= t_day) { fuzzy_string(t_day, "D"); } if (sec >= t_hour) { fuzzy_string(t_hour, "h"); } if (sec >= t_minute) { fuzzy_string(t_minute, "m"); } if (sec >= t_second) { fuzzy_string(t_second, "s"); } else { res += "0s:"; } res.pop_back(); return res; } static std::tuple seconds_to_hms(long int sec) { int hour {0}; int minute {0}; int second {0}; auto const calc = [&](long int const time_ref) { auto const t = (sec / time_ref); sec -= (t * time_ref); return t; }; if (sec > 0) { if (sec >= t_year) { calc(t_year); } if (sec >= t_month) { calc(t_month); } if (sec >= t_week) { calc(t_week); } if (sec >= t_day) { calc(t_day); } if (sec >= t_hour) { hour = calc(t_hour); } if (sec >= t_minute) { minute = calc(t_minute); } if (sec >= t_second) { second = calc(t_second); } } return {hour, minute, second}; } void update() { auto const stop = std::chrono::high_resolution_clock::now(); if (stop > _start) { _total += (stop - _start); } _start = stop; } bool _is_running {false}; std::chrono::time_point _start; std::chrono::time_point _total; }; // class Timer } // namespace OB #endif // OB_TIMER_HH