From 955be33cead7596506cf86211da6b0e53827ef96 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 22 Jul 2021 18:35:31 -0400 Subject: Avoid dynamic allocation when fetching interned nodes This is more or less a total rewrite of SerdNodes and the underlying ZixHash to make efficient use of the new node construction API. --- test/test_nodes.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 256 insertions(+), 26 deletions(-) (limited to 'test/test_nodes.c') diff --git a/test/test_nodes.c b/test/test_nodes.c index 74c99c11..c841acc4 100644 --- a/test/test_nodes.c +++ b/test/test_nodes.c @@ -19,9 +19,12 @@ #include "serd/serd.h" #include +#include #include #include +#define NS_XSD "http://www.w3.org/2001/XMLSchema#" + static void test_intern(void) { @@ -44,24 +47,6 @@ test_intern(void) serd_nodes_free(nodes); } -static void -test_manage(void) -{ - SerdNodes* nodes = serd_nodes_new(); - SerdNode* node = serd_new_string(SERD_STRING("node")); - - assert(!serd_nodes_manage(nodes, NULL)); - - const SerdNode* managed1 = serd_nodes_manage(nodes, node); - assert(managed1 == node); - - SerdNode* equal = serd_new_string(SERD_STRING("node")); - const SerdNode* managed2 = serd_nodes_manage(nodes, equal); - assert(managed2 == node); - - serd_nodes_free(nodes); -} - static void test_string(void) { @@ -80,6 +65,29 @@ test_string(void) serd_nodes_free(nodes); } +static void +test_invalid_literal(void) +{ + SerdNodes* const nodes = serd_nodes_new(); + + assert(!serd_nodes_literal(nodes, + SERD_STRING("double meta"), + SERD_HAS_LANGUAGE | SERD_HAS_DATATYPE, + SERD_STRING("What am I?"))); + + assert(!serd_nodes_literal(nodes, + SERD_STRING("empty language"), + SERD_HAS_LANGUAGE, + SERD_EMPTY_STRING())); + + assert(!serd_nodes_literal(nodes, + SERD_STRING("empty datatype"), + SERD_HAS_DATATYPE, + SERD_EMPTY_STRING())); + + serd_nodes_free(nodes); +} + static void test_plain_literal(void) { @@ -102,6 +110,24 @@ test_plain_literal(void) assert(serd_node_length(node) == string.len); assert(!strcmp(serd_node_string(node), string.buf)); + const SerdNode* const alias = + serd_nodes_literal(nodes, string, SERD_HAS_LANGUAGE, language); + + assert(alias == node); + + const SerdNode* const other = + serd_nodes_literal(nodes, string, SERD_HAS_LANGUAGE, SERD_STRING("de")); + + assert(other != node); + + const SerdNode* const other_language_node = serd_node_language(other); + assert(other_language_node); + assert(serd_node_type(other_language_node) == SERD_LITERAL); + assert(serd_node_length(other_language_node) == 2); + assert(!strcmp(serd_node_string(other_language_node), "de")); + assert(serd_node_length(other) == string.len); + assert(!strcmp(serd_node_string(other), string.buf)); + serd_nodes_free(nodes); } @@ -128,6 +154,152 @@ test_typed_literal(void) assert(serd_node_length(node) == string.len); assert(!strcmp(serd_node_string(node), string.buf)); + const SerdNode* const alias = + serd_nodes_literal(nodes, string, SERD_HAS_DATATYPE, datatype); + + assert(alias == node); + + serd_nodes_free(nodes); +} + +static void +test_boolean(void) +{ + SerdNodes* const nodes = serd_nodes_new(); + + const SerdNode* const false1 = serd_nodes_boolean(nodes, false); + const SerdNode* const false2 = serd_nodes_boolean(nodes, false); + const SerdNode* const true1 = serd_nodes_boolean(nodes, true); + const SerdNode* const true2 = serd_nodes_boolean(nodes, true); + + assert(false1 == false2); + assert(true1 == true2); + assert(false1 != true1); + assert(!strcmp(serd_node_string(false1), "false")); + assert(!strcmp(serd_node_string(true1), "true")); + assert(serd_node_length(false1) == strlen(serd_node_string(false1))); + assert(serd_node_length(true1) == strlen(serd_node_string(true1))); + assert(serd_nodes_size(nodes) == 2); + + const SerdNode* const true_datatype = serd_node_datatype(true1); + assert(true_datatype); + assert(!strcmp(serd_node_string(true_datatype), NS_XSD "boolean")); + + const SerdNode* const false_datatype = serd_node_datatype(false1); + assert(false_datatype); + assert(!strcmp(serd_node_string(false_datatype), NS_XSD "boolean")); + + serd_nodes_free(nodes); +} + +static void +test_decimal(void) +{ + SerdNodes* const nodes = serd_nodes_new(); + const SerdNode* const a = serd_nodes_decimal(nodes, -12.3456789); + const SerdNode* const b = serd_nodes_decimal(nodes, -12.3456789); + + assert(a == b); + assert(!strcmp(serd_node_string(a), "-12.3456789")); + assert(serd_node_length(a) == strlen(serd_node_string(a))); + assert(serd_nodes_size(nodes) == 1); + + const SerdNode* const default_datatype = serd_node_datatype(a); + assert(default_datatype); + assert(!strcmp(serd_node_string(default_datatype), NS_XSD "decimal")); + + serd_nodes_free(nodes); +} + +static void +test_double(void) +{ + SerdNodes* const nodes = serd_nodes_new(); + + const SerdNode* const a = serd_nodes_double(nodes, -1.2E3); + const SerdNode* const b = serd_nodes_double(nodes, -1.2E3); + + assert(a == b); + assert(!strcmp(serd_node_string(a), "-1.2E3")); + assert(serd_node_length(a) == strlen(serd_node_string(a))); + assert(serd_nodes_size(nodes) == 1); + + serd_nodes_free(nodes); +} + +static void +test_float(void) +{ + SerdNodes* const nodes = serd_nodes_new(); + + const SerdNode* const a = serd_nodes_float(nodes, -1.2E3f); + const SerdNode* const b = serd_nodes_float(nodes, -1.2E3f); + + assert(a == b); + assert(!strcmp(serd_node_string(a), "-1.2E3")); + assert(serd_node_length(a) == strlen(serd_node_string(a))); + assert(serd_nodes_size(nodes) == 1); + + serd_nodes_free(nodes); +} + +static void +test_integer(void) +{ + SerdNodes* const nodes = serd_nodes_new(); + + const SerdNode* const a = + serd_nodes_integer(nodes, -1234567890, SERD_EMPTY_STRING()); + + const SerdNode* const b = + serd_nodes_integer(nodes, -1234567890, SERD_EMPTY_STRING()); + + assert(a == b); + assert(!strcmp(serd_node_string(a), "-1234567890")); + assert(serd_node_length(a) == strlen(serd_node_string(a))); + assert(serd_nodes_size(nodes) == 1); + + const SerdNode* const default_datatype = serd_node_datatype(a); + assert(default_datatype); + assert(!strcmp(serd_node_string(default_datatype), NS_XSD "integer")); + + serd_nodes_free(nodes); +} + +static void +test_base64(void) +{ + static const char data[] = {'f', 'o', 'o', 'b', 'a', 'r'}; + + SerdNodes* const nodes = serd_nodes_new(); + + const SerdNode* const a = + serd_nodes_base64(nodes, &data, sizeof(data), SERD_EMPTY_STRING()); + + const SerdNode* const b = + serd_nodes_base64(nodes, &data, sizeof(data), SERD_EMPTY_STRING()); + + assert(a == b); + assert(!strcmp(serd_node_string(a), "Zm9vYmFy")); + assert(serd_node_length(a) == strlen(serd_node_string(a))); + assert(serd_nodes_size(nodes) == 1); + + const SerdNode* const default_datatype = serd_node_datatype(a); + assert(default_datatype); + assert(!strcmp(serd_node_string(default_datatype), NS_XSD "base64Binary")); + + const SerdStringView user_datatype = + SERD_STRING("http://example.org/UserDatatype"); + + const SerdNode* const custom = + serd_nodes_base64(nodes, &data, sizeof(data), user_datatype); + assert(custom); + assert(!strcmp(serd_node_string(custom), "Zm9vYmFy")); + + const SerdNode* const custom_datatype = serd_node_datatype(custom); + assert(custom_datatype); + assert(!strcmp(serd_node_string(custom_datatype), user_datatype.buf)); + serd_nodes_free(nodes); } @@ -149,6 +321,34 @@ test_uri(void) serd_nodes_free(nodes); } +static void +test_parsed_uri(void) +{ + static const SerdStringView string = SERD_STRING("http://example.org/"); + + SerdNodes* const nodes = serd_nodes_new(); + const SerdURIView uri = serd_parse_uri(string.buf); + const SerdNode* const node = serd_nodes_parsed_uri(nodes, uri); + + assert(node); + assert(serd_node_type(node) == SERD_URI); + assert(!serd_node_flags(node)); + assert(!serd_node_datatype(node)); + assert(!serd_node_language(node)); + assert(serd_node_length(node) == string.len); + assert(!strcmp(serd_node_string(node), string.buf)); + + const SerdNode* const alias = serd_nodes_parsed_uri(nodes, uri); + assert(alias == node); + + const SerdNode* const other = + serd_nodes_parsed_uri(nodes, serd_parse_uri("http://example.org/x")); + + assert(other != node); + + serd_nodes_free(nodes); +} + static void test_blank(void) { @@ -170,17 +370,40 @@ test_blank(void) static void test_deref(void) { - SerdNodes* nodes = serd_nodes_new(); - const SerdNode* managed = serd_nodes_string(nodes, SERD_STRING("node")); + SerdNodes* nodes = serd_nodes_new(); + const SerdNode* original = serd_nodes_string(nodes, SERD_STRING("node")); + const SerdNode* another = serd_nodes_string(nodes, SERD_STRING("node")); - serd_nodes_deref(nodes, managed); + assert(original == another); - SerdNode* node = serd_new_string(SERD_STRING("node")); - const SerdNode* interned = serd_nodes_intern(nodes, node); + // Dereference the original and ensure the other reference kept it alive + serd_nodes_deref(nodes, original); + assert(serd_node_length(another) == 4); + assert(!strcmp(serd_node_string(another), "node")); - assert(interned != node); + // Drop the other/final reference (freeing the node) + serd_nodes_deref(nodes, another); - serd_node_free(node); + /* Intern some other irrelevant node first to (hopefully) avoid the allocator + just giving us back the same piece of memory. */ + + const SerdNode* other = serd_nodes_string(nodes, SERD_STRING("XXXX")); + assert(!strcmp(serd_node_string(other), "XXXX")); + + // Intern a new equivalent node to the original and check that it's really new + const SerdNode* imposter = serd_nodes_string(nodes, SERD_STRING("node")); + assert(imposter != original); + assert(serd_node_length(imposter) == 4); + assert(!strcmp(serd_node_string(imposter), "node")); + + // Check that dereferencing some random unknown node doesn't crash + SerdNode* unmanaged = serd_new_string(SERD_STRING("unmanaged")); + serd_nodes_deref(nodes, unmanaged); + serd_node_free(unmanaged); + + serd_nodes_deref(nodes, NULL); + serd_nodes_deref(nodes, imposter); + serd_nodes_deref(nodes, other); serd_nodes_free(nodes); } @@ -205,11 +428,18 @@ int main(void) { test_intern(); - test_manage(); test_string(); + test_invalid_literal(); test_plain_literal(); test_typed_literal(); + test_boolean(); + test_decimal(); + test_double(); + test_float(); + test_integer(); + test_base64(); test_uri(); + test_parsed_uri(); test_blank(); test_deref(); test_get(); -- cgit v1.2.1