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 ); 71 /*! 72 ensures 73 - print_status() assumes it is called with values which are linearly 74 approaching target(). It will attempt to predict how much time is 75 remaining until cur becomes equal to target(). 76 - prints a status message to the screen which indicates how much 77 more time is left until cur is equal to target() 78 - if (always_print) then 79 - This function prints to the screen each time it is called. 80 - else 81 - This function throttles the printing so that at most 1 message is 82 printed each second. Note that it won't print anything to the screen 83 until about one second has elapsed. This means that the first call 84 to print_status() never prints to the screen. 85 - This function returns true if it prints to the screen and false 86 otherwise. 87 !*/ 88 89 private: 90 91 double target_val; 92 93 time_t start_time; 94 double first_val; 95 double seen_first_val; 96 time_t last_time; 97 98 }; 99 100 // ---------------------------------------------------------------------------------------- 101 // ---------------------------------------------------------------------------------------- 102 // IMPLEMENTATION DETAILS 103 // ---------------------------------------------------------------------------------------- 104 // ---------------------------------------------------------------------------------------- 105 106 console_progress_indicator:: console_progress_indicator(double target_value)107 console_progress_indicator ( 108 double target_value 109 ) : 110 target_val(target_value), 111 start_time(0), 112 first_val(0), 113 seen_first_val(false), 114 last_time(0) 115 { 116 } 117 118 // ---------------------------------------------------------------------------------------- 119 120 bool console_progress_indicator:: print_status(double cur,bool always_print)121 print_status ( 122 double cur, 123 bool always_print 124 ) 125 { 126 const time_t cur_time = std::time(0); 127 128 // if this is the first time print_status has been called 129 // then collect some information and exit. We will print status 130 // on the next call. 131 if (!seen_first_val) 132 { 133 start_time = cur_time; 134 last_time = cur_time; 135 first_val = cur; 136 seen_first_val = true; 137 return false; 138 } 139 140 if (cur_time != last_time || always_print) 141 { 142 last_time = cur_time; 143 double delta_t = static_cast<double>(cur_time - start_time); 144 double delta_val = std::abs(cur - first_val); 145 146 // don't do anything if cur is equal to first_val 147 if (delta_val < std::numeric_limits<double>::epsilon()) 148 return false; 149 150 double seconds = delta_t/delta_val * std::abs(target_val - cur); 151 152 std::ios::fmtflags oldflags = std::cout.flags(); 153 154 std::cout.setf(std::ios::fixed,std::ios::floatfield); 155 std::streamsize ss; 156 157 if (seconds < 60) 158 { 159 ss = std::cout.precision(0); 160 std::cout << "Time remaining: " << seconds << " seconds. \r" << std::flush; 161 } 162 else if (seconds < 60*60) 163 { 164 ss = std::cout.precision(2); 165 std::cout << "Time remaining: " << seconds/60 << " minutes. \r" << std::flush; 166 } 167 else 168 { 169 ss = std::cout.precision(2); 170 std::cout << "Time remaining: " << seconds/60/60 << " hours. \r" << std::flush; 171 } 172 173 // restore previous output flags and precision settings 174 std::cout.flags(oldflags); 175 std::cout.precision(ss); 176 177 return true; 178 } 179 180 return false; 181 } 182 183 // ---------------------------------------------------------------------------------------- 184 185 double console_progress_indicator:: target()186 target ( 187 ) const 188 { 189 return target_val; 190 } 191 192 // ---------------------------------------------------------------------------------------- 193 194 void console_progress_indicator:: reset(double target_value)195 reset ( 196 double target_value 197 ) 198 { 199 *this = console_progress_indicator(target_value); 200 } 201 202 // ---------------------------------------------------------------------------------------- 203 204 } 205 206 #endif // DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_ 207 208