Tree routines.
Overview
Trees are recursive objects which have an attached list of named attributes. More…
// typedefs typedef struct te_tree te_tree; typedef te_errno te_tree_traverse_fn( const te_tree *tree, void *data ); typedef te_errno te_tree_map_fn( const te_kvpair_h *src, te_kvpair_h *dst, void *data ); // global functions te_errno te_tree_get_int_attr(const te_tree* tree, const char* attr, intmax_t* result); te_errno te_tree_get_float_attr(const te_tree* tree, const char* attr, double* result); te_errno te_tree_get_bool_attr(const te_tree* tree, const char* attr, bool* result); te_tree* te_tree_alloc(void); void te_tree_free(te_tree* tree); te_errno te_tree_add_attr_va(te_tree* tree, const char* attr, const char* value_fmt, va_list va); te_errno te_tree_add_attr(te_tree* tree, const char* attr, const char* value_fmt, ...); te_errno te_tree_add_attrs(te_tree* tree, const te_kvpair_h* attrs); void te_tree_add_child(te_tree* tree, te_tree* child); void te_tree_add_kvpair_children(te_tree* tree, const te_kvpair_h* kvpair); te_tree* te_tree_make_typed(const char* name, const char* type, ...); const char* te_tree_get_attr(const te_tree* tree, const char* attr); const char* te_tree_get_type(const te_tree* tree); bool te_tree_has_attr(const te_tree* tree, const char* attr, const char* value); bool te_tree_has_attrs(const te_tree* tree, const te_kvpair_h* attrs); const te_kvpair_h* te_tree_attrs(const te_tree* tree); const te_tree* te_tree_parent(const te_tree* tree); const te_tree* te_tree_root(const te_tree* tree); unsigned int te_tree_level(const te_tree* tree); const te_tree* te_tree_first_child(const te_tree* tree); const te_tree* te_tree_last_child(const te_tree* tree); unsigned int te_tree_count_children(const te_tree* tree); const te_tree* te_tree_next(const te_tree* tree); const te_tree* te_tree_prev(const te_tree* tree); unsigned int te_tree_position(const te_tree* tree); const te_tree* te_tree_leftmost_leaf(const te_tree* tree); const te_tree* te_tree_rightmost_leaf(const te_tree* tree); const te_tree* te_tree_left(const te_tree* tree); const te_tree* te_tree_right(const te_tree* tree); const te_tree* te_tree_left_leaf(const te_tree* tree); const te_tree* te_tree_right_leaf(const te_tree* tree); const te_tree* te_tree_nth_child(const te_tree* tree, unsigned int nth); const te_tree* te_tree_child_by_attr(const te_tree* tree, const char* attr, const char* value); const te_tree* te_tree_child_by_attrs(const te_tree* tree, const te_kvpair_h* attrs); te_errno te_tree_traverse(const te_tree* tree, unsigned int minlevel, unsigned int maxlevel, te_tree_traverse_fn* pre_cb, te_tree_traverse_fn* post_cb, void* data); te_tree* te_tree_map(const te_tree* tree, te_tree_map_fn* fn, void* data); bool te_tree_validate_types(const te_tree* tree, bool allow_unknown, const te_tree** bad_node); // macros #define TE_TREE_ATTR_NAME #define TE_TREE_ATTR_TYPE #define TE_TREE_ATTR_TYPE_ANNOTATION #define TE_TREE_ATTR_TYPE_ARRAY #define TE_TREE_ATTR_TYPE_AUTO #define TE_TREE_ATTR_TYPE_BOOL #define TE_TREE_ATTR_TYPE_DICT #define TE_TREE_ATTR_TYPE_FLOAT #define TE_TREE_ATTR_TYPE_INT #define TE_TREE_ATTR_TYPE_NULL #define TE_TREE_ATTR_TYPE_STRING #define TE_TREE_ATTR_VALUE
Detailed Documentation
Trees are recursive objects which have an attached list of named attributes.
Attributes are just strings, but some attributes may have special meaning for various functions, in particular defining
the name of a given subtree;
its textual value;
its type.
Trees are mostly immutable: there are functions to build them incrementally, but once a tree is complete, it is not meant to change.
Trees cannot be shared: if a tree is added as a child of some other tree, it cannot be later added as a child of yet another tree.
The linear ordering of nodes is defined as follows:
all children follow their parent;
siblings follow each other.
This means that if a node has children, its immediate successor will be its first child, otherwise its next sibling if there is one, otherwise the next sibling of its parent and so on. In the same way, the immediate predecessor of a node will be the rightmost leaf node of its previous sibling, if any, otherwise its parent.
Typedefs
typedef struct te_tree te_tree
An opaque object representing trees.
typedef te_errno te_tree_traverse_fn( const te_tree *tree, void *data )
Function type for tree traversal.
If the function returns non-zero, the traversal stops immediately, but a value of TE_EOK is returned as zero from te_tree_traverse().
In a pre-callback TE_ESKIP may be returned to prevent descending into the tree children.
Parameters:
tree |
current (sub)tree |
data |
user data |
TE_EOK |
Stop traversing and report success to the caller. |
TE_ESKIP |
Do not descend into the children. |
Returns:
status code
typedef te_errno te_tree_map_fn( const te_kvpair_h *src, te_kvpair_h *dst, void *data )
Attribute mapping function type.
dst
is empty upon entry to this function, so it must do copying itself, if needed.
Parameters:
src |
source mapping |
dst |
destination mapping |
data |
user data |
Returns:
status code
Global Functions
te_errno te_tree_get_int_attr(const te_tree* tree, const char* attr, intmax_t* result)
Get an integral value of an attribute of a tree.
Parameters:
tree |
tree |
attr |
attribute name |
result |
resulting value |
TE_ENOENT |
No attribute |
TE_ERANGE |
The value does not fit into |
TE_EINVAL |
The value is not a valid integer in any base. |
Returns:
status code
te_errno te_tree_get_float_attr(const te_tree* tree, const char* attr, double* result)
Get a floating-point value of an attribute of a tree.
Parameters:
tree |
tree |
attr |
attribute name |
result |
resulting value |
TE_ENOENT |
No attribute |
TE_ERANGE |
The value does not fit into |
TE_EINVAL |
The value is not a valid floating-point representation. |
Returns:
status code
te_errno te_tree_get_bool_attr(const te_tree* tree, const char* attr, bool* result)
Get a boolean value of an attribute of a tree.
All “natural” way of representing booleans are supported:
true
,true
,True
,T
,t
,YES
,yes
,Yes
,Y
,y
,1
all map totrue
false
,false
,False
,F
,f
,NO
,no
,No
,N
, @xc n,0
and empty string all map tofalse
.
Parameters:
tree |
tree |
attr |
attribute name |
result |
resulting value |
TE_ENOENT |
No attribute |
TE_EINVAL |
The value is not a valid boolean representation. |
Returns:
status code
te_tree* te_tree_alloc(void)
Allocate an empty tree object.
Returns:
a dynamically allocated empty tree (should be freed with te_tree_free())
void te_tree_free(te_tree* tree)
Deallocate tree
and all its subtrees.
The function must only be called on a root tree, i.e. the one that is not attached to any parent.
Parameters:
tree |
root tree to deallocate |
te_errno te_tree_add_attr_va(te_tree* tree, const char* attr, const char* value_fmt, va_list va)
Add an attribute to a tree.
Parameters:
tree |
tree to modify |
attr |
attribute name |
value_fmt |
attribute value format @oaram va variadic list |
TE_EEXIST |
|
Returns:
status code
te_errno te_tree_add_attr(te_tree* tree, const char* attr, const char* value_fmt, ...)
Add an attribute to a tree.
Parameters:
tree |
tree to modify |
attr |
attribute name |
value_fmt |
attribute value format @oaram … variadic arguments |
TE_EEXIST |
|
Returns:
status code
te_errno te_tree_add_attrs(te_tree* tree, const te_kvpair_h* attrs)
Add attributes from the kvpair attrs
.
If the function returns TE_EEXIST code, all attributes from attrs
that were not in tree
, are still added to it.
Parameters:
tree |
tree to modify |
attrs |
list of attributes |
TE_EEXIST |
some attributes from |
Returns:
status code
void te_tree_add_child(te_tree* tree, te_tree* child)
Add a child to a tree.
child
becomes the last child of tree
.
child
must not be already added to any other tree and it must not be deallocated by the caller after it has been added.
Parameters:
tree |
tree to modify |
child |
child to add |
void te_tree_add_kvpair_children(te_tree* tree, const te_kvpair_h* kvpair)
Convert a key-value mapping to children of tree
.
All key-value pairs from kvpair
are converted to elementary trees each having two attributes: TE_TREE_ATTR_NAME holding the key and TE_TREE_ATTR_VALUE holding the value. These trees are appended as children to tree
in the order of keys in kvpair
.
Parameters:
tree |
tree to modify |
kvpair |
list of child descriptions |
te_tree* te_tree_make_typed(const char* name, const char* type, ...)
Create a tree with a name and a typed value.
name
becomes TE_TREE_ATTR_NAME, type
become TE_TREE_ATTR_TYPE, and the value is determined from the type and variadic arguments:
TE_TREE_ATTR_TYPE_AUTO is not supported;
TE_TREE_ATTR_TYPE_NULL accepts no additional arguments;
TE_TREE_ATTR_TYPE_STRING should have a single string argument;
TE_TREE_ATTR_TYPE_INT should have a single int argument;
TE_TREE_ATTR_TYPE_FLOAT should have a single double argument;
TE_TREE_ATTR_TYPE_BOOL should have a single int argument treated as boolean;
TE_TREE_ATTR_TYPE_ARRAY should have a
NULL-terminated
sequence of subtrees, none of which must have a TE_TREE_ATTR_NAME;TE_TREE_ATTR_TYPE_DICT should have a
NULL-terminated
sequence of pairs - name/subtree. Names will be added to subtrees as TE_TREE_ATTR_NAME attributes;TE_TREE_ATTR_TYPE_ANNOTATION is not supported.
If name
is NULL
, the resulting tree is unnamed.
In most other places TE_TREE_ATTR_TYPE_INT values are represented by intmax_t
. However, here a plain int argument is expected, since it should be a more common usecase.
te_tree_make_typed("node0", TE_TREE_ATTR_TYPE_NULL); te_tree_make_typed("node1", TE_TREE_ATTR_TYPE_STRING, "string value"); te_tree_make_typed("node2", TE_TREE_ATTR_TYPE_INT, 42); te_tree_make_typed("node3", TE_TREE_ATTR_TYPE_FLOAT, 42.0); te_tree_make_typed("node4", TE_TREE_ATTR_TYPE_BOOL, true); te_tree_make_typed("node6", TE_TREE_ATTR_TYPE_ARRAY, item1, item2, item3, NULL); te_tree_make_typed("node7", TE_TREE_ATTR_TYPE_DICT, "subnode1", subnode1, "subnode2", subnode2, NULL);
Parameters:
name |
name of a tree (may be |
type |
type of its value |
… |
variadic arguments defining value |
Returns:
a fresh tree or NULL
if there are any inconsistencies
const char* te_tree_get_attr(const te_tree* tree, const char* attr)
Get a value of an attribute of a tree.
Parameters:
tree |
tree |
attr |
attribute name |
Returns:
attribute value or NULL
if no such attribute
const char* te_tree_get_type(const te_tree* tree)
Get the type of a tree.
If the tree has TE_TREE_ATTR_TYPE attribute and its value is not TE_TREE_ATTR_TYPE_AUTO, it is returned.
Otherwise:
if it has TE_TREE_ATTR_VALUE and no children, the type is assumed to be TE_TREE_ATTR_TYPE_STRING;
otherwise if if has at least one child with a TE_TREE_ATTR_NAME which is not of TE_TREE_ATTR_TYPE_ANNOTATION type, the type is TE_TREE_ATTR_TYPE_DICT;
otherwise the type is TE_TREE_ATTR_TYPE_ARRAY; in particular, if a node has no TE_TREE_ATTR_VALUE and no children, it is assumed to represent an empty array.
All scalar nodes without explicit type are detected as TE_TREE_ATTR_TYPE_STRING, even if the value matches some more specific type such as an integer.
Parameters:
tree |
tree to inspect |
Returns:
type label of tree
(never NULL
)
bool te_tree_has_attr(const te_tree* tree, const char* attr, const char* value)
Test whether a tree has an attribute with a given name and value.
The presence of the attribute is checked by te_kvpairs_has_kv(), so both key
and value
may be NULL
, meaning “any string”.
Parameters:
tree |
tree |
attr |
attribute name (may be |
value |
attribute value (may be |
Returns:
true
if there is an attribute with a given name and value
bool te_tree_has_attrs(const te_tree* tree, const te_kvpair_h* attrs)
Test whether a tree has all attributes specified by attrs
.
Parameters:
tree |
tree |
attrs |
list of name-value pairs |
Returns:
true
if all attributes from attrs
have matching values in tree
const te_kvpair_h* te_tree_attrs(const te_tree* tree)
Get an immutable attribute list.
Parameters:
tree |
tree |
Returns:
a list of attribute name-value pairs
const te_tree* te_tree_parent(const te_tree* tree)
Get the parent of a tree.
Parameters:
tree |
tree |
Returns:
the parent of tree
or NULL
const te_tree* te_tree_root(const te_tree* tree)
Get the root of a tree.
Parameters:
tree |
tree |
Returns:
the root of tree
(never NULL
)
unsigned int te_tree_level(const te_tree* tree)
Get the level of a tree.
The level is the length of a path from the root to a given subtree. If the tree is the root, the level is 0.
Parameters:
tree |
tree |
Returns:
the level of tree
const te_tree* te_tree_first_child(const te_tree* tree)
Get the first (leftmost) child of a tree.
Parameters:
tree |
tree |
Returns:
the first child of tree
(NULL
if none)
const te_tree* te_tree_last_child(const te_tree* tree)
Get the last (rightmost) child of a tree.
Parameters:
tree |
tree |
Returns:
the first child of tree
(NULL
if none)
unsigned int te_tree_count_children(const te_tree* tree)
Count the number of children of a tree.
Parameters:
tree |
tree |
Returns:
the number of children of tree
const te_tree* te_tree_next(const te_tree* tree)
Get the next sibling of tree
.
Parameters:
tree |
tree |
Returns:
the next sibling of tree
or NULL
const te_tree* te_tree_prev(const te_tree* tree)
Get the previous sibling of tree
.
Parameters:
tree |
tree |
Returns:
the previous sibling of tree
or NULL
unsigned int te_tree_position(const te_tree* tree)
Get the position of a tree.
The position is the ordinal number of a tree among its siblings. The first child of its parent has a position 0
.
Parameters:
tree |
tree |
Returns:
the position of tree
const te_tree* te_tree_leftmost_leaf(const te_tree* tree)
Get the leftmost leaf descendant of tree
.
Parameters:
tree |
tree |
Returns:
the leftmost leaf of tree
(never NULL
)
const te_tree* te_tree_rightmost_leaf(const te_tree* tree)
Get the rightmost leaf descendant of tree
.
Parameters:
tree |
tree |
Returns:
the leftmost leaf of tree
(never NULL
)
const te_tree* te_tree_left(const te_tree* tree)
Get the tree immediately preceding tree
in linear order.
Parameters:
tree |
tree |
Returns:
the tree immediately preceding tree
or NULL
const te_tree* te_tree_right(const te_tree* tree)
Get the tree immediately following tree
in linear order.
Parameters:
tree |
tree |
Returns:
the tree immediately following tree
or NULL
const te_tree* te_tree_left_leaf(const te_tree* tree)
Get the nearest leaf following tree
in linear order.
Parameters:
tree |
tree |
Returns:
the leaf following tree
or NULL
const te_tree* te_tree_right_leaf(const te_tree* tree)
Get the nearest leaf preceding tree
in linear order.
Parameters:
tree |
tree |
Returns:
the leaf preceding tree
or NULL
const te_tree* te_tree_nth_child(const te_tree* tree, unsigned int nth)
Get the nth
child of tree
.
Parameters:
tree |
tree |
nth |
0-based index |
Returns:
the nth
child of tree
or NULL
const te_tree* te_tree_child_by_attr(const te_tree* tree, const char* attr, const char* value)
Get the first child with a given attribute.
The check is performed by te_tree_has_attr().
Parameters:
tree |
tree |
attr |
attribute name (may be |
value |
attribute name (may be |
Returns:
the first matching child or NULL
const te_tree* te_tree_child_by_attrs(const te_tree* tree, const te_kvpair_h* attrs)
Get the first child with given attributes.
The check is performed by te_tree_has_attrs().
Parameters:
tree |
tree |
attr |
attribute name (may be |
value |
attribute name (may be |
Returns:
the first matching child or NULL
te_errno te_tree_traverse(const te_tree* tree, unsigned int minlevel, unsigned int maxlevel, te_tree_traverse_fn* pre_cb, te_tree_traverse_fn* post_cb, void* data)
Traverse the tree
.
Callbacks are only called for subtrees that are at least minlevel
below tree
, and the traversal does not go deeper than maxlevel
below tree
. So for example to process only direct children of tree
, one may use:
te_tree_traverse(tree, 1, 1, child_cb, NULL, userdata);
Parameters:
tree |
tree to traverse |
minlevel |
minimum level to call callbacks on |
maxlevel |
maximum level to descend |
pre_cb |
preorder callback (may be |
post_cb |
postorder callback (may be |
Returns:
status code
te_tree* te_tree_map(const te_tree* tree, te_tree_map_fn* fn, void* data)
Construct a new tree from an old one converting attributes.
If the conversion function fn
ever returns non-zero, the new tree is destroyed and NULL
is returned.
No attributes of the tree are automatically copied, the mapping function should use te_kvpairs_copy() or te_kvpairs_copy_key() to copy the needed attributes.
Parameters:
tree |
source tree |
fn |
attribute translation function |
data |
user data |
Returns:
a fresh translated tree or NULL
bool te_tree_validate_types(const te_tree* tree, bool allow_unknown, const te_tree** bad_node)
Check that all subtrees have correct types and values.
The type of each node is detected by te_tree_get_type() and then the following constraints apply:
if the type is TE_TREE_ATTR_TYPE_NULL, the node must have no TE_TREE_ATTR_VALUE and no children;
if the type is scalar (one of TE_TREE_ATTR_TYPE_STRING, TE_TREE_ATTR_TYPE_BOOL, TE_TREE_ATTR_TYPE_INT, TE_TREE_ATTR_TYPE_FLOAT) it must have a TE_TREE_ATTR_VALUE and no children;
if the type is TE_TREE_ATTR_TYPE_BOOL, the value must be valid as per te_tree_get_bool_attr();
if the type is TE_TREE_ATTR_TYPE_INT, the value must be valid as per te_tree_get_int_attr();
if the type is TE_TREE_ATTR_TYPE_FLOAT, the value must be valid as per te_tree_get_float_attr();
if the type is TE_TREE_ATTR_TYPE_ARRAY, all children that are not annotations must have no names;
if the type is TE_TREE_ATTR_TYPE_DICT, all children that are not annotations must have names;
if the type is unknown and
allow_unknown
is true, the node itself is always considered valid; children are recursively checked; otherwise the node is invalid;if the type is TE_TREE_ATTR_TYPE_ANNOTATION, the node is considered valid and no children are further checked.
Parameters:
tree |
tree to check |
allow_unknown |
allow unknown types for tree nodes |
bad_node |
location for a pointer to the first detected bad node |
Returns:
true
if the tree is valid
Macros
#define TE_TREE_ATTR_NAME
Tree name.
#define TE_TREE_ATTR_TYPE
Tree value type.
#define TE_TREE_ATTR_TYPE_ANNOTATION
A node with metadata that should not be serialized in-band.
#define TE_TREE_ATTR_TYPE_ARRAY
Linear array.
#define TE_TREE_ATTR_TYPE_AUTO
Auto-detect type (the default if no type attribute).
#define TE_TREE_ATTR_TYPE_BOOL
Boolean type.
#define TE_TREE_ATTR_TYPE_DICT
Dictionary (an associative array).
#define TE_TREE_ATTR_TYPE_FLOAT
Floating-point type.
#define TE_TREE_ATTR_TYPE_INT
Integer type.
#define TE_TREE_ATTR_TYPE_NULL
Null type.
#define TE_TREE_ATTR_TYPE_STRING
String type.
#define TE_TREE_ATTR_VALUE
Tree value.