diff --git a/examples/BUCK b/examples/BUCK deleted file mode 100644 index 183564d..0000000 --- a/examples/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -# test driver -cxx_binary( - name = "testdrive", - srcs = [ - "main.cpp", - ], - link_style = "shared", - deps = [ - "//progressbar:progressbar", - "//logger:logger", - ], - deps_query = "$declared_deps", - labels = [], -) diff --git a/examples/main.cpp b/examples/main.cpp index da5c507..98e2db0 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -15,19 +15,18 @@ int main() { constexpr int test_size = 4; constexpr int test_size2 = 80000; - pbar::ProgressBar* progressBar = - new pbar::ProgressBar("fiiirst", test_size); + pbar::ProgressBar pBar("fiiirst", test_size); + pbar::ProgressBar pBar2("secoond", test_size2, true); for (int i = 0; i < test_size; i++) { - pbar::ProgressBar* progressBar2 = - new pbar::ProgressBar("secoond", test_size2, true); + pBar2.reset(); for (int j = 0; j < test_size2; j++) { - progressBar2->update(); + pBar2.update(); usleep(1); } - delete progressBar2; - progressBar->update(); + pBar.update(); } - delete progressBar; + pBar2.close(); + pBar.close(); std::cout << std::endl << std::endl; std::cout << "test driver END" << std::endl; diff --git a/pbar/BUCK b/pbar/BUCK deleted file mode 100644 index 04f1bc0..0000000 --- a/pbar/BUCK +++ /dev/null @@ -1,20 +0,0 @@ -cxx_library( - name = "progressbar", - srcs = [ - "pbar.cpp", - ], - headers = [], - exported_headers = [ - "pbar.h", - ], - header_namespace = "progressbar", - link_style = "shared", - preferred_linkage = "shared", - deps = [ - "//utils:builtin-color-util", - ], - visibility = [ - "//examples:testdrive" - ], - labels = [], -) diff --git a/pbar/pbar.cpp b/pbar/pbar.cpp index 6c95824..0f2c35a 100644 --- a/pbar/pbar.cpp +++ b/pbar/pbar.cpp @@ -8,11 +8,11 @@ #include "pbar.hpp" +#include #include #include #include -#include #include "unistd.h" namespace pbar { @@ -25,22 +25,25 @@ int window_width::operator()() const { return 0; } // static_window_width static_window_width::static_window_width(const int width) : width(width) {} +static_window_width::~static_window_width() {} int static_window_width::operator()() const { return this->width; } // dynamic_window_width dynamic_window_width::dynamic_window_width() {} +dynamic_window_width::~dynamic_window_width() {} int dynamic_window_width::operator()() const { ioctl(STDOUT_FILENO, TIOCGWINSZ, &(this->window_size)); return static_cast(this->window_size.ws_col); } } // namespace window_width -ProgressBar::ProgressBar(const std::string& description, const int total, +ProgressBar::ProgressBar(const std::string& description, const long long& total, const bool leave, const int width, const std::chrono::nanoseconds min_interval_time, - const std::string& bar_format, const int initial_value, - const int position) - : description(description), + const std::string& bar_format, + const long long& initial_value, const int position) + : initial_value(initial_value), + description(description), total(total), leave(leave), min_interval_time(min_interval_time), @@ -51,7 +54,8 @@ ProgressBar::ProgressBar(const std::string& description, const int total, n(initial_value), position(position), last_update_n(initial_value), - last_update_time(std::chrono::system_clock::now()) { + last_update_time(std::chrono::system_clock::now()), + disable(false) { if (width > 0) { this->window_width = new window_width::static_window_width(width); } else { @@ -61,28 +65,14 @@ ProgressBar::ProgressBar(const std::string& description, const int total, this->display(); } -ProgressBar::ProgressBar(const std::string& description, const int total, +ProgressBar::ProgressBar(const std::string& description, const long long& total, const bool leave) : ProgressBar(description, total, leave, -1, std::chrono::duration_cast( - std::chrono::milliseconds(100)), + std::chrono::milliseconds(10)), "", 0, ProgressBar::nbars) {} -ProgressBar::~ProgressBar() { - this->display(); - /* Cleanup and (depends on config) close the progressbar - */ - // TODO: think this through - if (this->leave) { - // leave this bar as it is - } else { - this->moveto(this->position); - std::cout << "\r" << aesc::cursor::EL(aesc::cursor::clear::to_end); - this->moveto(-this->position); - } - ProgressBar::nbars -= 1; - delete window_width; -} +ProgressBar::~ProgressBar() { this->close(); } inline float ProgressBar::percentage() { // TODO: deprecate and merge @@ -108,7 +98,7 @@ void ProgressBar::moveto(const int n) { */ if (n > 0) { - // moves down + // moves down, needs NEWLINE to actually create and move to lines below for (int i = 0; i != n; ++i) { std::cout << "\n"; } @@ -171,6 +161,8 @@ std::string ProgressBar::format_meter() { void ProgressBar::display() { /** Refresh display of this bar */ + const std::lock_guard guard(this->pbar_mutex); + if (this->position) { this->moveto(this->position); } @@ -184,7 +176,25 @@ void ProgressBar::display() { std::cout << std::flush; } +const std::chrono::nanoseconds ProgressBar::delta_time( + std::chrono::time_point& now) { + return std::chrono::duration_cast( + now - this->last_update_time); +} + +inline long ProgressBar::delta_iter() { + return static_cast(this->n - this->last_update_n); +} + void ProgressBar::update(const int n) { + if (this->disable) { + return; + } + + // HACK: for auto-refresh logic to work + if (n < 0) { + this->last_update_n += n; + } this->n += n; // BUG: TODO: consider last_print_n when n < 0 @@ -197,24 +207,64 @@ void ProgressBar::update(const int n) { if (this->delta_time(now) > this->min_interval_time) { this->display(); - // TODO: dynamic min_interval_iter adjustments - this->min_interval_iter = delta_iters / 3; + // TODO: find better dynamic min_interval_iter adjustments, might + // want to consider interval fluctuation Uses max number of + // iterations between two updates + this->min_interval_iter = + std::max(this->min_interval_iter, delta_iters); // TODO: how to evaluate this guess on next round - this->last_update_n = this->n; - this->last_update_time = std::move(now); + // Store old values for next call + { + std::lock_guard guard(this->pbar_mutex); + // this->last_update_n = this->n; + const long long tmp = this->n.load(); + this->last_update_n = tmp; + + this->last_update_time = std::move(now); + } } } } -const std::chrono::nanoseconds ProgressBar::delta_time( - std::chrono::time_point& now) { - return std::chrono::duration_cast( - now - this->last_update_time); +void ProgressBar::close() { + /* Clean up visuals, closes pbar if set not to leave it + * then resets + */ + if (this->disable) { + return; + } + // Prevent multiple closures + this->disable = true; + + // Remove pbar from record + ProgressBar::nbars -= 1; + // TODO: implement internal set instead of simple counting to maintain + // multi-bar order + delete window_width; + + this->display(); + // TODO: write final stats + + if (this->leave) { + // leave this bar as it is + } else { + // close (clean up) the pbar + const std::lock_guard guard(this->pbar_mutex); + + this->moveto(this->position); + std::cout << "\r" << aesc::cursor::EL(aesc::cursor::clear::to_end); + this->moveto(-this->position); + } } -long ProgressBar::delta_iter() { - return static_cast(this->n - this->last_update_n); +void ProgressBar::reset() { + /* encourages repeated use + */ + this->n = this->initial_value; + this->last_update_n = this->initial_value; + this->last_update_time = std::chrono::system_clock::now(); + this->display(); } } // namespace pbar diff --git a/pbar/pbar.hpp b/pbar/pbar.hpp index 9d639f8..1249824 100644 --- a/pbar/pbar.hpp +++ b/pbar/pbar.hpp @@ -11,24 +11,21 @@ #include +#include #include +#include #include #include #include namespace pbar { -class Bar { - public: - Bar(); - void refresh(); -}; - namespace window_width { // Functor class window_width { public: virtual int operator()() const; + virtual ~window_width() {} }; class static_window_width final : public window_width { @@ -38,6 +35,7 @@ class static_window_width final : public window_width { public: explicit static_window_width(const int width); int operator()() const final override; + ~static_window_width(); }; class dynamic_window_width final : public window_width { @@ -47,26 +45,33 @@ class dynamic_window_width final : public window_width { public: dynamic_window_width(); int operator()() const final override; + ~dynamic_window_width(); }; + } // namespace window_width class ProgressBar { - /* Not copyable, but movable + /* TODO: Not copyable, but movable */ private: static int nbars; // bar count + private: // initial values, used in reset() + long long initial_value; + private: - const std::string description; - const long long total; + std::string description; + long long total; const bool leave; std::chrono::nanoseconds min_interval_time; long min_interval_iter; - const std::string bar_format; - long long n; + std::string bar_format; + std::atomic n; const int position; - long long last_update_n; + std::atomic last_update_n; std::chrono::system_clock::time_point last_update_time; + bool disable; + std::mutex pbar_mutex; private: inline float percentage(); @@ -78,19 +83,21 @@ class ProgressBar { void display(); const std::chrono::nanoseconds delta_time( std::chrono::time_point& now); - long delta_iter(); + inline long delta_iter(); public: - explicit ProgressBar(const std::string& description, const int total, + explicit ProgressBar(const std::string& description, const long long& total, const bool leave, const int width, const std::chrono::nanoseconds min_interval_time, - const std::string& bar_format, const int initial_value, - const int position); - explicit ProgressBar(const std::string& description, const int total, + const std::string& bar_format, + const long long& initial_value, const int position); + explicit ProgressBar(const std::string& description, const long long& total, const bool leave = (ProgressBar::nbars ? false : true)); ~ProgressBar(); void update(const int n = 1); + void close(); + void reset(); }; } // namespace pbar