GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/progress.h
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 4 8 50.0%
Functions: 2 4 50.0%
Branches: 0 0 -%

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