1 // Copyright (C) 2010 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_ 4 #define DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_ 5 6 #include <ctime> 7 #include <cmath> 8 #include <limits> 9 #include <iostream> 10 11 namespace dlib 12 { 13 14 // ---------------------------------------------------------------------------------------- 15 16 class console_progress_indicator 17 { 18 /*! 19 WHAT THIS OBJECT REPRESENTS 20 This object is a tool for reporting how long a task will take 21 to complete. 22 23 For example, consider the following bit of code: 24 25 console_progress_indicator pbar(100) 26 for (int i = 1; i <= 100; ++i) 27 { 28 pbar.print_status(i); 29 long_running_operation(); 30 } 31 32 The above code will print a message to the console each iteration 33 which shows how much time is remaining until the loop terminates. 34 !*/ 35 36 public: 37 38 inline explicit console_progress_indicator ( 39 double target_value 40 ); 41 /*! 42 ensures 43 - #target() == target_value 44 !*/ 45 46 inline void reset ( 47 double target_value 48 ); 49 /*! 50 ensures 51 - #target() == target_value 52 - performs the equivalent of: 53 *this = console_progress_indicator(target_value) 54 (i.e. resets this object with a new target value) 55 56 !*/ 57 58 inline double target ( 59 ) const; 60 /*! 61 ensures 62 - This object attempts to measure how much time is 63 left until we reach a certain targeted value. This 64 function returns that targeted value. 65 !*/ 66 67 inline bool print_status ( 68 double cur, 69 bool always_print = false, 70 std::ostream& out = std::cout 71 ); 72 /*! 73 ensures 74 - print_status() assumes it is called with values which are linearly 75 approaching target(). It will attempt to predict how much time is 76 remaining until cur becomes equal to target(). 77 - prints a status message to out which indicates how much more time is 78 left until cur is equal to target() 79 - if (always_print) then 80 - This function prints to the screen each time it is called. 81 - else 82 - This function throttles the printing so that at most 1 message is 83 printed each second. Note that it won't print anything to the screen 84 until about one second has elapsed. This means that the first call 85 to print_status() never prints to the screen. 86 - This function returns true if it prints to the screen and false 87 otherwise. 88 !*/ 89 90 private: 91 92 double target_val; 93 94 time_t start_time; 95 double first_val; 96 double seen_first_val; 97 time_t last_time; 98 99 }; 100 101 // ---------------------------------------------------------------------------------------- 102 // ---------------------------------------------------------------------------------------- 103 // IMPLEMENTATION DETAILS 104 // ---------------------------------------------------------------------------------------- 105 // ---------------------------------------------------------------------------------------- 106 107 console_progress_indicator:: console_progress_indicator(double target_value)108 console_progress_indicator ( 109 double target_value 110 ) : 111 target_val(target_value), 112 start_time(0), 113 first_val(0), 114 seen_first_val(false), 115 last_time(0) 116 { 117 } 118 119 // ---------------------------------------------------------------------------------------- 120 121 bool console_progress_indicator:: print_status(double cur,bool always_print,std::ostream & out)122 print_status ( 123 double cur, 124 bool always_print, 125 std::ostream& out 126 ) 127 { 128 const time_t cur_time = std::time(0); 129 130 // if this is the first time print_status has been called 131 // then collect some information and exit. We will print status 132 // on the next call. 133 if (!seen_first_val) 134 { 135 start_time = cur_time; 136 last_time = cur_time; 137 first_val = cur; 138 seen_first_val = true; 139 return false; 140 } 141 142 if (cur_time != last_time || always_print) 143 { 144 last_time = cur_time; 145 double delta_t = static_cast<double>(cur_time - start_time); 146 double delta_val = std::abs(cur - first_val); 147 148 // don't do anything if cur is equal to first_val 149 if (delta_val < std::numeric_limits<double>::epsilon()) 150 return false; 151 152 double seconds = delta_t/delta_val * std::abs(target_val - cur); 153 154 std::ios::fmtflags oldflags = out.flags(); 155 156 out.setf(std::ios::fixed,std::ios::floatfield); 157 std::streamsize ss; 158 159 if (seconds < 60) 160 { 161 ss = out.precision(0); 162 out << "Time remaining: " << seconds << " seconds. \r" << std::flush; 163 } 164 else if (seconds < 60*60) 165 { 166 ss = out.precision(2); 167 out << "Time remaining: " << seconds/60 << " minutes. \r" << std::flush; 168 } 169 else 170 { 171 ss = out.precision(2); 172 out << "Time remaining: " << seconds/60/60 << " hours. \r" << std::flush; 173 } 174 175 // restore previous output flags and precision settings 176 out.flags(oldflags); 177 out.precision(ss); 178 179 return true; 180 } 181 182 return false; 183 } 184 185 // ---------------------------------------------------------------------------------------- 186 187 double console_progress_indicator:: target()188 target ( 189 ) const 190 { 191 return target_val; 192 } 193 194 // ---------------------------------------------------------------------------------------- 195 196 void console_progress_indicator:: reset(double target_value)197 reset ( 198 double target_value 199 ) 200 { 201 *this = console_progress_indicator(target_value); 202 } 203 204 // ---------------------------------------------------------------------------------------- 205 206 } 207 208 #endif // DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_ 209 210