ROSE  0.9.9.109
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://github.com/matzke1/sawyer.
4 
5 
6 
7 
8 // WARNING: Changes to this file must be contributed back to Sawyer or else they will
9 // be clobbered by the next update from Sawyer. The Sawyer repository is at
10 // https://github.com/matzke1/sawyer.
11 
12 
13 
14 
15 #ifndef Sawyer_ProgressBar_H
16 #define Sawyer_ProgressBar_H
17 
18 #include <Sawyer/Message.h>
19 #include <Sawyer/Optional.h>
20 #include <Sawyer/Sawyer.h>
21 
22 #include <boost/thread/locks.hpp>
23 #include <boost/thread/mutex.hpp>
24 #include <cmath>
25 #include <sstream>
26 
27 namespace Sawyer {
28 
29 // used internally by the ProgressBar<> classes. Since this is called only from ProgressBar objects and ProgressBar has
30 // a synchronized API, we don't need any synchronization at this level.
31 class SAWYER_EXPORT ProgressBarImpl {
32 public:
33 #include <Sawyer/WarningsOff.h>
34  double value_; // between zero and one, inclusive
35  size_t width_; // width of bar in characters
36  bool showPercent_; // show the percent after the progress bar
37  std::string leftEnd_, rightEnd_; // strings for left and right ends of progress bar
38  char barChar_, nonBarChar_; // characters for the bar and non-bar parts
39  std::string prefix_; // extra text before the bar (usually a short message)
40  std::string suffix_; // extra text to show after the bar (usually the value)
41  static double minUpdateInterval_; // min number of seconds between update
42  static double initialDelay_; // time to delay before emitting the first message
43  double lastUpdateTime_; // time of previous update
44  Message::MesgProps overridesAnsi_; // properties we override from the stream_ when using color
45  Message::SProxy stream_; // stream to which messages are sent
46  size_t nUpdates_; // number of times a message was emitted
47  bool shouldSpin_; // spin instead of progress
48  Message::Mesg textMesg_; // message used when ANSI escape sequences are not available
49  Optional<int> oldPercent_; // old percent value used when updating a non-color progress bar
50 #include <Sawyer/WarningsRestore.h>
51 
52  ProgressBarImpl(const Message::SProxy &stream)
53  : value_(0.0), width_(15), showPercent_(true), leftEnd_("["), rightEnd_("]"), barChar_('#'), nonBarChar_('-'),
54  lastUpdateTime_(0.0), stream_(stream), nUpdates_(0), shouldSpin_(false) {
55  init();
56  }
57  ~ProgressBarImpl() {
58  cleanup();
59  }
60 
61  void init();
62  void cleanup(); // deletes the progress bar from the screen
63  void update(double ratio, bool backward); // update regardless of time (if stream is enabled)
64  void configUpdate(double ratio, bool backward); // update for configuration changes
65  void valueUpdate(double ratio, bool backward); // update for changes in value
66  std::string makeBar(double ratio, bool backward); // make the bar itself
67  void updateTextMesg(double ratio); // update the textMesg_
68 };
69 
73 namespace ProgressBarSettings {
79  SAWYER_EXPORT double initialDelay();
80  SAWYER_EXPORT void initialDelay(double s);
86  SAWYER_EXPORT double minimumUpdateInterval();
87  SAWYER_EXPORT void minimumUpdateInterval(double s);
89 } // namespace
90 
91 
112 template<typename T, typename S=std::string>
113 class ProgressBar {
114 public:
115  typedef S Suffix;
116  typedef T ValueType;
117 private:
118  struct Position {
119  ValueType leftValue, curValue, rightValue;
120  Position(ValueType leftValue, ValueType curValue, ValueType rightValue)
121  : leftValue(leftValue), curValue(curValue), rightValue(rightValue) {}
122  bool operator==(const Position &other) const {
123  return curValue==other.curValue && leftValue==other.leftValue && rightValue==other.rightValue;
124  }
125  };
126 
127  mutable boost::mutex mutex_; // locks the following data members
128  Position value_;
129  ProgressBarImpl bar_;
130  bool showValue_;
131  Suffix suffix_;
132 
133 public:
137  explicit ProgressBar(const Message::SProxy &stream, const std::string &name="progress")
138  : value_(0, 0, 0), bar_(stream), showValue_(true) {
139  bar_.shouldSpin_ = true;
140  bar_.prefix_ = name;
141  }
142 
145  ProgressBar(ValueType rightValue, const Message::SProxy &stream, const std::string &name="progress")
146  : value_(0, 0, rightValue), bar_(stream), showValue_(true) {
147  bar_.shouldSpin_ = isEmptyNS();
148  bar_.prefix_ = name;
149  }
150 
154  ProgressBar(ValueType leftValue, ValueType curValue, ValueType rightValue, const Message::SProxy &stream,
155  const std::string &name="progress")
156  : value_(leftValue, curValue, rightValue), bar_(stream), showValue_(true) {
157  bar_.shouldSpin_ = isEmptyNS();
158  bar_.prefix_ = name;
159  }
160 
163  ValueType value() const {
164  boost::lock_guard<boost::mutex> lock(mutex_);
165  return value_.curValue;
166  }
167  void value(ValueType curValue) {
168  boost::lock_guard<boost::mutex> lock(mutex_);
169  value_.curValue = curValue;
170  valueUpdatedNS();
171  }
172 
173  void value(ValueType curValue, ValueType rightValue) {
174  boost::lock_guard<boost::mutex> lock(mutex_);
175  value_.curValue = curValue;
176  value_.rightValue = rightValue;
177  bar_.shouldSpin_ = isEmptyNS();
178  valueUpdatedNS();
179  }
180  void value(ValueType leftValue, ValueType curValue, ValueType rightValue) {
181  boost::lock_guard<boost::mutex> lock(mutex_);
182  value_ = Position(leftValue, curValue, rightValue);
183  bar_.shouldSpin_ = isEmptyNS();
184  valueUpdatedNS();
185  }
194  Suffix suffix() {
195  boost::lock_guard<boost::mutex> lock(mutex_);
196  return suffix_;
197  }
198  Suffix suffix() const {
199  boost::lock_guard<boost::mutex> lock(mutex_);
200  return suffix_;
201  }
202  ProgressBar& suffix(const Suffix &suffix) {
203  boost::lock_guard<boost::mutex> lock(mutex_);
204  suffix_ = suffix;
205  return *this;
206  }
212  double ratio() const {
213  boost::lock_guard<boost::mutex> lock(mutex_);
214  return ratioNS();
215  }
216 
218  bool isEmpty() const {
219  boost::lock_guard<boost::mutex> lock(mutex_);
220  return isEmptyNS();
221  }
222 
224  bool isBackward() const {
225  boost::lock_guard<boost::mutex> lock(mutex_);
226  return isBackwardNS();
227  }
228 
231  std::pair<ValueType, ValueType> domain() const {
232  boost::lock_guard<boost::mutex> lock(mutex_);
233  return std::make_pair(value_.leftValue, value_.rightValue);
234  }
235  void domain(const std::pair<ValueType, ValueType> &p) {
236  boost::lock_guard<boost::mutex> lock(mutex_);
237  value_.leftValue = p.first;
238  value_.rightValue = p.second;
239  configUpdatedNS();
240  }
241  void domain(ValueType leftValue, ValueType rightValue) {
242  boost::lock_guard<boost::mutex> lock(mutex_);
243  value_.leftValue = leftValue;
244  value_.rightValue = rightValue;
245  configUpdatedNS();
246  }
251  void increment(ValueType delta=1);
252  void decrement(ValueType delta=1);
254  increment(1);
255  return *this;
256  }
257  ProgressBar& operator++(int) { // same as a pre-increment
258  increment(1);
259  return *this;
260  }
262  decrement(1);
263  return *this;
264  }
265  ProgressBar& operator--(int) { // same as pre-decrement
266  decrement(1);
267  return *this;
268  }
269  ProgressBar& operator+=(ValueType delta) {
270  increment(delta);
271  return *this;
272  }
273  ProgressBar& operator-=(ValueType delta) {
274  decrement(delta);
275  return *this;
276  }
281  size_t width() const {
282  boost::lock_guard<boost::mutex> lock(mutex_);
283  return bar_.width_;
284  }
285  void width(size_t width) {
286  boost::lock_guard<boost::mutex> lock(mutex_);
287  bar_.width_ = width;
288  configUpdatedNS();
289  }
294  const std::string& prefix() const {
295  boost::lock_guard<boost::mutex> lock(mutex_);
296  return bar_.prefix_;
297  }
298  void prefix(const std::string &s) {
299  boost::lock_guard<boost::mutex> lock(mutex_);
300  bar_.prefix_ = s;
301  configUpdatedNS();
302  }
308  std::pair<char, char> barchars() const {
309  boost::lock_guard<boost::mutex> lock(mutex_);
310  return std::make_pair(bar_.barChar_, bar_.nonBarChar_);
311  }
312  void barchars(char bar, char nonBar) {
313  boost::lock_guard<boost::mutex> lock(mutex_);
314  bar_.barChar_ = bar;
315  bar_.nonBarChar_ = nonBar;
316  configUpdatedNS();
317  }
322  std::pair<std::string, std::string> endchars() const {
323  boost::lock_guard<boost::mutex> lock(mutex_);
324  return std::make_pair(bar_.leftEnd_, bar_.rightEnd_);
325  }
326  void endchars(const std::string &lt, const std::string &rt) {
327  boost::lock_guard<boost::mutex> lock(mutex_);
328  bar_.leftEnd_ = lt;
329  bar_.rightEnd_ = rt;
330  configUpdatedNS();
331  }
336  bool showPercent() const {
337  boost::lock_guard<boost::mutex> lock(mutex_);
338  return bar_.showPercent_;
339  }
340  void showPercent(bool b) {
341  boost::lock_guard<boost::mutex> lock(mutex_);
342  bar_.showPercent_ = b;
343  configUpdatedNS();
344  }
349  bool showValue() const {
350  boost::lock_guard<boost::mutex> lock(mutex_);
351  return showValue_;
352  }
353  void showValue(bool b) {
354  boost::lock_guard<boost::mutex> lock(mutex_);
355  showValue_ = b;
356  configUpdatedNS();
357  }
360 private:
361  bool isEmptyNS() const { // "NS" means "not synchronized" -- the caller must do that.
362  return value_.leftValue == value_.rightValue;
363  }
364 
365  double ratioNS() const;
366 
367  bool isBackwardNS() const {
368  return value_.leftValue > value_.rightValue;
369  }
370 
371  void valueUpdatedNS() {
372  if (showValue_) {
373  std::ostringstream ss;
374  ss <<value_.curValue <<suffix_;
375  bar_.suffix_ = ss.str();
376  } else {
377  bar_.suffix_.clear();
378  }
379  bar_.valueUpdate(ratioNS(), isBackwardNS());
380  }
381 
382  void configUpdatedNS() {
383  if (showValue_) {
384  std::ostringstream ss;
385  ss <<value_.curValue <<suffix_;
386  bar_.suffix_ = ss.str();
387  } else {
388  bar_.suffix_.clear();
389  }
390  bar_.configUpdate(ratioNS(), isBackwardNS());
391  }
392 };
393 
394 // try not to get negative values when subtracting because they might behave strangely if T is something weird.
395 template <typename T, typename S>
396 double ProgressBar<T, S>::ratioNS() const {
397  if (isEmptyNS()) {
398  return value_.curValue <= value_.leftValue ? 0.0 : 1.0;
399  } else if (isBackwardNS()) {
400  if (value_.curValue >= value_.leftValue) {
401  return 0.0;
402  } else if (value_.curValue <= value_.rightValue) {
403  return 1.0;
404  } else {
405  return 1.0 * (value_.leftValue - value_.curValue) / (value_.leftValue - value_.rightValue);
406  }
407  } else {
408  if (value_.curValue <= value_.leftValue) {
409  return 0.0;
410  } else if (value_.curValue >= value_.rightValue) {
411  return 1.0;
412  } else {
413  return 1.0 * (value_.curValue - value_.leftValue) / (value_.rightValue - value_.leftValue);
414  }
415  }
416 }
417 
418 template <typename T, typename S>
419 void ProgressBar<T, S>::increment(ValueType delta) {
420  boost::lock_guard<boost::mutex> lock(mutex_);
421  ValueType oldValue = value_.curValue;
422  value_.curValue += delta;
423  if (oldValue!=value_.curValue)
424  valueUpdatedNS();
425 }
426 
427 template <typename T, typename S>
428 void ProgressBar<T, S>::decrement(ValueType delta) {
429  boost::lock_guard<boost::mutex> lock(mutex_);
430  ValueType oldValue = value_.curValue;
431  value_.curValue -= delta;
432  if (oldValue!=value_.curValue)
433  valueUpdatedNS();
434 }
435 
436 } // namespace
437 
438 #endif
Suffix suffix() const
Property: suffix.
Definition: ProgressBar.h:198
void prefix(const std::string &s)
String to show before the beginning of the bar.
Definition: ProgressBar.h:298
double minimumUpdateInterval()
Minimum time between updates.
ProgressBar & operator-=(ValueType delta)
Increment or decrement the progress bar.
Definition: ProgressBar.h:273
ProgressBar & operator--()
Increment or decrement the progress bar.
Definition: ProgressBar.h:261
std::pair< char, char > barchars() const
Characters to use for the bar.
Definition: ProgressBar.h:308
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.
Definition: ProgressBar.h:154
void value(ValueType leftValue, ValueType curValue, ValueType rightValue)
Value for the progress bar.
Definition: ProgressBar.h:180
std::pair< std::string, std::string > endchars() const
Characters to use for the left and right ends of the bar.
Definition: ProgressBar.h:322
ProgressBar & operator++(int)
Increment or decrement the progress bar.
Definition: ProgressBar.h:257
ProgressBar & operator+=(ValueType delta)
Increment or decrement the progress bar.
Definition: ProgressBar.h:269
Name space for the entire library.
Definition: Access.h:11
void domain(const std::pair< ValueType, ValueType > &p)
Possible values.
Definition: ProgressBar.h:235
ProgressBar(ValueType rightValue, const Message::SProxy &stream, const std::string &name="progress")
Construct a progress bar incrementing from zero to some limit.
Definition: ProgressBar.h:145
ProgressBar & operator--(int)
Increment or decrement the progress bar.
Definition: ProgressBar.h:265
Properties for messages.
Definition: Message.h:424
ProgressBar & suffix(const Suffix &suffix)
Property: suffix.
Definition: ProgressBar.h:202
ProgressBar(const Message::SProxy &stream, const std::string &name="progress")
Construct spinning progress bar.
Definition: ProgressBar.h:137
std::pair< ValueType, ValueType > domain() const
Possible values.
Definition: ProgressBar.h:231
ValueType value() const
Value for the progress bar.
Definition: ProgressBar.h:163
bool showPercent() const
Whether to show the percent indication.
Definition: ProgressBar.h:336
ProgressBar & operator++()
Increment or decrement the progress bar.
Definition: ProgressBar.h:253
A single message.
Definition: Message.h:511
void showPercent(bool b)
Whether to show the percent indication.
Definition: ProgressBar.h:340
void value(ValueType curValue, ValueType rightValue)
Value for the progress bar.
Definition: ProgressBar.h:173
const std::string & prefix() const
String to show before the beginning of the bar.
Definition: ProgressBar.h:294
void decrement(ValueType delta=1)
Increment or decrement the progress bar.
Definition: ProgressBar.h:428
void width(size_t width)
Width of progress bar in characters at 100%.
Definition: ProgressBar.h:285
void increment(ValueType delta=1)
Increment or decrement the progress bar.
Definition: ProgressBar.h:419
void barchars(char bar, char nonBar)
Characters to use for the bar.
Definition: ProgressBar.h:312
Suffix suffix()
Property: suffix.
Definition: ProgressBar.h:194
void endchars(const std::string &lt, const std::string &rt)
Characters to use for the left and right ends of the bar.
Definition: ProgressBar.h:326
Progress bars.
Definition: ProgressBar.h:113
bool showValue() const
Whether to show the current value.
Definition: ProgressBar.h:349
double ratio() const
Value of progress bar as a ratio of completeness clipped between 0 and 1.
Definition: ProgressBar.h:212
bool isEmpty() const
True if the distance between the minimum and maximum is zero.
Definition: ProgressBar.h:218
void domain(ValueType leftValue, ValueType rightValue)
Possible values.
Definition: ProgressBar.h:241
void value(ValueType curValue)
Value for the progress bar.
Definition: ProgressBar.h:167
bool isBackward() const
True if the minimum value is greater than the maximum value.
Definition: ProgressBar.h:224
double initialDelay()
Delay before first message is emitted.
void showValue(bool b)
Whether to show the current value.
Definition: ProgressBar.h:353
size_t width() const
Width of progress bar in characters at 100%.
Definition: ProgressBar.h:281