diff --git a/README.md b/README.md index f47473b..bc4eaa2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,34 @@ -Progress-CPP +Progress-CPP-Throttled-HeaderOnly === +## What's new, TLDR + +By printing progress bar only when it is needed, performance got better. + +Added ETA(Estimated time of arrival), and Spinner. + +It is just one header file, like original. + + + +## What's new and why, in detail + +### Throttling added + +Displaying progress is important, but when printing too much console from your program, your program slows down. That's what exactly happened to me when using original library. So I added throttling feature, to print the progress bar only when it is needed. When `throttle_progress` is set to 1(default), then program will display the progress bar only when percentage changes. If we set `throttle_progress` larger than 1, then it will skip printing progress bar until added progress percentage gets larger than `throttle_progress` . + +### ETA added + +Time estimation is added. It can be enabled/disabled by variable `is_eta_enabled` + +### Spinner added + +Spinner is added. It can be enabled/disabled by variable `is_spinner_enabled` + + + +## Original README of Progress-CPP + A flexible ASCII progress bar for your console based C++ projects. ### Usage diff --git a/example/src/example.cpp b/example/src/example.cpp index 225ca55..5ab4b08 100644 --- a/example/src/example.cpp +++ b/example/src/example.cpp @@ -1,5 +1,11 @@ #include -#include + +#ifdef _WIN32 +#include +#else +//#include +#endif + #include "progresscpp/ProgressBar.hpp" /* Example usage of ProgressBar */ @@ -16,11 +22,14 @@ int main() { for (int i = 0; i < total; i++) { ++progressBar; // record the tick - usleep(200); // simulate work +#ifdef _WIN32 + Sleep(1); +#else + usleep(100); // simulate work +#endif // display the bar only at certain steps - if (i % 10 == 0) - progressBar.display(); + progressBar.display(); } // tell the bar to finish diff --git a/include/progresscpp/ProgressBar.hpp b/include/progresscpp/ProgressBar.hpp index e4c4cf3..27aa64f 100644 --- a/include/progresscpp/ProgressBar.hpp +++ b/include/progresscpp/ProgressBar.hpp @@ -1,7 +1,14 @@ #pragma once +/* + * from progress-cpp by prakhar1989 (@ref https://github.com/prakhar1989/progress-cpp) + * added throttling by sikbrad @ref https://github.com/sikbrad/progress-cpp-throttled.git + */ + #include #include +#include +#include namespace progresscpp { class ProgressBar { @@ -9,39 +16,126 @@ class ProgressBar { unsigned int ticks = 0; const unsigned int total_ticks; - const unsigned int bar_width; + const unsigned int bar_width = 70; const char complete_char = '='; const char incomplete_char = ' '; const std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); public: + int throttle_progress = 5; + bool is_eta_enabled = true; + bool is_spinner_enabled = true; + +private: + int prev_progress_percent = 0; + int throttle_counter = 0; + int count_display = 0; + +public: + bool is_displayed = false; + +public: + ProgressBar(unsigned int total, unsigned int width, char complete, char incomplete, int throttle, bool is_eta) : + total_ticks{total}, bar_width{width}, complete_char{complete}, incomplete_char{incomplete}, throttle_progress{throttle}, is_eta_enabled{is_eta} {} + ProgressBar(unsigned int total, unsigned int width, char complete, char incomplete) : total_ticks{total}, bar_width{width}, complete_char{complete}, incomplete_char{incomplete} {} ProgressBar(unsigned int total, unsigned int width) : total_ticks{total}, bar_width{width} {} + ProgressBar(unsigned int total) : total_ticks{total} {} + unsigned int operator++() { return ++ticks; } - void display() const { - float progress = (float) ticks / total_ticks; - int pos = (int) (bar_width * progress); + void _display() const { + } + + bool display() { + float progress = (float) (ticks+1) / total_ticks; + int curr_progress_percent = ceil(100 * progress); + bool is_print = false; + + //dont limit if set as zero + if(throttle_progress == 0){ + is_print = true; + } + //if limit is set, + else if(prev_progress_percent > 0){ + //detect percentage change + if(prev_progress_percent < curr_progress_percent){ + ++throttle_counter; + + //when throttle exceeds, then print and reset the counter. + if(throttle_counter >= throttle_progress){ + throttle_counter = 0; + is_print = true; + } + } + } + + if(is_print){ + int pos = (int) (bar_width * progress); + + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + auto time_elapsed = std::chrono::duration_cast(now - start_time).count(); + + std::cout << "["; - std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - auto time_elapsed = std::chrono::duration_cast(now - start_time).count(); + for (int i = 0; i < bar_width; ++i) { + if (i < pos) std::cout << complete_char; + else if (i == pos) std::cout << ">"; + else std::cout << incomplete_char; + } + std::cout << "] "; - std::cout << "["; + std::cout << "[" << int(progress * 100.0) << "% "; + std::cout << std::fixed << std::setprecision(2) << float(time_elapsed) / 1000.0 << "s"; + std::cout << "]"; - for (int i = 0; i < bar_width; ++i) { - if (i < pos) std::cout << complete_char; - else if (i == pos) std::cout << ">"; - else std::cout << incomplete_char; + if(is_eta_enabled){ + float expected = float(time_elapsed) / progress; + float eta = abs(expected - time_elapsed); + std::cout << " eta " << std::fixed << std::setprecision(2) << float(eta) / 1000.0 << "s "; + } + + if(is_spinner_enabled){ + //followed character spinner style of etaprogress(python) + //@ref https://pypi.org/project/etaprogress/ + const int total_pinchar = 4; + int idx_spinchar = count_display % total_pinchar; + char spinchar = ' '; + switch(idx_spinchar){ + case 0: + spinchar = '-'; break; + case 1: + spinchar = '\\'; break; + case 2: + spinchar = '|'; break; + case 3: + spinchar = '/'; break; + default: + break; + } + std::cout << " " << spinchar; + } + + + std::cout << " \r"; + std::cout.flush(); + + is_displayed = true; + count_display++; + }else{ + is_displayed = false; } - std::cout << "] " << int(progress * 100.0) << "% " - << float(time_elapsed) / 1000.0 << "s\r"; - std::cout.flush(); + + //save status + prev_progress_percent = curr_progress_percent; + + return is_displayed; } - void done() const { + void done() { display(); std::cout << std::endl; }