ProgressIndicator.cpp
Go to the documentation of this file.
1 // (C) Copyright Renaud Detry 2007-2015.
2 // Distributed under the GNU General Public License and under the
3 // BSD 3-Clause License (See accompanying file LICENSE.txt).
4 
5 /** @file */
6 
7 /**
8  * @file
9  */
10 
11 #include <iostream>
12 #include <string>
13 #include <unistd.h>
14 
16 #include <nuklei/Log.h>
17 #include <nuklei/Common.h>
18 
19 namespace nuklei
20 {
21 
22 
23  const int ProgressIndicator::spanStartDef = 0,
24  ProgressIndicator::spanEndDef = 100;
25  const std::string ProgressIndicator::messageDef = "Progress: ";
26  const std::string ProgressIndicator::backspaceSequence = "\033[A";
27 
28 
29  /** @brief Constructs a PI to go from spanStartDef to spanEndDef. */
31  {
32  initialize(spanStartDef, spanEndDef, messageDef, 0);
33  }
34 
35  /**
36  * @brief Constructs a PI which will scale [spanStartDef spanEnd]
37  * to [0 100].
38  */
40  const std::string &message,
41  const unsigned minLogLevel)
42  {
43  initialize(spanStartDef, spanEnd, message, minLogLevel);
44  }
45 
46  /**
47  * @brief Constructs a PI which will scale [spanStart spanEnd]
48  * to [0 100].
49  */
51  const int spanEnd,
52  const std::string &message,
53  const unsigned minLogLevel)
54  {
55  initialize(spanStart, spanEnd, message, minLogLevel);
56  }
57 
58  ProgressIndicator::~ProgressIndicator()
59  {
60  if (state_ == running)
61  forceEnd();
62  }
63 
64  void ProgressIndicator::initialize(const int spanStart,
65  const int spanEnd,
66  const std::string &message,
67  const unsigned minLogLevel)
68  {
69  minLogLevel_ = minLogLevel;
70 
71  int shellIsInteractive, shellTerminalFileNumber;
72 
73  current_ = 0;
74  message_ = message;
75  state_ = ready;
76  verbose_ = false;
77 
78  spanStart_ = spanStart;
79  spanEnd_ = spanEnd;
80  spanPos_ = spanStart_;
81  spanLength_ = spanEnd_ - spanStart_;
82  if (spanLength_ < 0)
83  NUKLEI_THROW("Error: `spanStart > spanEnd'.");
84 
85 
86  shellTerminalFileNumber = STDIN_FILENO;
87  shellIsInteractive = isatty(shellTerminalFileNumber);
88 
89  if (shellIsInteractive &&
90  getenv("TERM") != NULL &&
91  std::string(getenv("TERM")) != "dumb")
92  {
93  colorStart_ = NUKLEI_DBLACK;
94  colorEnd_ = NUKLEI_NOCOLOR;
95  }
96 
97  if ( !shellIsInteractive || !ENABLE_CONSOLE_BACKSPACE )
98  {
99  backspace_ = false;
100  scale_ = 10;
101  }
102  else
103  {
104  backspace_ = true;
105  scale_ = 100;
106  }
107 
108  if (verbose_)
109  std::cout << "isatty: " << shellIsInteractive << std::endl
110  << "spanLength: " << spanLength_ << " "
111  << spanStart_ << "->" << spanEnd_ << std::endl;
112 
113  setValue(spanStart_);
114  }
115 
116  void ProgressIndicator::setMinLogLevel(const unsigned l)
117  { minLogLevel_ = l; }
118  unsigned ProgressIndicator::getMinLogLevel() const
119  { return minLogLevel_; }
120 
121  void ProgressIndicator::setBackspace(const bool backspace)
122  {
123  backspace_ = backspace;
124  }
125 
126  /**
127  * Use inside the loop.
128  * @param value the progress value between spanStart
129  * and spanEnd.
130  */
131  void ProgressIndicator::setValue(const int value)
132  {
133  if (state_ == finished) return;
134  if (spanLength_ == 0) return;
135 
136  if (state_ == ready)
137  {
138  if (LOG_LEVEL >= minLogLevel_) std::cout << colorStart_ << message_ << "[ 0% ]" << colorEnd_ << std::endl;
139  state_ = running;
140  if (LOG_LEVEL >= minLogLevel_) LAST_OUTPUT_LINE_IS_PROGRESS = true;
141  }
142  spanPos_ = value;
143  int count = (value - spanStart_) * scale_ / spanLength_;
144  if (count > current_)
145  {
146  current_ = count;
147  if (LOG_LEVEL >= minLogLevel_)
148  {
149  if (backspace_)
150  {
151  if (LAST_OUTPUT_LINE_IS_PROGRESS)
152  std::cout << backspaceSequence;
153  std::cout << colorStart_ << message_ << "[ ";
154 
155  int width = std::cout.width();
156  std::cout.width(3);
157  std::cout << int(current_ * 100 / scale_);
158  std::cout.width(width);
159 
160  std::cout << "% ]" << colorEnd_ << std::endl;
161  LAST_OUTPUT_LINE_IS_PROGRESS = true;
162  }
163  else
164  {
165  std::cout << colorStart_ << message_ << "[ ";
166  int width = std::cout.width();
167  std::cout.width(3);
168  std::cout << int(current_ * 100 / scale_);
169  std::cout.width(width);
170  std::cout << "% ]" << colorEnd_ << std::endl;
171  LAST_OUTPUT_LINE_IS_PROGRESS = true;
172  }
173  }
174  if (current_ == scale_)
175  {
176  state_ = finished;
177  //if (backspace_)
178  // std::cout << std::endl;
179  }
180  }
181  }
182 
183  /**
184  * Use inside the loop.
185  * @param value the progress value between spanStart
186  * and spanEnd.
187  */
188  void ProgressIndicator::inc(const int value)
189  {
190  setValue(spanPos_+value);
191  }
192 
193  /**
194  * Use inside the loop.
195  * @param value the progress value between spanStart
196  * and spanEnd.
197  */
198  void ProgressIndicator::mtInc(const int value)
199  {
200  boost::unique_lock<boost::mutex> lock(Log::mutex_);
201  setValue(spanPos_+value);
202  }
203 
204  const std::string& ProgressIndicator::getMessage() const
205  {
206  return message_;
207  }
208 
209  void ProgressIndicator::setMessage(const std::string& message)
210  {
211  message_ = message;
212  }
213 
214  /**
215  * Gets the PI ready to be used again.
216  * This is not a reset, since spanStart, spanEnd etc. are not
217  * reset.
218  */
220  {
221  current_ = 0;
222  spanPos_ = 0;
223  state_ = ready;
224  }
225 
226  /** Forces the display of 100% and a new line. */
228  {
229  setValue(spanEnd_);
230  }
231 
232 
233  int ProgressIndicator::main(int argc, char ** argv)
234  {
235  if (argc < 3)
236  {
237  std::cout << "no no no, test 0 100" << std::endl;
238  return 1;
239  }
240 
241  int a = strtol(argv[1], NULL, 10);
242  int b = strtol(argv[2], NULL, 10);
243 
244  ProgressIndicator pi(a, b);
245 
246  for (int i = a; i <= b; i++)
247  {
248  pi.setValue(i);
249  for (unsigned int j = 0; j < 2000000; j++);
250  }
251 
252  pi.rewind();
253  std::string message = "Second use: ";
254  pi.setMessage(message);
255 
256  for (int i = a; i <= b + 50 - a; i++)
257  {
258  pi.setValue(i);
259  for (unsigned int j = 0; j < 7000000; j++);
260  }
261 
262  pi.forceEnd(); // since we know the loop only goes to 150
263 
264  return 0;
265  }
266 
267 }
268 
Public namespace.
Definition: Color.cpp:9
void inc(const int value=1)
void setValue(const int value)
void forceEnd()
ProgressIndicator()
Constructs a PI to go from spanStartDef to spanEndDef.
void mtInc(const int value=1)
void rewind()
#define NUKLEI_THROW(x)
Throws an Error.
Definition: Common.h:94
© Copyright 2007-2013 Renaud Detry.
Distributed under the terms of the GNU General Public License (GPL).
(See accompanying file LICENSE.txt or copy at http://www.gnu.org/copyleft/gpl.html.)
Revised Sun Sep 13 2020 19:10:06.