From 6bcd18ae60482790b645a345f718e7099250f261 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 13 Jan 2021 16:13:46 +0100 Subject: Simplify literal construction API --- include/serd/serd.h | 19 +++++--- src/env.c | 5 +-- src/node.c | 111 ++++++++++++++++++++++++++++++---------------- test/test_node.c | 62 ++++++++++++++++---------- test/test_reader_writer.c | 5 +-- 5 files changed, 131 insertions(+), 71 deletions(-) diff --git a/include/serd/serd.h b/include/serd/serd.h index 41ee9993..16c600ef 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -557,14 +557,23 @@ serd_new_string(SerdStringView string); /** Create a new literal node from `str`. - 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 NULL, 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 blank node SERD_API diff --git a/src/env.c b/src/env.c index f0d0705c..944319d8 100644 --- a/src/env.c +++ b/src/env.c @@ -210,9 +210,8 @@ serd_env_expand_node(const SerdEnv* env, const SerdNode* node) if (short_datatype) { SerdNode* const datatype = serd_env_expand_node(env, short_datatype); if (datatype) { - SerdNode* ret = serd_new_literal(serd_node_string_view(node), - serd_node_string_view(datatype), - SERD_EMPTY_STRING()); + SerdNode* ret = serd_new_typed_literal(serd_node_string_view(node), + serd_node_string_view(datatype)); serd_node_free(datatype); return ret; } diff --git a/src/node.c b/src/node.c index ed962150..007be2c0 100644 --- a/src/node.c +++ b/src/node.c @@ -183,57 +183,94 @@ 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) { - if (!str.len || (lang.len && datatype_uri.len && - strcmp(datatype_uri.buf, NS_RDF "langString"))) { - return NULL; - } + assert(str.len); + assert(lang.len); - SerdNodeFlags flags = 0; - const size_t n_bytes = serd_substrlen(str.buf, str.len, &flags); - const size_t len = serd_node_pad_size(n_bytes); + flags |= SERD_HAS_LANGUAGE; - SerdNode* node = NULL; - if (lang.len) { - const size_t total_len = len + sizeof(SerdNode) + lang.len; + const size_t len = serd_node_pad_size(str.len); + const size_t total_len = len + sizeof(SerdNode) + lang.len; - node = serd_node_malloc(total_len, flags | SERD_HAS_LANGUAGE, SERD_LITERAL); - node->n_bytes = n_bytes; - memcpy(serd_node_buffer(node), str.buf, n_bytes); + SerdNode* node = serd_node_malloc(total_len, flags, SERD_LITERAL); + memcpy(serd_node_buffer(node), str.buf, str.len); + node->n_bytes = str.len; - SerdNode* lang_node = node + 1 + (len / serd_node_align); - lang_node->type = SERD_LITERAL; - lang_node->n_bytes = lang.len; - memcpy(serd_node_buffer(lang_node), lang.buf, lang.len); - serd_node_check_padding(lang_node); + SerdNode* lang_node = node + 1 + (len / serd_node_align); + lang_node->type = SERD_LITERAL; + lang_node->n_bytes = lang.len; + memcpy(serd_node_buffer(lang_node), lang.buf, lang.len); + serd_node_check_padding(lang_node); - } else if (datatype_uri.len) { - const size_t total_len = len + sizeof(SerdNode) + datatype_uri.len; + serd_node_check_padding(node); + return node; +} - node = serd_node_malloc(total_len, flags | SERD_HAS_DATATYPE, SERD_LITERAL); - node->n_bytes = n_bytes; - memcpy(serd_node_buffer(node), str.buf, n_bytes); +/// Internal pre-measured implementation of serd_new_typed_literal +static SerdNode* +serd_new_typed_literal_i(const SerdStringView str, + SerdNodeFlags flags, + const SerdStringView datatype_uri) +{ + assert(str.len); + assert(datatype_uri.len); + assert(strcmp(datatype_uri.buf, NS_RDF "langString")); - SerdNode* datatype_node = node + 1 + (len / serd_node_align); - datatype_node->type = SERD_URI; - datatype_node->n_bytes = datatype_uri.len; - memcpy(serd_node_buffer(datatype_node), datatype_uri.buf, datatype_uri.len); - serd_node_check_padding(datatype_node); + flags |= SERD_HAS_DATATYPE; - } else { - node = serd_node_malloc(n_bytes, flags, SERD_LITERAL); - memcpy(serd_node_buffer(node), str.buf, n_bytes); - node->n_bytes = n_bytes; - } + const size_t len = serd_node_pad_size(str.len); + const size_t total_len = len + sizeof(SerdNode) + datatype_uri.len; + + SerdNode* node = serd_node_malloc(total_len, flags, SERD_LITERAL); + memcpy(serd_node_buffer(node), str.buf, str.len); + node->n_bytes = str.len; + + SerdNode* datatype_node = node + 1 + (len / serd_node_align); + datatype_node->n_bytes = datatype_uri.len; + datatype_node->type = SERD_URI; + memcpy(serd_node_buffer(datatype_node), datatype_uri.buf, datatype_uri.len); + serd_node_check_padding(datatype_node); serd_node_check_padding(node); return node; } +SerdNode* +serd_new_plain_literal(const SerdStringView str, const SerdStringView lang) +{ + if (!lang.len) { + return serd_new_string(str); + } + + SerdNodeFlags flags = 0; + serd_strlen(str.buf, &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.len) { + return serd_new_string(str); + } + + if (!strcmp(datatype_uri.buf, NS_RDF "langString")) { + return NULL; + } + + SerdNodeFlags flags = 0; + serd_strlen(str.buf, &flags); + + return serd_new_typed_literal_i(str, flags, datatype_uri); +} + SerdNode* serd_new_blank(const SerdStringView str) { diff --git a/test/test_node.c b/test/test_node.c index 93a408d6..8a93f215 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -174,10 +174,12 @@ test_node_equals(void) { static const uint8_t replacement_char_str[] = {0xEF, 0xBF, 0xBD, 0}; - SerdNode* const lhs = - serd_new_string(SERD_STRING_VIEW((const char*)replacement_char_str, 3)); + static const SerdStringView replacement_char = { + (const char*)replacement_char_str, 3}; + + SerdNode* lhs = serd_new_string(replacement_char); + SerdNode* rhs = serd_new_string(SERD_STATIC_STRING("123")); - SerdNode* const rhs = serd_new_string(SERD_STATIC_STRING("123")); assert(!serd_node_equals(lhs, rhs)); SerdNode* const qnode = serd_new_curie(SERD_STATIC_STRING("foo:bar")); @@ -220,40 +222,54 @@ test_simple_node(void) static void test_literal(void) { - SerdNode* hello2 = serd_new_literal( - SERD_STATIC_STRING("hello\""), SERD_EMPTY_STRING(), SERD_EMPTY_STRING()); + SerdNode* hello2 = serd_new_string(SERD_STATIC_STRING("hello\"")); assert(serd_node_length(hello2) == 6 && serd_node_flags(hello2) == SERD_HAS_QUOTE && !strcmp(serd_node_string(hello2), "hello\"")); + + SerdNode* hello3 = + serd_new_plain_literal(SERD_STATIC_STRING("hello\""), SERD_EMPTY_STRING()); + + assert(serd_node_equals(hello2, hello3)); + + SerdNode* hello4 = + serd_new_typed_literal(SERD_STATIC_STRING("hello\""), SERD_EMPTY_STRING()); + + 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_STATIC_STRING("hello_l\""), - SERD_EMPTY_STRING(), - SERD_STATIC_STRING("en")); + const char* lang_lit_str = "\"Hello\"@en"; + SerdNode* sliced_lang_lit = + serd_new_plain_literal(SERD_STRING_VIEW(lang_lit_str + 1, 5), + SERD_STRING_VIEW(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")); - serd_node_free(hello_l); + serd_node_free(sliced_lang_lit); - SerdNode* hello_dt = - serd_new_literal(SERD_STATIC_STRING("hello_dt\""), - SERD_STATIC_STRING("http://example.org/Thing"), - SERD_EMPTY_STRING()); + const char* type_lit_str = "\"Hallo\"^^"; + SerdNode* sliced_type_lit = + serd_new_typed_literal(SERD_STRING_VIEW(type_lit_str + 1, 5), + SERD_STRING_VIEW(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")); - serd_node_free(hello_dt); + assert(!strcmp(serd_node_string(datatype), "http://example.org/Greeting")); + serd_node_free(sliced_type_lit); + + SerdNode* const plain_lit = + serd_new_plain_literal(SERD_STATIC_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 b39ea761..cb3371b6 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -199,12 +199,11 @@ test_writer(const char* const path) assert(serd_sink_write(iface, 0, junk[i][0], junk[i][1], junk[i][2], NULL)); } - static const SerdStringView empty = SERD_EMPTY_STRING(); static const SerdStringView urn_Type = SERD_STATIC_STRING("urn:Type"); static const SerdStringView en = SERD_STATIC_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) { -- cgit v1.2.1