tree.cpp revision 1.1.1.1.12.2 1 1.1.1.1.12.2 yamt // Copyright 2012 Google Inc.
2 1.1.1.1.12.2 yamt // All rights reserved.
3 1.1.1.1.12.2 yamt //
4 1.1.1.1.12.2 yamt // Redistribution and use in source and binary forms, with or without
5 1.1.1.1.12.2 yamt // modification, are permitted provided that the following conditions are
6 1.1.1.1.12.2 yamt // met:
7 1.1.1.1.12.2 yamt //
8 1.1.1.1.12.2 yamt // * Redistributions of source code must retain the above copyright
9 1.1.1.1.12.2 yamt // notice, this list of conditions and the following disclaimer.
10 1.1.1.1.12.2 yamt // * Redistributions in binary form must reproduce the above copyright
11 1.1.1.1.12.2 yamt // notice, this list of conditions and the following disclaimer in the
12 1.1.1.1.12.2 yamt // documentation and/or other materials provided with the distribution.
13 1.1.1.1.12.2 yamt // * Neither the name of Google Inc. nor the names of its contributors
14 1.1.1.1.12.2 yamt // may be used to endorse or promote products derived from this software
15 1.1.1.1.12.2 yamt // without specific prior written permission.
16 1.1.1.1.12.2 yamt //
17 1.1.1.1.12.2 yamt // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 1.1.1.1.12.2 yamt // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 1.1.1.1.12.2 yamt // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 1.1.1.1.12.2 yamt // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 1.1.1.1.12.2 yamt // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 1.1.1.1.12.2 yamt // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 1.1.1.1.12.2 yamt // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 1.1.1.1.12.2 yamt // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 1.1.1.1.12.2 yamt // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 1.1.1.1.12.2 yamt // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 1.1.1.1.12.2 yamt // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1.1.1.1.12.2 yamt
29 1.1.1.1.12.2 yamt #include "utils/config/tree.ipp"
30 1.1.1.1.12.2 yamt
31 1.1.1.1.12.2 yamt #include "utils/config/exceptions.hpp"
32 1.1.1.1.12.2 yamt #include "utils/config/keys.hpp"
33 1.1.1.1.12.2 yamt #include "utils/config/nodes.ipp"
34 1.1.1.1.12.2 yamt #include "utils/format/macros.hpp"
35 1.1.1.1.12.2 yamt
36 1.1.1.1.12.2 yamt namespace config = utils::config;
37 1.1.1.1.12.2 yamt
38 1.1.1.1.12.2 yamt
39 1.1.1.1.12.2 yamt /// Constructor.
40 1.1.1.1.12.2 yamt config::tree::tree(void) :
41 1.1.1.1.12.2 yamt _root(new detail::static_inner_node())
42 1.1.1.1.12.2 yamt {
43 1.1.1.1.12.2 yamt }
44 1.1.1.1.12.2 yamt
45 1.1.1.1.12.2 yamt
46 1.1.1.1.12.2 yamt /// Constructor with a non-empty root.
47 1.1.1.1.12.2 yamt ///
48 1.1.1.1.12.2 yamt /// \param root The root to the tree to be owned by this instance.
49 1.1.1.1.12.2 yamt config::tree::tree(detail::static_inner_node* root) :
50 1.1.1.1.12.2 yamt _root(root)
51 1.1.1.1.12.2 yamt {
52 1.1.1.1.12.2 yamt }
53 1.1.1.1.12.2 yamt
54 1.1.1.1.12.2 yamt
55 1.1.1.1.12.2 yamt /// Destructor.
56 1.1.1.1.12.2 yamt config::tree::~tree(void)
57 1.1.1.1.12.2 yamt {
58 1.1.1.1.12.2 yamt }
59 1.1.1.1.12.2 yamt
60 1.1.1.1.12.2 yamt
61 1.1.1.1.12.2 yamt /// Generates a deep copy of the input tree.
62 1.1.1.1.12.2 yamt ///
63 1.1.1.1.12.2 yamt /// \return A new tree that is an exact copy of this tree.
64 1.1.1.1.12.2 yamt config::tree
65 1.1.1.1.12.2 yamt config::tree::deep_copy(void) const
66 1.1.1.1.12.2 yamt {
67 1.1.1.1.12.2 yamt detail::static_inner_node* new_root =
68 1.1.1.1.12.2 yamt dynamic_cast< detail::static_inner_node* >(_root->deep_copy());
69 1.1.1.1.12.2 yamt return config::tree(new_root);
70 1.1.1.1.12.2 yamt }
71 1.1.1.1.12.2 yamt
72 1.1.1.1.12.2 yamt
73 1.1.1.1.12.2 yamt /// Registers a node as being dynamic.
74 1.1.1.1.12.2 yamt ///
75 1.1.1.1.12.2 yamt /// This operation creates the given key as an inner node. Further set
76 1.1.1.1.12.2 yamt /// operations that trespass this node will automatically create any missing
77 1.1.1.1.12.2 yamt /// keys.
78 1.1.1.1.12.2 yamt ///
79 1.1.1.1.12.2 yamt /// This method does not raise errors on invalid/unknown keys or other
80 1.1.1.1.12.2 yamt /// tree-related issues. The reasons is that define() is a method that does not
81 1.1.1.1.12.2 yamt /// depend on user input: it is intended to pre-populate the tree with a
82 1.1.1.1.12.2 yamt /// specific structure, and that happens once at coding time.
83 1.1.1.1.12.2 yamt ///
84 1.1.1.1.12.2 yamt /// \param dotted_key The key to be registered in dotted representation.
85 1.1.1.1.12.2 yamt void
86 1.1.1.1.12.2 yamt config::tree::define_dynamic(const std::string& dotted_key)
87 1.1.1.1.12.2 yamt {
88 1.1.1.1.12.2 yamt try {
89 1.1.1.1.12.2 yamt const detail::tree_key key = detail::parse_key(dotted_key);
90 1.1.1.1.12.2 yamt _root->define(key, 0, detail::new_node< detail::dynamic_inner_node >);
91 1.1.1.1.12.2 yamt } catch (const error& e) {
92 1.1.1.1.12.2 yamt UNREACHABLE_MSG("define() failing due to key errors is a programming "
93 1.1.1.1.12.2 yamt "mistake: " + std::string(e.what()));
94 1.1.1.1.12.2 yamt }
95 1.1.1.1.12.2 yamt }
96 1.1.1.1.12.2 yamt
97 1.1.1.1.12.2 yamt
98 1.1.1.1.12.2 yamt /// Checks if a given node is set.
99 1.1.1.1.12.2 yamt ///
100 1.1.1.1.12.2 yamt /// \param dotted_key The key to be checked.
101 1.1.1.1.12.2 yamt ///
102 1.1.1.1.12.2 yamt /// \return True if the key is set to a specific value (not just defined).
103 1.1.1.1.12.2 yamt /// False if the key is not set or if the key does not exist.
104 1.1.1.1.12.2 yamt ///
105 1.1.1.1.12.2 yamt /// \throw invalid_key_error If the provided key has an invalid format.
106 1.1.1.1.12.2 yamt bool
107 1.1.1.1.12.2 yamt config::tree::is_set(const std::string& dotted_key) const
108 1.1.1.1.12.2 yamt {
109 1.1.1.1.12.2 yamt const detail::tree_key key = detail::parse_key(dotted_key);
110 1.1.1.1.12.2 yamt try {
111 1.1.1.1.12.2 yamt const detail::base_node* raw_node = _root->lookup_ro(key, 0);
112 1.1.1.1.12.2 yamt try {
113 1.1.1.1.12.2 yamt const leaf_node& child = dynamic_cast< const leaf_node& >(
114 1.1.1.1.12.2 yamt *raw_node);
115 1.1.1.1.12.2 yamt return child.is_set();
116 1.1.1.1.12.2 yamt } catch (const std::bad_cast& unused_error) {
117 1.1.1.1.12.2 yamt return false;
118 1.1.1.1.12.2 yamt }
119 1.1.1.1.12.2 yamt } catch (const unknown_key_error& unused_error) {
120 1.1.1.1.12.2 yamt return false;
121 1.1.1.1.12.2 yamt }
122 1.1.1.1.12.2 yamt }
123 1.1.1.1.12.2 yamt
124 1.1.1.1.12.2 yamt
125 1.1.1.1.12.2 yamt /// Pushes a leaf node's value onto the Lua stack.
126 1.1.1.1.12.2 yamt ///
127 1.1.1.1.12.2 yamt /// \param dotted_key The key to be pushed.
128 1.1.1.1.12.2 yamt /// \param state The Lua state into which to push the key's value.
129 1.1.1.1.12.2 yamt ///
130 1.1.1.1.12.2 yamt /// \throw invalid_key_error If the provided key has an invalid format.
131 1.1.1.1.12.2 yamt /// \throw unknown_key_error If the provided key is unknown.
132 1.1.1.1.12.2 yamt void
133 1.1.1.1.12.2 yamt config::tree::push_lua(const std::string& dotted_key, lutok::state& state) const
134 1.1.1.1.12.2 yamt {
135 1.1.1.1.12.2 yamt const detail::tree_key key = detail::parse_key(dotted_key);
136 1.1.1.1.12.2 yamt const detail::base_node* raw_node = _root->lookup_ro(key, 0);
137 1.1.1.1.12.2 yamt try {
138 1.1.1.1.12.2 yamt const leaf_node& child = dynamic_cast< const leaf_node& >(*raw_node);
139 1.1.1.1.12.2 yamt child.push_lua(state);
140 1.1.1.1.12.2 yamt } catch (const std::bad_cast& unused_error) {
141 1.1.1.1.12.2 yamt throw unknown_key_error(key);
142 1.1.1.1.12.2 yamt }
143 1.1.1.1.12.2 yamt }
144 1.1.1.1.12.2 yamt
145 1.1.1.1.12.2 yamt
146 1.1.1.1.12.2 yamt /// Sets a leaf node's value from a value in the Lua stack.
147 1.1.1.1.12.2 yamt ///
148 1.1.1.1.12.2 yamt /// \param dotted_key The key to be set.
149 1.1.1.1.12.2 yamt /// \param state The Lua state from which to retrieve the value.
150 1.1.1.1.12.2 yamt /// \param value_index The position in the Lua stack holding the value.
151 1.1.1.1.12.2 yamt ///
152 1.1.1.1.12.2 yamt /// \throw invalid_key_error If the provided key has an invalid format.
153 1.1.1.1.12.2 yamt /// \throw unknown_key_error If the provided key is unknown.
154 1.1.1.1.12.2 yamt /// \throw value_error If the value mismatches the node type.
155 1.1.1.1.12.2 yamt void
156 1.1.1.1.12.2 yamt config::tree::set_lua(const std::string& dotted_key, lutok::state& state,
157 1.1.1.1.12.2 yamt const int value_index)
158 1.1.1.1.12.2 yamt {
159 1.1.1.1.12.2 yamt const detail::tree_key key = detail::parse_key(dotted_key);
160 1.1.1.1.12.2 yamt detail::base_node* raw_node = _root->lookup_rw(
161 1.1.1.1.12.2 yamt key, 0, detail::new_node< string_node >);
162 1.1.1.1.12.2 yamt try {
163 1.1.1.1.12.2 yamt leaf_node& child = dynamic_cast< leaf_node& >(*raw_node);
164 1.1.1.1.12.2 yamt child.set_lua(state, value_index);
165 1.1.1.1.12.2 yamt } catch (const std::bad_cast& unused_error) {
166 1.1.1.1.12.2 yamt throw value_error(F("Invalid value for key '%s'") %
167 1.1.1.1.12.2 yamt detail::flatten_key(key));
168 1.1.1.1.12.2 yamt }
169 1.1.1.1.12.2 yamt }
170 1.1.1.1.12.2 yamt
171 1.1.1.1.12.2 yamt
172 1.1.1.1.12.2 yamt /// Gets the value of a node as a plain string.
173 1.1.1.1.12.2 yamt ///
174 1.1.1.1.12.2 yamt /// \param dotted_key The key to be looked up.
175 1.1.1.1.12.2 yamt ///
176 1.1.1.1.12.2 yamt /// \return The value of the located node as a string.
177 1.1.1.1.12.2 yamt ///
178 1.1.1.1.12.2 yamt /// \throw invalid_key_error If the provided key has an invalid format.
179 1.1.1.1.12.2 yamt /// \throw unknown_key_error If the provided key is unknown.
180 1.1.1.1.12.2 yamt std::string
181 1.1.1.1.12.2 yamt config::tree::lookup_string(const std::string& dotted_key) const
182 1.1.1.1.12.2 yamt {
183 1.1.1.1.12.2 yamt const detail::tree_key key = detail::parse_key(dotted_key);
184 1.1.1.1.12.2 yamt const detail::base_node* raw_node = _root->lookup_ro(key, 0);
185 1.1.1.1.12.2 yamt try {
186 1.1.1.1.12.2 yamt const leaf_node& child = dynamic_cast< const leaf_node& >(*raw_node);
187 1.1.1.1.12.2 yamt return child.to_string();
188 1.1.1.1.12.2 yamt } catch (const std::bad_cast& unused_error) {
189 1.1.1.1.12.2 yamt throw unknown_key_error(key);
190 1.1.1.1.12.2 yamt }
191 1.1.1.1.12.2 yamt }
192 1.1.1.1.12.2 yamt
193 1.1.1.1.12.2 yamt
194 1.1.1.1.12.2 yamt /// Sets the value of a leaf addressed by its key from a string value.
195 1.1.1.1.12.2 yamt ///
196 1.1.1.1.12.2 yamt /// This respects the native types of all the nodes that have been predefined.
197 1.1.1.1.12.2 yamt /// For new nodes under a dynamic subtree, this has no mechanism of determining
198 1.1.1.1.12.2 yamt /// what type they need to have, so they are created as plain string nodes.
199 1.1.1.1.12.2 yamt ///
200 1.1.1.1.12.2 yamt /// \param dotted_key The key to be registered in dotted representation.
201 1.1.1.1.12.2 yamt /// \param raw_value The string representation of the value to set the node to.
202 1.1.1.1.12.2 yamt ///
203 1.1.1.1.12.2 yamt /// \throw invalid_key_error If the provided key has an invalid format.
204 1.1.1.1.12.2 yamt /// \throw unknown_key_error If the provided key is unknown.
205 1.1.1.1.12.2 yamt /// \throw value_error If the value mismatches the node type.
206 1.1.1.1.12.2 yamt void
207 1.1.1.1.12.2 yamt config::tree::set_string(const std::string& dotted_key,
208 1.1.1.1.12.2 yamt const std::string& raw_value)
209 1.1.1.1.12.2 yamt {
210 1.1.1.1.12.2 yamt const detail::tree_key key = detail::parse_key(dotted_key);
211 1.1.1.1.12.2 yamt detail::base_node* raw_node = _root->lookup_rw(
212 1.1.1.1.12.2 yamt key, 0, detail::new_node< string_node >);
213 1.1.1.1.12.2 yamt try {
214 1.1.1.1.12.2 yamt leaf_node& child = dynamic_cast< leaf_node& >(*raw_node);
215 1.1.1.1.12.2 yamt child.set_string(raw_value);
216 1.1.1.1.12.2 yamt } catch (const std::bad_cast& unused_error) {
217 1.1.1.1.12.2 yamt throw value_error(F("Invalid value for key '%s'") %
218 1.1.1.1.12.2 yamt detail::flatten_key(key));
219 1.1.1.1.12.2 yamt }
220 1.1.1.1.12.2 yamt }
221 1.1.1.1.12.2 yamt
222 1.1.1.1.12.2 yamt
223 1.1.1.1.12.2 yamt /// Converts the tree to a collection of key/value string pairs.
224 1.1.1.1.12.2 yamt ///
225 1.1.1.1.12.2 yamt /// \param dotted_key Subtree from which to start the export.
226 1.1.1.1.12.2 yamt /// \param strip_key If true, remove the dotted_key prefix from the resulting
227 1.1.1.1.12.2 yamt /// properties.
228 1.1.1.1.12.2 yamt ///
229 1.1.1.1.12.2 yamt /// \return A map of keys to values in their textual representation.
230 1.1.1.1.12.2 yamt ///
231 1.1.1.1.12.2 yamt /// \throw invalid_key_error If the provided key has an invalid format.
232 1.1.1.1.12.2 yamt /// \throw unknown_key_error If the provided key is unknown.
233 1.1.1.1.12.2 yamt /// \throw value_error If the provided key points to a leaf.
234 1.1.1.1.12.2 yamt config::properties_map
235 1.1.1.1.12.2 yamt config::tree::all_properties(const std::string& dotted_key,
236 1.1.1.1.12.2 yamt const bool strip_key) const
237 1.1.1.1.12.2 yamt {
238 1.1.1.1.12.2 yamt PRE(!strip_key || !dotted_key.empty());
239 1.1.1.1.12.2 yamt
240 1.1.1.1.12.2 yamt properties_map properties;
241 1.1.1.1.12.2 yamt
242 1.1.1.1.12.2 yamt detail::tree_key key;
243 1.1.1.1.12.2 yamt const detail::base_node* raw_node;
244 1.1.1.1.12.2 yamt if (dotted_key.empty()) {
245 1.1.1.1.12.2 yamt raw_node = _root.get();
246 1.1.1.1.12.2 yamt } else {
247 1.1.1.1.12.2 yamt key = detail::parse_key(dotted_key);
248 1.1.1.1.12.2 yamt raw_node = _root->lookup_ro(key, 0);
249 1.1.1.1.12.2 yamt }
250 1.1.1.1.12.2 yamt try {
251 1.1.1.1.12.2 yamt const detail::inner_node& child =
252 1.1.1.1.12.2 yamt dynamic_cast< const detail::inner_node& >(*raw_node);
253 1.1.1.1.12.2 yamt child.all_properties(properties, key);
254 1.1.1.1.12.2 yamt } catch (const std::bad_cast& unused_error) {
255 1.1.1.1.12.2 yamt INV(!dotted_key.empty());
256 1.1.1.1.12.2 yamt throw value_error(F("Cannot export properties from a leaf node; "
257 1.1.1.1.12.2 yamt "'%s' given") % dotted_key);
258 1.1.1.1.12.2 yamt }
259 1.1.1.1.12.2 yamt
260 1.1.1.1.12.2 yamt if (strip_key) {
261 1.1.1.1.12.2 yamt properties_map stripped;
262 1.1.1.1.12.2 yamt for (properties_map::const_iterator iter = properties.begin();
263 1.1.1.1.12.2 yamt iter != properties.end(); ++iter) {
264 1.1.1.1.12.2 yamt stripped[(*iter).first.substr(dotted_key.length() + 1)] =
265 1.1.1.1.12.2 yamt (*iter).second;
266 1.1.1.1.12.2 yamt }
267 1.1.1.1.12.2 yamt properties = stripped;
268 1.1.1.1.12.2 yamt }
269 1.1.1.1.12.2 yamt
270 1.1.1.1.12.2 yamt return properties;
271 1.1.1.1.12.2 yamt }
272 1.1.1.1.12.2 yamt
273 1.1.1.1.12.2 yamt
274 1.1.1.1.12.2 yamt /// Equality comparator.
275 1.1.1.1.12.2 yamt ///
276 1.1.1.1.12.2 yamt /// \param other The other object to compare this one to.
277 1.1.1.1.12.2 yamt ///
278 1.1.1.1.12.2 yamt /// \return True if this object and other are equal; false otherwise.
279 1.1.1.1.12.2 yamt bool
280 1.1.1.1.12.2 yamt config::tree::operator==(const tree& other) const
281 1.1.1.1.12.2 yamt {
282 1.1.1.1.12.2 yamt // TODO(jmmv): Would be nicer to perform the comparison directly on the
283 1.1.1.1.12.2 yamt // nodes, instead of exporting the values to strings first.
284 1.1.1.1.12.2 yamt return _root == other._root || all_properties() == other.all_properties();
285 1.1.1.1.12.2 yamt }
286 1.1.1.1.12.2 yamt
287 1.1.1.1.12.2 yamt
288 1.1.1.1.12.2 yamt /// Inequality comparator.
289 1.1.1.1.12.2 yamt ///
290 1.1.1.1.12.2 yamt /// \param other The other object to compare this one to.
291 1.1.1.1.12.2 yamt ///
292 1.1.1.1.12.2 yamt /// \return True if this object and other are different; false otherwise.
293 1.1.1.1.12.2 yamt bool
294 1.1.1.1.12.2 yamt config::tree::operator!=(const tree& other) const
295 1.1.1.1.12.2 yamt {
296 1.1.1.1.12.2 yamt return !(*this == other);
297 1.1.1.1.12.2 yamt }
298