Skip to content

Commit

Permalink
Improve IterableBar (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
oir authored May 11, 2024
1 parent 6bcba84 commit 87aeca2
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 39 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,41 @@ __barkeep__ strives to be [non-intrusive](https://oir.github.io/barkeep/#/README
<img src="docs/rec/iter-bar-light.svg" width="700">
</picture>
<blockquote>
<details>
<summary>
Detail: IterableBar starts the display not at the time of construction, ...
</summary>
... but at the time of the first call to `begin()`.
Thus, it is possible to set it up prior to loop execution.
Similarly, it ends the display not at the time of destruction, but at the
first increment of the iterator past the end. Thus, even if the object stays
alive after the loop, the display will be stopped.
Therefore, you could initialize it earlier than the loop execution, and destroy
it late afterwards:
```cpp
std::vector<float> v(300, 0);
std::iota(v.begin(), v.end(), 1); // 1, 2, 3, ..., 300
float sum = 0;
bk::IterableBar bar(v, {.message = "Summing", .interval = .02});
// <-- At this point, display is not yet shown.
// Thus, more work can be done here.
for (auto x : bar) { // <-- Display starts showing.
std::this_thread::sleep_for(1.s/x);
sum += x;
}
// <-- Display stops here even if `bar` object is still alive.
// Thus, more work can be done here.
std::cout << "Sum: " << sum << std::endl;
```

</details>
</blockquote>

- Combine diplays using `|` operator to monitor multiple variables:

```cpp
Expand Down
91 changes: 54 additions & 37 deletions barkeep/barkeep.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

#include <atomic>
#include <cassert>
#include <cmath>
#include <chrono>
#include <cmath>
#include <condition_variable>
#include <iomanip>
#include <iostream>
Expand Down Expand Up @@ -260,7 +260,7 @@ struct AnimationConfig {

/// style as AnimationStyle or custom animation as a list of strings
std::variant<AnimationStyle, Strings> style = Ellipsis;

/// interval in which the animation is refreshed
std::variant<Duration, double> interval = Duration{0.};
bool no_tty = false; ///< no-tty mode if true (no \r, slower default refresh)
Expand Down Expand Up @@ -357,7 +357,7 @@ class Composite : public AsyncDisplay {
left_->done();
right_->done();
right_->out_ = left_->out_;
//show();
// show();
}

/// Copy constructor clones child displays.
Expand Down Expand Up @@ -553,13 +553,13 @@ class Counter : public AsyncDisplay {
format_,
std::make_format_args(progress,
speedom_ ? speedom_->speed() : std::nan(""),
red, // 2
green, // 3
yellow, // 4
blue, // 5
red, // 2
green, // 3
yellow, // 4
blue, // 5
magenta, // 6
cyan, // 7
reset) // 8
cyan, // 7
reset) // 8

);
return;
Expand Down Expand Up @@ -621,7 +621,7 @@ class Counter : public AsyncDisplay {
speedom_(std::move(other.speedom_)),
speed_unit_(other.speed_unit_) {
if (other.running()) { show(); }
}
}

~Counter() { done(); }

Expand All @@ -648,7 +648,7 @@ struct ProgressBarConfig {

/// progress bar style, or custom style as BarParts
std::variant<ProgressBarStyle, BarParts> style = Blocks;

/// interval in which the progress bar is refreshed
std::variant<Duration, double> interval = Duration{0.};
bool no_tty = false; ///< no-tty mode if true (no \r, slower default refresh)
Expand Down Expand Up @@ -797,26 +797,26 @@ class ProgressBar : public AsyncDisplay {
#elif defined(BARKEEP_ENABLE_STD_FORMAT)
if (not format_.empty()) {
value_t<Progress> progress = *progress_;

std::stringstream bar_ss;
render_progress_bar_(&bar_ss);

double percent = progress * 100. / total_;
*out_ << std::vformat(
format_,
std::make_format_args(progress, // 0
bar_ss.str(), // 1
percent, // 2
total_, // 3
speedom_ ? speedom_->speed() : std::nan(""), // 4
red, // 5
green, // 6
yellow, // 7
blue, // 8
magenta, // 9
cyan, // 10
reset)); // 11

*out_ << std::vformat(format_,
std::make_format_args(progress, // 0
bar_ss.str(), // 1
percent, // 2
total_, // 3
speedom_ ? speedom_->speed()
: std::nan(""), // 4
red, // 5
green, // 6
yellow, // 7
blue, // 8
magenta, // 9
cyan, // 10
reset)); // 11
return;
}
#endif
Expand Down Expand Up @@ -885,7 +885,7 @@ class ProgressBar : public AsyncDisplay {
total_(other.total_),
bar_parts_(std::move(other.bar_parts_)) {
if (other.running()) { show(); }
}
}

/// copy constructor
ProgressBar(const ProgressBar<Progress>& other)
Expand Down Expand Up @@ -932,30 +932,44 @@ struct IterableBarConfig {

/// A progress bar that can be used with range-based for loops, that
/// automatically tracks the progress of the loop.
///
/// IterableBar starts the display not at the time of construction, but at the
/// time of the first call to begin(). Thus, it is possible to set it up prior
/// to loop execution.
///
/// Similarly, it ends the display not at the time of destruction, but at the
/// first increment of the iterator past the end. Thus, even if the object stays
/// alive after the loop, the display will be stopped.
template <typename Container>
class IterableBar {
public:
using ProgressType = std::atomic<size_t>;
using ValueType = value_t<ProgressType>;
using Bar = ProgressBar<ProgressType>;

private:
Container& container_;
std::shared_ptr<ProgressType> idx_;
std::shared_ptr<ProgressBar<ProgressType>> bar_;
std::shared_ptr<Bar> bar_;

public:
class Iterator {
private:
typename Container::iterator it_;
typename Container::iterator it_, end_;
ProgressType& idx_;
std::shared_ptr<Bar> bar_;

public:
Iterator(typename Container::iterator it, ProgressType& idx)
: it_(it), idx_(idx) {}
Iterator(typename Container::iterator it,
typename Container::iterator end,
ProgressType& idx,
std::shared_ptr<Bar> bar)
: it_(it), end_(end), idx_(idx), bar_(std::move(bar)) {}

Iterator& operator++() {
it_++;
idx_++;
if (it_ == end_) { bar_->done(); }
return *this;
}

Expand All @@ -968,7 +982,7 @@ class IterableBar {
const IterableBarConfig<ValueType>& cfg = {})
: container_(container),
idx_(std::make_shared<ProgressType>(0)),
bar_(std::make_shared<ProgressBar<ProgressType>>(
bar_(std::make_shared<Bar>(
&*idx_,
ProgressBarConfig<ValueType>{cfg.out,
container.size(),
Expand All @@ -978,14 +992,17 @@ class IterableBar {
cfg.speed_unit,
cfg.style,
cfg.interval,
cfg.no_tty})) {}
cfg.no_tty,
/*show=*/false})) {}

auto begin() {
bar_->show();
return Iterator(container_.begin(), *idx_);
return Iterator(container_.begin(), container_.end(), *idx_, bar_);
}

auto end() { return Iterator(container_.end(), *idx_); }
auto end() {
return Iterator(container_.end(), container_.end(), *idx_, bar_);
}
};

} // namespace barkeep
Expand Down
37 changes: 36 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,48 @@ __barkeep__ also has [python bindings](https://pypi.python.org/pypi/barkeep).
}
std::cout << "Sum: " << sum << std::endl;
```
<picture>
<source media="(prefers-color-scheme: dark)" srcset="rec/iter-bar-dark.svg" width="700">
<source media="(prefers-color-scheme: light)" srcset="rec/iter-bar-light.svg" width="700">
<img src="rec/iter-bar-light.svg" width="700">
</picture>
<blockquote class="warn">
<details>
<summary>
Detail: IterableBar starts the display not at the time of construction, ...
</summary>
... but at the time of the first call to `begin()`.
Thus, it is possible to set it up prior to loop execution.
Similarly, it ends the display not at the time of destruction, but at the
first increment of the iterator past the end. Thus, even if the object stays
alive after the loop, the display will be stopped.
Therefore, you could initialize it earlier than the loop execution, and destroy
it late afterwards:
```cpp
std::vector<float> v(300, 0);
std::iota(v.begin(), v.end(), 1); // 1, 2, 3, ..., 300
float sum = 0;
bk::IterableBar bar(v, {.message = "Summing", .interval = .02});
// <-- At this point, display is not yet shown.
// Thus, more work can be done here.
for (auto x : bar) { // <-- Display starts showing.
std::this_thread::sleep_for(1.s/x);
sum += x;
}
// <-- Display stops here even if `bar` object is still alive.
// Thus, more work can be done here.
std::cout << "Sum: " << sum << std::endl;
```

</details>
</blockquote>

- Combine diplays using `|` operator to monitor multiple variables:

```cpp
Expand Down
1 change: 0 additions & 1 deletion tests/demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ int main(int /*argc*/, char** /*argv*/) {
}

{ // Iterable automatic progress bar

std::vector<float> v(300, 0);
std::iota(v.begin(), v.end(), 1); // 1, 2, 3, ..., 300
float sum = 0;
Expand Down

0 comments on commit 87aeca2

Please sign in to comment.