|
| 1 | +// The MIT License (MIT) |
| 2 | +// |
| 3 | +// Copyright (c) 2019 Luigi Pertoldi |
| 4 | +// |
| 5 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
| 6 | +// of this software and associated documentation files (the "Software"), to |
| 7 | +// deal in the Software without restriction, including without limitation the |
| 8 | +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
| 9 | +// sell copies of the Software, and to permit persons to whom the Software is |
| 10 | +// furnished to do so, subject to the following conditions: |
| 11 | +// |
| 12 | +// The above copyright notice and this permission notice shall be included in |
| 13 | +// all copies or substantial portions of the Software. |
| 14 | +// |
| 15 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 18 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 19 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 20 | +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 21 | +// IN THE SOFTWARE. |
| 22 | +// |
| 23 | +// ============================================================================ |
| 24 | +// ___ ___ ___ __ ___ ____ __ __ ___ __ ___ |
| 25 | +// | |_) | |_) / / \ / /`_ | |_) | |_ ( (` ( (` | |_) / /\ | |_) |
| 26 | +// |_| |_| \ \_\_/ \_\_/ |_| \ |_|__ _)_) _)_) |_|_) /_/--\ |_| \_ |
| 27 | +// |
| 28 | +// Very simple progress bar for c++ loops with internal running variable |
| 29 | +// |
| 30 | +// Author: Luigi Pertoldi |
| 31 | +// Created: 3 dic 2016 |
| 32 | +// |
| 33 | +// Notes: The bar must be used when there's no other possible source of output |
| 34 | +// inside the for loop |
| 35 | +// |
| 36 | + |
| 37 | +#ifndef __PROGRESSBAR_HPP |
| 38 | +#define __PROGRESSBAR_HPP |
| 39 | + |
| 40 | +#include <iostream> |
| 41 | +#include <ostream> |
| 42 | +#include <string> |
| 43 | +#include <stdexcept> |
| 44 | + |
| 45 | +class progressbar { |
| 46 | + |
| 47 | + public: |
| 48 | + // default destructor |
| 49 | + ~progressbar() = default; |
| 50 | + |
| 51 | + // delete everything else |
| 52 | + progressbar (progressbar const&) = delete; |
| 53 | + progressbar& operator=(progressbar const&) = delete; |
| 54 | + progressbar (progressbar&&) = delete; |
| 55 | + progressbar& operator=(progressbar&&) = delete; |
| 56 | + |
| 57 | + // default constructor, must call set_niter later |
| 58 | + inline progressbar(); |
| 59 | + inline progressbar(int n, bool showbar=true, std::ostream& out=std::cerr); |
| 60 | + |
| 61 | + // reset bar to use it again |
| 62 | + inline void reset(); |
| 63 | + // set number of loop iterations |
| 64 | + inline void set_niter(int iter); |
| 65 | + // chose your style |
| 66 | + inline void set_done_char(const std::string& sym) {done_char = sym;} |
| 67 | + inline void set_todo_char(const std::string& sym) {todo_char = sym;} |
| 68 | + inline void set_opening_bracket_char(const std::string& sym) {opening_bracket_char = sym;} |
| 69 | + inline void set_closing_bracket_char(const std::string& sym) {closing_bracket_char = sym;} |
| 70 | + // to show only the percentage |
| 71 | + inline void show_bar(bool flag = true) {do_show_bar = flag;} |
| 72 | + // set the output stream |
| 73 | + inline void set_output_stream(const std::ostream& stream) {output.rdbuf(stream.rdbuf());} |
| 74 | + // main function |
| 75 | + inline void update(); |
| 76 | + |
| 77 | + private: |
| 78 | + int progress; |
| 79 | + int n_cycles; |
| 80 | + int last_perc; |
| 81 | + bool do_show_bar; |
| 82 | + bool update_is_called; |
| 83 | + |
| 84 | + std::string done_char; |
| 85 | + std::string todo_char; |
| 86 | + std::string opening_bracket_char; |
| 87 | + std::string closing_bracket_char; |
| 88 | + |
| 89 | + std::ostream& output; |
| 90 | +}; |
| 91 | + |
| 92 | +inline progressbar::progressbar() : |
| 93 | + progress(0), |
| 94 | + n_cycles(0), |
| 95 | + last_perc(0), |
| 96 | + do_show_bar(true), |
| 97 | + update_is_called(false), |
| 98 | + done_char("#"), |
| 99 | + todo_char(" "), |
| 100 | + opening_bracket_char("["), |
| 101 | + closing_bracket_char("]"), |
| 102 | + output(std::cerr) {} |
| 103 | + |
| 104 | +inline progressbar::progressbar(int n, bool showbar, std::ostream& out) : |
| 105 | + progress(0), |
| 106 | + n_cycles(n), |
| 107 | + last_perc(0), |
| 108 | + do_show_bar(showbar), |
| 109 | + update_is_called(false), |
| 110 | + done_char("#"), |
| 111 | + todo_char(" "), |
| 112 | + opening_bracket_char("["), |
| 113 | + closing_bracket_char("]"), |
| 114 | + output(out) {} |
| 115 | + |
| 116 | +inline void progressbar::reset() { |
| 117 | + progress = 0, |
| 118 | + update_is_called = false; |
| 119 | + last_perc = 0; |
| 120 | + return; |
| 121 | +} |
| 122 | + |
| 123 | +inline void progressbar::set_niter(int niter) { |
| 124 | + if (niter <= 0) throw std::invalid_argument( |
| 125 | + "progressbar::set_niter: number of iterations null or negative"); |
| 126 | + n_cycles = niter; |
| 127 | + return; |
| 128 | +} |
| 129 | + |
| 130 | +inline void progressbar::update() { |
| 131 | + |
| 132 | + if (n_cycles == 0) throw std::runtime_error( |
| 133 | + "progressbar::update: number of cycles not set"); |
| 134 | + |
| 135 | + if (!update_is_called) { |
| 136 | + if (do_show_bar == true) { |
| 137 | + output << opening_bracket_char; |
| 138 | + for (int _ = 0; _ < 50; _++) output << todo_char; |
| 139 | + output << closing_bracket_char << " 0%"; |
| 140 | + } |
| 141 | + else output << "0%"; |
| 142 | + } |
| 143 | + update_is_called = true; |
| 144 | + |
| 145 | + int perc = 0; |
| 146 | + |
| 147 | + // compute percentage, if did not change, do nothing and return |
| 148 | + perc = progress*100./(n_cycles-1); |
| 149 | + if (perc < last_perc) return; |
| 150 | + |
| 151 | + // update percentage each unit |
| 152 | + if (perc == last_perc + 1) { |
| 153 | + // erase the correct number of characters |
| 154 | + if (perc <= 10) output << "\b\b" << perc << '%'; |
| 155 | + else if (perc > 10 and perc < 100) output << "\b\b\b" << perc << '%'; |
| 156 | + else if (perc == 100) output << "\b\b\b" << perc << '%'; |
| 157 | + } |
| 158 | + if (do_show_bar == true) { |
| 159 | + // update bar every ten units |
| 160 | + if (perc % 2 == 0) { |
| 161 | + // erase closing bracket |
| 162 | + output << std::string(closing_bracket_char.size(), '\b'); |
| 163 | + // erase trailing percentage characters |
| 164 | + if (perc < 10) output << "\b\b\b"; |
| 165 | + else if (perc >= 10 && perc < 100) output << "\b\b\b\b"; |
| 166 | + else if (perc == 100) output << "\b\b\b\b\b"; |
| 167 | + |
| 168 | + // erase 'todo_char' |
| 169 | + for (int j = 0; j < 50-(perc-1)/2; ++j) { |
| 170 | + output << std::string(todo_char.size(), '\b'); |
| 171 | + } |
| 172 | + |
| 173 | + // add one additional 'done_char' |
| 174 | + if (perc == 0) output << todo_char; |
| 175 | + else output << done_char; |
| 176 | + |
| 177 | + // refill with 'todo_char' |
| 178 | + for (int j = 0; j < 50-(perc-1)/2-1; ++j) output << todo_char; |
| 179 | + |
| 180 | + // readd trailing percentage characters |
| 181 | + output << closing_bracket_char << ' ' << perc << '%'; |
| 182 | + } |
| 183 | + } |
| 184 | + last_perc = perc; |
| 185 | + ++progress; |
| 186 | + output << std::flush; |
| 187 | + |
| 188 | + return; |
| 189 | +} |
| 190 | + |
| 191 | +#endif |
0 commit comments