aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-12-20 13:02:24 -0500
committerDavid Robillard <d@drobilla.net>2022-01-14 19:37:51 -0500
commit94eeeadeb5be3d9c9266bed5d3c32c6ff29695b4 (patch)
treed1c6de5dc7985f2f602ddd7daf9b24a2a5cd0945
parent4ac6d94d9a8826e09b81c6505408bed44d11e567 (diff)
downloadserd-94eeeadeb5be3d9c9266bed5d3c32c6ff29695b4.tar.gz
serd-94eeeadeb5be3d9c9266bed5d3c32c6ff29695b4.tar.bz2
serd-94eeeadeb5be3d9c9266bed5d3c32c6ff29695b4.zip
Add serd_node_compare()
-rw-r--r--include/serd/serd.h15
-rw-r--r--src/node.c27
-rw-r--r--src/node.h6
-rw-r--r--test/test_node.c51
4 files changed, 99 insertions, 0 deletions
diff --git a/include/serd/serd.h b/include/serd/serd.h
index 4067fa3f..5d0f7290 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -878,6 +878,21 @@ serd_node_equals(const SerdNode* SERD_NULLABLE a,
const SerdNode* SERD_NULLABLE b);
/**
+ Compare two nodes.
+
+ Returns less than, equal to, or greater than zero if `a` is less than, equal
+ to, or greater than `b`, respectively. NULL is treated as less than any
+ other node.
+
+ Nodes are ordered first by type, then by string value, then by language or
+ datatype, if present.
+*/
+SERD_PURE_API
+int
+serd_node_compare(const SerdNode* SERD_NONNULL a,
+ const SerdNode* SERD_NONNULL b);
+
+/**
@}
@defgroup serd_nodes Nodes
@{
diff --git a/src/node.c b/src/node.c
index 608f8bfb..fc9869a8 100644
--- a/src/node.c
+++ b/src/node.c
@@ -428,6 +428,33 @@ serd_node_equals(const SerdNode* const a, const SerdNode* const b)
return true;
}
+int
+serd_node_compare(const SerdNode* const a, const SerdNode* const b)
+{
+ assert(a);
+ assert(b);
+
+ int cmp = 0;
+
+ if ((cmp = ((int)a->type - (int)b->type)) ||
+ (cmp = strcmp(serd_node_string_i(a), serd_node_string_i(b))) ||
+ (cmp = ((int)a->flags - (int)b->flags)) ||
+ !(a->flags & (SERD_HAS_LANGUAGE | SERD_HAS_DATATYPE))) {
+ return cmp;
+ }
+
+ assert(a->flags == b->flags);
+ assert(a->flags & (SERD_HAS_LANGUAGE | SERD_HAS_DATATYPE));
+ assert(b->flags & (SERD_HAS_LANGUAGE | SERD_HAS_DATATYPE));
+ const SerdNode* const ma = serd_node_meta_c(a);
+ const SerdNode* const mb = serd_node_meta_c(b);
+
+ assert(ma->type == mb->type);
+ assert(ma->flags == mb->flags);
+
+ return strcmp(serd_node_string_i(ma), serd_node_string_i(mb));
+}
+
SerdNode*
serd_new_uri(const SerdStringView str)
{
diff --git a/src/node.h b/src/node.h
index eed7cb04..29164dc2 100644
--- a/src/node.h
+++ b/src/node.h
@@ -43,6 +43,12 @@ serd_node_buffer_c(const SerdNode* SERD_NONNULL node)
return (const char*)(node + 1);
}
+static inline const char* SERD_NONNULL
+serd_node_string_i(const SerdNode* const SERD_NONNULL node)
+{
+ return (const char*)(node + 1);
+}
+
SerdNode* SERD_ALLOCATED
serd_node_malloc(size_t length, SerdNodeFlags flags, SerdNodeType type);
diff --git a/test/test_node.c b/test/test_node.c
index 466655ef..72bd44e1 100644
--- a/test/test_node.c
+++ b/test/test_node.c
@@ -532,6 +532,56 @@ test_blank(void)
serd_node_free(blank);
}
+static void
+test_compare(void)
+{
+ SerdNode* xsd_short =
+ serd_new_uri(SERD_STRING("http://www.w3.org/2001/XMLSchema#short"));
+
+ SerdNode* angst =
+ serd_new_plain_literal(SERD_STRING("angst"), SERD_EMPTY_STRING());
+
+ SerdNode* angst_de =
+ serd_new_plain_literal(SERD_STRING("angst"), SERD_STRING("de"));
+
+ SerdNode* angst_en =
+ serd_new_plain_literal(SERD_STRING("angst"), SERD_STRING("en"));
+
+ SerdNode* hallo =
+ serd_new_plain_literal(SERD_STRING("Hallo"), SERD_STRING("de"));
+
+ SerdNode* hello = serd_new_string(SERD_STRING("Hello"));
+ SerdNode* universe = serd_new_string(SERD_STRING("Universe"));
+ SerdNode* integer = serd_new_integer(4, NULL);
+ SerdNode* short_integer = serd_new_integer(4, xsd_short);
+ SerdNode* blank = serd_new_blank(SERD_STRING("b1"));
+ SerdNode* uri = serd_new_uri(SERD_STRING("http://example.org/"));
+
+ // Types are ordered according to their SerdNodeType (more or less arbitrary)
+ assert(serd_node_compare(hello, uri) < 0);
+ assert(serd_node_compare(uri, blank) < 0);
+
+ // If the types are the same, then strings are compared
+ assert(serd_node_compare(hello, universe) < 0);
+
+ // If literal strings are the same, languages or datatypes are compared
+ assert(serd_node_compare(angst, angst_de) < 0);
+ assert(serd_node_compare(angst_de, angst_en) < 0);
+ assert(serd_node_compare(integer, short_integer) < 0);
+
+ serd_node_free(uri);
+ serd_node_free(blank);
+ serd_node_free(short_integer);
+ serd_node_free(integer);
+ serd_node_free(universe);
+ serd_node_free(hello);
+ serd_node_free(hallo);
+ serd_node_free(angst_en);
+ serd_node_free(angst_de);
+ serd_node_free(angst);
+ serd_node_free(xsd_short);
+}
+
int
main(void)
{
@@ -552,6 +602,7 @@ main(void)
test_simple_node();
test_literal();
test_blank();
+ test_compare();
printf("Success\n");
return 0;