From 0054cff3f5aa1e2c4b5e47fd9b2dfeeff6b17e53 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 12 Aug 2020 15:51:07 +0200 Subject: Remove double allocations in serd_env_expand() --- src/env.c | 20 +++++++++----- src/node.c | 81 +++++++++++++++++++++++++++++++++++++++++++++------------ src/node.h | 11 ++++++++ test/test_uri.c | 2 +- 4 files changed, 90 insertions(+), 24 deletions(-) diff --git a/src/env.c b/src/env.c index 529ae436..145ece33 100644 --- a/src/env.c +++ b/src/env.c @@ -276,13 +276,21 @@ expand_literal(const SerdEnv* env, const SerdNode* node) { assert(serd_node_type(node) == SERD_LITERAL); - SerdNode* datatype = serd_env_expand(env, serd_node_datatype(node)); - if (datatype) { - SerdNode* ret = serd_new_typed_literal(serd_node_string_view(node), - serd_node_string_view(datatype)); + const SerdNode* const datatype = serd_node_datatype(node); + if (datatype && serd_node_type(datatype) == SERD_CURIE) { + SerdStringView prefix; + SerdStringView suffix; + if (!serd_env_expand_in_place(env, datatype, &prefix, &suffix)) { + return serd_new_typed_literal_expanded( + serd_node_string_view(node), serd_node_flags(node), prefix, suffix); + } - serd_node_free(datatype); - return ret; + } else if (datatype && serd_node_type(datatype) == SERD_URI) { + return serd_new_typed_literal_uri( + serd_node_string_view(node), + serd_node_flags(node), + serd_resolve_uri(serd_parse_uri(serd_node_string(datatype)), + env->base_uri)); } return NULL; diff --git a/src/node.c b/src/node.c index 51dc8828..8323e036 100644 --- a/src/node.c +++ b/src/node.c @@ -234,35 +234,82 @@ serd_new_plain_literal_i(const SerdStringView str, return node; } -/// 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) +/// Internal implementation of serd_new_typed_literal from datatype URI parts +SerdNode* +serd_new_typed_literal_expanded(const SerdStringView str, + const SerdNodeFlags flags, + const SerdStringView datatype_prefix, + const SerdStringView datatype_suffix) { - assert(str.len); - assert(datatype_uri.len); - assert(strcmp(datatype_uri.buf, NS_RDF "langString")); + const size_t datatype_uri_len = datatype_prefix.len + datatype_suffix.len; + const size_t len = serd_node_pad_size(str.len); + const size_t total_len = len + sizeof(SerdNode) + datatype_uri_len; - flags |= SERD_HAS_DATATYPE; - - 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_HAS_DATATYPE, SERD_LITERAL); - 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 / sizeof(SerdNode)); - datatype_node->n_bytes = datatype_uri.len; - datatype_node->type = SERD_URI; - memcpy(serd_node_buffer(datatype_node), datatype_uri.buf, datatype_uri.len); + SerdNode* const datatype_node = node + 1 + (len / sizeof(SerdNode)); + char* const datatype_buf = serd_node_buffer(datatype_node); + + datatype_node->n_bytes = datatype_uri_len; + datatype_node->type = SERD_URI; + memcpy(datatype_buf, datatype_prefix.buf, datatype_prefix.len); + memcpy(datatype_buf + datatype_prefix.len, + datatype_suffix.buf, + datatype_suffix.len); + serd_node_check_padding(datatype_node); + serd_node_check_padding(node); + return node; +} + +/// Internal implementation of serd_new_typed_literal from a parsed datatype URI +SerdNode* +serd_new_typed_literal_uri(const SerdStringView str, + const SerdNodeFlags flags, + const SerdURIView datatype_uri) +{ + const size_t datatype_uri_len = serd_uri_string_length(&datatype_uri); + 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_HAS_DATATYPE, SERD_LITERAL); + + memcpy(serd_node_buffer(node), str.buf, str.len); + node->n_bytes = str.len; + + SerdNode* const datatype_node = node + 1 + (len / sizeof(SerdNode)); + char* ptr = serd_node_buffer(datatype_node); + + const size_t actual_len = serd_write_uri(datatype_uri, string_sink, &ptr); + + serd_node_buffer(datatype_node)[actual_len] = '\0'; + datatype_node->n_bytes = actual_len; + datatype_node->type = SERD_URI; + + serd_node_check_padding(datatype_node); serd_node_check_padding(node); return node; } +/// 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")); + + return serd_new_typed_literal_expanded( + str, flags, datatype_uri, SERD_EMPTY_STRING()); +} + SerdNode* serd_new_plain_literal(const SerdStringView str, const SerdStringView lang) { diff --git a/src/node.h b/src/node.h index 04452c98..a9b7120c 100644 --- a/src/node.h +++ b/src/node.h @@ -58,6 +58,17 @@ serd_node_zero_pad(SerdNode* SERD_NONNULL node); SerdNode* SERD_ALLOCATED serd_new_resolved_uri(SerdStringView string, SerdURIView base_uri); +SerdNode* SERD_ALLOCATED +serd_new_typed_literal_expanded(SerdStringView str, + SerdNodeFlags flags, + SerdStringView datatype_prefix, + SerdStringView datatype_suffix); + +SerdNode* SERD_ALLOCATED +serd_new_typed_literal_uri(SerdStringView str, + SerdNodeFlags flags, + SerdURIView datatype_uri); + ExessVariant serd_node_get_value_as(const SerdNode* SERD_NONNULL node, ExessDatatype value_type); diff --git a/test/test_uri.c b/test/test_uri.c index ea70508b..6eac9bb5 100644 --- a/test/test_uri.c +++ b/test/test_uri.c @@ -206,7 +206,7 @@ test_uri_resolution(void) const SerdURIView rel_foo_uri = serd_relative_uri(abs_foo_uri, base_uri); const SerdURIView resolved_uri = serd_resolve_uri(rel_foo_uri, base_uri); - SerdNode* const resolved = serd_new_parsed_uri(resolved_uri); +SerdNode* const resolved = serd_new_parsed_uri(resolved_uri); assert(!strcmp(serd_node_string(resolved), "http://example.org/a/b/c/foo")); serd_node_free(resolved); -- cgit v1.2.1