GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/environment.h
Date: 2026-09-07 02:25:23
Exec Total Coverage
Lines: 1 3 33.3%
Functions: 0 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_ENVIRONMENT
41 #define GEOGRAM_BASIC_ENVIRONMENT
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/smart_pointer.h>
45 #include <geogram/basic/counted.h>
46 #include <string>
47 #include <vector>
48 #include <map>
49
50 /**
51 * \file geogram/basic/environment.h
52 * \brief Provides a mechanism to store global
53 * variables, retrieve them by their names and
54 * attach observers to them.
55 */
56
57 namespace GEO {
58
59 class Environment;
60
61 /************************************************************************/
62
63 /**
64 * \brief Observes Environment variables.
65 * \details VariableObserver offers the possibility to receive
66 * notifications when a variable is changed in an Environment.
67 *
68 * To listen to a variable:
69 * -# Create a class derived class from VariableObserver
70 * and implement function value_changed().
71 * -# Create a MyObserver instance with name "my_variable", it will be
72 * automatically attached to the variable in the root Environment.
73 *
74 * \code
75 * struct MyObserver : VariableObserver {
76 * MyObserver(const std::string& name) : VariableObserver(name) {}
77 * virtual void value_changed(const std::string& new_value) {
78 * };
79 * std::auto_ptr<MyObserver> myobserver =
80 * new MyObserver("my_variable");
81 * \endcode
82 */
83 class GEOGRAM_API VariableObserver {
84 public:
85 /**
86 * \brief Creates a new variable observer.
87 * \details This creates a new observer for variable \p var_name and
88 * automatically adds itself to the variable's observers in the root
89 * environment.
90 * \param[in] var_name name of the variable observed.
91 */
92 VariableObserver(const std::string& var_name);
93
94 /**
95 * \brief Receives a change notification.
96 * \details This function is called by the Environment when
97 * the variable observed by this observer is modified.
98 * \param[in] new_value the new value of the observed variable.
99 */
100 virtual void value_changed(const std::string& new_value) = 0;
101
102 /**
103 * \brief Deletes the observer.
104 * \details This automatically removes this observer from the
105 * root environment.
106 */
107 virtual ~VariableObserver();
108
109 /**
110 * \brief Gets the observed variable.
111 * \return The name of the variable observed by this observer.
112 */
113 const std::string& observed_variable() const {
114 return observed_variable_;
115 }
116
117 private:
118 std::string observed_variable_;
119 Environment* environment_;
120 };
121
122 /************************************************************************/
123
124 /**
125 * \brief List of VariableObserver%s
126 * \details List of variable observers are attached to observed variables
127 * in the Environment%s.
128 */
129 class GEOGRAM_API VariableObserverList {
130 public:
131 /**
132 * \brief Creates an empty list of variable observers.
133 */
134 VariableObserverList() :
135 block_notify_(false) {
136 }
137
138 /**
139 * \brief Notifies all observers in the list.
140 * \param[in] value the value of the variable being changed.
141 */
142 void notify_observers(const std::string& value);
143
144 /**
145 * \brief Adds an observer to the list.
146 * This adds observer \p observer at the end of the list only if it is
147 * not already present.
148 * \param[in] observer a pointer to the VariableObserver to add.
149 */
150 void add_observer(VariableObserver* observer);
151
152 /**
153 * \brief Removes an observer from the list.
154 * \param[in] observer a pointer to the VariableObserver to remove.
155 */
156 void remove_observer(VariableObserver* observer);
157
158 private:
159 /** List of VariableObserver%s */
160 typedef std::vector<VariableObserver*> Observers;
161 Observers observers_;
162 bool block_notify_;
163 };
164
165 /************************************************************************/
166
167 /**
168 * \brief Application environment
169 * \details
170 * Environment is a flexible framework for storing and retrieving
171 * application properties. Most important client functions are:
172 * - get_value() to retrieve a property
173 * - set_value() to store a property
174 *
175 * By default, the framework provides a single root Environment that can
176 * be accessed with function instance(). This root environment uses a
177 * dictionary for storing application properties as name-value pairs.
178 *
179 * But developers can define custom Environment classes to access
180 * properties differently. For this, the custom Environment classes must
181 * reimplement low-level access functions get_local_value() and
182 * set_local_value(). For instance, one can redefine low-level functions
183 * to:
184 *
185 * - access properties in a file database
186 * - access properties as system environment variables (see
187 * SystemEnvironment)
188 * - expose/control a software module configuration:
189 * - get_local_value() exposes the module configuration as properties
190 * - set_local_value() allows to control the module configuration
191 * through properties.
192 *
193 * This technique is widely used in Vorpaline, for instance:
194 * - Process has a dedicated environment to control Process
195 * configuration (multithreading, FPE, ...)
196 * - Logger also has a dedicated environment to configure the Logger
197 * behavior, allowed features, ...
198 *
199 * Plugging custom Environment%s in the framework is as simple as adding
200 * the custom Environment as a child of the root Environment with function
201 * add_environment(). Setting a property in an environment affects
202 * this environment locally \b only if no child environment can store the
203 * property. Similarily, retrieving a property from an environment first
204 * checks if the property exists locally, then in all child environments.
205 *
206 * In addition, the Environment framework provides a mechanism for being
207 * notified when a property is modified: VariableObserver%s can be
208 * attached to specific properties to capture modifications of their value
209 * (for more details see VariableObserver).
210 */
211 class GEOGRAM_API Environment : public Counted {
212 public:
213 /**
214 * \brief Gets the root environment
215 * \details If the root environment does not yet exists, it is created
216 * on the fly.
217 * \return A pointer to the root environment
218 */
219 static Environment* instance();
220
221 /**
222 * \brief Cleans up the environment
223 * \details This destroys the whole root Environment hierarchy.
224 */
225 static void terminate();
226
227 /**
228 * \brief Adds a child environment
229 * \details Environment \p env is added as a child of this
230 * environment which takes ownership of \p env. The child environment
231 * will be deleted when this environment is deleted.
232 * \param[in] env the child environment
233 * \retval true if the child has been successfully added
234 * \retval false otherwise
235 */
236 virtual bool add_environment(Environment* env);
237
238 /**
239 * \brief Tests if a variable exists
240 * \param[in] name the name of the variable
241 * \retval true if the variable exists
242 * \retval false otherwise
243 */
244 bool has_value(const std::string& name) const;
245
246 /**
247 * \brief Retrieves the value of a variable
248 * \details Searches variable \p name and stores its value in the
249 * output string \p value. The function first checks if the variable
250 * exists locally, then in all child environments recursively.
251 * \param[in] name the name of the variable
252 * \param[out] value is set the variable value if it was found
253 * either locally or in a child environment.
254 * \retval true if the variable was found
255 * \retval false otherwise
256 */
257 virtual bool get_value(
258 const std::string& name, std::string& value
259 ) const;
260
261 /**
262 * \brief Retrieves the value of a variable
263 * \details This is a variant of get_value(name, value) that returns
264 * the variable value directly it it exists. If the variable is not
265 * found, then the function calls abort().
266 * \param[in] name the name of the variable
267 * \return the variable value if it exists.
268 */
269 std::string get_value(const std::string& name) const;
270
271 /**
272 * \brief Sets a variable value
273 * \details Sets the variable named \p name to the given \p value. The
274 * function first visits all child environments recursively until one
275 * of them accepts the variable. If no child environment can store the
276 * variable, the variable is set locally in this environment. If a
277 * variable is set in an environment, all the variable observers are
278 * notified, starting from the modified environment up to the root
279 * environment.
280 * \param[in] name the name of the variable
281 * \param[in] value the value of the variable
282 * \retval true if the variable was successfully added, either locally
283 * or in a child environment.
284 * \retval false otherwise
285 */
286 virtual bool set_value(
287 const std::string& name, const std::string& value
288 );
289
290 /**
291 * \brief Finds the environment that declares a variable as
292 * a local name.
293 * \param[in] name the name of the variable
294 * \return a pointer to the Environment that has \p name as a
295 * local variable, or nullptr if no such environment exists
296 */
297 virtual Environment* find_environment(const std::string& name);
298
299 /**
300 * \brief Attaches an observer to a variable
301 * \details Adds observer \p observer to the list of observers
302 * attached to variable \p name. If the observer is already attached
303 * to the variable, the function calls abort(). The environment does
304 * \b not take ownership of the observer, it is the responsibility of
305 * the caller to delete all the variable observers added to an
306 * Environment.
307 * \param[in] name the name of the variable
308 * \param[in] observer a variable observer to add
309 * \retval true if \p observer has been successfully added
310 * \retval false otherwise
311 */
312 virtual bool add_observer(
313 const std::string& name, VariableObserver* observer
314 );
315
316 /**
317 * \brief Detaches an observer from a variable
318 * \details Removes observer \p observer from the list of observers
319 * attached to variable \p name. If the observer is not attached to
320 * the variable, the function calls abort(). The environment does \b
321 * not delete the removed observer, it is the responsibility of the
322 * caller to delete all the variable observers added to an
323 * Environment.
324 * \param[in] name the name of the variable
325 * \param[in] observer a variable observer to remove
326 * \retval true if \p observer has been successfully removed
327 * \retval false otherwise
328 */
329 virtual bool remove_observer(
330 const std::string& name, VariableObserver* observer
331 );
332
333 /**
334 * \brief Notifies observers
335 * \details This notifies the observers attached to variable \p
336 * name in this environment, passing them the current value of the
337 * variable. If \p recursive is set to \c true, then the function
338 * recursively notifies observers in the child contexts.
339 * \param[in] name the name of the variable
340 * \param[in] recursive if \c true, notifies observers in the child
341 * contexts. This is \c false by default.
342 * \return \c true
343 */
344 virtual bool notify_observers(
345 const std::string& name, bool recursive = false
346 );
347
348 protected:
349 /**
350 * \brief Environment destructor
351 * \details This deletes all the child environments, but it does \b
352 * not delete the variable observers.
353 */
354 ~Environment() override;
355
356 /**
357 * \brief Retrieves a variable value locally
358 * \details This function is used internally. It searches variable \p
359 * name \b locally and stores its value in the output string \p value.
360 * \param[in] name the name of the variable
361 * \param[out] value is set the variable value if it was found \b
362 * locally.
363 * \retval true if the variable was found
364 * \retval false if not
365 * \note This function must be reimplemented in derived custom
366 * environments.
367 */
368 virtual bool get_local_value(
369 const std::string& name, std::string& value
370 ) const = 0;
371
372 /**
373 * \brief Sets a variable value locally
374 * \details This function is used internally. It sets the variable
375 * named \p name to the given \p value \b locally.
376 * \param[in] name the name of the variable
377 * \param[in] value the value of the variable
378 * \retval true if the variable was successfully added \b locally
379 * \retval false otherwise
380 * \note This function must be reimplemented in derived custom
381 * environments.
382 */
383 virtual bool set_local_value(
384 const std::string& name, const std::string& value
385 ) = 0;
386
387 /**
388 * \brief Notifies observers
389 * \details This function is used internally. It notifies the
390 * observers attached to variable \p name in this environment, passing
391 * them the modified value \p value. If \p recursive is \c true, then
392 * the function recursively notifies observers in the child contexts.
393 * \param[in] name the name of the variable
394 * \param[in] value the modified value
395 * \param[in] recursive if \c true, notifies observers in the child
396 * contexts.
397 * \return \c true
398 */
399 bool notify_observers(
400 const std::string& name, const std::string& value,
401 bool recursive
402 );
403
404 /**
405 * \brief Notifies local observers
406 * \details This function is used internally. It notifies the
407 * observers attached to variable \p name in this environment, passing
408 * them the modified value \p value. Observers in child environments
409 * are \b not notified.
410 * \param[in] name the name of the variable
411 * \param[in] value the modified value
412 * \return \c true
413 */
414 bool notify_local_observers(
415 const std::string& name, const std::string& value
416 );
417
418 private:
419 /** Smart pointer that contains a Environment object */
420 typedef SmartPointer<Environment> Environment_var;
421
422 /** List of child environments */
423 typedef std::vector<Environment_var> Environments;
424
425 /** Stores VariableObserverList indexed by name */
426 typedef std::map<std::string, VariableObserverList> ObserverMap;
427
428 static Environment_var instance_;
429 Environments environments_;
430 ObserverMap observers_;
431 };
432
433 /************************************************************************/
434
435 /**
436 * \brief System environment
437 * \details
438 * This class is a specialization of Environment that retrieves the
439 * variable values from the system environment, but does not allow to set
440 * them.
441 */
442 249 class SystemEnvironment : public Environment {
443 protected:
444 /** SystemEnvironment destructor */
445 ~SystemEnvironment() override;
446
447 /**
448 * \copydoc Environment::set_local_value()
449 * This function does actually \b not update the system environment
450 * and always returns \c false.
451 */
452 bool set_local_value(
453 const std::string& name, const std::string& value
454 ) override;
455
456 /**
457 * \copydoc Environment::get_local_value()
458 * The value is retrieved from the system environment using the system
459 * function getenv().
460 */
461 bool get_local_value(
462 const std::string& name, std::string& value
463 ) const override;
464 };
465 }
466
467 #endif
468