FlightGear next
ViewPropertyEvaluator.hxx
Go to the documentation of this file.
1// This program is free software; you can redistribute it and/or
2// modify it under the terms of the GNU General Public License as
3// published by the Free Software Foundation; either version 2 of the
4// License, or (at your option) any later version.
5//
6// This program is distributed in the hope that it will be useful, but
7// WITHOUT ANY WARRANTY; without even the implied warranty of
8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9// General Public License for more details.
10//
11// You should have received a copy of the GNU General Public License
12// along with this program; if not, write to the Free Software
13// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14
15#pragma once
16
17#include "simgear/props/props.hxx"
18
19#include <map>
20#include <ostream>
21#include <string>
22#include <vector>
23
24
25namespace ViewPropertyEvaluator {
26
27 /*
28 Overview:
29
30 We provide efficient evaluation of 'nested properties', where the path
31 of the property to be evaluated is determined by the value of other,
32 possibly dynamically-changing, properties.
33
34 Details:
35
36 Code is expected to specify a nested property as a C string 'spec'
37 using (...) to denote evaluation of a substring as a property path
38 where required. We use the raw address of C string specs as keys in an
39 internal std::map, to provide fast lookup of previously-created specs
40 using just a small number of raw pointer comparisons. This requires
41 that the C string specs remain valid and unchanged; typically they will
42 be immediate strings specifed directly in source code.
43
44 We set up listeners to detect changes to relevant property nodes so
45 that we can force re-evaluation of dependent nested properties when
46 required. Thus most lookups end up not touching the property system at
47 all, and instead access cached values directly.
48
49 For example this:
50
51 SGPropertyNode* node = ViewPropertyEvaluator::getDoubleValue(
52 "((/sim/view[0]/config/root)/position/altitude-ft)"
53 );
54
55 - will behave like this:
56
57 globals->get_props()->getDoubleValue(
58 globals->get_props()->getStringValue(
59 "/sim/view[0]/config/root",
60 true |*create*|
61 )
62 + "/position/altitude-ft",
63 true |*create *|
64 );
65
66 In this example, an internal listener will be set up to detect changes
67 to property '/sim/view[0]/config/root'; if this listener has not fired,
68 we will use a cached SGPropertyNode_ptr* directly without querying the
69 property tree.
70
71 Note that with ViewPropertyEvaluator::getDoubleValue, while the final
72 SGPropertyNode* is cached, its value is not cached. Instead we always
73 call SGPropertyNode::getDoubleValue(). This is in anticipation of
74 typical usage where the final double values will change frequently, so
75 caching its value becomes less useful.
76
77 Missing property nodes:
78
79 If a spec (or part of a spec) evaluates to a property node path that
80 does not exist, a new property node is created with value "".
81
82 [This allows us to set up a listener for the property node so we can
83 detect changes to its value; it might be nice to instead add something
84 to Simgear that allows one to listen to creation of a particular path.]
85 */
86
87
88 /* Evaluates a spec as a string. The returned reference will be valid for
89 ever (until ViewPropertyEvaluator::clear() is called); its value will be
90 unchanged until the next time the spec (or a spec that depends on it) is
91 evaluated.
92
93 For example, getStringValue("/sim/chase-distance-m") will return
94 "/sim/chase-distance-m", while getStringValue("(/sim/chase-distance-m)")
95 will return "-25" or similar, depending on the aircraft.
96 */
97 const std::string& getStringValue(const char* spec);
98
99 /* Evaluates a spec as a double. Only makes sense if <spec> has top-level
100 "(...)".
101
102 For example, getDoubleValue("(/sim/chase-distance-m)") will return -25.0 or
103 similar, depending on the aircraft.
104
105 When this function is used, it doesn't install a listener for the top-level
106 node, instead it always calls <top-level-node>->getDoubleValue().
107 */
108 double getDoubleValue(const char* spec, double default_=0);
109
110 /* Similar to getDoubleValue(). */
111 bool getBoolValue(const char* spec, bool default_=false);
112
113
114 /* Outputs detailed information about all specs that have been seen.
115
116 E.g.:
117 SG_LOG(SG_VIEW, SG_DEBUG, "ViewPropertyEvaluator:\n" << ViewPropertyEvaluator::Dump());
118 */
119 struct Dump {};
120 std::ostream& operator << (std::ostream& out, const Dump& dump);
121
122 struct DumpOne {
123 explicit DumpOne(const char* spec);
124 const char* _spec;
125 };
126 std::ostream& operator << (std::ostream& out, const DumpOne& dumpone);
127
128
129 /* Clears all internal state. */
130 void clear();
131
132}
const std::string & getStringValue(const char *spec)
double getDoubleValue(const char *spec, double default_)
std::ostream & operator<<(std::ostream &out, const Dump &dump)
bool getBoolValue(const char *spec, bool default_)