Skip to content

Commit

Permalink
adt: add extra features
Browse files Browse the repository at this point in the history
  • Loading branch information
zpl-zak authored May 26, 2022
1 parent cd2f59d commit 719b531
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 42 deletions.
7 changes: 7 additions & 0 deletions code/apps/examples/json_get.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ int main(void) {
zpl_json_object *num_42_node = zpl_adt_get(&root, "numbers/[value=42]");
ZPL_ASSERT_NOT_NULL(num_42_node);

zpl_json_object *arr_idx_node = zpl_adt_get(&root, "array/3");
ZPL_ASSERT_NOT_NULL(arr_idx_node);
ZPL_ASSERT(arr_idx_node->integer == 4);

zpl_json_object *arr_val_node = zpl_adt_get(&root, "array/[4]");
ZPL_ASSERT_NOT_NULL(arr_val_node);

zpl_json_free(&root);
zpl_file_free_contents(&fc);
return 0;
Expand Down
18 changes: 18 additions & 0 deletions code/header/adt.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,25 @@ ZPL_DEF zpl_u8 zpl_adt_destroy_branch(zpl_adt_node *node);

ZPL_DEF zpl_u8 zpl_adt_make_leaf(zpl_adt_node *node, char const *name, zpl_u8 type);


/**
* @brief Fetch a node using provided URI string.
*
* This method uses a basic syntax to fetch a node from the ADT. The following features are available
* to retrieve the data:
* 1) "a/b/c" navigates through objects "a" and "b" to get to "c"
* 2) "arr/[foo=123]/bar" iterates over "arr" to find any object whose param "foo" matches the value "123", then gets its field called "bar"
* 3) "arr/3" retrieves the 4th element in "arr"
* 4) "arr/[apple]" retrieves the first element of value "apple" in "arr"
*
* @param node ADT node
* @param uri Locator string as described above
* @return zpl_adt_node*
*
* @see code/apps/examples/json_get.c
*/
ZPL_DEF zpl_adt_node *zpl_adt_get(zpl_adt_node *node, char const *uri);

ZPL_DEF zpl_adt_node *zpl_adt_find(zpl_adt_node *node, char const *name, zpl_b32 deep_search);

ZPL_DEF zpl_adt_node *zpl_adt_alloc_at(zpl_adt_node *parent, zpl_isize index);
Expand Down
76 changes: 54 additions & 22 deletions code/source/adt.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ zpl_internal zpl_adt_node *zpl__adt_get_value(zpl_adt_node *node, char const *va
case ZPL_ADT_TYPE_REAL: {
char back[4096]={0};
zpl_file tmp;

/* allocate a file descriptor for a memory-mapped number to string conversion, input source buffer is not cloned, however. */
zpl_file_stream_open(&tmp, zpl_heap(), (zpl_u8*)back, zpl_size_of(back), ZPL_FILE_STREAM_WRITABLE);
zpl_adt_print_number(&tmp, node);

Expand Down Expand Up @@ -98,14 +100,17 @@ zpl_internal zpl_adt_node *zpl__adt_get_field(zpl_adt_node *node, char *name, ch

zpl_adt_node *zpl_adt_get(zpl_adt_node *node, char const *uri) {
ZPL_ASSERT_NOT_NULL(uri);
if (!node || (node->type != ZPL_ADT_TYPE_OBJECT && node->type != ZPL_ADT_TYPE_ARRAY)) {
return NULL;

if (*uri == '/') {
uri++;
}

if (*uri == 0) {
return node;
}
else if (*uri == '/') {
uri++;

if (!node || (node->type != ZPL_ADT_TYPE_OBJECT && node->type != ZPL_ADT_TYPE_ARRAY)) {
return NULL;
}

#if defined ZPL_ADT_URI_DEBUG || 0
Expand All @@ -125,48 +130,75 @@ zpl_adt_node *zpl_adt_get(zpl_adt_node *node, char const *uri) {
l_e = (char*)zpl_str_skip(l_p, '=');
l_e2 = (char*)zpl_str_skip(l_p, ']');

if (!*l_e || !*l_e2) {
if ((!*l_e && node->type != ZPL_ADT_TYPE_ARRAY) || !*l_e2) {
ZPL_ASSERT_MSG(0, "Invalid field value lookup");
return NULL;
}

*l_e = 0;
l_b2 = l_e+1;
*l_e2 = 0;

if (node->type == ZPL_ADT_TYPE_OBJECT) {
found_node = zpl__adt_get_field(node, l_b, l_b2);
/* [field=value] */
if (*l_e) {
*l_e = 0;
l_b2 = l_e+1;

/* run a value comparison against our own fields */
if (node->type == ZPL_ADT_TYPE_OBJECT) {
found_node = zpl__adt_get_field(node, l_b, l_b2);
}

/* run a value comparison against any child that is an object node */
else if (node->type == ZPL_ADT_TYPE_ARRAY) {
for (zpl_isize i = 0; i < zpl_array_count(node->nodes); i++) {
zpl_adt_node *child = &node->nodes[i];
if (child->type != ZPL_ADT_TYPE_OBJECT) {
continue;
}

found_node = zpl__adt_get_field(child, l_b, l_b2);

if (found_node)
break;
}
}
}
else if (node->type == ZPL_ADT_TYPE_ARRAY) {
/* [value] */
else {
for (zpl_isize i = 0; i < zpl_array_count(node->nodes); i++) {
zpl_adt_node *child = &node->nodes[i];
if (child->type != ZPL_ADT_TYPE_OBJECT) {
continue;
if (zpl__adt_get_value(child, l_b2)) {
found_node = child;
break; /* we found a matching value in array, ignore the rest of it */
}

found_node = zpl__adt_get_field(child, l_b, l_b2);

if (found_node)
break;
}
}

ZPL_ASSERT_NOT_NULL(found_node);

/* go deeper if uri continues */
if (*p) {
return zpl_adt_get(found_node, p+1);
if (*e) {
return zpl_adt_get(found_node, e+1);
}
}
/* handle field name lookup */
else {
else if (node->type == ZPL_ADT_TYPE_OBJECT) {
found_node = zpl_adt_find(node, buf, false);

/* go deeper if uri continues */
if (*e) {
return zpl_adt_get(found_node, e+1);
}
}
/* handle array index lookup */
else {
zpl_isize idx = (zpl_isize)zpl_str_to_i64(buf, NULL, 10);
if (idx >= 0 && idx < zpl_array_count(node->nodes)) {
found_node = &node->nodes[idx];

/* go deeper if uri continues */
if (*e) {
return zpl_adt_get(found_node, e+1);
}
}
}

return found_node;
}
Expand Down
80 changes: 60 additions & 20 deletions code/tests/cases/adt.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
MODULE(adt, {
IT("can build an ADT tree", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_inset_int(&root, "foo", 42);
zpl_adt_inset_str(&root, "bar", "life");
EQUALS(root.nodes[0].integer, 42);
STREQUALS(root.nodes[1].string, "life");
zpl_adt_destroy_branch(&root);
});
IT("can build a deeper ADT tree", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_inset_int(&root, "foo", 42);
zpl_adt_inset_str(&root, "bar", "life");
EQUALS(root.nodes[0].integer, 42);
Expand All @@ -21,11 +20,10 @@ MODULE(adt, {
zpl_adt_inset_int(array, NULL, 2);
zpl_adt_inset_int(array, NULL, 3);
EQUALS(root.nodes[2].nodes[2].integer, 3);
zpl_adt_destroy_branch(&root);
});
IT("can find a node within ADT tree", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_inset_int(&root, "foo", 42);
zpl_adt_inset_str(&root, "bar", "life");
zpl_adt_inset_str(&root, "question", "answer");
Expand All @@ -35,11 +33,10 @@ MODULE(adt, {
zpl_adt_node *question_node = zpl_adt_find(&root, "question", false);
STREQUALS(question_node->string, "answer");

zpl_adt_destroy_branch(&root);
});
IT("can find a node buried deep within ADT tree", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_inset_int(&root, "foo", 42);
zpl_adt_inset_str(&root, "bar", "life");

Expand All @@ -53,49 +50,92 @@ MODULE(adt, {
zpl_adt_node *question_node = zpl_adt_find(&root, "question", true);
STREQUALS(question_node->string, "answer");

zpl_adt_destroy_branch(&root);
});
IT("can swap 2 nodes", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_node *n1 = zpl_adt_inset_int(&root, "foo", 42);
zpl_adt_node *n2 = zpl_adt_inset_str(&root, "bar", "life");
zpl_adt_swap_nodes(n1, n2, &root);
EQUALS(root.nodes[1].integer, 42);
STREQUALS(root.nodes[0].string, "life");
zpl_adt_destroy_branch(&root);
});
IT("can swap 2 nodes between 2 parents", {
zpl_adt_node root, root2;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root2, "root2", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_set_obj(&root2, "root2", mem_alloc);
zpl_adt_node *n1 = zpl_adt_inset_int(&root, "foo", 42);
zpl_adt_node *n2 = zpl_adt_inset_str(&root2, "bar", "life");
zpl_adt_swap_nodes_between_parents(n1, n2, &root, &root2);
EQUALS(root2.nodes[0].integer, 42);
STREQUALS(root.nodes[0].string, "life");
zpl_adt_destroy_branch(&root);
zpl_adt_destroy_branch(&root2);
});
IT("can remove a node from tree", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_node *n1 = zpl_adt_inset_int(&root, "foo", 42);
zpl_adt_remove_node(n1, &root);
EQUALS(zpl_array_count(root.nodes), 0);
zpl_adt_destroy_branch(&root);
});
IT("can move a node from one parent to another", {
zpl_adt_node root, root2;
zpl_adt_set_obj(&root, "root", zpl_heap());
zpl_adt_set_obj(&root2, "root2", zpl_heap());
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_set_obj(&root2, "root2", mem_alloc);
zpl_adt_node *n1 = zpl_adt_inset_int(&root, "foo", 42);
EQUALS(root.nodes[0].integer, 42);
EQUALS(zpl_array_count(root2.nodes), 0);
zpl_adt_move_node(n1, &root, &root2);
EQUALS(root2.nodes[0].integer, 42);
EQUALS(zpl_array_count(root.nodes), 0);
zpl_adt_destroy_branch(&root);
zpl_adt_destroy_branch(&root2);
});
IT("can find a nested node in a tree", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_node *a = zpl_adt_inset_obj(&root, "a");
zpl_adt_node *b = zpl_adt_inset_obj(a, "b");
zpl_adt_node *c = zpl_adt_inset_obj(b, "c");

zpl_adt_node *node = zpl_adt_get(&root, "a/b/c");

EQUALS(c, node);
});
IT("can find a node in an array where an object matches param=value", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_node *arr = zpl_adt_inset_arr(&root, "arr");

zpl_adt_node *a = zpl_adt_inset_obj(arr, 0);
zpl_adt_inset_int(a, "foo", 456);
zpl_adt_node *a2 = zpl_adt_inset_obj(arr, 0);
zpl_adt_inset_int(a2, "foo", 123);
zpl_adt_node *a3 = zpl_adt_inset_obj(arr, 0);
zpl_adt_inset_int(a3, "foo", 789);
zpl_adt_node *node = zpl_adt_get(&root, "arr/[foo=123]");

EQUALS(a2, node);
});
IT("can retrieve a node in an array at a specific index", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_node *arr = zpl_adt_inset_arr(&root, "arr");

zpl_adt_inset_int(arr, 0, 1);
zpl_adt_inset_int(arr, 0, 2);
zpl_adt_inset_int(arr, 0, 3);
zpl_adt_node *node = zpl_adt_get(&root, "arr/1");

EQUALS(2, node->integer);
});
IT("can find a node in an array of a specific value", {
zpl_adt_node root;
zpl_adt_set_obj(&root, "root", mem_alloc);
zpl_adt_node *arr = zpl_adt_inset_arr(&root, "arr");

zpl_adt_inset_int(arr, "1", 1);
zpl_adt_inset_int(arr, "2", 2);
zpl_adt_inset_int(arr, "3", 3);
zpl_adt_node *node = zpl_adt_get(&root, "arr/[2]");

EQUALS(2, node->integer);
});
});
4 changes: 4 additions & 0 deletions misc/data/glsl_diffuse.json5
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
{ value: 68 }
],

array: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
],

/* GLSL shader code */
code: `
uniform vec3 l_pos;
Expand Down

0 comments on commit 719b531

Please sign in to comment.