xref: /freebsd/contrib/kyua/utils/config/nodes.ipp (revision 87b759f0fa1f7554d50ce640c40138512bbded44)
1// Copyright 2012 The Kyua Authors.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9//   notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright
11//   notice, this list of conditions and the following disclaimer in the
12//   documentation and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors
14//   may be used to endorse or promote products derived from this software
15//   without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "utils/config/nodes.hpp"
30
31#if !defined(UTILS_CONFIG_NODES_IPP)
32#define UTILS_CONFIG_NODES_IPP
33
34#include <memory>
35#include <typeinfo>
36
37#include "utils/config/exceptions.hpp"
38#include "utils/defs.hpp"
39#include "utils/format/macros.hpp"
40#include "utils/optional.ipp"
41#include "utils/text/exceptions.hpp"
42#include "utils/text/operations.ipp"
43#include "utils/sanity.hpp"
44
45namespace utils {
46
47
48namespace config {
49namespace detail {
50
51
52/// Type of the new_node() family of functions.
53typedef base_node* (*new_node_hook)(void);
54
55
56/// Creates a new leaf node of a given type.
57///
58/// \tparam NodeType The type of the leaf node to create.
59///
60/// \return A pointer to the newly-created node.
61template< class NodeType >
62base_node*
63new_node(void)
64{
65    return new NodeType();
66}
67
68
69/// Internal node of the tree.
70///
71/// This abstract base class provides the mechanism to implement both static and
72/// dynamic nodes.  Ideally, the implementation would be split in subclasses and
73/// this class would not include the knowledge of whether the node is dynamic or
74/// not.  However, because the static/dynamic difference depends on the leaf
75/// types, we need to declare template functions and these cannot be virtual.
76class inner_node : public base_node {
77    /// Whether the node is dynamic or not.
78    bool _dynamic;
79
80protected:
81    /// Type to represent the collection of children of this node.
82    ///
83    /// Note that these are one-level keys.  They cannot contain dots, and thus
84    /// is why we use a string rather than a tree_key.
85    typedef std::map< std::string, base_node* > children_map;
86
87    /// Mapping of keys to values that are descendants of this node.
88    children_map _children;
89
90    void copy_into(inner_node*) const;
91    void combine_into(const tree_key&, const base_node*, inner_node*) const;
92
93private:
94    void combine_children_into(const tree_key&,
95                               const children_map&, const children_map&,
96                               inner_node*) const;
97
98public:
99    inner_node(const bool);
100    virtual ~inner_node(void) = 0;
101
102    const base_node* lookup_ro(const tree_key&,
103                               const tree_key::size_type) const;
104    leaf_node* lookup_rw(const tree_key&, const tree_key::size_type,
105                         new_node_hook);
106
107    void all_properties(properties_map&, const tree_key&) const;
108};
109
110
111/// Static internal node of the tree.
112///
113/// The direct children of this node must be pre-defined by calls to define().
114/// Attempts to traverse this node and resolve a key that is not a pre-defined
115/// children will result in an "unknown key" error.
116class static_inner_node : public config::detail::inner_node {
117public:
118    static_inner_node(void);
119
120    virtual base_node* deep_copy(void) const;
121    virtual base_node* combine(const tree_key&, const base_node*) const;
122
123    void define(const tree_key&, const tree_key::size_type, new_node_hook);
124};
125
126
127/// Dynamic internal node of the tree.
128///
129/// The children of this node need not be pre-defined.  Attempts to traverse
130/// this node and resolve a key will result in such key being created.  Any
131/// intermediate non-existent nodes of the traversal will be created as dynamic
132/// inner nodes as well.
133class dynamic_inner_node : public config::detail::inner_node {
134public:
135    virtual base_node* deep_copy(void) const;
136    virtual base_node* combine(const tree_key&, const base_node*) const;
137
138    dynamic_inner_node(void);
139};
140
141
142}  // namespace detail
143}  // namespace config
144
145
146/// Constructor for a node with an undefined value.
147///
148/// This should only be called by the tree's define() method as a way to
149/// register a node as known but undefined.  The node will then serve as a
150/// placeholder for future values.
151template< typename ValueType >
152config::typed_leaf_node< ValueType >::typed_leaf_node(void) :
153    _value(none)
154{
155}
156
157
158/// Checks whether the node has been set by the user.
159///
160/// Nodes of the tree are predefined by the caller to specify the valid
161/// types of the leaves.  Such predefinition results in the creation of
162/// nodes within the tree, but these nodes have not yet been set.
163/// Traversing these nodes is invalid and should result in an "unknown key"
164/// error.
165///
166/// \return True if a value has been set in the node.
167template< typename ValueType >
168bool
169config::typed_leaf_node< ValueType >::is_set(void) const
170{
171    return static_cast< bool >(_value);
172}
173
174
175/// Gets the value stored in the node.
176///
177/// \pre The node must have a value.
178///
179/// \return The value in the node.
180template< typename ValueType >
181const typename config::typed_leaf_node< ValueType >::value_type&
182config::typed_leaf_node< ValueType >::value(void) const
183{
184    PRE(is_set());
185    return _value.get();
186}
187
188
189/// Gets the read-write value stored in the node.
190///
191/// \pre The node must have a value.
192///
193/// \return The value in the node.
194template< typename ValueType >
195typename config::typed_leaf_node< ValueType >::value_type&
196config::typed_leaf_node< ValueType >::value(void)
197{
198    PRE(is_set());
199    return _value.get();
200}
201
202
203/// Sets the value of the node.
204///
205/// \param value_ The new value to set the node to.
206///
207/// \throw value_error If the value is invalid, according to validate().
208template< typename ValueType >
209void
210config::typed_leaf_node< ValueType >::set(const value_type& value_)
211{
212    validate(value_);
213    _value = optional< value_type >(value_);
214}
215
216
217/// Checks a given value for validity.
218///
219/// This is called internally by the node right before updating the recorded
220/// value.  This method can be redefined by subclasses.
221///
222/// \throw value_error If the value is not valid.
223template< typename ValueType >
224void
225config::typed_leaf_node< ValueType >::validate(
226    const value_type& /* new_value */) const
227{
228}
229
230
231/// Sets the value of the node from a raw string representation.
232///
233/// \param raw_value The value to set the node to.
234///
235/// \throw value_error If the value is invalid.
236template< typename ValueType >
237void
238config::native_leaf_node< ValueType >::set_string(const std::string& raw_value)
239{
240    try {
241        typed_leaf_node< ValueType >::set(text::to_type< ValueType >(
242            raw_value));
243    } catch (const text::value_error& e) {
244        throw config::value_error(F("Failed to convert string value '%s' to "
245                                    "the node's type") % raw_value);
246    }
247}
248
249
250/// Converts the contents of the node to a string.
251///
252/// \pre The node must have a value.
253///
254/// \return A string representation of the value held by the node.
255template< typename ValueType >
256std::string
257config::native_leaf_node< ValueType >::to_string(void) const
258{
259    PRE(typed_leaf_node< ValueType >::is_set());
260    return F("%s") % typed_leaf_node< ValueType >::value();
261}
262
263
264/// Constructor for a node with an undefined value.
265///
266/// This should only be called by the tree's define() method as a way to
267/// register a node as known but undefined.  The node will then serve as a
268/// placeholder for future values.
269template< typename ValueType >
270config::base_set_node< ValueType >::base_set_node(void) :
271    _value(none)
272{
273}
274
275
276/// Checks whether the node has been set.
277///
278/// Remember that a node can exist before holding a value (i.e. when the node
279/// has been defined as "known" but not yet set by the user).  This function
280/// checks whether the node laready holds a value.
281///
282/// \return True if a value has been set in the node.
283template< typename ValueType >
284bool
285config::base_set_node< ValueType >::is_set(void) const
286{
287    return static_cast< bool >(_value);
288}
289
290
291/// Gets the value stored in the node.
292///
293/// \pre The node must have a value.
294///
295/// \return The value in the node.
296template< typename ValueType >
297const typename config::base_set_node< ValueType >::value_type&
298config::base_set_node< ValueType >::value(void) const
299{
300    PRE(is_set());
301    return _value.get();
302}
303
304
305/// Gets the read-write value stored in the node.
306///
307/// \pre The node must have a value.
308///
309/// \return The value in the node.
310template< typename ValueType >
311typename config::base_set_node< ValueType >::value_type&
312config::base_set_node< ValueType >::value(void)
313{
314    PRE(is_set());
315    return _value.get();
316}
317
318
319/// Sets the value of the node.
320///
321/// \param value_ The new value to set the node to.
322///
323/// \throw value_error If the value is invalid, according to validate().
324template< typename ValueType >
325void
326config::base_set_node< ValueType >::set(const value_type& value_)
327{
328    validate(value_);
329    _value = optional< value_type >(value_);
330}
331
332
333/// Sets the value of the node from a raw string representation.
334///
335/// \param raw_value The value to set the node to.
336///
337/// \throw value_error If the value is invalid.
338template< typename ValueType >
339void
340config::base_set_node< ValueType >::set_string(const std::string& raw_value)
341{
342    std::set< ValueType > new_value;
343
344    const std::vector< std::string > words = text::split(raw_value, ' ');
345    for (std::vector< std::string >::const_iterator iter = words.begin();
346         iter != words.end(); ++iter) {
347        if (!(*iter).empty())
348            new_value.insert(parse_one(*iter));
349    }
350
351    set(new_value);
352}
353
354
355/// Converts the contents of the node to a string.
356///
357/// \pre The node must have a value.
358///
359/// \return A string representation of the value held by the node.
360template< typename ValueType >
361std::string
362config::base_set_node< ValueType >::to_string(void) const
363{
364    PRE(is_set());
365    return text::join(_value.get(), " ");
366}
367
368
369/// Pushes the node's value onto the Lua stack.
370template< typename ValueType >
371void
372config::base_set_node< ValueType >::push_lua(lutok::state& /* state */) const
373{
374    UNREACHABLE;
375}
376
377
378/// Sets the value of the node from an entry in the Lua stack.
379///
380/// \throw value_error If the value in state(value_index) cannot be
381///     processed by this node.
382template< typename ValueType >
383void
384config::base_set_node< ValueType >::set_lua(
385    lutok::state& state,
386    const int value_index)
387{
388    if (state.is_string(value_index)) {
389        set_string(state.to_string(value_index));
390        return;
391    }
392
393    UNREACHABLE;
394}
395
396
397/// Checks a given value for validity.
398///
399/// This is called internally by the node right before updating the recorded
400/// value.  This method can be redefined by subclasses.
401///
402/// \throw value_error If the value is not valid.
403template< typename ValueType >
404void
405config::base_set_node< ValueType >::validate(
406    const value_type& /* new_value */) const
407{
408}
409
410
411}  // namespace utils
412
413#endif  // !defined(UTILS_CONFIG_NODES_IPP)
414