HelenOS sources
This source file includes following definitions.
- blob_destroy
- node_destroy
- bithenge_node_dec_ref
- get_for_each_func
- bithenge_node_get
- bithenge_init_internal_node
- internal_node_indestructible
- empty_internal_node_for_each
- empty_internal_node_get
- bithenge_new_empty_internal_node
- node_as_simple
- simple_as_node
- simple_internal_node_for_each
- simple_internal_node_destroy
- bithenge_new_simple_internal_node
- bithenge_new_boolean_node
- bithenge_new_integer_node
- bithenge_new_string_node
- bithenge_node_equal
#include <errno.h>
#include <stdlib.h>
#include <bithenge/blob.h>
#include <bithenge/tree.h>
#include "common.h"
static void blob_destroy(bithenge_node_t *base)
{
bithenge_blob_t *self = bithenge_node_as_blob(base);
assert(self->base.blob_ops);
self->base.blob_ops->destroy(self);
}
static void node_destroy(bithenge_node_t *self)
{
switch (bithenge_node_type(self)) {
case BITHENGE_NODE_BLOB:
blob_destroy(self);
return;
case BITHENGE_NODE_STRING:
if (self->string_value.needs_free)
free((void *)self->string_value.ptr);
break;
case BITHENGE_NODE_INTERNAL:
self->internal_ops->destroy(self);
return;
case BITHENGE_NODE_BOOLEAN:
return;
case BITHENGE_NODE_INTEGER:
break;
}
free(self);
}
void bithenge_node_dec_ref(bithenge_node_t *node)
{
if (!node)
return;
assert (node->refs > 0);
if (--node->refs == 0)
node_destroy(node);
}
typedef struct {
bithenge_node_t *key;
bithenge_node_t **out;
} get_for_each_data_t;
static errno_t get_for_each_func(bithenge_node_t *key, bithenge_node_t *value,
void *raw_data)
{
get_for_each_data_t *data = (get_for_each_data_t *)raw_data;
bool equal;
errno_t rc = bithenge_node_equal(&equal, key, data->key);
bithenge_node_dec_ref(key);
if (rc != EOK)
return rc;
if (equal) {
*data->out = value;
return EEXIST;
}
bithenge_node_dec_ref(value);
return EOK;
}
errno_t bithenge_node_get(bithenge_node_t *self, bithenge_node_t *key,
bithenge_node_t **out)
{
if (self->type == BITHENGE_NODE_BLOB) {
if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
bithenge_node_dec_ref(key);
return ENOENT;
}
bithenge_int_t offset = bithenge_integer_node_value(key);
bithenge_node_dec_ref(key);
uint8_t byte;
aoff64_t size = 1;
errno_t rc = bithenge_blob_read(bithenge_node_as_blob(self),
offset, (char *)&byte, &size);
if (rc != EOK)
return rc;
if (size != 1)
return ENOENT;
return bithenge_new_integer_node(out, byte);
}
assert(self->type == BITHENGE_NODE_INTERNAL);
if (self->internal_ops->get)
return self->internal_ops->get(self, key, out);
*out = NULL;
get_for_each_data_t data = { key, out };
errno_t rc = bithenge_node_for_each(self, get_for_each_func, &data);
bithenge_node_dec_ref(key);
if (rc == EEXIST && *out)
return EOK;
if (rc == EOK)
rc = ENOENT;
bithenge_node_dec_ref(*out);
return rc;
}
errno_t bithenge_init_internal_node(bithenge_node_t *self,
const bithenge_internal_node_ops_t *ops)
{
self->type = BITHENGE_NODE_INTERNAL;
self->refs = 1;
self->internal_ops = ops;
return EOK;
}
static void internal_node_indestructible(bithenge_node_t *self)
{
assert(false);
}
static errno_t empty_internal_node_for_each(bithenge_node_t *base,
bithenge_for_each_func_t func, void *data)
{
return EOK;
}
static errno_t empty_internal_node_get(bithenge_node_t *self, bithenge_node_t *key,
bithenge_node_t **out)
{
return ENOENT;
}
static const bithenge_internal_node_ops_t empty_internal_node_ops = {
.for_each = empty_internal_node_for_each,
.get = empty_internal_node_get,
.destroy = internal_node_indestructible,
};
static bithenge_node_t empty_internal_node = {
BITHENGE_NODE_INTERNAL,
1,
{ .internal_ops = &empty_internal_node_ops },
};
errno_t bithenge_new_empty_internal_node(bithenge_node_t **out)
{
if (bithenge_should_fail())
return ENOMEM;
bithenge_node_inc_ref(&empty_internal_node);
*out = &empty_internal_node;
return EOK;
}
typedef struct {
bithenge_node_t base;
bithenge_node_t **nodes;
bithenge_int_t len;
bool needs_free;
} simple_internal_node_t;
static simple_internal_node_t *node_as_simple(bithenge_node_t *node)
{
return (simple_internal_node_t *)node;
}
static bithenge_node_t *simple_as_node(simple_internal_node_t *node)
{
return &node->base;
}
static errno_t simple_internal_node_for_each(bithenge_node_t *base,
bithenge_for_each_func_t func, void *data)
{
errno_t rc;
simple_internal_node_t *self = node_as_simple(base);
for (bithenge_int_t i = 0; i < self->len; i++) {
bithenge_node_inc_ref(self->nodes[2 * i + 0]);
bithenge_node_inc_ref(self->nodes[2 * i + 1]);
rc = func(self->nodes[2 * i + 0], self->nodes[2 * i + 1], data);
if (rc != EOK)
return rc;
}
return EOK;
}
static void simple_internal_node_destroy(bithenge_node_t *base)
{
simple_internal_node_t *self = node_as_simple(base);
for (bithenge_int_t i = 0; i < 2 * self->len; i++)
bithenge_node_dec_ref(self->nodes[i]);
if (self->needs_free)
free(self->nodes);
free(self);
}
static bithenge_internal_node_ops_t simple_internal_node_ops = {
.for_each = simple_internal_node_for_each,
.destroy = simple_internal_node_destroy,
};
errno_t bithenge_new_simple_internal_node(bithenge_node_t **out,
bithenge_node_t **nodes, bithenge_int_t len, bool needs_free)
{
errno_t rc;
assert(out);
simple_internal_node_t *self = malloc(sizeof(*self));
if (!self) {
rc = ENOMEM;
goto error;
}
rc = bithenge_init_internal_node(simple_as_node(self),
&simple_internal_node_ops);
if (rc != EOK)
goto error;
self->nodes = nodes;
self->len = len;
self->needs_free = needs_free;
*out = simple_as_node(self);
return EOK;
error:
for (bithenge_int_t i = 0; i < 2 * len; i++)
bithenge_node_dec_ref(nodes[i]);
if (needs_free)
free(nodes);
free(self);
return rc;
}
static bithenge_node_t false_node = { BITHENGE_NODE_BOOLEAN, 1, .boolean_value = false };
static bithenge_node_t true_node = { BITHENGE_NODE_BOOLEAN, 1, .boolean_value = true };
errno_t bithenge_new_boolean_node(bithenge_node_t **out, bool value)
{
assert(out);
if (bithenge_should_fail())
return ENOMEM;
*out = value ? &true_node : &false_node;
(*out)->refs++;
return EOK;
}
errno_t bithenge_new_integer_node(bithenge_node_t **out, bithenge_int_t value)
{
assert(out);
bithenge_node_t *self = malloc(sizeof(*self));
if (!self)
return ENOMEM;
self->type = BITHENGE_NODE_INTEGER;
self->refs = 1;
self->integer_value = value;
*out = self;
return EOK;
}
errno_t bithenge_new_string_node(bithenge_node_t **out, const char *value, bool needs_free)
{
assert(out);
bithenge_node_t *self = malloc(sizeof(*self));
if (!self) {
if (needs_free)
free((void *)value);
return ENOMEM;
}
self->type = BITHENGE_NODE_STRING;
self->refs = 1;
self->string_value.ptr = value;
self->string_value.needs_free = needs_free;
*out = self;
return EOK;
}
errno_t bithenge_node_equal(bool *out, bithenge_node_t *a, bithenge_node_t *b)
{
if (a->type != b->type) {
*out = false;
return EOK;
}
switch (a->type) {
case BITHENGE_NODE_INTERNAL:
*out = false;
return EOK;
case BITHENGE_NODE_BOOLEAN:
*out = a->boolean_value == b->boolean_value;
return EOK;
case BITHENGE_NODE_INTEGER:
*out = a->integer_value == b->integer_value;
return EOK;
case BITHENGE_NODE_STRING:
*out = !str_cmp(a->string_value.ptr, b->string_value.ptr);
return EOK;
case BITHENGE_NODE_BLOB:
return bithenge_blob_equal(out, bithenge_node_as_blob(a),
bithenge_node_as_blob(b));
}
return EINVAL;
}
HelenOS homepage, sources at GitHub