Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
Progress-CPP
Progress-CPP-Throttled-HeaderOnly
===

## What's new, TLDR

By printing progress bar only when it is needed, performance got better.

Added ETA(Estimated time of arrival), and Spinner.

It is just one header file, like original.



## What's new and why, in detail

### Throttling added

Displaying progress is important, but when printing too much console from your program, your program slows down. That's what exactly happened to me when using original library. So I added throttling feature, to print the progress bar only when it is needed. When `throttle_progress` is set to 1(default), then program will display the progress bar only when percentage changes. If we set `throttle_progress` larger than 1, then it will skip printing progress bar until added progress percentage gets larger than `throttle_progress` .

### ETA added

Time estimation is added. It can be enabled/disabled by variable `is_eta_enabled`

### Spinner added

Spinner is added. It can be enabled/disabled by variable `is_spinner_enabled`



## Original README of Progress-CPP

A flexible ASCII progress bar for your console based C++ projects.

### Usage
Expand Down
17 changes: 13 additions & 4 deletions example/src/example.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#include <iostream>
#include <unistd.h>

#ifdef _WIN32
#include <windows.h>
#else
//#include <unistd.h>
#endif

#include "progresscpp/ProgressBar.hpp"

/* Example usage of ProgressBar */
Expand All @@ -16,11 +22,14 @@ int main() {
for (int i = 0; i < total; i++) {
++progressBar; // record the tick

usleep(200); // simulate work
#ifdef _WIN32
Sleep(1);
#else
usleep(100); // simulate work
#endif

// display the bar only at certain steps
if (i % 10 == 0)
progressBar.display();
progressBar.display();
}

// tell the bar to finish
Expand Down
124 changes: 109 additions & 15 deletions include/progresscpp/ProgressBar.hpp
Original file line number Diff line number Diff line change
@@ -1,47 +1,141 @@
#pragma once

/*
* from progress-cpp by prakhar1989 (@ref https://github.com/prakhar1989/progress-cpp)
* added throttling by sikbrad @ref https://github.com/sikbrad/progress-cpp-throttled.git
*/

#include <chrono>
#include <iostream>
#include <math.h>
#include <iomanip>

namespace progresscpp {
class ProgressBar {
private:
unsigned int ticks = 0;

const unsigned int total_ticks;
const unsigned int bar_width;
const unsigned int bar_width = 70;
const char complete_char = '=';
const char incomplete_char = ' ';
const std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();

public:
int throttle_progress = 5;
bool is_eta_enabled = true;
bool is_spinner_enabled = true;

private:
int prev_progress_percent = 0;
int throttle_counter = 0;
int count_display = 0;

public:
bool is_displayed = false;

public:
ProgressBar(unsigned int total, unsigned int width, char complete, char incomplete, int throttle, bool is_eta) :
total_ticks{total}, bar_width{width}, complete_char{complete}, incomplete_char{incomplete}, throttle_progress{throttle}, is_eta_enabled{is_eta} {}

ProgressBar(unsigned int total, unsigned int width, char complete, char incomplete) :
total_ticks{total}, bar_width{width}, complete_char{complete}, incomplete_char{incomplete} {}

ProgressBar(unsigned int total, unsigned int width) : total_ticks{total}, bar_width{width} {}

ProgressBar(unsigned int total) : total_ticks{total} {}

unsigned int operator++() { return ++ticks; }

void display() const {
float progress = (float) ticks / total_ticks;
int pos = (int) (bar_width * progress);
void _display() const {
}

bool display() {
float progress = (float) (ticks+1) / total_ticks;
int curr_progress_percent = ceil(100 * progress);
bool is_print = false;

//dont limit if set as zero
if(throttle_progress == 0){
is_print = true;
}
//if limit is set,
else if(prev_progress_percent > 0){
//detect percentage change
if(prev_progress_percent < curr_progress_percent){
++throttle_counter;

//when throttle exceeds, then print and reset the counter.
if(throttle_counter >= throttle_progress){
throttle_counter = 0;
is_print = true;
}
}
}

if(is_print){
int pos = (int) (bar_width * progress);

std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();

std::cout << "[";

std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
for (int i = 0; i < bar_width; ++i) {
if (i < pos) std::cout << complete_char;
else if (i == pos) std::cout << ">";
else std::cout << incomplete_char;
}
std::cout << "] ";

std::cout << "[";
std::cout << "[" << int(progress * 100.0) << "% ";
std::cout << std::fixed << std::setprecision(2) << float(time_elapsed) / 1000.0 << "s";
std::cout << "]";

for (int i = 0; i < bar_width; ++i) {
if (i < pos) std::cout << complete_char;
else if (i == pos) std::cout << ">";
else std::cout << incomplete_char;
if(is_eta_enabled){
float expected = float(time_elapsed) / progress;
float eta = abs(expected - time_elapsed);
std::cout << " eta " << std::fixed << std::setprecision(2) << float(eta) / 1000.0 << "s ";
}

if(is_spinner_enabled){
//followed character spinner style of etaprogress(python)
//@ref https://pypi.org/project/etaprogress/
const int total_pinchar = 4;
int idx_spinchar = count_display % total_pinchar;
char spinchar = ' ';
switch(idx_spinchar){
case 0:
spinchar = '-'; break;
case 1:
spinchar = '\\'; break;
case 2:
spinchar = '|'; break;
case 3:
spinchar = '/'; break;
default:
break;
}
std::cout << " " << spinchar;
}


std::cout << " \r";
std::cout.flush();

is_displayed = true;
count_display++;
}else{
is_displayed = false;
}
std::cout << "] " << int(progress * 100.0) << "% "
<< float(time_elapsed) / 1000.0 << "s\r";
std::cout.flush();

//save status
prev_progress_percent = curr_progress_percent;

return is_displayed;
}

void done() const {
void done() {
display();
std::cout << std::endl;
}
Expand Down