blob: 8ba10386bb8029f10e4c06b8171cc47a68d63dd7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
#include "util/stream/multi_progress.hh"
// TODO: merge some functionality with the simple progress bar?
#include "util/ersatz_progress.hh"
#include <iostream>
#include <limits>
#include <string.h>
#if !defined(_WIN32) && !defined(_WIN64)
#include <unistd.h>
#endif
namespace util { namespace stream {
namespace {
const char kDisplayCharacters[] = "-+*#0123456789";
uint64_t Next(unsigned char stone, uint64_t complete) {
return (static_cast<uint64_t>(stone + 1) * complete + MultiProgress::kWidth - 1) / MultiProgress::kWidth;
}
} // namespace
MultiProgress::MultiProgress() : active_(false), complete_(std::numeric_limits<uint64_t>::max()), character_handout_(0) {}
MultiProgress::~MultiProgress() {
if (active_ && complete_ != std::numeric_limits<uint64_t>::max())
std::cerr << '\n';
}
void MultiProgress::Activate() {
active_ =
#if !defined(_WIN32) && !defined(_WIN64)
// Is stderr a terminal?
(isatty(2) == 1)
#else
true
#endif
;
}
void MultiProgress::SetTarget(uint64_t complete) {
if (!active_) return;
complete_ = complete;
if (!complete) complete_ = 1;
memset(display_, 0, sizeof(display_));
character_handout_ = 0;
std::cerr << kProgressBanner;
}
WorkerProgress MultiProgress::Add() {
if (!active_)
return WorkerProgress(std::numeric_limits<uint64_t>::max(), *this, '\0');
std::size_t character_index;
{
boost::unique_lock<boost::mutex> lock(mutex_);
character_index = character_handout_++;
if (character_handout_ == sizeof(kDisplayCharacters) - 1)
character_handout_ = 0;
}
return WorkerProgress(Next(0, complete_), *this, kDisplayCharacters[character_index]);
}
void MultiProgress::Finished() {
if (!active_ || complete_ == std::numeric_limits<uint64_t>::max()) return;
std::cerr << '\n';
complete_ = std::numeric_limits<uint64_t>::max();
}
void MultiProgress::Milestone(WorkerProgress &worker) {
if (!active_ || complete_ == std::numeric_limits<uint64_t>::max()) return;
unsigned char stone = std::min(static_cast<uint64_t>(kWidth), worker.current_ * kWidth / complete_);
for (char *i = &display_[worker.stone_]; i < &display_[stone]; ++i) {
*i = worker.character_;
}
worker.next_ = Next(stone, complete_);
worker.stone_ = stone;
{
boost::unique_lock<boost::mutex> lock(mutex_);
std::cerr << '\r' << display_ << std::flush;
}
}
}} // namespaces
|