2 * Copyright (c) 2012 Sean Bartell
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup bithenge
39 #include <bithenge/blob.h>
40 #include <bithenge/os.h>
41 #include <bithenge/tree.h>
43 static void blob_destroy(bithenge_node_t
*base
)
45 bithenge_blob_t
*self
= bithenge_node_as_blob(base
);
46 assert(self
->base
.blob_ops
);
47 self
->base
.blob_ops
->destroy(self
);
50 static void node_destroy(bithenge_node_t
*self
)
52 switch (bithenge_node_type(self
)) {
53 case BITHENGE_NODE_BLOB
:
56 case BITHENGE_NODE_STRING
:
57 if (self
->string_value
.needs_free
)
58 free((void *)self
->string_value
.ptr
);
60 case BITHENGE_NODE_INTERNAL
:
61 self
->internal_ops
->destroy(self
);
63 case BITHENGE_NODE_BOOLEAN
:
64 return; /* The boolean nodes are allocated statically below. */
65 case BITHENGE_NODE_INTEGER
: /* pass-through */
71 /** Decrement a node's reference count and free it if appropriate.
72 * @memberof bithenge_node_t
73 * @param node The node to dereference, or NULL. */
74 void bithenge_node_dec_ref(bithenge_node_t
*node
)
78 assert (node
->refs
> 0);
79 if (--node
->refs
== 0)
85 bithenge_node_t
**out
;
86 } get_for_each_data_t
;
88 static int get_for_each_func(bithenge_node_t
*key
, bithenge_node_t
*value
,
91 get_for_each_data_t
*data
= (get_for_each_data_t
*)raw_data
;
93 int rc
= bithenge_node_equal(&equal
, key
, data
->key
);
94 bithenge_node_dec_ref(key
);
101 bithenge_node_dec_ref(value
);
105 /** Get a child of a node. Takes ownership of the key. If the node does not
106 * provide this function, for_each will be used as an alternative, which may be
107 * very slow. Also works for blob nodes to find the byte value at a given
109 * @memberof bithenge_node_t
110 * @param self The internal/blob node to find a child of.
111 * @param key The key to search for.
112 * @param[out] out Holds the found node.
113 * @return EOK on success, ENOENT if not found, or another error code from
115 int bithenge_node_get(bithenge_node_t
*self
, bithenge_node_t
*key
,
116 bithenge_node_t
**out
)
118 if (self
->type
== BITHENGE_NODE_BLOB
) {
119 if (bithenge_node_type(key
) != BITHENGE_NODE_INTEGER
) {
120 bithenge_node_dec_ref(key
);
123 bithenge_int_t offset
= bithenge_integer_node_value(key
);
124 bithenge_node_dec_ref(key
);
127 int rc
= bithenge_blob_read(bithenge_node_as_blob(self
),
128 offset
, (char *)&byte
, &size
);
134 return bithenge_new_integer_node(out
, byte
);
137 assert(self
->type
== BITHENGE_NODE_INTERNAL
);
138 if (self
->internal_ops
->get
)
139 return self
->internal_ops
->get(self
, key
, out
);
141 get_for_each_data_t data
= {key
, out
};
142 int rc
= bithenge_node_for_each(self
, get_for_each_func
, &data
);
143 bithenge_node_dec_ref(key
);
144 if (rc
== EEXIST
&& *out
)
148 bithenge_node_dec_ref(*out
);
152 /** Initialize an internal node.
153 * @memberof bithenge_node_t
154 * @param[out] self The node.
155 * @param[in] ops The operations provided.
156 * @return EOK on success or an error code from errno.h. */
157 int bithenge_init_internal_node(bithenge_node_t
*self
,
158 const bithenge_internal_node_ops_t
*ops
)
160 self
->type
= BITHENGE_NODE_INTERNAL
;
162 self
->internal_ops
= ops
;
166 static void internal_node_indestructible(bithenge_node_t
*self
)
171 static int empty_internal_node_for_each(bithenge_node_t
*base
,
172 bithenge_for_each_func_t func
, void *data
)
177 static int empty_internal_node_get(bithenge_node_t
*self
, bithenge_node_t
*key
,
178 bithenge_node_t
**out
)
183 static const bithenge_internal_node_ops_t empty_internal_node_ops
= {
184 .for_each
= empty_internal_node_for_each
,
185 .get
= empty_internal_node_get
,
186 .destroy
= internal_node_indestructible
,
189 static bithenge_node_t empty_internal_node
= {
190 BITHENGE_NODE_INTERNAL
,
192 { .internal_ops
= &empty_internal_node_ops
},
195 /** Create an empty internal node.
196 * @param[out] out Holds the created node.
197 * @return EOK on success or an error code from errno.h. */
198 int bithenge_new_empty_internal_node(bithenge_node_t
**out
)
200 if (bithenge_should_fail())
202 bithenge_node_inc_ref(&empty_internal_node
);
203 *out
= &empty_internal_node
;
209 bithenge_node_t base
;
210 bithenge_node_t
**nodes
;
213 } simple_internal_node_t
;
215 static simple_internal_node_t
*node_as_simple(bithenge_node_t
*node
)
217 return (simple_internal_node_t
*)node
;
220 static bithenge_node_t
*simple_as_node(simple_internal_node_t
*node
)
225 static int simple_internal_node_for_each(bithenge_node_t
*base
,
226 bithenge_for_each_func_t func
, void *data
)
229 simple_internal_node_t
*self
= node_as_simple(base
);
230 for (bithenge_int_t i
= 0; i
< self
->len
; i
++) {
231 bithenge_node_inc_ref(self
->nodes
[2*i
+0]);
232 bithenge_node_inc_ref(self
->nodes
[2*i
+1]);
233 rc
= func(self
->nodes
[2*i
+0], self
->nodes
[2*i
+1], data
);
240 static void simple_internal_node_destroy(bithenge_node_t
*base
)
242 simple_internal_node_t
*self
= node_as_simple(base
);
243 for (bithenge_int_t i
= 0; i
< 2 * self
->len
; i
++)
244 bithenge_node_dec_ref(self
->nodes
[i
]);
245 if (self
->needs_free
)
250 static bithenge_internal_node_ops_t simple_internal_node_ops
= {
251 .for_each
= simple_internal_node_for_each
,
252 .destroy
= simple_internal_node_destroy
,
255 /** Create an internal node from a set of keys and values. This function takes
256 * ownership of a reference to the key and value nodes, and optionally the
258 * @memberof bithenge_node_t
259 * @param[out] out Stores the created internal node.
260 * @param nodes The array of key-value pairs. Keys are stored at even indices
261 * and values are stored at odd indices.
262 * @param len The number of key-value pairs in the node array.
263 * @param needs_free If true, when the internal node is destroyed it will free
264 * the nodes array rather than just dereferencing each node inside it.
265 * @return EOK on success or an error code from errno.h. */
266 int bithenge_new_simple_internal_node(bithenge_node_t
**out
,
267 bithenge_node_t
**nodes
, bithenge_int_t len
, bool needs_free
)
271 simple_internal_node_t
*self
= malloc(sizeof(*self
));
276 rc
= bithenge_init_internal_node(simple_as_node(self
),
277 &simple_internal_node_ops
);
282 self
->needs_free
= needs_free
;
283 *out
= simple_as_node(self
);
286 for (bithenge_int_t i
= 0; i
< 2 * len
; i
++)
287 bithenge_node_dec_ref(nodes
[i
]);
294 static bithenge_node_t false_node
= { BITHENGE_NODE_BOOLEAN
, 1, .boolean_value
= false };
295 static bithenge_node_t true_node
= { BITHENGE_NODE_BOOLEAN
, 1, .boolean_value
= true };
297 /** Create a boolean node.
298 * @memberof bithenge_node_t
299 * @param[out] out Stores the created boolean node.
300 * @param value The value for the node to hold.
301 * @return EOK on success or an error code from errno.h. */
302 int bithenge_new_boolean_node(bithenge_node_t
**out
, bool value
)
305 if (bithenge_should_fail())
307 *out
= value
? &true_node
: &false_node
;
312 /** Create an integer node.
313 * @memberof bithenge_node_t
314 * @param[out] out Stores the created integer node.
315 * @param value The value for the node to hold.
316 * @return EOK on success or an error code from errno.h. */
317 int bithenge_new_integer_node(bithenge_node_t
**out
, bithenge_int_t value
)
320 bithenge_node_t
*self
= malloc(sizeof(*self
));
323 self
->type
= BITHENGE_NODE_INTEGER
;
325 self
->integer_value
= value
;
330 /** Create a string node.
331 * @memberof bithenge_node_t
332 * @param[out] out Stores the created string node. On error, this is unchanged.
333 * @param value The value for the node to hold.
334 * @param needs_free Whether the string should be freed when the node is
336 * @return EOK on success or an error code from errno.h. */
337 int bithenge_new_string_node(bithenge_node_t
**out
, const char *value
, bool needs_free
)
340 bithenge_node_t
*self
= malloc(sizeof(*self
));
346 self
->type
= BITHENGE_NODE_STRING
;
348 self
->string_value
.ptr
= value
;
349 self
->string_value
.needs_free
= needs_free
;
354 /** Check whether the contents of two nodes are equal. Does not yet work for
355 * internal nodes. Takes ownership of nothing.
356 * @memberof bithenge_node_t
357 * @param[out] out Holds whether the nodes are equal.
358 * @param a, b Nodes to compare.
359 * @return EOK on success or an error code from errno.h.
360 * @todo Add support for internal nodes. */
361 int bithenge_node_equal(bool *out
, bithenge_node_t
*a
, bithenge_node_t
*b
)
363 if (a
->type
!= b
->type
) {
368 case BITHENGE_NODE_INTERNAL
:
371 case BITHENGE_NODE_BOOLEAN
:
372 *out
= a
->boolean_value
== b
->boolean_value
;
374 case BITHENGE_NODE_INTEGER
:
375 *out
= a
->integer_value
== b
->integer_value
;
377 case BITHENGE_NODE_STRING
:
378 *out
= !str_cmp(a
->string_value
.ptr
, b
->string_value
.ptr
);
380 case BITHENGE_NODE_BLOB
:
381 return bithenge_blob_equal(out
, bithenge_node_as_blob(a
),
382 bithenge_node_as_blob(b
));