Advertisement
HasteBin0

C++ Progress Indicator for Command-line Programs

Oct 14th, 2017
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.61 KB | None | 0 0
  1. /// Header
  2.  
  3. #ifndef PROGRESSSPINNER_H
  4. #define PROGRESSSPINNER_H
  5.  
  6. #include <thread>
  7. #include <mutex>
  8.  
  9. class ProgressSpinner {
  10.     public:
  11.         ProgressSpinner(unsigned);
  12.         ProgressSpinner(const ProgressSpinner&) = delete;
  13.         ~ProgressSpinner();
  14.  
  15.         bool start();
  16.         bool stop();
  17.  
  18.         bool resume();
  19.         bool pause();
  20.  
  21.         bool is_running();
  22.         bool is_paused ();
  23.         bool is_online ();
  24.  
  25.         unsigned get_speed();
  26.         void set_speed(unsigned);
  27.  
  28.     private:
  29.         unsigned speed;
  30.         bool running, paused;
  31.         int8_t spin;
  32.         std::thread* runner;
  33.         std::mutex lock;
  34.         void run();
  35.         bool moving();
  36. };
  37.  
  38. #endif // PROGRESSSPINNER_H
  39.  
  40. /// Source
  41.  
  42. #include "ProgressSpinner.hpp"
  43.  
  44. #include <cstdio>
  45. #include <chrono>
  46.  
  47. const char spinner[9] = "|\\-/|\\-/";
  48. const int8_t spins=9;
  49.  
  50. ProgressSpinner::ProgressSpinner(unsigned speedv) {
  51.     this->running = false;
  52.     this->paused  = true ;
  53.     this->speed   = speedv? speedv:1;
  54.     this->runner  = nullptr;
  55.     this->spin    = 0;
  56. }
  57.  
  58. ProgressSpinner::~ProgressSpinner() {
  59.     this->stop();
  60. }
  61.  
  62. bool ProgressSpinner::start() {
  63.     this->lock.lock();
  64.     bool out=false;
  65.     if (!this->running) { // not already started
  66.         try {
  67.             this->runner = new std::thread(ProgressSpinner::run, this); // start thread
  68.         } catch (...) { // bad_alloc or runtime_error?
  69.             delete this->runner;
  70.             this->runner = nullptr;
  71.             goto _end;
  72.         }
  73.         this->running = (bool) (this->runner); // register start
  74.         this->paused  = !this->running; // go/stop
  75.         this->spin    = 1;
  76.         out = this->running;
  77.     }
  78.     _end:
  79.     this->lock.unlock();
  80.     return out;
  81. }
  82.  
  83. bool ProgressSpinner::stop() {
  84.     this->lock.lock();
  85.     bool out=false;
  86.     if (this->running) { // not already stopped
  87.         this->running = false; // queue to stop
  88.         this->paused  = false;
  89.         // allow to stop
  90.         this->lock.unlock();
  91.         // wait for stop-confirmation
  92.         while (true) {
  93.             this->lock.lock();
  94.             if (this->paused) { // confirmation received
  95.                 this->lock.unlock();
  96.                 break; // stop blocking
  97.             }
  98.             // or continue waiting
  99.             this->lock.unlock();
  100.         }
  101.         // after stop
  102.         this->lock.lock();
  103.         // handle thread
  104.         this->runner->join();
  105.         delete this->runner;
  106.         this->runner = nullptr;
  107.         // success
  108.         out = true;
  109.     }
  110.     this->lock.unlock();
  111.     return out;
  112. }
  113.  
  114. bool ProgressSpinner::resume() {
  115.     this->lock.lock();
  116.     bool out=false;
  117.     if (this->paused) {
  118.         this->paused = false;
  119.         out = true;
  120.     }
  121.     this->lock.unlock();
  122.     return out;
  123. }
  124.  
  125. bool ProgressSpinner::pause() {
  126.     this->lock.lock();
  127.     bool out=false;
  128.     if (!this->paused) {
  129.         this->paused = true;
  130.         out = true;
  131.     }
  132.     this->lock.unlock();
  133.     return out;
  134. }
  135.  
  136. bool ProgressSpinner::is_running() {
  137.     this->lock.lock();
  138.     bool running_tmp = this->running;
  139.     this->lock.unlock();
  140.     return running_tmp;
  141. }
  142.  
  143. bool ProgressSpinner::is_paused() {
  144.     this->lock.lock();
  145.     bool paused_tmp = this->paused;
  146.     this->lock.unlock();
  147.     return paused_tmp;
  148. }
  149.  
  150. bool ProgressSpinner::is_online() {
  151.     this->lock.lock();
  152.     bool online = this->moving();
  153.     this->lock.unlock();
  154.     return online;
  155. }
  156.  
  157. unsigned ProgressSpinner::get_speed() {
  158.     this->lock.lock();
  159.     unsigned speed_tmp = this->speed;
  160.     this->lock.unlock();
  161.     return speed_tmp;
  162. }
  163.  
  164. void ProgressSpinner::set_speed(unsigned speedv) {
  165.     this->lock.lock();
  166.     this->speed = speedv? speedv:1;
  167.     this->lock.unlock();
  168. }
  169.  
  170. void ProgressSpinner::run() {
  171.     std::chrono::milliseconds speedv;
  172.     while (true) {
  173.         this->lock.lock();
  174.         if (!this->paused) {
  175.             if (this->spin == spins) {this->spin = (int8_t) 1;} // reset after display cycle
  176.             printf("%c\b", spinner[(unsigned short) this->spin++]); // DO THE WHOLE POINT PT. 1
  177.             fflush(stdout);
  178.         }
  179.         if (!this->running) { // stop
  180.             this->paused = true; // give confirmation
  181.             printf(" \b"); // clean up - WHOLE POINT PT. 2
  182.             fflush(stdout);
  183.             this->lock.unlock(); // allow ...
  184.             break;
  185.         }
  186.         speedv = std::chrono::milliseconds(this->speed);
  187.         this->lock.unlock();
  188.         std::this_thread::sleep_for(speedv);
  189.     }
  190. }
  191.  
  192. bool ProgressSpinner::moving() {
  193.     return this->running && !this->paused;
  194. }
  195.  
  196. /// End
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement