// Copyright (C) 2010 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_ #define DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_ #include <ctime> #include <cmath> #include <limits> #include <iostream> namespace dlib { // ---------------------------------------------------------------------------------------- class console_progress_indicator { /*! WHAT THIS OBJECT REPRESENTS This object is a tool for reporting how long a task will take to complete. For example, consider the following bit of code: console_progress_indicator pbar(100) for (int i = 1; i <= 100; ++i) { pbar.print_status(i); long_running_operation(); } The above code will print a message to the console each iteration which shows how much time is remaining until the loop terminates. !*/ public: inline explicit console_progress_indicator ( double target_value ); /*! ensures - #target() == target_value !*/ inline void reset ( double target_value ); /*! ensures - #target() == target_value - performs the equivalent of: *this = console_progress_indicator(target_value) (i.e. resets this object with a new target value) !*/ inline double target ( ) const; /*! ensures - This object attempts to measure how much time is left until we reach a certain targeted value. This function returns that targeted value. !*/ inline bool print_status ( double cur, bool always_print = false ); /*! ensures - print_status() assumes it is called with values which are linearly approaching target(). It will attempt to predict how much time is remaining until cur becomes equal to target(). - prints a status message to the screen which indicates how much more time is left until cur is equal to target() - if (always_print) then - This function prints to the screen each time it is called. - else - This function throttles the printing so that at most 1 message is printed each second. Note that it won't print anything to the screen until about one second has elapsed. This means that the first call to print_status() never prints to the screen. - This function returns true if it prints to the screen and false otherwise. !*/ private: double target_val; time_t start_time; double first_val; double seen_first_val; time_t last_time; }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // IMPLEMENTATION DETAILS // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- console_progress_indicator:: console_progress_indicator ( double target_value ) : target_val(target_value), start_time(0), first_val(0), seen_first_val(false), last_time(0) { } // ---------------------------------------------------------------------------------------- bool console_progress_indicator:: print_status ( double cur, bool always_print ) { const time_t cur_time = std::time(0); // if this is the first time print_status has been called // then collect some information and exit. We will print status // on the next call. if (!seen_first_val) { start_time = cur_time; last_time = cur_time; first_val = cur; seen_first_val = true; return false; } if (cur_time != last_time || always_print) { last_time = cur_time; double delta_t = static_cast<double>(cur_time - start_time); double delta_val = std::abs(cur - first_val); // don't do anything if cur is equal to first_val if (delta_val < std::numeric_limits<double>::epsilon()) return false; double seconds = delta_t/delta_val * std::abs(target_val - cur); std::ios::fmtflags oldflags = std::cout.flags(); std::cout.flags(); std::cout.setf(std::ios::fixed,std::ios::floatfield); std::streamsize ss; if (seconds < 60) { ss = std::cout.precision(0); std::cout << "Time remaining: " << seconds << " seconds. \r" << std::flush; } else if (seconds < 60*60) { ss = std::cout.precision(2); std::cout << "Time remaining: " << seconds/60 << " minutes. \r" << std::flush; } else { ss = std::cout.precision(2); std::cout << "Time remaining: " << seconds/60/60 << " hours. \r" << std::flush; } // restore previous output flags and precision settings std::cout.flags(oldflags); std::cout.precision(ss); return true; } return false; } // ---------------------------------------------------------------------------------------- double console_progress_indicator:: target ( ) const { return target_val; } // ---------------------------------------------------------------------------------------- void console_progress_indicator:: reset ( double target_value ) { *this = console_progress_indicator(target_value); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_