From bcdd68d6515d157a7cede0a17a9c805085680e27 Mon Sep 17 00:00:00 2001 From: Joanna Hulboj Date: Wed, 18 Dec 2024 20:59:06 +0000 Subject: [PATCH 1/3] Support using std::function for progress observer --- barkeep/barkeep.h | 193 ++++++++++++++++++++++++++++++++---------- python/barkeep.cpp | 37 +++++--- tests/demo.cpp | 16 ++++ tests/test-fmtlib.cpp | 6 +- tests/test-stdfmt.cpp | 6 +- tests/test.cpp | 29 +++++-- 6 files changed, 219 insertions(+), 68 deletions(-) diff --git a/barkeep/barkeep.h b/barkeep/barkeep.h index b204e23..c9d6446 100644 --- a/barkeep/barkeep.h +++ b/barkeep/barkeep.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -472,18 +473,113 @@ inline auto Status(const AnimationConfig& cfg = {}) { return std::make_shared(cfg); } +template +struct Provider; + +template +struct Provider { + using value_type = T; + using provider_type = T*; + using underlying_type = T; + + Provider(provider_type ptr) noexcept : ptr_{ptr} {} + Provider(const Provider&) = default; + Provider& operator=(const Provider&) = default; + + [[nodiscard]] T load() const noexcept { return *ptr_; } + + [[nodiscard]] bool ok() const noexcept { return ptr_; } + + provider_type ptr_{nullptr}; +}; + +template +struct Provider*> { + using value_type = T; + using provider_type = std::atomic*; + using underlying_type = std::atomic; + + Provider(provider_type ptr) noexcept : ptr_{ptr} {} + Provider(const Provider&) = default; + Provider& operator=(const Provider&) = default; + + [[nodiscard]] T load() const noexcept { return ptr_->load(std::memory_order_relaxed); } + + [[nodiscard]] bool ok() const noexcept { return ptr_; } + + provider_type ptr_{nullptr}; +}; + +template +struct Provider> { + using value_type = T; + using provider_type = std::function; + using underlying_type = std::function; + + Provider(provider_type fun) : fun_{std::move(fun)} {} + Provider(const Provider&) = default; + Provider& operator=(const Provider&) = default; + + [[nodiscard]] T load() const { return fun_(); } + + [[nodiscard]] bool ok() const noexcept { return fun_; } + + provider_type fun_; +}; + +template +struct ProviderSelector; + +template +struct ProviderSelector { + using type_t = Provider; +}; + +template +struct ProviderSelector*> { + using type_t = Provider*>; +}; + +template +struct ProviderSelector< + T, + std::enable_if_t>>> { + using type_t = Provider()>>; +}; + +template +using provider_t = typename ProviderSelector::type_t; + /// Trait class to extract underlying value type from numerics and /// std::atomics of numerics. template -struct AtomicTraits { +struct AtomicTraits; + +template +struct AtomicTraits { using value_type = T; }; template -struct AtomicTraits> { +struct AtomicTraits*> { using value_type = T; }; +template +struct AtomicTraits> { + using value_type = typename Provider::value_type; +}; + +template +struct AtomicTraits*>> { + using value_type = typename Provider*>::value_type; +}; + +template +struct AtomicTraits>> { + using value_type = typename Provider>::value_type; +}; + template using value_t = typename AtomicTraits::value_type; @@ -493,13 +589,13 @@ using signed_t = typename std::conditional_t, std::common_type>::type; /// Helper class to measure and display speed of progress. -template +template class Speedometer { private: - Progress* progress_; // Current amount of work done + const ProgressProvider& progress_provider_; // Current amount of work done double discount_; - using ValueType = value_t; + using ValueType = value_t; using SignedType = signed_t; using Clock = std::chrono::steady_clock; using Time = std::chrono::time_point; @@ -516,7 +612,8 @@ class Speedometer { Duration dur = now - last_start_time_; last_start_time_ = now; - ValueType progress_copy = *progress_; // to avoid progress_ changing below + ValueType progress_copy = + progress_provider_.load(); // to avoid progress_ changing below SignedType progress_increment = SignedType(progress_copy) - SignedType(last_progress_); last_progress_ = progress_copy; @@ -551,7 +648,8 @@ class Speedometer { /// Start computing the speed based on the amount of change in progress. void start() { - last_progress_ = *progress_; + last_progress_ = progress_provider_.load(); + ; last_start_time_ = Clock::now(); } @@ -562,8 +660,8 @@ class Speedometer { /// If discount is 0, all increments are weighted equally. /// If discount is 1, only the most recent increment is /// considered. - Speedometer(Progress* progress, double discount) - : progress_(progress), discount_(discount) { + Speedometer(const ProgressProvider& progress_provider, double discount) + : progress_provider_(progress_provider), discount_(discount) { if (discount < 0 or discount > 1) { throw std::runtime_error("Discount must be in [0, 1]"); } @@ -592,11 +690,12 @@ struct CounterConfig { }; /// Monitors and displays a single numeric variable -template +template class CounterDisplay : public BaseDisplay { protected: - Progress* progress_ = nullptr; // current amount of work done - std::unique_ptr> speedom_; + using ProgressProvider = provider_t; + ProgressProvider progress_provider_; // current amount of work done + std::unique_ptr> speedom_; std::string speed_unit_ = "it/s"; // unit of speed text next to speed std::stringstream ss_; @@ -604,7 +703,7 @@ class CounterDisplay : public BaseDisplay { protected: /// Write the value of progress to the output stream void render_counts_(const std::string& end = " ") { - ss_ << *progress_; + ss_ << progress_provider_.load(); out() << ss_.str() << end; ss_.str(""); } @@ -614,7 +713,7 @@ class CounterDisplay : public BaseDisplay { #if defined(BARKEEP_ENABLE_FMT_FORMAT) if (not format_.empty()) { using namespace fmt::literals; - value_t progress = *progress_; + value_t progress = progress_provider_.load(); if (speedom_) { fmt::print(out(), fmt::runtime(format_), @@ -643,7 +742,7 @@ class CounterDisplay : public BaseDisplay { } #elif defined(BARKEEP_ENABLE_STD_FORMAT) if (not format_.empty()) { - value_t progress = *progress_; + value_t progress = progress_provider_.load(); auto speed = speedom_ ? speedom_->speed() : std::nan(""); out() << std::vformat(format_, std::make_format_args(progress, @@ -673,7 +772,7 @@ class CounterDisplay : public BaseDisplay { } void start() override { - if constexpr (std::is_floating_point_v>) { + if constexpr (std::is_floating_point_v>) { ss_ << std::fixed << std::setprecision(2); } if (speedom_) { speedom_->start(); } @@ -683,16 +782,17 @@ class CounterDisplay : public BaseDisplay { /// Constructor. /// @param progress Variable to be monitored and displayed /// @param cfg Counter parameters - CounterDisplay(Progress* progress, const CounterConfig& cfg = {}) + CounterDisplay(Progress progress_provider, const CounterConfig& cfg = {}) : BaseDisplay(cfg.out, as_duration(cfg.interval), cfg.message, cfg.format.empty() ? "" : cfg.format + " ", cfg.no_tty), - progress_(progress), + progress_provider_(std::move(progress_provider)), speed_unit_(cfg.speed_unit) { if (cfg.speed) { - speedom_ = std::make_unique>(progress_, *cfg.speed); + speedom_ = std::make_unique>( + progress_provider_, *cfg.speed); } if (displayer_->interval() == Duration{0.}) { displayer_->interval(default_interval_(cfg.no_tty)); @@ -705,9 +805,11 @@ class CounterDisplay : public BaseDisplay { /// Convenience factory function to create a shared_ptr to CounterDisplay. /// Prefer this to constructing CounterDisplay directly. -template -auto Counter(Progress* progress, const CounterConfig& cfg = {}) { - return std::make_shared>(progress, cfg); +template > +auto Counter(SomeProgress progress, const CounterConfig& cfg = {}) { + return std::make_shared>(std::move(progress), + cfg); } /// Progress bar parameters @@ -741,10 +843,11 @@ struct ProgressBarConfig { template class ProgressBarDisplay : public BaseDisplay { protected: - using ValueType = value_t; + using ProgressProvider = provider_t; + using ValueType = value_t; - Progress* progress_; // work done so far - std::unique_ptr> speedom_; + ProgressProvider progress_provider_; // work done so far + std::unique_ptr> speedom_; std::string speed_unit_ = "it/s"; // unit of speed text next to speed static constexpr size_t width_ = 30; // width of progress bar // (TODO: make customizable?) @@ -756,8 +859,9 @@ class ProgressBarDisplay : public BaseDisplay { /// Compute the shape of the progress bar based on progress and write to /// output stream. void render_progress_bar_(std::ostream* out) { - ValueType progress_copy = *progress_; // to avoid progress_ changing - // during computations below + ValueType progress_copy = + progress_provider_.load(); // to avoid progress_ changing + // during computations below bool complete = progress_copy >= total_; int on = int(ValueType(width_) * progress_copy / total_); size_t partial = size_t(ValueType(bar_parts_.fill.size()) * @@ -810,14 +914,14 @@ class ProgressBarDisplay : public BaseDisplay { /// Progress width is expanded (and right justified) to match width of total. void render_counts_(const std::string& end = " ") { std::stringstream ss, totals; - if (std::is_floating_point_v) { + if (std::is_floating_point_v) { ss << std::fixed << std::setprecision(2); totals << std::fixed << std::setprecision(2); } totals << total_; auto width = static_cast(totals.str().size()); ss.width(width); - ss << std::right << *progress_ << "/" << total_ << end; + ss << std::right << progress_provider_.load() << "/" << total_ << end; out() << ss.str(); } @@ -826,7 +930,7 @@ class ProgressBarDisplay : public BaseDisplay { std::stringstream ss; ss << std::fixed << std::setprecision(2); ss.width(6); - ss << std::right << *progress_ * 100. / total_ << "%" << end; + ss << std::right << progress_provider_.load() * 100. / total_ << "%" << end; out() << ss.str(); } @@ -835,7 +939,7 @@ class ProgressBarDisplay : public BaseDisplay { #if defined(BARKEEP_ENABLE_FMT_FORMAT) if (not format_.empty()) { using namespace fmt::literals; - value_t progress = *progress_; + value_t progress = progress_provider_.load(); std::stringstream bar_ss; render_progress_bar_(&bar_ss); @@ -876,7 +980,7 @@ class ProgressBarDisplay : public BaseDisplay { } #elif defined(BARKEEP_ENABLE_STD_FORMAT) if (not format_.empty()) { - value_t progress = *progress_; + value_t progress = progress_provider_.load(); std::stringstream bar_ss; render_progress_bar_(&bar_ss); @@ -941,14 +1045,14 @@ class ProgressBarDisplay : public BaseDisplay { /// Constructor. /// @param progress Variable to be monitored to measure completion /// @param cfg ProgressBar parameters - ProgressBarDisplay(Progress* progress, + ProgressBarDisplay(Progress progress_provider, const ProgressBarConfig& cfg = {}) : BaseDisplay(cfg.out, as_duration(cfg.interval), cfg.message, cfg.format.empty() ? "" : cfg.format + " ", cfg.no_tty), - progress_(progress), + progress_provider_(std::move(progress_provider)), speed_unit_(cfg.speed_unit), total_(cfg.total) { if (std::holds_alternative(cfg.style)) { @@ -958,7 +1062,8 @@ class ProgressBarDisplay : public BaseDisplay { std::get(cfg.style))]; } if (cfg.speed) { - speedom_ = std::make_unique>(progress_, *cfg.speed); + speedom_ = std::make_unique>( + progress_provider_, *cfg.speed); } if (displayer_->interval() == Duration{0.}) { displayer_->interval(default_interval_(cfg.no_tty)); @@ -971,10 +1076,12 @@ class ProgressBarDisplay : public BaseDisplay { /// Convenience factory function to create a shared_ptr to ProgressBarDisplay. /// Prefer this to constructing ProgressBarDisplay directly. -template -auto ProgressBar(Progress* progress, - const ProgressBarConfig>& cfg = {}) { - return std::make_shared>(progress, cfg); +template > +auto ProgressBar(SomeProgress progress, + const ProgressBarConfig>& cfg = {}) { + return std::make_shared>(std::move(progress), + cfg); } /// Creates a composite display out of multiple child displays to show @@ -1033,13 +1140,13 @@ class CompositeDisplay : public BaseDisplay { /// Convenience factory function to create a shared_ptr to CompositeDisplay. /// Prefer this to constructing CompositeDisplay directly. inline auto Composite(const std::vector>& displays, - std::string delim = " ") { + std::string delim = " ") { return std::make_shared(displays, std::move(delim)); } /// Pipe operator can be used to combine two displays into a Composite. inline auto operator|(std::shared_ptr left, - std::shared_ptr right) { + std::shared_ptr right) { return std::make_shared( std::vector{std::move(left), std::move(right)}); } @@ -1080,8 +1187,8 @@ template class IterableBar { public: using ProgressType = std::atomic; - using ValueType = value_t; - using Bar = ProgressBarDisplay; + using ValueType = value_t; + using Bar = ProgressBarDisplay; private: Container& container_; diff --git a/python/barkeep.cpp b/python/barkeep.cpp index 4842935..cfb0d29 100644 --- a/python/barkeep.cpp +++ b/python/barkeep.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -121,11 +122,13 @@ class Status_ : public StatusDisplay { template class Counter_ : public CounterDisplay { protected: + using ProviderUnderlyingType = typename provider_t::underlying_type; using CounterDisplay::render_; using CounterDisplay::default_interval_; public: - std::shared_ptr work = std::make_shared(0); + std::shared_ptr work = + std::make_shared(0); Counter_(py::object file = py::none(), std::string format = "", @@ -144,7 +147,8 @@ class Counter_ : public CounterDisplay { .no_tty = no_tty, .show = false}) { if (speed) { - this->speedom_ = std::make_unique>(work.get(), *speed); + this->speedom_ = + std::make_unique>>(work.get(), *speed); } std::shared_ptr fp = nullptr; if (not file.is_none()) { @@ -154,8 +158,8 @@ class Counter_ : public CounterDisplay { interval == 0. ? this->default_interval_(no_tty) : Duration(interval); this->displayer_ = std::make_shared(this, fp, interval_, no_tty); - this->progress_ = work.get(); - assert(this->progress_ != nullptr); + this->progress_provider_ = work.get(); + assert(this->progress_provider_.ok()); } auto& operator+=(value_t v) { @@ -177,11 +181,13 @@ class Counter_ : public CounterDisplay { template class ProgressBar_ : public ProgressBarDisplay { protected: + using ProviderUnderlyingType = typename provider_t::underlying_type; using ProgressBarDisplay::render_; using ProgressBarDisplay::default_interval_; public: - std::shared_ptr work = std::make_shared(0); + std::shared_ptr work = + std::make_shared(0); ProgressBar_(py::object file = py::none(), value_t total = 100, @@ -204,7 +210,8 @@ class ProgressBar_ : public ProgressBarDisplay { .no_tty = no_tty, .show = false}) { if (speed) { - this->speedom_ = std::make_unique>(work.get(), *speed); + this->speedom_ = + std::make_unique>>(work.get(), *speed); } std::shared_ptr fp = nullptr; if (not file.is_none()) { @@ -214,8 +221,8 @@ class ProgressBar_ : public ProgressBarDisplay { interval == 0. ? this->default_interval_(no_tty) : Duration(interval); this->displayer_ = std::make_shared(this, fp, interval_, no_tty); - this->progress_ = work.get(); - assert(this->progress_ != nullptr); + this->progress_provider_ = work.get(); + assert(this->progress_provider_.ok()); } auto& operator+=(value_t v) { @@ -403,7 +410,10 @@ PYBIND11_MODULE(barkeep, m) { }; auto bind_counter = [&](auto& m, auto pv, const char* name) { - bind_display(m, Counter_(), decltype(pv)(), name); + bind_display(m, + Counter_>(), + std::add_pointer_t(), + name); }; bind_counter(m, Int(), "IntCounter"); @@ -429,7 +439,7 @@ PYBIND11_MODULE(barkeep, m) { std::shared_ptr rval; auto make_counter = [&](auto pv) { - using T = decltype(pv); + using T = std::add_pointer_t; auto c = std::make_shared>(file, fmt.value_or(""), msg, @@ -498,7 +508,10 @@ PYBIND11_MODULE(barkeep, m) { py::keep_alive<0, 2>()); // keep file alive while the counter is alive auto bind_progress_bar = [&](auto& m, auto pv, const char* name) { - bind_display(m, ProgressBar_(), decltype(pv)(), name); + bind_display(m, + ProgressBar_>(), + std::add_pointer_t(), + name); }; bind_progress_bar(m, Int(), "IntProgressBar"); @@ -524,7 +537,7 @@ PYBIND11_MODULE(barkeep, m) { DType dtype, bool show) -> std::shared_ptr { auto make_progress_bar = [&](auto pv) { - using T = decltype(pv); + using T = std::add_pointer_t; auto bar = std::make_shared>(file, total, fmt.value_or(""), diff --git a/tests/demo.cpp b/tests/demo.cpp index 284b4fd..d81b69a 100644 --- a/tests/demo.cpp +++ b/tests/demo.cpp @@ -195,6 +195,22 @@ Demo decreasing_bar( // ... } }); +Demo decreasing_bar_lambda( // ... + "decreasing_bar_lambda", + "Decreasing progress bar with lambda", + []() { + unsigned long work{1010}; + auto bar = bk::ProgressBar([&] { return work; }, + { + .total = 1010, + .speed = 1., + }); + for (int i = 0; i < 1010; i++) { + std::this_thread::sleep_for(7ms); + work--; + } + }); + Demo bar_and_counter( "bar_and_counter", "Composite display of a ProgressBar and Counter", diff --git a/tests/test-fmtlib.cpp b/tests/test-fmtlib.cpp index 181bcb9..911c0a5 100644 --- a/tests/test-fmtlib.cpp +++ b/tests/test-fmtlib.cpp @@ -21,7 +21,7 @@ using ProgressTypeList = TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto sp = GENERATE(as>(), std::nullopt, 1); @@ -74,7 +74,7 @@ TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; ValueType initial = amount; @@ -133,7 +133,7 @@ TEMPLATE_LIST_TEST_CASE("Progress bar", "[bar]", ProgressTypeList) { bool no_tty = GENERATE(true, false); - using ValueType = value_t; + using ValueType = value_t; std::string value_fmt = std::is_floating_point_v ? "{value:.2f}" : "{value:2d}"; diff --git a/tests/test-stdfmt.cpp b/tests/test-stdfmt.cpp index c98181d..4a4b3e8 100644 --- a/tests/test-stdfmt.cpp +++ b/tests/test-stdfmt.cpp @@ -20,7 +20,7 @@ using ProgressTypeList = TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto sp = GENERATE(as>(), std::nullopt, 1); @@ -73,7 +73,7 @@ TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; ValueType initial = amount; @@ -132,7 +132,7 @@ TEMPLATE_LIST_TEST_CASE("Progress bar", "[bar]", ProgressTypeList) { bool no_tty = GENERATE(true, false); - using ValueType = value_t; + using ValueType = value_t; std::string value_fmt = std::is_floating_point_v ? "{0:.2f}" : "{0:2d}"; diff --git a/tests/test.cpp b/tests/test.cpp index f05dfc2..36d004f 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1,6 +1,7 @@ #define CATCH_CONFIG_MAIN #include +#include #include #include #include @@ -139,7 +140,7 @@ using ProgressTypeList = std::tuple, int, unsigned, float, double>; TEMPLATE_LIST_TEST_CASE("Counter default", "[counter]", ProgressTypeList) { - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto ctr = Counter(&amount, {.show = false}); @@ -149,7 +150,7 @@ TEMPLATE_LIST_TEST_CASE("Counter default", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto sp = GENERATE(as>(), std::nullopt, 1); @@ -193,7 +194,7 @@ TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; ValueType initial = amount; @@ -288,7 +289,7 @@ auto factory_helper>(bool speedy) { } template <> -auto factory_helper>(bool speedy) { +auto factory_helper>(bool speedy) { static float progress; static std::stringstream hide; if (speedy) { @@ -298,6 +299,19 @@ auto factory_helper>(bool speedy) { } } +template <> +auto factory_helper>>(bool speedy) { + static float progress; + static std::stringstream hide; + auto lambda = [&] { return progress; }; + if (speedy) { + return ProgressBar(std::move(lambda), + {.out = &hide, .speed = 1, .show = false}); + } else { + return ProgressBar(std::move(lambda), {.out = &hide, .show = false}); + } +} + template <> auto factory_helper(bool speedy) { static size_t progress; @@ -314,7 +328,8 @@ auto factory_helper(bool speedy) { using DisplayTypes = std::tuple, - ProgressBarDisplay, + ProgressBarDisplay, + ProgressBarDisplay>, CompositeDisplay>; TEMPLATE_LIST_TEST_CASE("Error cases", "[edges]", DisplayTypes) { @@ -496,7 +511,7 @@ TEST_CASE("Iterable bar", "[bar]") { TEMPLATE_LIST_TEST_CASE("Speedy progress bar", "[bar]", ProgressTypeList) { std::stringstream out; TestType progress{0}; - using ValueType = value_t; + using ValueType = value_t; bool no_tty = GENERATE(true, false); auto sty = GENERATE(Bars, Blocks, Rich); @@ -782,4 +797,4 @@ TEST_CASE("Three bars multiline", "[composite]") { check_shrinking_space(interleaved_parts[0], Rich); check_shrinking_space(interleaved_parts[1], Rich); check_shrinking_space(interleaved_parts[2], Rich); -} \ No newline at end of file +} From f7d9dbc3e7c429dad3b702bb0692de11e040e44e Mon Sep 17 00:00:00 2001 From: Joanna Hulboj Date: Sun, 22 Dec 2024 18:00:06 +0000 Subject: [PATCH 2/3] Restore the old typing () --- barkeep/barkeep.h | 99 +++++++++++++++++++++++++++++-------------- python/barkeep.cpp | 16 +++---- tests/test-fmtlib.cpp | 8 ++-- tests/test-stdfmt.cpp | 8 ++-- tests/test.cpp | 12 +++--- 5 files changed, 86 insertions(+), 57 deletions(-) diff --git a/barkeep/barkeep.h b/barkeep/barkeep.h index c9d6446..356c510 100644 --- a/barkeep/barkeep.h +++ b/barkeep/barkeep.h @@ -16,6 +16,7 @@ #define BARKEEP_H #include +#include #include #include #include @@ -474,10 +475,7 @@ inline auto Status(const AnimationConfig& cfg = {}) { } template -struct Provider; - -template -struct Provider { +struct Provider { using value_type = T; using provider_type = T*; using underlying_type = T; @@ -494,7 +492,7 @@ struct Provider { }; template -struct Provider*> { +struct Provider> { using value_type = T; using provider_type = std::atomic*; using underlying_type = std::atomic; @@ -528,16 +526,26 @@ struct Provider> { }; template -struct ProviderSelector; +struct ReasonablyInvocable { + constexpr static auto value = false; +}; template -struct ProviderSelector { - using type_t = Provider; +struct ReasonablyInvocable>>> { + constexpr static auto value = true; }; template -struct ProviderSelector*> { - using type_t = Provider*>; +constexpr bool ReasonablyInvocableV = ReasonablyInvocable::value; + +template +struct ProviderSelector { + using type_t = Provider; +}; + +template +struct ProviderSelector> { + using type_t = Provider>; }; template @@ -553,26 +561,23 @@ using provider_t = typename ProviderSelector::type_t; /// Trait class to extract underlying value type from numerics and /// std::atomics of numerics. template -struct AtomicTraits; - -template -struct AtomicTraits { +struct AtomicTraits { using value_type = T; }; template -struct AtomicTraits*> { +struct AtomicTraits> { using value_type = T; }; template -struct AtomicTraits> { - using value_type = typename Provider::value_type; +struct AtomicTraits> { + using value_type = typename Provider::value_type; }; template -struct AtomicTraits*>> { - using value_type = typename Provider*>::value_type; +struct AtomicTraits>> { + using value_type = typename Provider>::value_type; }; template @@ -782,7 +787,7 @@ class CounterDisplay : public BaseDisplay { /// Constructor. /// @param progress Variable to be monitored and displayed /// @param cfg Counter parameters - CounterDisplay(Progress progress_provider, const CounterConfig& cfg = {}) + CounterDisplay(provider_t progress_provider, const CounterConfig& cfg = {}) : BaseDisplay(cfg.out, as_duration(cfg.interval), cfg.message, @@ -800,16 +805,30 @@ class CounterDisplay : public BaseDisplay { if (cfg.show) { show(); } } + CounterDisplay(Progress* progress_provider, const CounterConfig& cfg = {}) + : CounterDisplay(provider_t(progress_provider), cfg) + {} + + CounterDisplay(Progress progress_provider, const CounterConfig& cfg = {}) + : CounterDisplay(provider_t(std::move(progress_provider)), cfg) + {} + ~CounterDisplay() { done(); } }; /// Convenience factory function to create a shared_ptr to CounterDisplay. /// Prefer this to constructing CounterDisplay directly. -template > -auto Counter(SomeProgress progress, const CounterConfig& cfg = {}) { - return std::make_shared>(std::move(progress), - cfg); +template , + typename std::enable_if_t, bool> = true> +auto Counter(Progress&& progress, const CounterConfig& cfg = {}) { + return std::make_shared>(std::forward(progress), cfg); +} + +template > +auto Counter(Progress* progress, const CounterConfig& cfg = {}) { + return std::make_shared>(progress, cfg); } /// Progress bar parameters @@ -1045,7 +1064,7 @@ class ProgressBarDisplay : public BaseDisplay { /// Constructor. /// @param progress Variable to be monitored to measure completion /// @param cfg ProgressBar parameters - ProgressBarDisplay(Progress progress_provider, + ProgressBarDisplay(provider_t progress_provider, const ProgressBarConfig& cfg = {}) : BaseDisplay(cfg.out, as_duration(cfg.interval), @@ -1071,19 +1090,35 @@ class ProgressBarDisplay : public BaseDisplay { if (cfg.show) { show(); } } + ProgressBarDisplay(Progress* progress_provider, const ProgressBarConfig& cfg = {}) + : ProgressBarDisplay(provider_t(progress_provider), cfg) + {} + + ProgressBarDisplay(Progress progress_provider, const ProgressBarConfig& cfg = {}) + : ProgressBarDisplay(provider_t(std::move(progress_provider)), cfg) + {} + ~ProgressBarDisplay() { done(); } }; /// Convenience factory function to create a shared_ptr to ProgressBarDisplay. /// Prefer this to constructing ProgressBarDisplay directly. -template > -auto ProgressBar(SomeProgress progress, +template , + typename std::enable_if_t, bool> = true> +auto ProgressBar(Progress&& progress, const ProgressBarConfig>& cfg = {}) { - return std::make_shared>(std::move(progress), + return std::make_shared>(std::forward(progress), cfg); } +template > +auto ProgressBar(Progress* progress, + const ProgressBarConfig>& cfg = {}) { + return std::make_shared>(progress, cfg); +} + /// Creates a composite display out of multiple child displays to show /// them together. /// For instance, you can combine two Counter objects, or a Counter and a @@ -1187,8 +1222,8 @@ template class IterableBar { public: using ProgressType = std::atomic; - using ValueType = value_t; - using Bar = ProgressBarDisplay; + using ValueType = value_t; + using Bar = ProgressBarDisplay; private: Container& container_; diff --git a/python/barkeep.cpp b/python/barkeep.cpp index cfb0d29..7117723 100644 --- a/python/barkeep.cpp +++ b/python/barkeep.cpp @@ -410,10 +410,7 @@ PYBIND11_MODULE(barkeep, m) { }; auto bind_counter = [&](auto& m, auto pv, const char* name) { - bind_display(m, - Counter_>(), - std::add_pointer_t(), - name); + bind_display(m, Counter_(), decltype(pv)(), name); }; bind_counter(m, Int(), "IntCounter"); @@ -439,7 +436,7 @@ PYBIND11_MODULE(barkeep, m) { std::shared_ptr rval; auto make_counter = [&](auto pv) { - using T = std::add_pointer_t; + using T = decltype(pv); auto c = std::make_shared>(file, fmt.value_or(""), msg, @@ -508,10 +505,7 @@ PYBIND11_MODULE(barkeep, m) { py::keep_alive<0, 2>()); // keep file alive while the counter is alive auto bind_progress_bar = [&](auto& m, auto pv, const char* name) { - bind_display(m, - ProgressBar_>(), - std::add_pointer_t(), - name); + bind_display(m, ProgressBar_(), decltype(pv)(), name); }; bind_progress_bar(m, Int(), "IntProgressBar"); @@ -537,7 +531,7 @@ PYBIND11_MODULE(barkeep, m) { DType dtype, bool show) -> std::shared_ptr { auto make_progress_bar = [&](auto pv) { - using T = std::add_pointer_t; + using T = decltype(pv); auto bar = std::make_shared>(file, total, fmt.value_or(""), @@ -626,4 +620,4 @@ PYBIND11_MODULE(barkeep, m) { } return Composite({self, other}); }); -} \ No newline at end of file +} diff --git a/tests/test-fmtlib.cpp b/tests/test-fmtlib.cpp index 911c0a5..96c6b38 100644 --- a/tests/test-fmtlib.cpp +++ b/tests/test-fmtlib.cpp @@ -21,7 +21,7 @@ using ProgressTypeList = TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto sp = GENERATE(as>(), std::nullopt, 1); @@ -74,7 +74,7 @@ TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; ValueType initial = amount; @@ -133,7 +133,7 @@ TEMPLATE_LIST_TEST_CASE("Progress bar", "[bar]", ProgressTypeList) { bool no_tty = GENERATE(true, false); - using ValueType = value_t; + using ValueType = value_t; std::string value_fmt = std::is_floating_point_v ? "{value:.2f}" : "{value:2d}"; @@ -268,4 +268,4 @@ TEST_CASE("Composite bar-counter", "[composite]") { last_count = count; } } -} \ No newline at end of file +} diff --git a/tests/test-stdfmt.cpp b/tests/test-stdfmt.cpp index 4a4b3e8..a009a3e 100644 --- a/tests/test-stdfmt.cpp +++ b/tests/test-stdfmt.cpp @@ -20,7 +20,7 @@ using ProgressTypeList = TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto sp = GENERATE(as>(), std::nullopt, 1); @@ -73,7 +73,7 @@ TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; ValueType initial = amount; @@ -132,7 +132,7 @@ TEMPLATE_LIST_TEST_CASE("Progress bar", "[bar]", ProgressTypeList) { bool no_tty = GENERATE(true, false); - using ValueType = value_t; + using ValueType = value_t; std::string value_fmt = std::is_floating_point_v ? "{0:.2f}" : "{0:2d}"; @@ -264,4 +264,4 @@ TEST_CASE("Composite bar-counter", "[composite]") { last_count = count; } } -} \ No newline at end of file +} diff --git a/tests/test.cpp b/tests/test.cpp index 36d004f..2f91e16 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -140,7 +140,7 @@ using ProgressTypeList = std::tuple, int, unsigned, float, double>; TEMPLATE_LIST_TEST_CASE("Counter default", "[counter]", ProgressTypeList) { - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto ctr = Counter(&amount, {.show = false}); @@ -150,7 +150,7 @@ TEMPLATE_LIST_TEST_CASE("Counter default", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; auto sp = GENERATE(as>(), std::nullopt, 1); @@ -194,7 +194,7 @@ TEMPLATE_LIST_TEST_CASE("Counter constant", "[counter]", ProgressTypeList) { TEMPLATE_LIST_TEST_CASE("Counter", "[counter]", ProgressTypeList) { std::stringstream out; - using ValueType = value_t; + using ValueType = value_t; TestType amount{GENERATE(as(), 0, 3)}; ValueType initial = amount; @@ -289,7 +289,7 @@ auto factory_helper>(bool speedy) { } template <> -auto factory_helper>(bool speedy) { +auto factory_helper>(bool speedy) { static float progress; static std::stringstream hide; if (speedy) { @@ -328,7 +328,7 @@ auto factory_helper(bool speedy) { using DisplayTypes = std::tuple, - ProgressBarDisplay, + ProgressBarDisplay, ProgressBarDisplay>, CompositeDisplay>; @@ -511,7 +511,7 @@ TEST_CASE("Iterable bar", "[bar]") { TEMPLATE_LIST_TEST_CASE("Speedy progress bar", "[bar]", ProgressTypeList) { std::stringstream out; TestType progress{0}; - using ValueType = value_t; + using ValueType = value_t; bool no_tty = GENERATE(true, false); auto sty = GENERATE(Bars, Blocks, Rich); From a08babc8b9238b6f80b23df8b8f17ed9a5158c5f Mon Sep 17 00:00:00 2001 From: Joanna Hulboj Date: Wed, 25 Dec 2024 09:57:37 +0000 Subject: [PATCH 3/3] Fix (python bindings) barkeep.cpp to make valgrind happier --- barkeep/barkeep.h | 2 +- python/barkeep.cpp | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/barkeep/barkeep.h b/barkeep/barkeep.h index 356c510..094ef97 100644 --- a/barkeep/barkeep.h +++ b/barkeep/barkeep.h @@ -695,7 +695,7 @@ struct CounterConfig { }; /// Monitors and displays a single numeric variable -template +template class CounterDisplay : public BaseDisplay { protected: using ProgressProvider = provider_t; diff --git a/python/barkeep.cpp b/python/barkeep.cpp index 7117723..666095d 100644 --- a/python/barkeep.cpp +++ b/python/barkeep.cpp @@ -146,9 +146,11 @@ class Counter_ : public CounterDisplay { .interval = interval, .no_tty = no_tty, .show = false}) { + + this->progress_provider_ = work.get(); if (speed) { this->speedom_ = - std::make_unique>>(work.get(), *speed); + std::make_unique>>(this->progress_provider_, *speed); } std::shared_ptr fp = nullptr; if (not file.is_none()) { @@ -158,9 +160,10 @@ class Counter_ : public CounterDisplay { interval == 0. ? this->default_interval_(no_tty) : Duration(interval); this->displayer_ = std::make_shared(this, fp, interval_, no_tty); - this->progress_provider_ = work.get(); assert(this->progress_provider_.ok()); } + + ~Counter_() { this->done(); } auto& operator+=(value_t v) { *work += v; @@ -209,9 +212,11 @@ class ProgressBar_ : public ProgressBarDisplay { .interval = interval, .no_tty = no_tty, .show = false}) { + + this->progress_provider_ = work.get(); if (speed) { this->speedom_ = - std::make_unique>>(work.get(), *speed); + std::make_unique>>(this->progress_provider_, *speed); } std::shared_ptr fp = nullptr; if (not file.is_none()) { @@ -221,10 +226,11 @@ class ProgressBar_ : public ProgressBarDisplay { interval == 0. ? this->default_interval_(no_tty) : Duration(interval); this->displayer_ = std::make_shared(this, fp, interval_, no_tty); - this->progress_provider_ = work.get(); assert(this->progress_provider_.ok()); } + ~ProgressBar_() { this->done(); } + auto& operator+=(value_t v) { *work += v; return *this;