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