source: mainline/uspace/app/bithenge/tree.c@ da0fef6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da0fef6 was da0fef6, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: port to Linux and allow choosing a data source

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Trees and nodes.
35 */
36
37#include <errno.h>
38#include <stdlib.h>
39#include "blob.h"
40#include "os.h"
41#include "tree.h"
42
43static int blob_destroy(bithenge_node_t *base)
44{
45 bithenge_blob_t *blob = bithenge_node_as_blob(base);
46 assert(blob->base.blob_ops);
47 return blob->base.blob_ops->destroy(blob);
48}
49
50/** Destroy a node.
51 * @memberof bithenge_node_t
52 * @param node The node to destroy.
53 * @return EOK on success or an error code from errno.h. */
54int bithenge_node_destroy(bithenge_node_t *node)
55{
56 switch (bithenge_node_type(node)) {
57 case BITHENGE_NODE_BLOB:
58 return blob_destroy(node);
59 case BITHENGE_NODE_STRING:
60 if (node->string_value.needs_free)
61 free((void *)node->string_value.ptr);
62 break;
63 case BITHENGE_NODE_INTERNAL:
64 return node->internal_ops->destroy(node);
65 case BITHENGE_NODE_BOOLEAN:
66 return EOK; // the boolean nodes are allocated statically below
67 case BITHENGE_NODE_INTEGER: /* pass-through */
68 break;
69 }
70 free(node);
71 return EOK;
72}
73
74typedef struct
75{
76 bithenge_node_t base;
77 bithenge_node_t **nodes;
78 bithenge_int_t len;
79 bool needs_free;
80} simple_internal_node_t;
81
82static simple_internal_node_t *node_as_simple(bithenge_node_t *node)
83{
84 return (simple_internal_node_t *)node;
85}
86
87static int simple_internal_node_for_each(bithenge_node_t *base,
88 bithenge_for_each_func_t func, void *data)
89{
90 int rc;
91 simple_internal_node_t *node = node_as_simple(base);
92 for (bithenge_int_t i = 0; i < node->len; i++) {
93 rc = func(node->nodes[2*i+0], node->nodes[2*i+1], data);
94 if (rc != EOK)
95 return rc;
96 }
97 return EOK;
98}
99
100static int simple_internal_node_destroy(bithenge_node_t *base)
101{
102 int rc;
103 simple_internal_node_t *node = node_as_simple(base);
104 for (bithenge_int_t i = 0; i < node->len; i++) {
105 rc = bithenge_node_destroy(node->nodes[2*i+0]);
106 if (rc != EOK)
107 return rc;
108 rc = bithenge_node_destroy(node->nodes[2*i+1]);
109 if (rc != EOK)
110 return rc;
111 }
112 if (node->needs_free)
113 free(node->nodes);
114 free(node);
115 return EOK;
116}
117
118static bithenge_internal_node_ops_t simple_internal_node_ops = {
119 .for_each = simple_internal_node_for_each,
120 .destroy = simple_internal_node_destroy,
121};
122
123static bithenge_node_t *simple_internal_as_node(simple_internal_node_t *node)
124{
125 return &node->base;
126}
127
128/** Create an internal node from a set of keys and values. The node must be
129 * freed with @a bithenge_node_t::bithenge_node_destroy after it is used, which
130 * will also destroy all the key and value nodes.
131 * @memberof bithenge_node_t
132 * @param[out] out Stores the created internal node.
133 * @param nodes The array of key-value pairs. Keys are stored at even indices
134 * and values are stored at odd indices.
135 * @param len The number of key-value pairs in the node array.
136 * @param needs_free If true, when the internal node is destroyed it will free
137 * the nodes array as well as destroying each node inside it.
138 * @return EOK on success or an error code from errno.h. */
139int bithenge_new_simple_internal_node(bithenge_node_t **out,
140 bithenge_node_t **nodes, bithenge_int_t len, bool needs_free)
141{
142 assert(out);
143 simple_internal_node_t *node = malloc(sizeof(*node));
144 if (!node)
145 return ENOMEM;
146 node->base.type = BITHENGE_NODE_INTERNAL;
147 node->base.internal_ops = &simple_internal_node_ops;
148 node->nodes = nodes;
149 node->len = len;
150 node->needs_free = needs_free;
151 *out = simple_internal_as_node(node);
152 return EOK;
153}
154
155static bithenge_node_t false_node = { BITHENGE_NODE_BOOLEAN, .boolean_value = false };
156static bithenge_node_t true_node = { BITHENGE_NODE_BOOLEAN, .boolean_value = true };
157
158/** Create a boolean node. The node must be freed with @a
159 * bithenge_node_t::bithenge_node_destroy after it is used.
160 * @memberof bithenge_node_t
161 * @param[out] out Stores the created boolean node.
162 * @param value The value for the node to hold.
163 * @return EOK on success or an error code from errno.h. */
164int bithenge_new_boolean_node(bithenge_node_t **out, bool value)
165{
166 assert(out);
167 *out = value ? &true_node : &false_node;
168 return EOK;
169}
170
171/** Create an integer node. The node must be freed with @a
172 * bithenge_node_t::bithenge_node_destroy after it is used.
173 * @memberof bithenge_node_t
174 * @param[out] out Stores the created integer node.
175 * @param value The value for the node to hold.
176 * @return EOK on success or an error code from errno.h. */
177int bithenge_new_integer_node(bithenge_node_t **out, bithenge_int_t value)
178{
179 assert(out);
180 bithenge_node_t *node = malloc(sizeof(*node));
181 if (!node)
182 return ENOMEM;
183 node->type = BITHENGE_NODE_INTEGER;
184 node->integer_value = value;
185 *out = node;
186 return EOK;
187}
188
189/** Create a string node. The node must be freed with @a
190 * bithenge_node_t::bithenge_node_destroy after it is used.
191 * @memberof bithenge_node_t
192 * @param[out] out Stores the created string node.
193 * @param value The value for the node to hold.
194 * @param needs_free Whether the string should be freed when the node is
195 * destroyed.
196 * @return EOK on success or an error code from errno.h. */
197int bithenge_new_string_node(bithenge_node_t **out, const char *value, bool needs_free)
198{
199 assert(out);
200 bithenge_node_t *node = malloc(sizeof(*node));
201 if (!node)
202 return ENOMEM;
203 node->type = BITHENGE_NODE_STRING;
204 node->string_value.ptr = value;
205 node->string_value.needs_free = needs_free;
206 *out = node;
207 return EOK;
208}
209
210/** Check whether the contents of two nodes are equal. Does not yet work for
211 * internal nodes.
212 * @memberof bithenge_node_t
213 * @param a, b Nodes to compare.
214 * @return Whether the nodes are equal. If an error occurs, returns false.
215 * @todo Add support for internal nodes.
216 */
217bool bithenge_node_equal(bithenge_node_t *a, bithenge_node_t *b)
218{
219 if (a->type != b->type)
220 return false;
221 switch (a->type) {
222 case BITHENGE_NODE_INTERNAL:
223 return false;
224 case BITHENGE_NODE_BOOLEAN:
225 return a->boolean_value == b->boolean_value;
226 case BITHENGE_NODE_INTEGER:
227 return a->integer_value == b->integer_value;
228 case BITHENGE_NODE_STRING:
229 return !str_cmp(a->string_value.ptr, b->string_value.ptr);
230 case BITHENGE_NODE_BLOB:
231 return bithenge_blob_equal(bithenge_node_as_blob(a),
232 bithenge_node_as_blob(b));
233 }
234 return false;
235}
236
237/** @}
238 */
Note: See TracBrowser for help on using the repository browser.