/** * \file * \brief Utilities header * * \author * Christos Choutouridis AEM:8997 * */ #ifndef UTILS_HPP_ #define UTILS_HPP_ #include #include #include #include #include #include "config.h" /*! * A Logger for entire program. */ struct Log { struct Endl {} endl; //!< a tag object to to use it as a new line request. //! We provide logging via << operator template Log &operator<<(T &&t) { if (config.verbose) { if (line_) { std::cout << "[Log]: " << t; line_ = false; } else std::cout << t; } return *this; } // overload for special end line handling Log &operator<<(Endl e) { (void) e; if (config.verbose) { std::cout << '\n'; line_ = true; } return *this; } private: bool line_{true}; }; extern Log logger; /*! * A small timing utility based on chrono that supports timing rounds * and returning the median of them. Time can accumulate to the measurement * for each round. */ struct Timing { using Tpoint = std::chrono::steady_clock::time_point; using Tduration = std::chrono::microseconds; using microseconds = std::chrono::microseconds; using milliseconds = std::chrono::milliseconds; using seconds = std::chrono::seconds; //! Setup measurement rounds void init(size_t rounds) { duration_.resize(rounds); for (auto& d : duration_) d = Tduration::zero(); } //! tool to mark the starting point Tpoint start() noexcept { return mark_ = std::chrono::steady_clock::now(); } //! tool to mark the ending point Tpoint stop() noexcept { Tpoint now = std::chrono::steady_clock::now(); duration_[current_] += dt(now, mark_); return now; } //! Switch timing slot void next() noexcept { ++current_; current_ %= duration_.size(); } Tduration& median() noexcept { std::sort(duration_.begin(), duration_.end()); return duration_[duration_.size()/2]; } //! A duration calculation utility static Tduration dt(Tpoint t2, Tpoint t1) noexcept { return std::chrono::duration_cast(t2 - t1); } //! Tool to print the time interval static void print_duration(const Tduration& duration, const char *what) noexcept { if (std::chrono::duration_cast(duration).count() < 10000) std::cout << "[Timing] " << what << ": " << std::to_string(std::chrono::duration_cast(duration).count()) << " [usec]\n"; else if (std::chrono::duration_cast(duration).count() < 10000) std::cout << "[Timing] " << what << ": " << std::to_string(std::chrono::duration_cast(duration).count()) << " [msec]\n"; else { char stime[26]; // fit ulong auto sec = std::chrono::duration_cast(duration).count(); auto msec = (std::chrono::duration_cast(duration).count() % 1000) / 10; // keep 2 digit std::sprintf(stime, "%ld.%1ld", sec, msec); std::cout << "[Timing] " << what << ": " << stime << " [sec]\n"; } } private: size_t current_{0}; Tpoint mark_{}; std::vector duration_{1}; }; /*! * A "high level function"-like utility macro to forward a function call * and accumulate the execution time to the corresponding timing object. * * @param Tim The Timing object [Needs to have methods start() and stop()] * @param Func The function name * @param ... The arguments to pass to function (the preprocessor way) */ #define timeCall(Tim, Func, ...) \ Tim.start(); \ Func(__VA_ARGS__); \ Tim.stop(); \ /*! * A utility to check if a number is power of two * * @tparam Integral The integral type of the number to check * @param x The number to check * @return True if it is power of 2, false otherwise */ template constexpr inline bool isPowerOfTwo(Integral x) noexcept { return (!(x & (x - 1)) && x); } #endif /* UTILS_HPP_ */