| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2022 Inria | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions are met: | ||
| 7 | * | ||
| 8 | * * Redistributions of source code must retain the above copyright notice, | ||
| 9 | * this list of conditions and the following disclaimer. | ||
| 10 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
| 11 | * this list of conditions and the following disclaimer in the documentation | ||
| 12 | * and/or other materials provided with the distribution. | ||
| 13 | * * Neither the name of the ALICE Project-Team nor the names of its | ||
| 14 | * contributors may be used to endorse or promote products derived from this | ||
| 15 | * software without specific prior written permission. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
| 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 27 | * POSSIBILITY OF SUCH DAMAGE. | ||
| 28 | * | ||
| 29 | * Contact: Bruno Levy | ||
| 30 | * | ||
| 31 | * https://www.inria.fr/fr/bruno-levy | ||
| 32 | * | ||
| 33 | * Inria, | ||
| 34 | * Domaine de Voluceau, | ||
| 35 | * 78150 Le Chesnay - Rocquencourt | ||
| 36 | * FRANCE | ||
| 37 | * | ||
| 38 | */ | ||
| 39 | |||
| 40 | #ifndef GEOGRAM_BASIC_PROGRESS | ||
| 41 | #define GEOGRAM_BASIC_PROGRESS | ||
| 42 | |||
| 43 | #include <geogram/basic/common.h> | ||
| 44 | #include <geogram/basic/logger.h> | ||
| 45 | #include <geogram/basic/counted.h> | ||
| 46 | #include <geogram/basic/smart_pointer.h> | ||
| 47 | |||
| 48 | /** | ||
| 49 | * \file geogram/basic/progress.h | ||
| 50 | * \brief Functions and classes for displaying progress bars | ||
| 51 | */ | ||
| 52 | |||
| 53 | namespace GEO { | ||
| 54 | |||
| 55 | /** | ||
| 56 | * \brief Task progress listener | ||
| 57 | * \details ProgressClient is an abstract interface for listening to the | ||
| 58 | * progress of tasks tracked by the ProgressTask. The main purpose of a | ||
| 59 | * ProgressClient is to make the progress visible to the end user (to the | ||
| 60 | * console, to a progress bar). | ||
| 61 | * | ||
| 62 | * To implement a specific progress client, you must create a derived | ||
| 63 | * class of ProgressClient and implement the 3 functions: | ||
| 64 | * - begin() | ||
| 65 | * - progress() | ||
| 66 | * - end() | ||
| 67 | * | ||
| 68 | * Then the client must be registered to the Progress system with | ||
| 69 | * Progress::set_client(). The client can access the status of the current | ||
| 70 | * task at any with Progress::current_progress_task(). | ||
| 71 | * time | ||
| 72 | * | ||
| 73 | * \see Progress | ||
| 74 | * \see ProgressTask | ||
| 75 | */ | ||
| 76 | class GEOGRAM_API ProgressClient : public Counted { | ||
| 77 | public: | ||
| 78 | /** | ||
| 79 | * \brief Starts listening progress | ||
| 80 | * \details This function is called by the ProgressTask to start | ||
| 81 | * tracking the execution of a new task. Clients are free to do | ||
| 82 | * whatever is appropriate (show a progress bar, a progress dialog, | ||
| 83 | * ...) | ||
| 84 | */ | ||
| 85 | virtual void begin() = 0; | ||
| 86 | |||
| 87 | /** | ||
| 88 | * \brief Tracks progress | ||
| 89 | * \details This function is called by the ProgressTask repeatedly | ||
| 90 | * during the execution of the task. Clients are free to do whatever | ||
| 91 | * is appropriate (update a progress bar, log the current values, | ||
| 92 | * ...). | ||
| 93 | * \param[in] step the current progress step | ||
| 94 | * \param[in] percent the percentage of completion of the task | ||
| 95 | */ | ||
| 96 | virtual void progress(index_t step, index_t percent) = 0; | ||
| 97 | |||
| 98 | /** | ||
| 99 | * \brief Stops listening progress | ||
| 100 | * \details This function is called by the ProgressTask to stop | ||
| 101 | * tracking the execution of the task. Clients are free to do whatever | ||
| 102 | * is appropriate (hide a progress bar, a progress dialog, log the | ||
| 103 | * elapsed time, ...). If the task was not terminated normally (i.e., | ||
| 104 | * canceled() then parameter \p canceled is set to \c true. | ||
| 105 | * \param[in] canceled set to \c true if the task was canceled, \c | ||
| 106 | * false otherwise. | ||
| 107 | */ | ||
| 108 | virtual void end(bool canceled) = 0; | ||
| 109 | |||
| 110 | protected: | ||
| 111 | /** ProgressClient destructor */ | ||
| 112 | ~ProgressClient() override; | ||
| 113 | }; | ||
| 114 | |||
| 115 | /** Smart pointer that contains a ProgressClient object */ | ||
| 116 | typedef SmartPointer<ProgressClient> ProgressClient_var; | ||
| 117 | |||
| 118 | /************************************************************************/ | ||
| 119 | |||
| 120 | /** | ||
| 121 | * \brief Exception thrown when a task is canceled | ||
| 122 | * \see Progress::cancel() | ||
| 123 | */ | ||
| 124 | struct GEOGRAM_API TaskCanceled : std::exception { | ||
| 125 | /** | ||
| 126 | * \brief Gets the string identifying the exception | ||
| 127 | */ | ||
| 128 | const char* what() const GEO_NOEXCEPT override; | ||
| 129 | }; | ||
| 130 | |||
| 131 | /************************************************************************/ | ||
| 132 | |||
| 133 | class ProgressTask; | ||
| 134 | |||
| 135 | /** | ||
| 136 | * \brief Framework for tracking the progression of a task | ||
| 137 | */ | ||
| 138 | namespace Progress { | ||
| 139 | /** | ||
| 140 | * \brief Initializes the Progress framework | ||
| 141 | * \details This function must be called once at program startup to | ||
| 142 | * create the unique instance of the Progress class and | ||
| 143 | * set a default LoggerClient that logs progress to the console. | ||
| 144 | * \note This function is called by the Vorpaline initialization | ||
| 145 | * function. | ||
| 146 | * \see GEO::initialize() | ||
| 147 | * \see CmdLine | ||
| 148 | */ | ||
| 149 | void GEOGRAM_API initialize(); | ||
| 150 | |||
| 151 | /** | ||
| 152 | * \brief Cleans up the Progress framework | ||
| 153 | * \details This function must be called when the program exits to | ||
| 154 | * cleanup the framework. It is called by the Vorpaline cleanup | ||
| 155 | * function \c GEO::terminate(). | ||
| 156 | */ | ||
| 157 | void GEOGRAM_API terminate(); | ||
| 158 | |||
| 159 | /** | ||
| 160 | * \brief Sets the Progress client | ||
| 161 | * \details Sets the Progress client to \p client. The Progress | ||
| 162 | * instance takes ownership of the client so there's no need to delete | ||
| 163 | * it when the Progress terminates. | ||
| 164 | * \param[in] client a pointer to a ProgressClient | ||
| 165 | */ | ||
| 166 | void GEOGRAM_API set_client(ProgressClient* client); | ||
| 167 | |||
| 168 | /** | ||
| 169 | * \brief Gets the current task | ||
| 170 | * \details The current task is the last ProgressTask being created, | ||
| 171 | * which corresponds to the top-most ProgressTask in the execution | ||
| 172 | * call stack. | ||
| 173 | * \return a pointer the current ProgressTask if any or a null pointer | ||
| 174 | * if there's no current task. | ||
| 175 | */ | ||
| 176 | GEOGRAM_API const ProgressTask* current_progress_task(); | ||
| 177 | |||
| 178 | /** | ||
| 179 | * \brief Cancels the current task | ||
| 180 | * \details This sets a cancellation flag to \c true. | ||
| 181 | * This makes the next call to | ||
| 182 | * ProgressTask::progress() throw an exception TaskCanceled. It is the | ||
| 183 | * responsibility of the client code to catch this exception and do | ||
| 184 | * appropriate cleanup. The cancellation flag can be tested with | ||
| 185 | * is_canceled() before ProgressTask::progress() is being called by | ||
| 186 | * the current task. | ||
| 187 | * \see is_canceled() | ||
| 188 | * \see TaskCanceled | ||
| 189 | */ | ||
| 190 | void GEOGRAM_API cancel(); | ||
| 191 | |||
| 192 | /** | ||
| 193 | * \brief Checks if the current task is canceled | ||
| 194 | * \details This returns \c true if a request was made to cancel the | ||
| 195 | * task (e.g., from the user interface). | ||
| 196 | * \retval true if the task was canceled with cancel() | ||
| 197 | * \retval false otherwise | ||
| 198 | */ | ||
| 199 | bool GEOGRAM_API is_canceled(); | ||
| 200 | |||
| 201 | /** | ||
| 202 | * \brief Clears the cancellation flag | ||
| 203 | */ | ||
| 204 | void GEOGRAM_API clear_canceled(); | ||
| 205 | } | ||
| 206 | |||
| 207 | /************************************************************************/ | ||
| 208 | |||
| 209 | /** | ||
| 210 | * \brief Tracks the progress of a task. | ||
| 211 | * \details | ||
| 212 | * The progress of a task can be represented by a number of steps to | ||
| 213 | * execute. As the task progresses, the client code informs the | ||
| 214 | * ProgressTask of the execution step by calling function next() or | ||
| 215 | * progress(), which notify the LoggerClient%s of the progress. Finally, | ||
| 216 | * when the current logger goes out of scope (is destroyed), the logger | ||
| 217 | * notifies the LoggerClient%s that the task is terminated. | ||
| 218 | * | ||
| 219 | * When a task is canceled by Progress::cancel() the next call to | ||
| 220 | * progress() throws an exception TaskCanceled. It is the | ||
| 221 | * responsibility of the client code to catch this exception and do | ||
| 222 | * appropriate cleanup. The recommended usage of ProgressTask is | ||
| 223 | * illustrated below: | ||
| 224 | * \code | ||
| 225 | * try { | ||
| 226 | * ProgressTask task("something to do", 100); | ||
| 227 | * for(size_t i = 0; i < 100; ++i) { | ||
| 228 | * do_something(); | ||
| 229 | * task.progress(i); | ||
| 230 | * } | ||
| 231 | * } | ||
| 232 | * catch(const TaskCanceled&) { | ||
| 233 | * // Do early cleanup | ||
| 234 | * } | ||
| 235 | * \endcode | ||
| 236 | * | ||
| 237 | * ProgressTask can be sub-classed by client code, typically to route | ||
| 238 | * progress display to a progress bar. | ||
| 239 | */ | ||
| 240 | class GEOGRAM_API ProgressTask { | ||
| 241 | public: | ||
| 242 | /** | ||
| 243 | * \brief Creates a logger for a task | ||
| 244 | * \details This creates a ProgressTask object for task \p | ||
| 245 | * task_name with a number of steps given by \p max_steps. The | ||
| 246 | * registered LoggerClient is notified to start listening to the | ||
| 247 | * progress of the task. | ||
| 248 | * \param[in] task_name the name of the task | ||
| 249 | * \param[in] max_steps the number of steps of the task | ||
| 250 | * \param[in] quiet set to \c true to make the progress silent | ||
| 251 | * \see LoggerClient::begin() | ||
| 252 | */ | ||
| 253 | ProgressTask( | ||
| 254 | const std::string& task_name, index_t max_steps, | ||
| 255 | bool quiet | ||
| 256 | ); | ||
| 257 | |||
| 258 | /** | ||
| 259 | * \brief Creates a logger for a task | ||
| 260 | * \details This creates a ProgressTask object for task \p | ||
| 261 | * task_name with a number of steps given by \p max_steps. The | ||
| 262 | * registered LoggerClient is notified to start listening to the | ||
| 263 | * progress of the task. | ||
| 264 | * \param[in] task_name the name of the task | ||
| 265 | * \param[in] max_steps the number of steps of the task | ||
| 266 | */ | ||
| 267 | ProgressTask( | ||
| 268 | const std::string& task_name = "", index_t max_steps = 100 | ||
| 269 | ); | ||
| 270 | |||
| 271 | /** | ||
| 272 | * \brief Destroys a ProgressTask | ||
| 273 | * \details This notifies the registered LoggerClient%s that the | ||
| 274 | * task is terminated. | ||
| 275 | * \see LoggerClient::end() | ||
| 276 | */ | ||
| 277 | virtual ~ProgressTask(); | ||
| 278 | |||
| 279 | /** | ||
| 280 | * \brief Sets the current execution step | ||
| 281 | * \details This sets the current step value to \p step. The new | ||
| 282 | * value must not be greater than the configured number of steps in | ||
| 283 | * the ProgressTask constructor. This updates the percentage of | ||
| 284 | * completion of the task and notifies the registered | ||
| 285 | * LoggerClient%s that the execution step has changed. | ||
| 286 | * \param[in] step the new step value | ||
| 287 | * \see update() | ||
| 288 | * \throw TaskCanceled whenever the user has canced the task | ||
| 289 | */ | ||
| 290 | virtual void progress(index_t step); | ||
| 291 | |||
| 292 | /** | ||
| 293 | * \brief Goes to the next step | ||
| 294 | * \details This increments the current step value by 1. This updates | ||
| 295 | * the percentage of completion of the task and notifies | ||
| 296 | * the registered LoggerClient%s that the execution step has changed. | ||
| 297 | * \see update() | ||
| 298 | */ | ||
| 299 | virtual void next(); | ||
| 300 | |||
| 301 | /** | ||
| 302 | * \brief Checks if the task is canceled | ||
| 303 | * \details This function must be called as often as possible during | ||
| 304 | * the execution of the current task to stop the current task | ||
| 305 | * in case a request was made to cancel it (e.g., from the user | ||
| 306 | * interface). | ||
| 307 | * \retval true if the task was canceled | ||
| 308 | * \retval false otherwise | ||
| 309 | */ | ||
| 310 | bool is_canceled() const; | ||
| 311 | |||
| 312 | /** | ||
| 313 | * \brief Resets the execution step | ||
| 314 | * \details Resets progress at the beginning. This updates the | ||
| 315 | * percentage of completion of the task and notifies the | ||
| 316 | * registered LoggerClient%s that the execution step has changed. This | ||
| 317 | * is equivalent to call \c progress(0). | ||
| 318 | * \see progress() | ||
| 319 | */ | ||
| 320 | void reset(); | ||
| 321 | |||
| 322 | /** | ||
| 323 | * \brief Resets the execution step | ||
| 324 | * \details This changes the maximum number of steps to \p max_steps and | ||
| 325 | * resets progress at the beginning. This updates the percentage of | ||
| 326 | * completion of the task and notifies the registered | ||
| 327 | * LoggerClient%s that the execution step has changed. | ||
| 328 | * \param[in] max_steps the new number of steps of the task. | ||
| 329 | * \see LoggerClient::progress() | ||
| 330 | */ | ||
| 331 | void reset(index_t max_steps); | ||
| 332 | |||
| 333 | /** | ||
| 334 | * \brief Gets the name of the task | ||
| 335 | */ | ||
| 336 | 1040 | const std::string& task_name() const { | |
| 337 | 1040 | return task_name_; | |
| 338 | } | ||
| 339 | |||
| 340 | /** | ||
| 341 | * \brief Gets the start time of the task | ||
| 342 | */ | ||
| 343 | 43 | double start_time() const { | |
| 344 | 43 | return start_time_; | |
| 345 | } | ||
| 346 | |||
| 347 | /** | ||
| 348 | * \brief Gets the number of steps of the task | ||
| 349 | */ | ||
| 350 | ✗ | index_t max_steps() const { | |
| 351 | ✗ | return max_steps_; | |
| 352 | } | ||
| 353 | |||
| 354 | /** | ||
| 355 | * \brief Gets the current step of the task | ||
| 356 | */ | ||
| 357 | index_t step() const { | ||
| 358 | return step_; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * \brief Gets the percentage of completion of the task | ||
| 363 | */ | ||
| 364 | ✗ | index_t percent() const { | |
| 365 | ✗ | return percent_; | |
| 366 | } | ||
| 367 | |||
| 368 | protected: | ||
| 369 | /** | ||
| 370 | * \brief Updates progress values | ||
| 371 | * \details Updates the percentage of completion of the task and | ||
| 372 | * notifies the registered LoggerClient%s that the execution step has | ||
| 373 | * changed. | ||
| 374 | * \see LoggerClient::progress() | ||
| 375 | */ | ||
| 376 | virtual void update(); | ||
| 377 | |||
| 378 | private: | ||
| 379 | std::string task_name_; | ||
| 380 | double start_time_; | ||
| 381 | bool quiet_; | ||
| 382 | index_t max_steps_; | ||
| 383 | index_t step_; | ||
| 384 | index_t percent_; | ||
| 385 | }; | ||
| 386 | } | ||
| 387 | |||
| 388 | #endif | ||
| 389 |