1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:57:45 +00:00

LibC: Implement twalk

This commit is contained in:
Tim Schumacher 2021-10-14 20:46:26 +02:00 committed by Brian Gianforcaro
parent 7448626bae
commit 4b423a5ec7
3 changed files with 145 additions and 0 deletions

View file

@ -6,6 +6,7 @@
#include <LibTest/TestCase.h> #include <LibTest/TestCase.h>
#include <AK/Format.h>
#include <bits/search.h> #include <bits/search.h>
#include <search.h> #include <search.h>
#include <string.h> #include <string.h>
@ -13,6 +14,17 @@
#define NODE(node) static_cast<struct search_tree_node*>(node) #define NODE(node) static_cast<struct search_tree_node*>(node)
#define ROOTP(root) reinterpret_cast<void**>(root) #define ROOTP(root) reinterpret_cast<void**>(root)
#define COMP(func) reinterpret_cast<int (*)(const void*, const void*)>(func) #define COMP(func) reinterpret_cast<int (*)(const void*, const void*)>(func)
#define U8(value) static_cast<u8>(value)
struct twalk_test_entry {
const void* node;
VISIT order;
int depth;
};
#define TWALK_SET_DATA (-2)
#define TWALK_CHECK_END (-3)
#define TWALK_END_MARKER (-4)
TEST_CASE(tsearch) TEST_CASE(tsearch)
{ {
@ -137,3 +149,104 @@ TEST_CASE(tfind)
delete_node_recursive(root); delete_node_recursive(root);
} }
void twalk_action(const void* node, VISIT order, int depth);
void twalk_action(const void* node, VISIT order, int depth)
{
static int count = 0;
static const struct twalk_test_entry* tests = nullptr;
// Special case: Set test data.
if (depth == TWALK_SET_DATA) {
count = 0;
tests = static_cast<const struct twalk_test_entry*>(node);
return;
}
// Special case: End signaled by tester.
if (depth == TWALK_CHECK_END) {
if (tests[count].depth != TWALK_END_MARKER) {
FAIL(String::formatted("Expected action (node={:#x}, order={}, depth={}), but twalk ended early.",
tests[count].node, U8(tests[count].order), tests[count].depth));
}
return;
}
// Special case: End marker reached.
if (tests[count].depth == TWALK_END_MARKER) {
FAIL(String::formatted("Expected end, but twalk sent another action (node={:#x}, order={}, depth={}).",
node, U8(order), depth));
return;
}
EXPECT_EQ(node, tests[count].node);
EXPECT_EQ(U8(order), U8(tests[count].order));
EXPECT_EQ(depth, tests[count].depth);
count++;
}
TEST_CASE(twalk)
{
struct search_tree_node* root = nullptr;
// Try an empty tree.
struct twalk_test_entry tests1[] = {
{ nullptr, leaf, TWALK_END_MARKER },
};
twalk_action(tests1, leaf, TWALK_SET_DATA);
twalk(nullptr, twalk_action);
twalk_action(nullptr, leaf, TWALK_CHECK_END);
// Try a single node.
root = new_tree_node("5");
struct twalk_test_entry tests2[] = {
{ root, leaf, 0 },
{ nullptr, leaf, TWALK_END_MARKER },
};
twalk_action(tests2, leaf, TWALK_SET_DATA);
twalk(root, twalk_action);
twalk_action(nullptr, leaf, TWALK_CHECK_END);
// Try two layers of nodes.
root->left = new_tree_node("3");
root->right = new_tree_node("7");
struct twalk_test_entry tests3[] = {
{ root, preorder, 0 },
{ root->left, leaf, 1 },
{ root, postorder, 0 },
{ root->right, leaf, 1 },
{ root, endorder, 0 },
{ nullptr, leaf, TWALK_END_MARKER },
};
twalk_action(tests3, leaf, TWALK_SET_DATA);
twalk(root, twalk_action);
twalk_action(nullptr, leaf, TWALK_CHECK_END);
// Try three layers of nodes.
root->left->left = new_tree_node("2");
root->left->right = new_tree_node("4");
root->right->left = new_tree_node("6");
root->right->right = new_tree_node("8");
struct twalk_test_entry tests4[] = {
{ root, preorder, 0 },
{ root->left, preorder, 1 },
{ root->left->left, leaf, 2 },
{ root->left, postorder, 1 },
{ root->left->right, leaf, 2 },
{ root->left, endorder, 1 },
{ root, postorder, 0 },
{ root->right, preorder, 1 },
{ root->right->left, leaf, 2 },
{ root->right, postorder, 1 },
{ root->right->right, leaf, 2 },
{ root->right, endorder, 1 },
{ root, endorder, 0 },
{ nullptr, leaf, TWALK_END_MARKER },
};
twalk_action(tests4, leaf, TWALK_SET_DATA);
twalk(root, twalk_action);
twalk_action(nullptr, leaf, TWALK_CHECK_END);
delete_node_recursive(root);
}

View file

@ -89,4 +89,28 @@ void* tfind(const void* key, void* const* rootp, int (*comparator)(const void*,
return nullptr; return nullptr;
} }
static void twalk_internal(const struct search_tree_node* node, void (*action)(const void*, VISIT, int), int depth)
{
if (!node)
return;
if (!node->right && !node->left) {
action(node, leaf, depth);
return;
}
action(node, preorder, depth);
twalk_internal(node->left, action, depth + 1);
action(node, postorder, depth);
twalk_internal(node->right, action, depth + 1);
action(node, endorder, depth);
}
void twalk(const void* rootp, void (*action)(const void*, VISIT, int))
{
auto node = static_cast<const struct search_tree_node*>(rootp);
twalk_internal(node, action, 0);
}
} }

View file

@ -8,7 +8,15 @@
__BEGIN_DECLS __BEGIN_DECLS
typedef enum {
preorder,
postorder,
endorder,
leaf,
} VISIT;
void* tsearch(const void*, void**, int (*)(const void*, const void*)); void* tsearch(const void*, void**, int (*)(const void*, const void*));
void* tfind(const void*, void* const*, int (*)(const void*, const void*)); void* tfind(const void*, void* const*, int (*)(const void*, const void*));
void twalk(const void*, void (*)(const void*, VISIT, int));
__END_DECLS __END_DECLS