Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node properties #54

Merged
merged 2 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions graph.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "graph.h"
#include "allocator.h"
#include <string.h>

struct Graph {
Node *head;
Expand All @@ -8,13 +9,24 @@ struct Graph {
struct Node {
Node *next;
Edge *edges;
NodeProperty *properties;
NodeType type;
union {
Formation *formation;
Climb *climb;
} data;
};

struct NodeProperty {
NodePropertyType type;
char *key;
union {
char *string;
} data;

NodeProperty *next;
};

struct Edge {
Node *node;
Edge *next;
Expand Down Expand Up @@ -45,6 +57,7 @@ Node *Node_new()
if ((node = climblib_malloc(sizeof(Node)))) {
node->next = NULL;
node->edges = NULL;
node->properties = NULL;
node->type = NodeType_UNDEFINED;
}

Expand Down Expand Up @@ -182,6 +195,94 @@ Climb *Node_get_climb(const Node *node)
}
}

NodeProperty *Node_property(const Node *node, const char *name)
{
NodeProperty *property;

property = node->properties;

while (property != NULL && strcmp(name, property->key)) {
property = property->next;
}

return property;
}

void Node_add_property(Node *node, const char *name, NodeProperty *property)
{
property->key = strdup(name);

if (node->properties) {
NodeProperty *last = node->properties;
while (last->next != NULL) {
last = last->next;
}

last->next = property;
} else {
node->properties = property;
}
}

NodeProperty *Node_remove_property(Node *node, const char *name)
{
NodeProperty *property = node->properties;
NodeProperty *previous = NULL;

while (property != NULL && strcmp(name, property->key)) {
previous = property;
property = property->next;
}

if (property == NULL) {
return NULL;
}

if (previous == NULL) {
node->properties = property->next;
} else {
previous->next = property->next;
}

return property;
}

NodeProperty *NodeProperty_new_string(const char *string)
{
NodeProperty *property;

if ((property = climblib_malloc(sizeof(NodeProperty)))) {
property->type = NodePropertyType_String;
property->key = NULL;
property->data.string = strdup(string);
property->next = NULL;
}

return property;
}

NodePropertyType NodeProperty_type(const NodeProperty *property)
{
return property->type;
}

int NodeProperty_string(const NodeProperty *property, const char **string)
{
*string = property->data.string;
return 0;
}

void NodeProperty_free(NodeProperty *property)
{
if (property) {
climblib_free(property->data.string);

if (property->key) climblib_free(property->key);

climblib_free(property);
}
}

Node *Edge_get_node(Edge *edge)
{
return edge->node;
Expand Down
49 changes: 49 additions & 0 deletions graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ typedef enum {

// TODO Edges should only make sense if the nodes are in the same graph

/**
* @brief A node property
*/
typedef struct NodeProperty NodeProperty;

/**
* @brief A node property type
*/
typedef enum {
NodePropertyType_String,
} NodePropertyType;

/**
* @brief An opaque edge between two nodes
*/
Expand Down Expand Up @@ -111,6 +123,43 @@ Formation *Node_get_formation(const Node *);
*/
Climb *Node_get_climb(const Node *);

/**
* @brief Gets named property from node.
*/
NodeProperty *Node_property(const Node *, const char *);

/**
* @brief Adds named property to node.
*/
void Node_add_property(Node *, const char *, NodeProperty *);

/**
* @brief Removes a named property.
*/
NodeProperty *Node_remove_property(Node *, const char *);

/**
* @brief Creates a new string node property.
*/
NodeProperty *NodeProperty_new_string(const char *);

/**
* @brief Gets the type of the prop.erty
*/
NodePropertyType NodeProperty_type(const NodeProperty *);

/**
* @brief Gets the string property.
*
* @returns 0 on success, non-zero otherwise.
*/
int NodeProperty_string(const NodeProperty *, const char **);

/**
* @brief Frees a @ref NodeProperty.
*/
void NodeProperty_free(NodeProperty *);

/**
* @brief Gets the end-node of an edge
*/
Expand Down
70 changes: 69 additions & 1 deletion tests/graph.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <check.h>
#include <stdlib.h>
#include <string.h>

#include "graph.h"
#include "climb.h"
Expand Down Expand Up @@ -157,10 +158,72 @@ START_TEST(test_edges)
}
END_TEST

START_TEST(test_node_str_props)
{
NodeProperty *prop;
char str[] = "abcdefg";
const char *result;

NodeProperty_free(NULL);

climblib_set_alloc(bad_malloc, NULL, NULL);
ck_assert_ptr_null(prop = NodeProperty_new_string(str));
climblib_set_alloc(NULL, NULL, NULL);

ck_assert_ptr_nonnull(prop = NodeProperty_new_string(str));
ck_assert_int_eq(NodeProperty_type(prop), NodePropertyType_String);
ck_assert_int_eq(NodeProperty_string(prop, &result), 0);
ck_assert_ptr_nonnull(result);
ck_assert_int_eq(strcmp(str, result), 0);

NodeProperty_free(prop);
}
END_TEST

START_TEST(test_add_node_property)
{
Climb *climb;
Node *node;
NodeProperty *prop1, *prop2, *prop3;
const char key1[] = "key1";
const char key2[] = "key2";
const char key3[] = "key3";

climb = Climb_new();
node = Node_new_climb(climb);
prop1 = NodeProperty_new_string("value1");
prop2 = NodeProperty_new_string("value2");
prop3 = NodeProperty_new_string("value3");

ck_assert_ptr_null(Node_remove_property(node, key1));

Node_add_property(node, key1, prop1);
ck_assert_ptr_eq(Node_property(node, key1), prop1);

Node_add_property(node, key2, prop2);
ck_assert_ptr_eq(Node_property(node, key2), prop2);

Node_add_property(node, key3, prop3);
ck_assert_ptr_eq(Node_property(node, key3), prop3);

ck_assert_ptr_eq(Node_remove_property(node, key1), prop1);
ck_assert_ptr_null(Node_property(node, key1));

ck_assert_ptr_eq(Node_remove_property(node, key3), prop3);
ck_assert_ptr_null(Node_property(node, key3));

NodeProperty_free(prop1);
NodeProperty_free(prop2);
NodeProperty_free(prop3);
Node_free(node);
Climb_free(climb);
}
END_TEST

static Suite *suite()
{
Suite *s;
TCase *tc_core;
TCase *tc_core, *tc_node_props;

s = suite_create("Graph");

Expand All @@ -171,7 +234,12 @@ static Suite *suite()
tcase_add_test(tc_core, test_climb_node);
tcase_add_test(tc_core, test_edges);

tc_node_props = tcase_create("Node Properties");
tcase_add_test(tc_node_props, test_node_str_props);
tcase_add_test(tc_node_props, test_add_node_property);

suite_add_tcase(s, tc_core);
suite_add_tcase(s, tc_node_props);

return s;
}
Expand Down