diff options
author | David Robillard <d@drobilla.net> | 2021-01-13 16:13:46 +0100 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2023-12-02 16:27:02 -0500 |
commit | 413b4d1f58bdf1d6aed785ae9b076c7b7b9a7350 (patch) | |
tree | 454cf92d9668431cbdcff8889e7597fcf162bf41 | |
parent | cd89a74a2f7bf8c3efc3ecf1597cf39d6295db00 (diff) | |
download | serd-413b4d1f58bdf1d6aed785ae9b076c7b7b9a7350.tar.gz serd-413b4d1f58bdf1d6aed785ae9b076c7b7b9a7350.tar.bz2 serd-413b4d1f58bdf1d6aed785ae9b076c7b7b9a7350.zip |
Simplify literal construction API
-rw-r--r-- | include/serd/node.h | 26 | ||||
-rw-r--r-- | src/node.c | 92 | ||||
-rw-r--r-- | test/test_node.c | 66 | ||||
-rw-r--r-- | test/test_reader_writer.c | 5 | ||||
-rw-r--r-- | test/test_writer.c | 4 |
5 files changed, 123 insertions, 70 deletions
diff --git a/include/serd/node.h b/include/serd/node.h index 2f4384bd..5a3990b0 100644 --- a/include/serd/node.h +++ b/include/serd/node.h @@ -115,15 +115,23 @@ SERD_API SerdNode* SERD_ALLOCATED serd_new_string(SerdStringView string); /** - Create a new literal node from `str`. + Create a new plain literal node from `str` with `lang`. - Either `datatype_uri` or `lang` can be given, but not both, unless - `datatype_uri` is rdf:langString in which case it is ignored. + A plain literal has no datatype, but may have a language tag. The `lang` + may be empty, in which case this is equivalent to `serd_new_string()`. */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_literal(SerdStringView string, - SerdStringView datatype_uri, - SerdStringView lang); +serd_new_plain_literal(SerdStringView str, SerdStringView lang); + +/** + Create a new typed literal node from `str`. + + A typed literal has no language tag, but may have a datatype. The + `datatype` may be NULL, in which case this is equivalent to + `serd_new_string()`. +*/ +SERD_API SerdNode* SERD_ALLOCATED +serd_new_typed_literal(SerdStringView str, SerdStringView datatype_uri); /** Create a new node from a blank node label. @@ -159,7 +167,7 @@ SERD_API SerdNode* SERD_ALLOCATED serd_new_file_uri(SerdStringView path, SerdStringView hostname); /** - Create a new node by serialising `d` into an xsd:decimal string. + Create a new canonical xsd:decimal literal. The resulting node will always contain a '.', start with a digit, and end with a digit (i.e. will have a leading and/or trailing '0' if necessary). @@ -180,7 +188,7 @@ serd_new_decimal(double d, const SerdNode* SERD_NULLABLE datatype); /** - Create a new node by serialising `i` into an xsd:integer string. + Create a new canonical xsd:integer literal. @param i Integer value to serialise. @param datatype Datatype of node, or NULL for xsd:integer. @@ -189,7 +197,7 @@ SERD_API SerdNode* SERD_ALLOCATED serd_new_integer(int64_t i, const SerdNode* SERD_NULLABLE datatype); /** - Create a node by serialising `buf` into an xsd:base64Binary string. + Create a new canonical xsd:base64Binary literal. This function can be used to make a serialisable node out of arbitrary binary data, which can be decoded using serd_base64_decode(). @@ -4,12 +4,14 @@ #include "node.h" #include "base64.h" +#include "serd_internal.h" #include "string_utils.h" #include "system.h" #include "serd/attributes.h" #include "serd/buffer.h" #include "serd/node.h" +#include "serd/string.h" #include "serd/string_view.h" #include "serd/uri.h" @@ -179,47 +181,75 @@ serd_new_string(const SerdStringView str) return node; } -SerdNode* -serd_new_literal(const SerdStringView str, - const SerdStringView datatype_uri, - const SerdStringView lang) +/// Internal pre-measured implementation of serd_new_plain_literal +static SerdNode* +serd_new_plain_literal_i(const SerdStringView str, + SerdNodeFlags flags, + const SerdStringView lang) { - SerdNodeFlags flags = 0; - const size_t length = serd_substrlen(str.data, str.length, &flags); - const size_t len = serd_node_pad_size(length); + assert(str.length); + assert(lang.length); - SerdNode* node = NULL; - if (lang.length) { - const size_t total_len = len + sizeof(SerdNode) + lang.length; + flags |= SERD_HAS_LANGUAGE; - node = serd_node_malloc(total_len, flags | SERD_HAS_LANGUAGE, SERD_LITERAL); - node->length = length; - memcpy(serd_node_buffer(node), str.data, length); + const size_t len = serd_node_pad_size(str.length); + const size_t total_len = len + sizeof(SerdNode) + lang.length; - SerdNode* lang_node = node + 1 + (len / sizeof(SerdNode)); - lang_node->type = SERD_LITERAL; - lang_node->length = lang.length; - memcpy(serd_node_buffer(lang_node), lang.data, lang.length); + SerdNode* node = serd_node_malloc(total_len, flags, SERD_LITERAL); + memcpy(serd_node_buffer(node), str.data, str.length); + node->length = str.length; - } else if (datatype_uri.length) { - const size_t total_len = len + sizeof(SerdNode) + datatype_uri.length; + SerdNode* lang_node = node + 1 + (len / sizeof(SerdNode)); + lang_node->type = SERD_LITERAL; + lang_node->length = lang.length; + memcpy(serd_node_buffer(lang_node), lang.data, lang.length); - node = serd_node_malloc(total_len, flags | SERD_HAS_DATATYPE, SERD_LITERAL); - node->length = length; - memcpy(serd_node_buffer(node), str.data, length); + return node; +} - SerdNode* datatype_node = node + 1 + (len / sizeof(SerdNode)); - datatype_node->type = SERD_URI; - datatype_node->length = datatype_uri.length; - memcpy( - serd_node_buffer(datatype_node), datatype_uri.data, datatype_uri.length); +SerdNode* +serd_new_plain_literal(const SerdStringView str, const SerdStringView lang) +{ + if (!lang.length) { + return serd_new_string(str); + } - } else { - node = serd_node_malloc(length, flags, SERD_LITERAL); - memcpy(serd_node_buffer(node), str.data, length); - node->length = length; + SerdNodeFlags flags = 0; + serd_strlen(str.data, &flags); + + return serd_new_plain_literal_i(str, flags, lang); +} + +SerdNode* +serd_new_typed_literal(const SerdStringView str, + const SerdStringView datatype_uri) +{ + if (!datatype_uri.length) { + return serd_new_string(str); + } + + if (!strcmp(datatype_uri.data, NS_RDF "langString")) { + return NULL; } + SerdNodeFlags flags = 0U; + serd_strlen(str.data, &flags); + + flags |= SERD_HAS_DATATYPE; + + const size_t len = serd_node_pad_size(str.length); + const size_t total_len = len + sizeof(SerdNode) + datatype_uri.length; + + SerdNode* node = serd_node_malloc(total_len, flags, SERD_LITERAL); + memcpy(serd_node_buffer(node), str.data, str.length); + node->length = str.length; + + SerdNode* datatype_node = node + 1 + (len / sizeof(SerdNode)); + datatype_node->length = datatype_uri.length; + datatype_node->type = SERD_URI; + memcpy( + serd_node_buffer(datatype_node), datatype_uri.data, datatype_uri.length); + return node; } diff --git a/test/test_node.c b/test/test_node.c index 3cdff51a..fc9f1151 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -26,6 +26,7 @@ #endif #define NS_XSD "http://www.w3.org/2001/XMLSchema#" +#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" static void test_strtod(double dbl, double max_delta) @@ -169,12 +170,13 @@ test_node_equals(void) { static const uint8_t replacement_char_str[] = {0xEF, 0xBF, 0xBD, 0}; - SerdNode* const lhs = - serd_new_string(serd_substring((const char*)replacement_char_str, 3)); + static const SerdStringView replacement_char = { + (const char*)replacement_char_str, 3}; - assert(serd_node_equals(lhs, lhs)); + SerdNode* lhs = serd_new_string(replacement_char); + SerdNode* rhs = serd_new_string(serd_string("123")); - SerdNode* const rhs = serd_new_string(serd_string("123")); + assert(serd_node_equals(lhs, lhs)); assert(!serd_node_equals(lhs, rhs)); SerdNode* const qnode = serd_new_curie(serd_string("foo:bar")); @@ -230,42 +232,58 @@ check_copy_equals(const SerdNode* const node) static void test_literal(void) { - SerdNode* hello2 = serd_new_literal( - serd_string("hello\""), serd_empty_string(), serd_empty_string()); + SerdNode* hello2 = serd_new_string(serd_string("hello\"")); assert(serd_node_length(hello2) == 6 && serd_node_flags(hello2) == SERD_HAS_QUOTE && !strcmp(serd_node_string(hello2), "hello\"")); + check_copy_equals(hello2); + + SerdNode* hello3 = + serd_new_plain_literal(serd_string("hello\""), serd_empty_string()); + + assert(serd_node_equals(hello2, hello3)); + + SerdNode* hello4 = + serd_new_typed_literal(serd_string("hello\""), serd_empty_string()); + + assert(!serd_new_typed_literal(serd_string("plain"), + serd_string(NS_RDF "langString"))); + + assert(serd_node_equals(hello4, hello2)); + + serd_node_free(hello4); + serd_node_free(hello3); serd_node_free(hello2); - SerdNode* hello_l = serd_new_literal( - serd_string("hello_l\""), serd_empty_string(), serd_string("en")); + const char* lang_lit_str = "\"Hello\"@en"; + SerdNode* sliced_lang_lit = serd_new_plain_literal( + serd_substring(lang_lit_str + 1, 5), serd_substring(lang_lit_str + 8, 2)); - assert(serd_node_length(hello_l) == 8); - assert(!strcmp(serd_node_string(hello_l), "hello_l\"")); - assert(serd_node_flags(hello_l) == (SERD_HAS_QUOTE | SERD_HAS_LANGUAGE)); + assert(!strcmp(serd_node_string(sliced_lang_lit), "Hello")); - const SerdNode* const lang = serd_node_language(hello_l); + const SerdNode* const lang = serd_node_language(sliced_lang_lit); assert(lang); assert(!strcmp(serd_node_string(lang), "en")); - check_copy_equals(hello_l); - serd_node_free(hello_l); + check_copy_equals(sliced_lang_lit); + serd_node_free(sliced_lang_lit); - SerdNode* hello_dt = serd_new_literal(serd_string("hello_dt\""), - serd_string("http://example.org/Thing"), - serd_empty_string()); + const char* type_lit_str = "\"Hallo\"^^<http://example.org/Greeting>"; + SerdNode* sliced_type_lit = serd_new_typed_literal( + serd_substring(type_lit_str + 1, 5), serd_substring(type_lit_str + 10, 27)); - assert(serd_node_length(hello_dt) == 9); - assert(!strcmp(serd_node_string(hello_dt), "hello_dt\"")); - assert(serd_node_flags(hello_dt) == (SERD_HAS_QUOTE | SERD_HAS_DATATYPE)); + assert(!strcmp(serd_node_string(sliced_type_lit), "Hallo")); - const SerdNode* const datatype = serd_node_datatype(hello_dt); + const SerdNode* const datatype = serd_node_datatype(sliced_type_lit); assert(datatype); - assert(!strcmp(serd_node_string(datatype), "http://example.org/Thing")); + assert(!strcmp(serd_node_string(datatype), "http://example.org/Greeting")); + serd_node_free(sliced_type_lit); - check_copy_equals(hello_dt); - serd_node_free(hello_dt); + SerdNode* const plain_lit = + serd_new_plain_literal(serd_string("Plain"), serd_empty_string()); + assert(!strcmp(serd_node_string(plain_lit), "Plain")); + serd_node_free(plain_lit); } static void diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c index b1121cbc..9183af5c 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -475,12 +475,11 @@ test_writer(const char* const path) writer, 0, NULL, junk[i][0], junk[i][1], junk[i][2])); } - const SerdStringView empty = serd_empty_string(); const SerdStringView urn_Type = serd_string("urn:Type"); const SerdStringView en = serd_string("en"); - SerdNode* const t = serd_new_literal(buf_view, urn_Type, empty); - SerdNode* const l = serd_new_literal(buf_view, empty, en); + SerdNode* const t = serd_new_typed_literal(buf_view, urn_Type); + SerdNode* const l = serd_new_plain_literal(buf_view, en); const SerdNode* good[][3] = {{s, p, o}, {s, p, t}, {s, p, l}}; for (size_t i = 0; i < sizeof(good) / (sizeof(SerdNode*) * 3); ++i) { diff --git a/test/test_writer.c b/test/test_writer.c index b15f7fdc..76d046d7 100644 --- a/test/test_writer.c +++ b/test/test_writer.c @@ -56,9 +56,7 @@ test_write_long_literal(void) SerdNode* s = serd_new_uri(serd_string("http://example.org/s")); SerdNode* p = serd_new_uri(serd_string("http://example.org/p")); - SerdNode* o = serd_new_literal(serd_string("hello \"\"\"world\"\"\"!"), - serd_empty_string(), - serd_empty_string()); + SerdNode* o = serd_new_string(serd_string("hello \"\"\"world\"\"\"!")); assert(!serd_writer_write_statement(writer, 0, NULL, s, p, o)); |