#pragma once #include <chrono> namespace geode::utils { template <typename T> struct is_chrono_duration { static constexpr bool value = false; }; template <typename Rep, typename Period> struct is_chrono_duration<std::chrono::duration<Rep, Period>> { static constexpr bool value = true; }; template <class Clock = std::chrono::high_resolution_clock> class Timer { public: using clock_point = std::chrono::time_point<Clock>; private: clock_point m_start; public: Timer() { m_start = Clock::now(); } void reset() { m_start = Clock::now(); } clock_point time() const { return m_start; } template <typename Duration = std::chrono::milliseconds> int64_t elapsed() const { static_assert( is_chrono_duration<Duration>::value, "Duration must be a std::chrono::duration" ); auto end = Clock::now(); return std::chrono::duration_cast<Duration>(end - m_start).count(); } template <typename Duration = std::chrono::milliseconds> std::string elapsedAsString() const { static_assert( is_chrono_duration<Duration>::value, "Duration must be a std::chrono::duration" ); if constexpr (std::is_same<Duration, std::chrono::milliseconds>::value) { return std::to_string(this->elapsed<Duration>()) + "ms"; } else if constexpr (std::is_same<Duration, std::chrono::microseconds>::value) { return std::to_string(this->elapsed<Duration>()) + "us"; } else if constexpr (std::is_same<Duration, std::chrono::nanoseconds>::value) { return std::to_string(this->elapsed<Duration>()) + "ns"; } else { // static_assert(!std::is_same_v<bool, bool>, "Unsupported duration type"); } } }; template < typename Duration = std::chrono::milliseconds, class Clock = std::chrono::high_resolution_clock> struct LogPerformance { std::ostream& m_output; std::string m_msg; Timer<Clock> m_timer; LogPerformance(std::string const& msg = "", std::ostream& out = std::cout) : m_msg(msg), m_output(out) { m_timer = Timer<Clock>(); }; ~LogPerformance() { m_output << "Running \"" << m_msg << "\" took " << m_timer.template elapsedAsString<Duration>() << std::endl; } }; }