ROSE 0.11.145.192
ProgressBar.h
1// WARNING: Changes to this file must be contributed back to Sawyer or else they will
2// be clobbered by the next update from Sawyer. The Sawyer repository is at
3// https://gitlab.com/charger7534/sawyer.git.
4
5
6
7
8#ifndef Sawyer_ProgressBar_H
9#define Sawyer_ProgressBar_H
10
11#include <Sawyer/Message.h>
12#include <Sawyer/Optional.h>
13#include <Sawyer/Sawyer.h>
14
15#include <boost/thread/locks.hpp>
16#include <boost/thread/mutex.hpp>
17#include <cmath>
18#include <sstream>
19
20namespace Sawyer {
21
22// used internally by the ProgressBar<> classes. Since this is called only from ProgressBar objects and ProgressBar has
23// a synchronized API, we don't need any synchronization at this level.
24class SAWYER_EXPORT ProgressBarImpl {
25public:
26#include <Sawyer/WarningsOff.h>
27 double value_; // between zero and one, inclusive
28 size_t width_; // width of bar in characters
29 bool showPercent_; // show the percent after the progress bar
30 std::string leftEnd_, rightEnd_; // strings for left and right ends of progress bar
31 char barChar_, nonBarChar_; // characters for the bar and non-bar parts
32 std::string prefix_; // extra text before the bar (usually a short message)
33 std::string suffix_; // extra text to show after the bar (usually the value)
34 static double minUpdateInterval_; // min number of seconds between update
35 static double initialDelay_; // time to delay before emitting the first message
36 double lastUpdateTime_; // time of previous update
37 Message::MesgProps overridesAnsi_; // properties we override from the stream_ when using color
38 Message::SProxy stream_; // stream to which messages are sent
39 size_t nUpdates_; // number of times a message was emitted
40 bool shouldSpin_; // spin instead of progress
41 Message::Mesg textMesg_; // message used when ANSI escape sequences are not available
42 Optional<int> oldPercent_; // old percent value used when updating a non-color progress bar
43#include <Sawyer/WarningsRestore.h>
44
45 ProgressBarImpl(const Message::SProxy &stream)
46 : value_(0.0), width_(15), showPercent_(true), leftEnd_("["), rightEnd_("]"), barChar_('#'), nonBarChar_('-'),
47 lastUpdateTime_(0.0), stream_(stream), nUpdates_(0), shouldSpin_(false) {
48 init();
49 }
51 cleanup();
52 }
53
54 void init();
55 void cleanup(); // deletes the progress bar from the screen
56 void update(double ratio, bool backward); // update regardless of time (if stream is enabled)
57 void configUpdate(double ratio, bool backward); // update for configuration changes
58 void valueUpdate(double ratio, bool backward); // update for changes in value
59 std::string makeBar(double ratio, bool backward); // make the bar itself
60 void updateTextMesg(double ratio); // update the textMesg_
61};
62
66namespace ProgressBarSettings {
72 SAWYER_EXPORT double initialDelay();
73 SAWYER_EXPORT void initialDelay(double s);
79 SAWYER_EXPORT double minimumUpdateInterval();
80 SAWYER_EXPORT void minimumUpdateInterval(double s);
82} // namespace
83
84
108template<typename T, typename S=std::string>
110public:
111 typedef S Suffix;
112 typedef T ValueType;
113private:
114 struct Position {
115 ValueType leftValue, curValue, rightValue;
116 Position(ValueType leftValue, ValueType curValue, ValueType rightValue)
117 : leftValue(leftValue), curValue(curValue), rightValue(rightValue) {}
118 bool operator==(const Position &other) const {
119 return curValue==other.curValue && leftValue==other.leftValue && rightValue==other.rightValue;
120 }
121 };
122
123 mutable boost::mutex mutex_; // locks the following data members
124 Position value_;
125 ProgressBarImpl bar_;
126 bool showValue_;
127 Suffix suffix_;
128
129public:
133 explicit ProgressBar(const Message::SProxy &stream, const std::string &name="progress")
134 : value_(0, 0, 0), bar_(stream), showValue_(true) {
135 bar_.shouldSpin_ = true;
136 bar_.prefix_ = name;
137 }
138
141 ProgressBar(ValueType rightValue, const Message::SProxy &stream, const std::string &name="progress")
142 : value_(0, 0, rightValue), bar_(stream), showValue_(true) {
143 bar_.shouldSpin_ = isEmptyNS();
144 bar_.prefix_ = name;
145 }
146
150 ProgressBar(ValueType leftValue, ValueType curValue, ValueType rightValue, const Message::SProxy &stream,
151 const std::string &name="progress")
152 : value_(leftValue, curValue, rightValue), bar_(stream), showValue_(true) {
153 bar_.shouldSpin_ = isEmptyNS();
154 bar_.prefix_ = name;
155 }
156
159 ValueType value() const {
160 boost::lock_guard<boost::mutex> lock(mutex_);
161 return value_.curValue;
162 }
163 void value(ValueType curValue) {
164 boost::lock_guard<boost::mutex> lock(mutex_);
165 value_.curValue = curValue;
166 valueUpdatedNS();
167 }
168
169 void value(ValueType curValue, ValueType rightValue) {
170 boost::lock_guard<boost::mutex> lock(mutex_);
171 value_.curValue = curValue;
172 value_.rightValue = rightValue;
173 bar_.shouldSpin_ = isEmptyNS();
174 valueUpdatedNS();
175 }
176 void value(ValueType leftValue, ValueType curValue, ValueType rightValue) {
177 boost::lock_guard<boost::mutex> lock(mutex_);
178 value_ = Position(leftValue, curValue, rightValue);
179 bar_.shouldSpin_ = isEmptyNS();
180 valueUpdatedNS();
181 }
190 Suffix suffix() {
191 boost::lock_guard<boost::mutex> lock(mutex_);
192 return suffix_;
193 }
194 Suffix suffix() const {
195 boost::lock_guard<boost::mutex> lock(mutex_);
196 return suffix_;
197 }
198 ProgressBar& suffix(const Suffix &suffix) {
199 boost::lock_guard<boost::mutex> lock(mutex_);
200 suffix_ = suffix;
201 return *this;
202 }
208 double ratio() const {
209 boost::lock_guard<boost::mutex> lock(mutex_);
210 return ratioNS();
211 }
212
214 bool isEmpty() const {
215 boost::lock_guard<boost::mutex> lock(mutex_);
216 return isEmptyNS();
217 }
218
220 bool isBackward() const {
221 boost::lock_guard<boost::mutex> lock(mutex_);
222 return isBackwardNS();
223 }
224
227 std::pair<ValueType, ValueType> domain() const {
228 boost::lock_guard<boost::mutex> lock(mutex_);
229 return std::make_pair(value_.leftValue, value_.rightValue);
230 }
231 void domain(const std::pair<ValueType, ValueType> &p) {
232 boost::lock_guard<boost::mutex> lock(mutex_);
233 value_.leftValue = p.first;
234 value_.rightValue = p.second;
235 configUpdatedNS();
236 }
237 void domain(ValueType leftValue, ValueType rightValue) {
238 boost::lock_guard<boost::mutex> lock(mutex_);
239 value_.leftValue = leftValue;
240 value_.rightValue = rightValue;
241 configUpdatedNS();
242 }
247 void increment(ValueType delta=1);
248 void decrement(ValueType delta=1);
250 increment(1);
251 return *this;
252 }
253 ProgressBar& operator++(int) { // same as a pre-increment
254 increment(1);
255 return *this;
256 }
258 decrement(1);
259 return *this;
260 }
261 ProgressBar& operator--(int) { // same as pre-decrement
262 decrement(1);
263 return *this;
264 }
265 ProgressBar& operator+=(ValueType delta) {
266 increment(delta);
267 return *this;
268 }
269 ProgressBar& operator-=(ValueType delta) {
270 decrement(delta);
271 return *this;
272 }
277 size_t width() const {
278 boost::lock_guard<boost::mutex> lock(mutex_);
279 return bar_.width_;
280 }
281 void width(size_t width) {
282 boost::lock_guard<boost::mutex> lock(mutex_);
283 bar_.width_ = width;
284 configUpdatedNS();
285 }
290 const std::string& prefix() const {
291 boost::lock_guard<boost::mutex> lock(mutex_);
292 return bar_.prefix_;
293 }
294 void prefix(const std::string &s) {
295 boost::lock_guard<boost::mutex> lock(mutex_);
296 bar_.prefix_ = s;
297 configUpdatedNS();
298 }
304 std::pair<char, char> barchars() const {
305 boost::lock_guard<boost::mutex> lock(mutex_);
306 return std::make_pair(bar_.barChar_, bar_.nonBarChar_);
307 }
308 void barchars(char bar, char nonBar) {
309 boost::lock_guard<boost::mutex> lock(mutex_);
310 bar_.barChar_ = bar;
311 bar_.nonBarChar_ = nonBar;
312 configUpdatedNS();
313 }
318 std::pair<std::string, std::string> endchars() const {
319 boost::lock_guard<boost::mutex> lock(mutex_);
320 return std::make_pair(bar_.leftEnd_, bar_.rightEnd_);
321 }
322 void endchars(const std::string &lt, const std::string &rt) {
323 boost::lock_guard<boost::mutex> lock(mutex_);
324 bar_.leftEnd_ = lt;
325 bar_.rightEnd_ = rt;
326 configUpdatedNS();
327 }
332 bool showPercent() const {
333 boost::lock_guard<boost::mutex> lock(mutex_);
334 return bar_.showPercent_;
335 }
336 void showPercent(bool b) {
337 boost::lock_guard<boost::mutex> lock(mutex_);
338 bar_.showPercent_ = b;
339 configUpdatedNS();
340 }
345 bool showValue() const {
346 boost::lock_guard<boost::mutex> lock(mutex_);
347 return showValue_;
348 }
349 void showValue(bool b) {
350 boost::lock_guard<boost::mutex> lock(mutex_);
351 showValue_ = b;
352 configUpdatedNS();
353 }
356private:
357 bool isEmptyNS() const { // "NS" means "not synchronized" -- the caller must do that.
358 return value_.leftValue == value_.rightValue;
359 }
360
361 double ratioNS() const;
362
363 bool isBackwardNS() const {
364 return value_.leftValue > value_.rightValue;
365 }
366
367 void valueUpdatedNS() {
368 if (showValue_) {
369 std::ostringstream ss;
370 ss <<value_.curValue <<suffix_;
371 bar_.suffix_ = ss.str();
372 } else {
373 bar_.suffix_.clear();
374 }
375 bar_.valueUpdate(ratioNS(), isBackwardNS());
376 }
377
378 void configUpdatedNS() {
379 if (showValue_) {
380 std::ostringstream ss;
381 ss <<value_.curValue <<suffix_;
382 bar_.suffix_ = ss.str();
383 } else {
384 bar_.suffix_.clear();
385 }
386 bar_.configUpdate(ratioNS(), isBackwardNS());
387 }
388};
389
390// try not to get negative values when subtracting because they might behave strangely if T is something weird.
391template <typename T, typename S>
392double ProgressBar<T, S>::ratioNS() const {
393 if (isEmptyNS()) {
394 return value_.curValue <= value_.leftValue ? 0.0 : 1.0;
395 } else if (isBackwardNS()) {
396 if (value_.curValue >= value_.leftValue) {
397 return 0.0;
398 } else if (value_.curValue <= value_.rightValue) {
399 return 1.0;
400 } else {
401 return 1.0 * (value_.leftValue - value_.curValue) / (value_.leftValue - value_.rightValue);
402 }
403 } else {
404 if (value_.curValue <= value_.leftValue) {
405 return 0.0;
406 } else if (value_.curValue >= value_.rightValue) {
407 return 1.0;
408 } else {
409 return 1.0 * (value_.curValue - value_.leftValue) / (value_.rightValue - value_.leftValue);
410 }
411 }
412}
413
414template <typename T, typename S>
415void ProgressBar<T, S>::increment(ValueType delta) {
416 boost::lock_guard<boost::mutex> lock(mutex_);
417 ValueType oldValue = value_.curValue;
418 value_.curValue += delta;
419 if (oldValue!=value_.curValue)
420 valueUpdatedNS();
421}
422
423template <typename T, typename S>
424void ProgressBar<T, S>::decrement(ValueType delta) {
425 boost::lock_guard<boost::mutex> lock(mutex_);
426 ValueType oldValue = value_.curValue;
427 value_.curValue -= delta;
428 if (oldValue!=value_.curValue)
429 valueUpdatedNS();
430}
431
432} // namespace
433
434#endif
A single message.
Definition Message.h:513
Holds a value or nothing.
Definition Optional.h:56
Progress bars.
size_t width() const
Width of progress bar in characters at 100%.
ProgressBar & operator--(int)
Increment or decrement the progress bar.
void domain(ValueType leftValue, ValueType rightValue)
Possible values.
ProgressBar & operator+=(ValueType delta)
Increment or decrement the progress bar.
void showPercent(bool b)
Whether to show the percent indication.
void value(ValueType curValue)
Value for the progress bar.
std::pair< char, char > barchars() const
Characters to use for the bar.
void domain(const std::pair< ValueType, ValueType > &p)
Possible values.
ProgressBar(ValueType leftValue, ValueType curValue, ValueType rightValue, const Message::SProxy &stream, const std::string &name="progress")
Construct a progress bar with left and right limits.
bool isBackward() const
True if the minimum value is greater than the maximum value.
const std::string & prefix() const
String to show before the beginning of the bar.
void barchars(char bar, char nonBar)
Characters to use for the bar.
Suffix suffix() const
Property: suffix.
void decrement(ValueType delta=1)
Increment or decrement the progress bar.
bool showPercent() const
Whether to show the percent indication.
Suffix suffix()
Property: suffix.
ValueType value() const
Value for the progress bar.
void showValue(bool b)
Whether to show the current value.
bool isEmpty() const
True if the distance between the minimum and maximum is zero.
ProgressBar & operator--()
Increment or decrement the progress bar.
void endchars(const std::string &lt, const std::string &rt)
Characters to use for the left and right ends of the bar.
void prefix(const std::string &s)
String to show before the beginning of the bar.
std::pair< std::string, std::string > endchars() const
Characters to use for the left and right ends of the bar.
void value(ValueType leftValue, ValueType curValue, ValueType rightValue)
Value for the progress bar.
ProgressBar(ValueType rightValue, const Message::SProxy &stream, const std::string &name="progress")
Construct a progress bar incrementing from zero to some limit.
ProgressBar & suffix(const Suffix &suffix)
Property: suffix.
void increment(ValueType delta=1)
Increment or decrement the progress bar.
double ratio() const
Value of progress bar as a ratio of completeness clipped between 0 and 1.
ProgressBar & operator++(int)
Increment or decrement the progress bar.
ProgressBar & operator-=(ValueType delta)
Increment or decrement the progress bar.
void value(ValueType curValue, ValueType rightValue)
Value for the progress bar.
bool showValue() const
Whether to show the current value.
ProgressBar & operator++()
Increment or decrement the progress bar.
std::pair< ValueType, ValueType > domain() const
Possible values.
void width(size_t width)
Width of progress bar in characters at 100%.
ProgressBar(const Message::SProxy &stream, const std::string &name="progress")
Construct spinning progress bar.
double minimumUpdateInterval()
Minimum time between updates.
double initialDelay()
Delay before first message is emitted.
Sawyer support library.
Properties for messages.
Definition Message.h:426