aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-08-12 15:51:07 +0200
committerDavid Robillard <d@drobilla.net>2021-03-08 23:23:06 -0500
commit0054cff3f5aa1e2c4b5e47fd9b2dfeeff6b17e53 (patch)
treeb267a6fa76129ef10e91bf953ca63cf20abc6407
parentbf01cef66e561ea0cd2ad0babf08194b00f84b77 (diff)
downloadserd-0054cff3f5aa1e2c4b5e47fd9b2dfeeff6b17e53.tar.gz
serd-0054cff3f5aa1e2c4b5e47fd9b2dfeeff6b17e53.tar.bz2
serd-0054cff3f5aa1e2c4b5e47fd9b2dfeeff6b17e53.zip
Remove double allocations in serd_env_expand()
-rw-r--r--src/env.c20
-rw-r--r--src/node.c81
-rw-r--r--src/node.h11
-rw-r--r--test/test_uri.c2
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);