ROSE  0.9.10.196
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 #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 
20 namespace 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.
24 class SAWYER_EXPORT ProgressBarImpl {
25 public:
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  }
50  ~ProgressBarImpl() {
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 
66 namespace 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 
108 template<typename T, typename S=std::string>
109 class ProgressBar {
110 public:
111  typedef S Suffix;
112  typedef T ValueType;
113 private:
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 
129 public:
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  }
356 private:
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.
391 template <typename T, typename S>
392 double 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 
414 template <typename T, typename S>
415 void 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 
423 template <typename T, typename S>
424 void 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
Suffix suffix() const
Property: suffix.
Definition: ProgressBar.h:194
void prefix(const std::string &s)
String to show before the beginning of the bar.
Definition: ProgressBar.h:294
double minimumUpdateInterval()
Minimum time between updates.
ProgressBar & operator-=(ValueType delta)
Increment or decrement the progress bar.
Definition: ProgressBar.h:269
ProgressBar & operator--()
Increment or decrement the progress bar.
Definition: ProgressBar.h:257
std::pair< char, char > barchars() const
Characters to use for the bar.
Definition: ProgressBar.h:304
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:150
void value(ValueType leftValue, ValueType curValue, ValueType rightValue)
Value for the progress bar.
Definition: ProgressBar.h:176
std::pair< std::string, std::string > endchars() const
Characters to use for the left and right ends of the bar.
Definition: ProgressBar.h:318
ProgressBar & operator++(int)
Increment or decrement the progress bar.
Definition: ProgressBar.h:253
ProgressBar & operator+=(ValueType delta)
Increment or decrement the progress bar.
Definition: ProgressBar.h:265
Name space for the entire library.
void domain(const std::pair< ValueType, ValueType > &p)
Possible values.
Definition: ProgressBar.h:231
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:141
ProgressBar & operator--(int)
Increment or decrement the progress bar.
Definition: ProgressBar.h:261
Properties for messages.
Definition: Message.h:424
ProgressBar & suffix(const Suffix &suffix)
Property: suffix.
Definition: ProgressBar.h:198
ProgressBar(const Message::SProxy &stream, const std::string &name="progress")
Construct spinning progress bar.
Definition: ProgressBar.h:133
std::pair< ValueType, ValueType > domain() const
Possible values.
Definition: ProgressBar.h:227
ValueType value() const
Value for the progress bar.
Definition: ProgressBar.h:159
bool showPercent() const
Whether to show the percent indication.
Definition: ProgressBar.h:332
ProgressBar & operator++()
Increment or decrement the progress bar.
Definition: ProgressBar.h:249
A single message.
Definition: Message.h:511
void showPercent(bool b)
Whether to show the percent indication.
Definition: ProgressBar.h:336
void value(ValueType curValue, ValueType rightValue)
Value for the progress bar.
Definition: ProgressBar.h:169
const std::string & prefix() const
String to show before the beginning of the bar.
Definition: ProgressBar.h:290
void decrement(ValueType delta=1)
Increment or decrement the progress bar.
Definition: ProgressBar.h:424
void width(size_t width)
Width of progress bar in characters at 100%.
Definition: ProgressBar.h:281
void increment(ValueType delta=1)
Increment or decrement the progress bar.
Definition: ProgressBar.h:415
void barchars(char bar, char nonBar)
Characters to use for the bar.
Definition: ProgressBar.h:308
Suffix suffix()
Property: suffix.
Definition: ProgressBar.h:190
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:322
Progress bars.
Definition: ProgressBar.h:109
bool showValue() const
Whether to show the current value.
Definition: ProgressBar.h:345
double ratio() const
Value of progress bar as a ratio of completeness clipped between 0 and 1.
Definition: ProgressBar.h:208
bool isEmpty() const
True if the distance between the minimum and maximum is zero.
Definition: ProgressBar.h:214
void domain(ValueType leftValue, ValueType rightValue)
Possible values.
Definition: ProgressBar.h:237
void value(ValueType curValue)
Value for the progress bar.
Definition: ProgressBar.h:163
bool isBackward() const
True if the minimum value is greater than the maximum value.
Definition: ProgressBar.h:220
double initialDelay()
Delay before first message is emitted.
void showValue(bool b)
Whether to show the current value.
Definition: ProgressBar.h:349
size_t width() const
Width of progress bar in characters at 100%.
Definition: ProgressBar.h:277