Skip to content

Commit

Permalink
Add ability to specify delimiter for Composite, remove Arrow bar (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
oir authored Jul 15, 2024
1 parent 2977de7 commit 8ee6f8d
Show file tree
Hide file tree
Showing 12 changed files with 358 additions and 222 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ jobs:
- [ubuntu-20.04, musllinux, aarch64]
- [ubuntu-20.04, musllinux, ppc64le]
- [ubuntu-20.04, musllinux, s390x]
- [macos-13, macosx, x86_64]
- [macos-14, macosx, arm64]
- [macos-13, macosx, x86_64] # macOS 13 is x86
- [macos-14, macosx, arm64] # macOS 14 is ARM
version: [39, 310, 311, 312]
steps:
- uses: actions/checkout@v4
Expand Down
105 changes: 59 additions & 46 deletions barkeep/barkeep.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const static StringsList animation_stills_{
};

/// Kind of bar being displayed for ProgressBar.
enum ProgressBarStyle : unsigned short { Bars, Blocks, Arrow, Pip };
enum ProgressBarStyle : unsigned short { Bars, Blocks, Pip };

struct BarParts {
std::string left;
Expand Down Expand Up @@ -95,7 +95,6 @@ const static std::string reset = "\033[0m";
const static std::vector<BarParts> progress_bar_parts_{
{"|", "|", {"|"}, {" "}},
{"|", "|", {"", "", "", "", "", "", "", ""}, {" "}},
{"|", "|", {">", "="}, {" "}},
{"",
"",
{"", ""},
Expand Down Expand Up @@ -131,7 +130,7 @@ class AsyncDisplay {

protected:
/// Render a display: animation, progress bar, etc.
virtual void render_() = 0;
virtual void render_(const std::string& end = " ") = 0;

virtual Duration default_interval_() const = 0;

Expand Down Expand Up @@ -282,9 +281,9 @@ class Animation : public AsyncDisplay {
Strings stills_;

protected:
void render_() override {
void render_(const std::string& end = " ") override {
render_message_();
*out_ << stills_[frame_] << " ";
*out_ << stills_[frame_] << end;
frame_ = (frame_ + 1) % stills_.size();
}

Expand Down Expand Up @@ -326,46 +325,57 @@ class Animation : public AsyncDisplay {
/// For instance, you can combine two Counter objects to monitor two variables.
class Composite : public AsyncDisplay {
protected:
std::unique_ptr<AsyncDisplay> left_, right_;
std::string delim_ = " ";
std::vector<std::unique_ptr<AsyncDisplay>> displays_;

void render_() override {
left_->render_();
*out_ << " ";
right_->render_();
void render_(const std::string& end = " ") override {
for (auto it = displays_.begin(); it != displays_.end(); it++) {
if (it != displays_.begin()) { *out_ << delim_; }
(*it)->render_((it != displays_.end() - 1) ? "" : end);
}
}

Duration default_interval_() const override {
// TODO: maybe make this the min of the two?
return left_->default_interval_();
// TODO: maybe make this the min of all?
return displays_.front()->default_interval_();
}

void start() override {
left_->start();
right_->start();
for (auto& display : displays_) { display->start(); }
}

public:
Composite(std::unique_ptr<AsyncDisplay> left,
std::unique_ptr<AsyncDisplay> right)
: AsyncDisplay(left->out_,
left->interval_,
left->message_,
/// Variadic constructor to combine multiple displays into a Composite.
template <typename... Displays>
Composite(const AsyncDisplay& head, const Displays&... tail)
: AsyncDisplay(head.out_,
head.interval_,
"",
left->no_tty_ or right->no_tty_),
left_(std::move(left)),
right_(std::move(right)) {
left_->done();
right_->done();
right_->out_ = left_->out_;
"",
head.no_tty_ or (... or tail.no_tty_)) {
displays_.emplace_back(head.clone());
(displays_.emplace_back(tail.clone()), ...);
for (auto& display : displays_) {
display->done();
display->out_ = displays_.front()->out_;
}
// show();
}

/// Constructor to combine multiple displays into a Composite with a
/// delimiter.
template <typename... Displays>
Composite(std::string delim, const Displays&... displays)
: Composite(displays...) {
delim_ = std::move(delim);
}

/// Copy constructor clones child displays.
Composite(const Composite& other)
: AsyncDisplay(other),
left_(other.left_->clone()),
right_(other.right_->clone()) {
right_->out_ = left_->out_;
Composite(const Composite& other) : AsyncDisplay(other) {
for (const auto& display : other.displays_) {
displays_.push_back(display->clone());
displays_.back()->out_ = displays_.front()->out_;
}
if (other.running()) { show(); }
}
~Composite() { done(); }
Expand All @@ -377,7 +387,7 @@ class Composite : public AsyncDisplay {

/// Pipe operator can be used to combine two displays into a Composite.
auto operator|(const AsyncDisplay& left, const AsyncDisplay& right) {
return Composite(left.clone(), right.clone());
return Composite(left, right);
}

/// Trait class to extract underlying value type from numerics and
Expand Down Expand Up @@ -439,16 +449,19 @@ class Speedometer {

/// Write speed to given output stream. Speed is a double (written with
/// precision 2), possibly followed by a unit of speed.
void render_speed(std::ostream* out, const std::string& speed_unit) {
void render_speed(std::ostream* out,
const std::string& speed_unit,
const std::string& end = " ") {
std::stringstream ss; // use local stream to avoid disturbing `out` with
// std::fixed and std::setprecision
double speed = this->speed();
ss << std::fixed << std::setprecision(2) << "(" << speed;
if (speed_unit.empty()) {
ss << ") ";
ss << ")";
} else {
ss << " " << speed_unit << ") ";
ss << " " << speed_unit << ")";
}
ss << end;

auto s = ss.str();
*out << s;
Expand Down Expand Up @@ -508,14 +521,14 @@ class Counter : public AsyncDisplay {

protected:
/// Write the value of progress to the output stream
void render_counts_() {
void render_counts_(const std::string& end = " ") {
ss_ << *progress_;
*out_ << ss_.str() << " ";
*out_ << ss_.str() << end;
ss_.str("");
}

/// Write the value of progress with the message to the output stream
void render_() override {
void render_(const std::string& end = " ") override {
#if defined(BARKEEP_ENABLE_FMT_FORMAT)
if (not format_.empty()) {
using namespace fmt::literals;
Expand Down Expand Up @@ -566,8 +579,8 @@ class Counter : public AsyncDisplay {
}
#endif
render_message_();
render_counts_();
if (speedom_) { speedom_->render_speed(out_, speed_unit_); }
render_counts_(speedom_ ? " " : end);
if (speedom_) { speedom_->render_speed(out_, speed_unit_, end); }
}

/// Default interval in which the display is refreshed, if interval() is not
Expand Down Expand Up @@ -728,7 +741,7 @@ class ProgressBar : public AsyncDisplay {

/// Write progress value with the total, e.g. 50/100, to output stream.
/// Progress width is expanded (and right justified) to match width of total.
void render_counts_() {
void render_counts_(const std::string& end = " ") {
std::stringstream ss, totals;
if (std::is_floating_point_v<Progress>) {
ss << std::fixed << std::setprecision(2);
Expand All @@ -737,21 +750,21 @@ class ProgressBar : public AsyncDisplay {
totals << total_;
auto width = static_cast<std::streamsize>(totals.str().size());
ss.width(width);
ss << std::right << *progress_ << "/" << total_ << " ";
ss << std::right << *progress_ << "/" << total_ << end;
*out_ << ss.str();
}

/// Write the percent completed to output stream
void render_percentage_() {
void render_percentage_(const std::string& end = " ") {
std::stringstream ss;
ss << std::fixed << std::setprecision(2);
ss.width(6);
ss << std::right << *progress_ * 100. / total_ << "% ";
ss << std::right << *progress_ * 100. / total_ << "%" << end;
*out_ << ss.str();
}

/// Run all of the individual render methods to write everything to stream
void render_() override {
void render_(const std::string& end = " ") override {
#if defined(BARKEEP_ENABLE_FMT_FORMAT)
if (not format_.empty()) {
using namespace fmt::literals;
Expand Down Expand Up @@ -831,12 +844,12 @@ class ProgressBar : public AsyncDisplay {
*out_ << " ";

*out_ << bar_parts_.value_left_modifier;
render_counts_();
render_counts_(speedom_ ? " " : end);
*out_ << bar_parts_.value_right_modifier;

if (speedom_) {
*out_ << bar_parts_.speed_left_modifier;
speedom_->render_speed(out_, speed_unit_);
speedom_->render_speed(out_, speed_unit_, end);
*out_ << bar_parts_.speed_right_modifier;
}
}
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ environment = { CXXFLAGS = "-DBARKEEP_ENABLE_ATOMIC_FLOAT=0" }
test-command = "pytest --no-atomic-float {project}/python/tests/test.py"

[[tool.cibuildwheel.overrides]]
select = "*-macosx_arm64*" # TODO: use g++ when cross compiling
select = "*-macosx_arm64*"
environment = { CXX = "$(brew --prefix llvm@15)/bin/clang++", CXXFLAGS = "-DBARKEEP_ENABLE_ATOMIC_FLOAT=0" }
test-command = "pytest --no-atomic-float {project}/python/tests/test.py"

Expand Down
3 changes: 1 addition & 2 deletions python/barkeep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ PYBIND11_MODULE(barkeep, m) {
py::enum_<ProgressBarStyle>(m, "ProgressBarStyle")
.value("Bars", ProgressBarStyle::Bars)
.value("Blocks", ProgressBarStyle::Blocks)
.value("Arrow", ProgressBarStyle::Arrow)
.export_values();

py::enum_<DType>(m, "DType")
Expand Down Expand Up @@ -562,6 +561,6 @@ PYBIND11_MODULE(barkeep, m) {
other.done();
throw std::runtime_error("Cannot combine running AsyncDisplay objects!");
}
return Composite_(self.clone(), other.clone());
return Composite_(self, other);
});
}
12 changes: 8 additions & 4 deletions python/tests/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def counter():

def progress_bar():
speeds = [None, 0, 0.1, 1]
styles = [ProgressBarStyle.Bars, ProgressBarStyle.Arrow, ProgressBarStyle.Blocks]
styles = [ProgressBarStyle.Bars, ProgressBarStyle.Blocks]

for speed in speeds:
for sty in styles:
Expand Down Expand Up @@ -152,11 +152,15 @@ def fmt():
nargs="*",
)

# cosmetic
reset = "\033[0m"
bold = "\033[1m"
dim = "\033[2m"

args = parser.parse_args()
demos_to_run = args.demo or demos.keys()
for i, demo in enumerate(demos_to_run):
if i > 0:
print()
print(f"Running {demo}...")
print(dim + "─" * 80 + reset)
print(f"{dim}Running{reset} {bold}{demo}{reset}{dim}...{reset}")
demos[demo]()
print(f"Finished {demo}.")
6 changes: 3 additions & 3 deletions python/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def test_invalid_speed_discount(Display, discount):

@pytest.mark.parametrize("dtype", dtypes, indirect=True)
@pytest.mark.parametrize(
"sty", [ProgressBarStyle.Bars, ProgressBarStyle.Blocks, ProgressBarStyle.Arrow]
"sty", [ProgressBarStyle.Bars, ProgressBarStyle.Blocks]
)
@pytest.mark.parametrize("no_tty", [True, False])
def test_progress_bar(dtype, sty, no_tty):
Expand Down Expand Up @@ -380,7 +380,7 @@ def test_composite_bar_counter(no_tty):

for part in parts:
assert part.startswith("Sents ")
assert part[54:61] == " Toks "
assert part[54:60] == " Toks "
part = part.rstrip()
assert part[-7:] == " tok/s)"

Expand All @@ -398,7 +398,7 @@ def test_composite_bar_counter(no_tty):
i += 1

# check counter correctness
count_part = part[61:]
count_part = part[60:]
i = count_part.find(" ")
count = int(count_part[:i])
assert count >= last_count
Expand Down
2 changes: 1 addition & 1 deletion tests/demo-fmtlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ int main(int /*argc*/, char** /*argv*/) {
for (
std::string fmtstr : {
"Picking flowers {value:4d}/1010 {bar} ({speed:.1f} flo/s)",
"Picking flowers {blue}{value:4d}/1010 {green}{bar} {yellow}{percent:3.0f}%{reset} ({speed:.1f} flo/s)",
"Picking flowers {blue}{value:4d}/1010 {green}{bar} {yellow}{percent:3.0f}%{reset} ({speed:.1f} flo/s)",
}) {
std::atomic<size_t> work{0};
auto bar = bk::ProgressBar(
Expand Down
2 changes: 1 addition & 1 deletion tests/demo-stdfmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ int main(int /*argc*/, char** /*argv*/) {
for (
std::string fmtstr : {
"Picking flowers {0:4d}/1010 {1} ({4:.1f} flo/s)",
"Picking flowers {8}{0:4d}/1010 {6}{1} {7}{2:3.0f}%{11} ({4:.1f} flo/s)",
"Picking flowers {8}{0:4d}/1010 {6}{1} {7}{2:3.0f}%{11} ({4:.1f} flo/s)",
}) {
std::atomic<size_t> work{0};
auto bar = bk::ProgressBar(&work, {.total = 1010, .format = fmtstr, .speed = speed});
Expand Down
Loading

0 comments on commit 8ee6f8d

Please sign in to comment.