Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
// Copyright 2012 The Kyua Authors.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "utils/config/nodes.hpp"

#if !defined(UTILS_CONFIG_NODES_IPP)
#define UTILS_CONFIG_NODES_IPP

#include <memory>
#include <typeinfo>

#include "utils/config/exceptions.hpp"
#include "utils/defs.hpp"
#include "utils/format/macros.hpp"
#include "utils/optional.ipp"
#include "utils/text/exceptions.hpp"
#include "utils/text/operations.ipp"
#include "utils/sanity.hpp"

namespace utils {


namespace config {
namespace detail {


/// Type of the new_node() family of functions.
typedef base_node* (*new_node_hook)(void);


/// Creates a new leaf node of a given type.
///
/// \tparam NodeType The type of the leaf node to create.
///
/// \return A pointer to the newly-created node.
template< class NodeType >
base_node*
new_node(void)
{
    return new NodeType();
}


/// Internal node of the tree.
///
/// This abstract base class provides the mechanism to implement both static and
/// dynamic nodes.  Ideally, the implementation would be split in subclasses and
/// this class would not include the knowledge of whether the node is dynamic or
/// not.  However, because the static/dynamic difference depends on the leaf
/// types, we need to declare template functions and these cannot be virtual.
class inner_node : public base_node {
    /// Whether the node is dynamic or not.
    bool _dynamic;

protected:
    /// Type to represent the collection of children of this node.
    ///
    /// Note that these are one-level keys.  They cannot contain dots, and thus
    /// is why we use a string rather than a tree_key.
    typedef std::map< std::string, base_node* > children_map;

    /// Mapping of keys to values that are descendants of this node.
    children_map _children;

    void copy_into(inner_node*) const;
    void combine_into(const tree_key&, const base_node*, inner_node*) const;

private:
    void combine_children_into(const tree_key&,
                               const children_map&, const children_map&,
                               inner_node*) const;

public:
    inner_node(const bool);
    virtual ~inner_node(void) = 0;

    const base_node* lookup_ro(const tree_key&,
                               const tree_key::size_type) const;
    leaf_node* lookup_rw(const tree_key&, const tree_key::size_type,
                         new_node_hook);

    void all_properties(properties_map&, const tree_key&) const;
};


/// Static internal node of the tree.
///
/// The direct children of this node must be pre-defined by calls to define().
/// Attempts to traverse this node and resolve a key that is not a pre-defined
/// children will result in an "unknown key" error.
class static_inner_node : public config::detail::inner_node {
public:
    static_inner_node(void);

    virtual base_node* deep_copy(void) const;
    virtual base_node* combine(const tree_key&, const base_node*) const;

    void define(const tree_key&, const tree_key::size_type, new_node_hook);
};


/// Dynamic internal node of the tree.
///
/// The children of this node need not be pre-defined.  Attempts to traverse
/// this node and resolve a key will result in such key being created.  Any
/// intermediate non-existent nodes of the traversal will be created as dynamic
/// inner nodes as well.
class dynamic_inner_node : public config::detail::inner_node {
public:
    virtual base_node* deep_copy(void) const;
    virtual base_node* combine(const tree_key&, const base_node*) const;

    dynamic_inner_node(void);
};


}  // namespace detail
}  // namespace config


/// Constructor for a node with an undefined value.
///
/// This should only be called by the tree's define() method as a way to
/// register a node as known but undefined.  The node will then serve as a
/// placeholder for future values.
template< typename ValueType >
config::typed_leaf_node< ValueType >::typed_leaf_node(void) :
    _value(none)
{
}


/// Checks whether the node has been set by the user.
///
/// Nodes of the tree are predefined by the caller to specify the valid
/// types of the leaves.  Such predefinition results in the creation of
/// nodes within the tree, but these nodes have not yet been set.
/// Traversing these nodes is invalid and should result in an "unknown key"
/// error.
///
/// \return True if a value has been set in the node.
template< typename ValueType >
bool
config::typed_leaf_node< ValueType >::is_set(void) const
{
    return static_cast< bool >(_value);
}


/// Gets the value stored in the node.
///
/// \pre The node must have a value.
///
/// \return The value in the node.
template< typename ValueType >
const typename config::typed_leaf_node< ValueType >::value_type&
config::typed_leaf_node< ValueType >::value(void) const
{
    PRE(is_set());
    return _value.get();
}


/// Gets the read-write value stored in the node.
///
/// \pre The node must have a value.
///
/// \return The value in the node.
template< typename ValueType >
typename config::typed_leaf_node< ValueType >::value_type&
config::typed_leaf_node< ValueType >::value(void)
{
    PRE(is_set());
    return _value.get();
}


/// Sets the value of the node.
///
/// \param value_ The new value to set the node to.
///
/// \throw value_error If the value is invalid, according to validate().
template< typename ValueType >
void
config::typed_leaf_node< ValueType >::set(const value_type& value_)
{
    validate(value_);
    _value = optional< value_type >(value_);
}


/// Checks a given value for validity.
///
/// This is called internally by the node right before updating the recorded
/// value.  This method can be redefined by subclasses.
///
/// \throw value_error If the value is not valid.
template< typename ValueType >
void
config::typed_leaf_node< ValueType >::validate(
    const value_type& /* new_value */) const
{
}


/// Sets the value of the node from a raw string representation.
///
/// \param raw_value The value to set the node to.
///
/// \throw value_error If the value is invalid.
template< typename ValueType >
void
config::native_leaf_node< ValueType >::set_string(const std::string& raw_value)
{
    try {
        typed_leaf_node< ValueType >::set(text::to_type< ValueType >(
            raw_value));
    } catch (const text::value_error& e) {
        throw config::value_error(F("Failed to convert string value '%s' to "
                                    "the node's type") % raw_value);
    }
}


/// Converts the contents of the node to a string.
///
/// \pre The node must have a value.
///
/// \return A string representation of the value held by the node.
template< typename ValueType >
std::string
config::native_leaf_node< ValueType >::to_string(void) const
{
    PRE(typed_leaf_node< ValueType >::is_set());
    return F("%s") % typed_leaf_node< ValueType >::value();
}


/// Constructor for a node with an undefined value.
///
/// This should only be called by the tree's define() method as a way to
/// register a node as known but undefined.  The node will then serve as a
/// placeholder for future values.
template< typename ValueType >
config::base_set_node< ValueType >::base_set_node(void) :
    _value(none)
{
}


/// Checks whether the node has been set.
///
/// Remember that a node can exist before holding a value (i.e. when the node
/// has been defined as "known" but not yet set by the user).  This function
/// checks whether the node laready holds a value.
///
/// \return True if a value has been set in the node.
template< typename ValueType >
bool
config::base_set_node< ValueType >::is_set(void) const
{
    return static_cast< bool >(_value);
}


/// Gets the value stored in the node.
///
/// \pre The node must have a value.
///
/// \return The value in the node.
template< typename ValueType >
const typename config::base_set_node< ValueType >::value_type&
config::base_set_node< ValueType >::value(void) const
{
    PRE(is_set());
    return _value.get();
}


/// Gets the read-write value stored in the node.
///
/// \pre The node must have a value.
///
/// \return The value in the node.
template< typename ValueType >
typename config::base_set_node< ValueType >::value_type&
config::base_set_node< ValueType >::value(void)
{
    PRE(is_set());
    return _value.get();
}


/// Sets the value of the node.
///
/// \param value_ The new value to set the node to.
///
/// \throw value_error If the value is invalid, according to validate().
template< typename ValueType >
void
config::base_set_node< ValueType >::set(const value_type& value_)
{
    validate(value_);
    _value = optional< value_type >(value_);
}


/// Sets the value of the node from a raw string representation.
///
/// \param raw_value The value to set the node to.
///
/// \throw value_error If the value is invalid.
template< typename ValueType >
void
config::base_set_node< ValueType >::set_string(const std::string& raw_value)
{
    std::set< ValueType > new_value;

    const std::vector< std::string > words = text::split(raw_value, ' ');
    for (std::vector< std::string >::const_iterator iter = words.begin();
         iter != words.end(); ++iter) {
        if (!(*iter).empty())
            new_value.insert(parse_one(*iter));
    }

    set(new_value);
}


/// Converts the contents of the node to a string.
///
/// \pre The node must have a value.
///
/// \return A string representation of the value held by the node.
template< typename ValueType >
std::string
config::base_set_node< ValueType >::to_string(void) const
{
    PRE(is_set());
    return text::join(_value.get(), " ");
}


/// Pushes the node's value onto the Lua stack.
template< typename ValueType >
void
config::base_set_node< ValueType >::push_lua(lutok::state& /* state */) const
{
    UNREACHABLE;
}


/// Sets the value of the node from an entry in the Lua stack.
///
/// \throw value_error If the value in state(value_index) cannot be
///     processed by this node.
template< typename ValueType >
void
config::base_set_node< ValueType >::set_lua(
    lutok::state& /* state */,
    const int /* value_index */)
{
    UNREACHABLE;
}


/// Checks a given value for validity.
///
/// This is called internally by the node right before updating the recorded
/// value.  This method can be redefined by subclasses.
///
/// \throw value_error If the value is not valid.
template< typename ValueType >
void
config::base_set_node< ValueType >::validate(
    const value_type& /* new_value */) const
{
}


}  // namespace utils

#endif  // !defined(UTILS_CONFIG_NODES_IPP)