00001 #include "util/stream/multi_progress.hh"
00002
00003
00004 #include "util/ersatz_progress.hh"
00005
00006 #include <iostream>
00007 #include <limits>
00008
00009 #include <cstring>
00010
00011 #if !defined(_WIN32) && !defined(_WIN64)
00012 #include <unistd.h>
00013 #endif
00014
00015 namespace util { namespace stream {
00016
00017 namespace {
00018 const char kDisplayCharacters[] = "-+*#0123456789";
00019
00020 uint64_t Next(unsigned char stone, uint64_t complete) {
00021 return (static_cast<uint64_t>(stone + 1) * complete + MultiProgress::kWidth - 1) / MultiProgress::kWidth;
00022 }
00023
00024 }
00025
00026 MultiProgress::MultiProgress() : active_(false), complete_(std::numeric_limits<uint64_t>::max()), character_handout_(0) {}
00027
00028 MultiProgress::~MultiProgress() {
00029 if (active_ && complete_ != std::numeric_limits<uint64_t>::max())
00030 std::cerr << '\n';
00031 }
00032
00033 void MultiProgress::Activate() {
00034 active_ =
00035 #if !defined(_WIN32) && !defined(_WIN64)
00036
00037 (isatty(2) == 1)
00038 #else
00039 true
00040 #endif
00041 ;
00042 }
00043
00044 void MultiProgress::SetTarget(uint64_t complete) {
00045 if (!active_) return;
00046 complete_ = complete;
00047 if (!complete) complete_ = 1;
00048 memset(display_, 0, sizeof(display_));
00049 character_handout_ = 0;
00050 std::cerr << kProgressBanner;
00051 }
00052
00053 WorkerProgress MultiProgress::Add() {
00054 if (!active_)
00055 return WorkerProgress(std::numeric_limits<uint64_t>::max(), *this, '\0');
00056 std::size_t character_index;
00057 {
00058 boost::unique_lock<boost::mutex> lock(mutex_);
00059 character_index = character_handout_++;
00060 if (character_handout_ == sizeof(kDisplayCharacters) - 1)
00061 character_handout_ = 0;
00062 }
00063 return WorkerProgress(Next(0, complete_), *this, kDisplayCharacters[character_index]);
00064 }
00065
00066 void MultiProgress::Finished() {
00067 if (!active_ || complete_ == std::numeric_limits<uint64_t>::max()) return;
00068 std::cerr << '\n';
00069 complete_ = std::numeric_limits<uint64_t>::max();
00070 }
00071
00072 void MultiProgress::Milestone(WorkerProgress &worker) {
00073 if (!active_ || complete_ == std::numeric_limits<uint64_t>::max()) return;
00074 unsigned char stone = std::min(static_cast<uint64_t>(kWidth), worker.current_ * kWidth / complete_);
00075 for (char *i = &display_[worker.stone_]; i < &display_[stone]; ++i) {
00076 *i = worker.character_;
00077 }
00078 worker.next_ = Next(stone, complete_);
00079 worker.stone_ = stone;
00080 {
00081 boost::unique_lock<boost::mutex> lock(mutex_);
00082 std::cerr << '\r' << display_ << std::flush;
00083 }
00084 }
00085
00086 }}