From d4a38eb034fad6fdfb707df5d1b8e3c482323cf3 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Sat, 22 Feb 2020 11:02:16 +0530 Subject: [PATCH 1/2] Closes 25 - Changed to --- README.md | 2 +- include/indicators/details/stream_helper.hpp | 4 ++-- include/indicators/dynamic_progress.hpp | 2 +- include/indicators/multi_progress.hpp | 7 +++++++ include/indicators/progress_bar.hpp | 14 +++++++------- include/indicators/progress_spinner.hpp | 10 +++++----- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5c4d580..528ce9f 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ To introduce a progress bar in your application, include `indicators/progress_ba ^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^ ``` -The amount of progress in ProgressBar is maintained as a float in range `[0, 100]`. When progress reaches 100, the progression is complete. +The amount of progress in ProgressBar is maintained as a size_t in range `[0, 100]`. When progress reaches 100, the progression is complete. From application-level code, there are two ways in which you can update this progress: diff --git a/include/indicators/details/stream_helper.hpp b/include/indicators/details/stream_helper.hpp index d85c2e9..eececed 100644 --- a/include/indicators/details/stream_helper.hpp +++ b/include/indicators/details/stream_helper.hpp @@ -102,8 +102,8 @@ public: const std::string &lead, const std::string &remainder) : os(os), bar_width(bar_width), fill(fill), lead(lead), remainder(remainder) {} - std::ostream &write(float progress) { - auto pos = static_cast(progress * static_cast(bar_width) / 100.0); + std::ostream &write(size_t progress) { + auto pos = static_cast(progress * bar_width / 100.0); for (size_t i = 0; i < bar_width; ++i) { if (i < pos) os << fill; diff --git a/include/indicators/dynamic_progress.hpp b/include/indicators/dynamic_progress.hpp index bc8f8a7..f97a7aa 100644 --- a/include/indicators/dynamic_progress.hpp +++ b/include/indicators/dynamic_progress.hpp @@ -123,7 +123,7 @@ private: for (size_t i = 0; i < total_count_; ++i) std::cout << "\x1b[A"; } - for (auto &bar: bars_) { + for (auto &bar : bars_) { bar.get().print_progress(true); std::cout << "\n"; } diff --git a/include/indicators/multi_progress.hpp b/include/indicators/multi_progress.hpp index ae8065f..41c4e86 100644 --- a/include/indicators/multi_progress.hpp +++ b/include/indicators/multi_progress.hpp @@ -45,6 +45,13 @@ public: } } + template + typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(size_t value) { + if (!bars_[index].get().is_completed()) + bars_[index].get().set_progress(value); + print_progress(); + } + template typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(float value) { if (!bars_[index].get().is_completed()) diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index 200eac5..4959755 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -126,9 +126,9 @@ public: } } - void set_progress(float new_progress) { + void set_progress(size_t new_progress) { { - std::lock_guard lck(mutex_); + std::lock_guard lock(mutex_); progress_ = new_progress; } @@ -147,7 +147,7 @@ public: size_t current() { std::lock_guard lock{mutex_}; - return std::min(static_cast(progress_), size_t(100)); + return std::min(progress_, size_t(100)); } bool is_completed() const { return get_value(); } @@ -169,7 +169,7 @@ private: return details::get_value(settings_).value; } - float progress_{0}; + size_t progress_{0}; Settings settings_; std::chrono::nanoseconds elapsed_; std::chrono::time_point start_time_point_; @@ -192,7 +192,7 @@ private: void print_progress(bool from_multi_progress = false) { std::lock_guard lock{mutex_}; if (multi_progress_mode_ && !from_multi_progress) { - if (progress_ > 100.0) { + if (progress_ > 100) { get_value() = true; } return; @@ -217,7 +217,7 @@ private: std::cout << get_value(); if (get_value()) { - std::cout << " " << std::min(static_cast(progress_), size_t(100)) << "%"; + std::cout << " " << std::min(progress_, size_t(100)) << "%"; } if (get_value()) { @@ -246,7 +246,7 @@ private: << std::string(get_value(), ' ') << "\r"; std::cout.flush(); - if (progress_ > 100.0) { + if (progress_ > 100) { get_value() = true; } if (get_value() && diff --git a/include/indicators/progress_spinner.hpp b/include/indicators/progress_spinner.hpp index 9a4d7c2..a69c316 100644 --- a/include/indicators/progress_spinner.hpp +++ b/include/indicators/progress_spinner.hpp @@ -119,7 +119,7 @@ public: } } - void set_progress(float value) { + void set_progress(size_t value) { { std::lock_guard lock{mutex_}; progress_ = value; @@ -139,7 +139,7 @@ public: size_t current() { std::lock_guard lock{mutex_}; - return std::min(static_cast(progress_), size_t(100)); + return std::min(progress_, size_t(100)); } bool is_completed() const { return get_value(); } @@ -151,7 +151,7 @@ public: private: Settings settings_; - float progress_{0.0}; + size_t progress_{0}; size_t index_{0}; std::chrono::time_point start_time_point_; std::mutex mutex_; @@ -189,7 +189,7 @@ private: std::cout << get_value() [index_ % get_value().size()]; if (get_value()) { - std::cout << " " << std::min(static_cast(progress_), size_t(100)) << "%"; + std::cout << " " << std::min(progress_, size_t(100)) << "%"; } if (get_value()) { @@ -219,7 +219,7 @@ private: << "\r"; std::cout.flush(); index_ += 1; - if (progress_ > 100.0) { + if (progress_ > 100) { get_value() = true; } if (get_value()) From 201ce9c4fb669049402ccd1b4bb4e1a9ed236b23 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Sat, 22 Feb 2020 11:13:04 +0530 Subject: [PATCH 2/2] Bumped to v1.8 --- CMakeLists.txt | 2 +- README.md | 2 +- single_include/indicators/indicators.hpp | 199 ++++++++++++++++++----- 3 files changed, 159 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 528bcfd..3965793 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ if(DEFINED PROJECT_NAME) set(INDICATORS_SUBPROJECT ON) endif() -project(indicators VERSION 1.7.0 LANGUAGES CXX +project(indicators VERSION 1.8.0 LANGUAGES CXX HOMEPAGE_URL "https://github.com/p-ranav/indicators" DESCRIPTION "Activity Indicators for Modern C++") diff --git a/README.md b/README.md index 528ce9f..1389b77 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ license - version + version

diff --git a/single_include/indicators/indicators.hpp b/single_include/indicators/indicators.hpp index 42453cb..be0e964 100644 --- a/single_include/indicators/indicators.hpp +++ b/single_include/indicators/indicators.hpp @@ -502,6 +502,8 @@ inline void win_change_attributes(std::ostream &stream, int foreground, int back #endif // TERMCOLOR_HPP_ +// details/stream_helper.hpp + namespace indicators { namespace details { @@ -591,8 +593,8 @@ public: const std::string &lead, const std::string &remainder) : os(os), bar_width(bar_width), fill(fill), lead(lead), remainder(remainder) {} - std::ostream &write(float progress) { - auto pos = static_cast(progress * static_cast(bar_width) / 100.0); + std::ostream &write(size_t progress) { + auto pos = static_cast(progress * bar_width / 100.0); for (size_t i = 0; i < bar_width; ++i) { if (i < pos) os << fill; @@ -615,32 +617,9 @@ private: } // namespace details } // namespace indicators -/* -Activity Indicators for Modern C++ -https://github.com/p-ranav/indicators - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2019 Dawid Pilarski . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ +// +// setting.hpp +// namespace indicators { @@ -695,7 +674,8 @@ enum class ProgressBarOption { saved_start_time, foreground_color, spinner_show, - spinner_states + spinner_states, + hide_bar_when_complete }; template struct Setting { @@ -806,9 +786,15 @@ using ForegroundColor = details::Setting; using SpinnerStates = details::Setting, details::ProgressBarOption::spinner_states>; +using HideBarWhenComplete = + details::BooleanSetting; } // namespace option } // namespace indicators +// +// progress_bar.hpp +// + namespace indicators { class ProgressBar { @@ -893,9 +879,9 @@ public: } } - void set_progress(float new_progress) { + void set_progress(size_t new_progress) { { - std::lock_guard lck(mutex_); + std::lock_guard lock(mutex_); progress_ = new_progress; } @@ -914,7 +900,7 @@ public: size_t current() { std::lock_guard lock{mutex_}; - return std::min(static_cast(progress_), size_t(100)); + return std::min(progress_, size_t(100)); } bool is_completed() const { return get_value(); } @@ -936,13 +922,14 @@ private: return details::get_value(settings_).value; } - float progress_{0}; + size_t progress_{0}; Settings settings_; std::chrono::nanoseconds elapsed_; std::chrono::time_point start_time_point_; std::mutex mutex_; template friend class MultiProgress; + template friend class DynamicProgress; std::atomic multi_progress_mode_{false}; void save_start_time() { @@ -956,13 +943,13 @@ private: } void print_progress(bool from_multi_progress = false) { + std::lock_guard lock{mutex_}; if (multi_progress_mode_ && !from_multi_progress) { - if (progress_ > 100.0) { + if (progress_ > 100) { get_value() = true; } return; } - std::lock_guard lock{mutex_}; auto now = std::chrono::high_resolution_clock::now(); if (!get_value()) elapsed_ = std::chrono::duration_cast(now - start_time_point_); @@ -983,7 +970,7 @@ private: std::cout << get_value(); if (get_value()) { - std::cout << " " << std::min(static_cast(progress_), size_t(100)) << "%"; + std::cout << " " << std::min(progress_, size_t(100)) << "%"; } if (get_value()) { @@ -1012,7 +999,7 @@ private: << std::string(get_value(), ' ') << "\r"; std::cout.flush(); - if (progress_ > 100.0) { + if (progress_ > 100) { get_value() = true; } if (get_value() && @@ -1023,6 +1010,10 @@ private: } // namespace indicators +// +// block_progress_bar.hpp +// + namespace indicators { class BlockProgressBar { @@ -1147,6 +1138,7 @@ private: std::mutex mutex_; template friend class MultiProgress; + template friend class DynamicProgress; std::atomic multi_progress_mode_{false}; void save_start_time() { @@ -1221,6 +1213,10 @@ private: } // namespace indicators +// +// progress_spinner.hpp +// + namespace indicators { class ProgressSpinner { @@ -1298,7 +1294,7 @@ public: } } - void set_progress(float value) { + void set_progress(size_t value) { { std::lock_guard lock{mutex_}; progress_ = value; @@ -1318,7 +1314,7 @@ public: size_t current() { std::lock_guard lock{mutex_}; - return std::min(static_cast(progress_), size_t(100)); + return std::min(progress_, size_t(100)); } bool is_completed() const { return get_value(); } @@ -1330,7 +1326,7 @@ public: private: Settings settings_; - float progress_{0.0}; + size_t progress_{0}; size_t index_{0}; std::chrono::time_point start_time_point_; std::mutex mutex_; @@ -1368,7 +1364,7 @@ private: std::cout << get_value() [index_ % get_value().size()]; if (get_value()) { - std::cout << " " << std::min(static_cast(progress_), size_t(100)) << "%"; + std::cout << " " << std::min(progress_, size_t(100)) << "%"; } if (get_value()) { @@ -1398,7 +1394,7 @@ private: << "\r"; std::cout.flush(); index_ += 1; - if (progress_ > 100.0) { + if (progress_ > 100) { get_value() = true; } if (get_value()) @@ -1408,6 +1404,10 @@ private: } // namespace indicators +// +// multi_progress.hpp +// + namespace indicators { template class MultiProgress { @@ -1421,6 +1421,13 @@ public: } } + template + typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(size_t value) { + if (!bars_[index].get().is_completed()) + bars_[index].get().set_progress(value); + print_progress(); + } + template typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(float value) { if (!bars_[index].get().is_completed()) @@ -1468,3 +1475,111 @@ private: }; } // namespace indicators + +// +// dynamic_progress.hpp +// + +namespace indicators { + +template class DynamicProgress { + using Settings = std::tuple; + +public: + template explicit DynamicProgress(Indicators &... bars) { + bars_ = {bars...}; + for (auto &bar : bars_) { + bar.get().multi_progress_mode_ = true; + ++total_count_; + ++incomplete_count_; + } + } + + Indicator &operator[](size_t index) { + print_progress(); + std::lock_guard lock{mutex_}; + return bars_[index].get(); + } + + size_t push_back(Indicator &bar) { + std::lock_guard lock{mutex_}; + bar.multi_progress_mode_ = true; + bars_.push_back(bar); + return bars_.size() - 1; + } + + template + void set_option(details::Setting &&setting) { + static_assert(!std::is_same( + std::declval()))>::type>::value, + "Setting has wrong type!"); + std::lock_guard lock(mutex_); + get_value() = std::move(setting).value; + } + + template + void set_option(const details::Setting &setting) { + static_assert(!std::is_same( + std::declval()))>::type>::value, + "Setting has wrong type!"); + std::lock_guard lock(mutex_); + get_value() = setting.value; + } + +private: + Settings settings_; + std::atomic started_{false}; + std::mutex mutex_; + std::vector> bars_; + std::atomic total_count_{0}; + std::atomic incomplete_count_{0}; + + template + auto get_value() -> decltype((details::get_value(std::declval()).value)) { + return details::get_value(settings_).value; + } + + template + auto get_value() const + -> decltype((details::get_value(std::declval()).value)) { + return details::get_value(settings_).value; + } + + void print_progress() { + std::lock_guard lock{mutex_}; + auto &hide_bar_when_complete = get_value(); + if (hide_bar_when_complete) { + // Hide completed bars + if (started_) { + for (size_t i = 0; i < incomplete_count_; ++i) + std::cout << "\033[A\r\033[K" << std::flush; + } + incomplete_count_ = 0; + for (auto &bar : bars_) { + if (!bar.get().is_completed()) { + bar.get().print_progress(true); + std::cout << "\n"; + ++incomplete_count_; + } + } + if (!started_) + started_ = true; + } else { + // Don't hide any bars + if (started_) { + for (size_t i = 0; i < total_count_; ++i) + std::cout << "\x1b[A"; + } + for (auto &bar : bars_) { + bar.get().print_progress(true); + std::cout << "\n"; + } + if (!started_) + started_ = true; + } + total_count_ = bars_.size(); + std::cout << termcolor::reset; + } +}; + +} // namespace indicators