aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-07-22 23:39:39 -0400
committerDavid Robillard <d@drobilla.net>2022-01-14 19:37:51 -0500
commita63a8f19c54dfee75e092819d6622b8d36fe1d39 (patch)
tree3c2fe49c257e27d369365a0c08c1524baaf74a4c /src
parent64e81dfd6ec04995fd396269deb6b32fe2d1192d (diff)
downloadserd-a63a8f19c54dfee75e092819d6622b8d36fe1d39.tar.gz
serd-a63a8f19c54dfee75e092819d6622b8d36fe1d39.tar.bz2
serd-a63a8f19c54dfee75e092819d6622b8d36fe1d39.zip
Expose low-level node construction API
Diffstat (limited to 'src')
-rw-r--r--src/env.c28
-rw-r--r--src/n3.c5
-rw-r--r--src/node.c660
-rw-r--r--src/node.h52
-rw-r--r--src/nodes.c2
-rw-r--r--src/static_nodes.h41
-rw-r--r--src/world.c2
7 files changed, 519 insertions, 271 deletions
diff --git a/src/env.c b/src/env.c
index d4ae1937..434d1a3b 100644
--- a/src/env.c
+++ b/src/env.c
@@ -258,7 +258,7 @@ serd_env_expand_in_place(const SerdEnv* const env,
return SERD_ERR_BAD_CURIE;
}
- uri_prefix->buf = serd_node_string(prefix->uri);
+ uri_prefix->buf = prefix->uri ? serd_node_string(prefix->uri) : "";
uri_prefix->len = prefix->uri ? prefix->uri->length : 0;
uri_suffix->buf = colon + 1;
uri_suffix->len = curie.len - name_len - 1;
@@ -279,20 +279,24 @@ serd_env_expand_curie(const SerdEnv* const env, const SerdStringView curie)
return NULL;
}
- const size_t len = prefix.len + suffix.len;
- SerdNode* const ret = serd_node_malloc(len, 0u, SERD_URI);
- if (!ret) {
- return NULL;
- }
+ const size_t len = prefix.len + suffix.len;
- char* const string = serd_node_buffer(ret);
- assert(string);
- assert(prefix.buf);
+ const size_t real_length = serd_node_pad_length(len);
+ const size_t node_size = sizeof(SerdNode) + real_length;
+ SerdNode* node = serd_node_malloc(node_size);
- memcpy(string, prefix.buf, prefix.len);
- memcpy(string + prefix.len, suffix.buf, suffix.len);
+ if (node) {
+ node->length = len;
+ node->flags = 0u;
+ node->type = SERD_URI;
+
+ char* const string = (char*)(node + 1u);
+ assert(prefix.buf);
+ memcpy(string, prefix.buf, prefix.len);
+ memcpy(string + prefix.len, suffix.buf, suffix.len);
+ }
- return ret;
+ return node;
}
SerdNode*
diff --git a/src/n3.c b/src/n3.c
index 6813bccc..79a48a93 100644
--- a/src/n3.c
+++ b/src/n3.c
@@ -369,7 +369,7 @@ resolve_IRIREF(SerdReader* const reader,
temp->length = serd_write_uri(uri, write_to_stack, &ctx);
if (!ctx.status) {
// Replace the destination with the new expanded node
- memmove(dest, temp, serd_node_total_size(temp));
+ memmove(dest, temp, sizeof(SerdNode) + serd_node_pad_length(temp->length));
serd_stack_pop_to(&reader->stack, string_start_offset + dest->length);
}
@@ -438,7 +438,8 @@ read_PrefixedName(SerdReader* const reader,
}
// Replace the destination with the new expanded node
- const size_t total_size = serd_node_total_size(temp);
+ const size_t total_size =
+ sizeof(SerdNode) + serd_node_pad_length(temp->length);
memmove(dest, temp, total_size);
diff --git a/src/node.c b/src/node.c
index d29a6119..6958ea5e 100644
--- a/src/node.c
+++ b/src/node.c
@@ -17,7 +17,6 @@
#include "node.h"
#include "namespaces.h"
-#include "static_nodes.h"
#include "string_utils.h"
#include "system.h"
@@ -28,53 +27,24 @@
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdlib.h>
#include <string.h>
-typedef struct {
- const void* SERD_NULLABLE buf;
- size_t len;
-} SerdConstBuffer;
+#ifndef NDEBUG
+# define MUST_SUCCEED(status) assert(!(status))
+#else
+# define MUST_SUCCEED(status) ((void)(status))
+#endif
static const SerdNodeFlags meta_mask = (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE);
+// Round size up to an even multiple of the node alignment
static size_t
-string_sink(const void* const buf,
- const size_t size,
- const size_t nmemb,
- void* const stream)
+serd_node_pad_size(const size_t size)
{
- char** ptr = (char**)stream;
- memcpy(*ptr, buf, size * nmemb);
- *ptr += size * nmemb;
- return nmemb;
-}
+ const size_t n_trailing = size % serd_node_align;
+ const size_t n_pad = n_trailing ? (serd_node_align - n_trailing) : 0u;
-static size_t
-serd_node_pad_length(const size_t n_bytes)
-{
- const size_t pad = sizeof(SerdNode) - (n_bytes + 2) % sizeof(SerdNode);
- const size_t size = n_bytes + 2 + pad;
- assert(size % sizeof(SerdNode) == 0);
- return size;
-}
-
-static const SerdNode*
-serd_node_meta_c(const SerdNode* const node)
-{
- return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
-}
-
-static SerdNode*
-serd_node_meta(SerdNode* const node)
-{
- return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
-}
-
-static const SerdNode*
-serd_node_maybe_get_meta_c(const SerdNode* const node)
-{
- return (node->flags & meta_mask) ? serd_node_meta_c(node) : NULL;
+ return size + n_pad;
}
static void
@@ -88,7 +58,8 @@ serd_node_check_padding(const SerdNode* node)
assert(serd_node_buffer_c(node)[node->length + i] == '\0');
}
- serd_node_check_padding(serd_node_maybe_get_meta_c(node));
+ serd_node_check_padding(serd_node_datatype(node));
+ serd_node_check_padding(serd_node_language(node));
}
#endif
}
@@ -96,27 +67,37 @@ serd_node_check_padding(const SerdNode* node)
size_t
serd_node_total_size(const SerdNode* const node)
{
- return node ? (sizeof(SerdNode) + serd_node_pad_length(node->length) +
- serd_node_total_size(serd_node_maybe_get_meta_c(node)))
- : 0;
+ const size_t real_length = serd_node_pad_length(node->length);
+ const size_t base_size = sizeof(SerdNode) + real_length;
+
+ if (!(node->flags & meta_mask)) {
+ return base_size;
+ }
+
+ const SerdNode* const meta = serd_node_meta_c(node);
+ const size_t meta_real_length = serd_node_pad_length(meta->length);
+
+ return base_size + sizeof(SerdNode) + meta_real_length;
}
SerdNode*
-serd_node_malloc(const size_t length,
- const SerdNodeFlags flags,
- const SerdNodeType type)
+serd_node_malloc(const size_t size)
{
- const size_t size = sizeof(SerdNode) + serd_node_pad_length(length);
- SerdNode* node = (SerdNode*)serd_calloc_aligned(serd_node_align, size);
-
- node->length = 0;
- node->flags = flags;
- node->type = type;
+ SerdNode* const node =
+ (SerdNode*)serd_calloc_aligned(serd_node_align, serd_node_pad_size(size));
assert((uintptr_t)node % serd_node_align == 0);
return node;
}
+SerdNode*
+serd_node_try_malloc(const SerdWriteResult r)
+{
+ return (r.status && r.status != SERD_ERR_OVERFLOW)
+ ? NULL
+ : serd_node_malloc(r.count);
+}
+
void
serd_node_set(SerdNode** const dst, const SerdNode* const src)
{
@@ -163,46 +144,42 @@ result(const SerdStatus status, const size_t count)
return result;
}
-SerdNode*
-serd_new_token(const SerdNodeType type, const SerdStringView str)
-{
- SerdNodeFlags flags = 0u;
- const size_t length = str.buf ? str.len : 0u;
- SerdNode* node = serd_node_malloc(length, flags, type);
+static SerdWriteResult
+serd_node_construct_simple(const size_t buf_size,
+ void* const buf,
+ const SerdNodeType type,
+ const SerdNodeFlags flags,
+ const SerdStringView string)
+{
+ const size_t total_size = sizeof(SerdNode) + serd_node_pad_length(string.len);
+ if (!buf || total_size > buf_size) {
+ return result(SERD_ERR_OVERFLOW, total_size);
+ }
- if (node) {
- if (str.buf) {
- memcpy(serd_node_buffer(node), str.buf, length);
- }
+ SerdNode* const node = (SerdNode*)buf;
- node->length = length;
- }
+ node->length = string.len;
+ node->flags = flags;
+ node->type = type;
- serd_node_check_padding(node);
+ if (string.buf) {
+ memcpy(serd_node_buffer(node), string.buf, string.len);
+ }
- return node;
+ serd_node_zero_pad(node);
+ return result(SERD_SUCCESS, total_size);
}
-SerdNode*
-serd_new_string(const SerdStringView str)
+SerdWriteResult
+serd_node_construct_token(const size_t buf_size,
+ void* const buf,
+ const SerdNodeType type,
+ const SerdStringView string)
{
- SerdNodeFlags flags = 0u;
- SerdNode* node = serd_node_malloc(str.len, flags, SERD_LITERAL);
-
- if (node) {
- if (str.buf && str.len) {
- memcpy(serd_node_buffer(node), str.buf, str.len);
- }
-
- node->length = str.len;
- serd_node_check_padding(node);
- }
-
- return node;
+ return serd_node_construct_simple(buf_size, buf, type, 0u, string);
}
-SERD_PURE_FUNC
-static bool
+bool
is_langtag(const SerdStringView string)
{
// First character must be a letter
@@ -231,57 +208,296 @@ is_langtag(const SerdStringView string)
return true;
}
-SerdNode*
-serd_new_literal(const SerdStringView string,
- const SerdNodeFlags flags,
- const SerdStringView meta)
+SerdWriteResult
+serd_node_construct_literal(const size_t buf_size,
+ void* const buf,
+ const SerdStringView string,
+ const SerdNodeFlags flags,
+ const SerdStringView meta)
{
if (!(flags & (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE))) {
- SerdNode* node = serd_node_malloc(string.len, flags, SERD_LITERAL);
-
- memcpy(serd_node_buffer(node), string.buf, string.len);
- node->length = string.len;
- serd_node_check_padding(node);
- return node;
+ return serd_node_construct_simple(
+ buf_size, buf, SERD_LITERAL, flags, string);
}
if ((flags & SERD_HAS_DATATYPE) && (flags & SERD_HAS_LANGUAGE)) {
- return NULL;
+ return result(SERD_ERR_BAD_ARG, 0);
}
if (!meta.len) {
- return NULL;
+ return result(SERD_ERR_BAD_ARG, 0);
}
if (((flags & SERD_HAS_DATATYPE) &&
(!serd_uri_string_has_scheme(meta.buf) ||
!strcmp(meta.buf, NS_RDF "langString"))) ||
((flags & SERD_HAS_LANGUAGE) && !is_langtag(meta))) {
- return NULL;
+ return result(SERD_ERR_BAD_ARG, 0);
}
- const size_t len = serd_node_pad_length(string.len);
- const size_t meta_len = serd_node_pad_length(meta.len);
- const size_t meta_size = sizeof(SerdNode) + meta_len;
+ const size_t padded_length = serd_node_pad_length(string.len);
+
+ const size_t meta_size = sizeof(SerdNode) + serd_node_pad_length(meta.len);
+ const size_t total_size = sizeof(SerdNode) + padded_length + meta_size;
+ if (!buf || total_size > buf_size) {
+ return result(SERD_ERR_OVERFLOW, total_size);
+ }
+
+ SerdNode* const node = (SerdNode*)buf;
- SerdNode* node = serd_node_malloc(len + meta_size, flags, SERD_LITERAL);
- memcpy(serd_node_buffer(node), string.buf, string.len);
node->length = string.len;
+ node->flags = flags;
+ node->type = SERD_LITERAL;
- SerdNode* meta_node = node + 1u + (len / sizeof(SerdNode));
- meta_node->length = meta.len;
+ memcpy(serd_node_buffer(node), string.buf, string.len);
+
+ SerdNode* meta_node = node + 1 + (padded_length / sizeof(SerdNode));
meta_node->type = (flags & SERD_HAS_DATATYPE) ? SERD_URI : SERD_LITERAL;
+ meta_node->length = meta.len;
memcpy(serd_node_buffer(meta_node), meta.buf, meta.len);
- serd_node_check_padding(meta_node);
+ serd_node_zero_pad(node);
+ return result(SERD_SUCCESS, total_size);
+}
+
+SerdWriteResult
+serd_node_construct(const size_t buf_size,
+ void* const buf,
+ const SerdNodeType type,
+ const SerdStringView string,
+ const SerdNodeFlags flags,
+ const SerdStringView meta)
+{
+ return ((type == SERD_LITERAL)
+ ? serd_node_construct_literal(buf_size, buf, string, flags, meta)
+ : (meta.len > 0u)
+ ? result(SERD_ERR_BAD_ARG, 0)
+ : serd_node_construct_token(buf_size, buf, type, string));
+}
+
+SerdWriteResult
+serd_node_construct_boolean(const size_t buf_size,
+ void* const buf,
+ const bool value)
+{
+ char temp[EXESS_MAX_BOOLEAN_LENGTH + 1] = {0};
+
+ const ExessResult r = exess_write_boolean(value, sizeof(temp), temp);
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
+
+ return serd_node_construct_literal(buf_size,
+ buf,
+ SERD_SUBSTRING(temp, r.count),
+ SERD_HAS_DATATYPE,
+ SERD_STRING(EXESS_XSD_URI "boolean"));
+}
+
+SerdWriteResult
+serd_node_construct_decimal(const size_t buf_size,
+ void* const buf,
+ const double value)
+{
+ char temp[EXESS_MAX_DECIMAL_LENGTH + 1] = {0};
+
+ const ExessResult r = exess_write_decimal(value, sizeof(temp), temp);
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
+
+ return serd_node_construct_literal(buf_size,
+ buf,
+ SERD_SUBSTRING(temp, r.count),
+ SERD_HAS_DATATYPE,
+ SERD_STRING(EXESS_XSD_URI "decimal"));
+}
+
+SerdWriteResult
+serd_node_construct_double(const size_t buf_size,
+ void* const buf,
+ const double value)
+{
+ char temp[EXESS_MAX_DOUBLE_LENGTH + 1] = {0};
+
+ const ExessResult r = exess_write_double(value, sizeof(temp), temp);
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
+
+ return serd_node_construct_literal(buf_size,
+ buf,
+ SERD_SUBSTRING(temp, r.count),
+ SERD_HAS_DATATYPE,
+ SERD_STRING(EXESS_XSD_URI "double"));
+}
+
+SerdWriteResult
+serd_node_construct_float(const size_t buf_size,
+ void* const buf,
+ const float value)
+{
+ char temp[EXESS_MAX_FLOAT_LENGTH + 1] = {0};
+
+ const ExessResult r = exess_write_float(value, sizeof(temp), temp);
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
+
+ return serd_node_construct_literal(buf_size,
+ buf,
+ SERD_SUBSTRING(temp, r.count),
+ SERD_HAS_DATATYPE,
+ SERD_STRING(EXESS_XSD_URI "float"));
+}
+
+SerdWriteResult
+serd_node_construct_integer(const size_t buf_size,
+ void* const buf,
+ const int64_t value,
+ const SerdStringView datatype)
+{
+ if (datatype.len && !serd_uri_string_has_scheme(datatype.buf)) {
+ return result(SERD_ERR_BAD_ARG, 0);
+ }
+
+ char temp[24] = {0};
+ const ExessResult r = exess_write_long(value, sizeof(temp), temp);
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
+
+ return serd_node_construct_literal(
+ buf_size,
+ buf,
+ SERD_SUBSTRING(temp, r.count),
+ SERD_HAS_DATATYPE,
+ datatype.len ? datatype : SERD_STRING(NS_XSD "integer"));
+}
+
+SerdWriteResult
+serd_node_construct_base64(const size_t buf_size,
+ void* const buf,
+ const size_t value_size,
+ const void* const value,
+ const SerdStringView datatype)
+{
+ static const SerdStringView xsd_base64Binary =
+ SERD_STRING(NS_XSD "base64Binary");
+
+ // Verify argument sanity
+ if (!value || !value_size ||
+ (datatype.len && !serd_uri_string_has_scheme(datatype.buf))) {
+ return result(SERD_ERR_BAD_ARG, 0);
+ }
+
+ // Determine the type to use (default to xsd:base64Binary)
+ const SerdStringView type = datatype.len ? datatype : xsd_base64Binary;
+ const size_t type_length = serd_node_pad_length(type.len);
+ const size_t type_size = sizeof(SerdNode) + type_length;
+
+ // Find the length of the encoded string (just an O(1) arithmetic expression)
+ ExessResult r = exess_write_base64(value_size, value, 0, NULL);
+
+ // Check that the provided buffer is large enough
+ const size_t padded_length = serd_node_pad_length(r.count);
+ const size_t total_size = sizeof(SerdNode) + padded_length + type_size;
+ if (!buf || total_size > buf_size) {
+ return result(SERD_ERR_OVERFLOW, total_size);
+ }
+
+ SerdNode* const node = (SerdNode*)buf;
+ node->length = r.count;
+ node->flags = SERD_HAS_DATATYPE;
+ node->type = SERD_LITERAL;
+
+ // Write the encoded base64 into the node body
+ r = exess_write_base64(
+ value_size, value, total_size - sizeof(SerdNode), serd_node_buffer(node));
+
+ MUST_SUCCEED(r.status);
+ (void)r;
+
+ // Append datatype
+ SerdNode* meta_node = node + 1 + (padded_length / sizeof(SerdNode));
+ meta_node->length = type.len;
+ meta_node->flags = 0u;
+ meta_node->type = SERD_URI;
+ memcpy(serd_node_buffer(meta_node), type.buf, type.len);
+
+ return result(SERD_SUCCESS, total_size);
+}
+
+static size_t
+string_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
+{
+ char** ptr = (char**)stream;
+ memcpy(*ptr, buf, size * nmemb);
+ *ptr += size * nmemb;
+ return nmemb;
+}
+
+SerdWriteResult
+serd_node_construct_uri(const size_t buf_size,
+ void* const buf,
+ const SerdURIView uri)
+{
+ const size_t length = serd_uri_string_length(uri);
+ const size_t required_size = sizeof(SerdNode) + serd_node_pad_length(length);
+ if (!buf || buf_size < required_size) {
+ return result(SERD_ERR_OVERFLOW, required_size);
+ }
+
+ // Write node header
+ SerdNode* const node = (SerdNode*)buf;
+ node->length = length;
+ node->flags = 0u;
+ node->type = SERD_URI;
+
+ // Serialise URI to node body
+ char* ptr = serd_node_buffer(node);
+ const size_t actual_length = serd_write_uri(uri, string_sink, &ptr);
+ assert(actual_length == length);
+
+ serd_node_buffer(node)[actual_length] = '\0';
serd_node_check_padding(node);
+ return result(SERD_SUCCESS, required_size);
+}
+
+SerdNode*
+serd_node_new(const SerdNodeType type,
+ const SerdStringView string,
+ const SerdNodeFlags flags,
+ const SerdStringView meta)
+{
+ SerdWriteResult r = serd_node_construct(0, NULL, type, string, flags, meta);
+ if (r.status != SERD_ERR_OVERFLOW) {
+ return NULL;
+ }
+
+ assert(r.count % sizeof(SerdNode) == 0);
+
+ SerdNode* const node = serd_node_malloc(sizeof(SerdNode) + r.count + 1);
+
+ if (node) {
+ r = serd_node_construct(r.count, node, type, string, flags, meta);
+ MUST_SUCCEED(r.status); // Any error should have been reported above
+ }
+
return node;
}
SerdNode*
-serd_new_blank(const SerdStringView str)
+serd_new_token(const SerdNodeType type, const SerdStringView string)
+{
+ return serd_node_new(type, string, 0u, SERD_EMPTY_STRING());
+}
+
+SerdNode*
+serd_new_string(const SerdStringView str)
+{
+ return serd_node_new(SERD_LITERAL, str, 0u, SERD_EMPTY_STRING());
+}
+
+SerdNode*
+serd_new_literal(const SerdStringView str,
+ const SerdNodeFlags flags,
+ const SerdStringView meta)
{
- return serd_new_token(SERD_BLANK, str);
+ return serd_node_new(SERD_LITERAL, str, flags, meta);
}
ExessResult
@@ -454,68 +670,96 @@ serd_node_compare(const SerdNode* const a, const SerdNode* const b)
}
SerdNode*
-serd_new_uri(const SerdStringView str)
+serd_new_uri(const SerdStringView string)
{
- return serd_new_token(SERD_URI, str);
+ return serd_new_token(SERD_URI, string);
}
SerdNode*
serd_new_parsed_uri(const SerdURIView uri)
{
- const size_t len = serd_uri_string_length(uri);
- SerdNode* const node = serd_node_malloc(len, 0, SERD_URI);
- char* ptr = serd_node_buffer(node);
- const size_t actual_len = serd_write_uri(uri, string_sink, &ptr);
-
- assert(actual_len == len);
+ SerdWriteResult r = serd_node_construct_uri(0u, NULL, uri);
+ SerdNode* const node = serd_node_try_malloc(r);
- serd_node_buffer(node)[actual_len] = '\0';
- node->length = actual_len;
+ if (node) {
+ r = serd_node_construct_uri(r.count, node, uri);
+ MUST_SUCCEED(r.status);
+ }
- serd_node_check_padding(node);
return node;
}
-SerdNode*
-serd_new_file_uri(const SerdStringView path, const SerdStringView hostname)
-{
- SerdBuffer buffer = {NULL, 0u};
+typedef struct {
+ char* buf;
+ size_t len;
+ size_t offset;
+} ConstructWriteHead;
- serd_write_file_uri(path, hostname, serd_buffer_sink, &buffer);
- serd_buffer_sink_finish(&buffer);
+static size_t
+construct_write(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
+{
+ const size_t n_bytes = size * nmemb;
+ ConstructWriteHead* const head = (ConstructWriteHead*)stream;
- SerdNode* node =
- serd_new_uri(SERD_SUBSTRING((const char*)buffer.buf, buffer.len - 1));
+ if (head->buf && head->offset + n_bytes <= head->len) {
+ memcpy(head->buf + head->offset, buf, n_bytes);
+ }
- free(buffer.buf);
- serd_node_check_padding(node);
- return node;
+ head->offset += n_bytes;
+ return n_bytes;
}
-typedef size_t (*SerdWriteLiteralFunc)(const void* user_data,
- size_t buf_size,
- char* buf);
+SerdWriteResult
+serd_node_construct_file_uri(const size_t buf_size,
+ void* const buf,
+ const SerdStringView path,
+ const SerdStringView hostname)
+{
+ SerdNode* const node = (SerdNode*)buf;
+ ConstructWriteHead head = {(char*)buf, buf_size, 0u};
+ size_t count = 0u;
+
+ // Write node header
+ SerdNode header = {0u, 0u, SERD_URI};
+ count += construct_write(&header, 1, sizeof(header), &head);
+
+ // Write URI string node body
+ const size_t length =
+ serd_write_file_uri(path, hostname, construct_write, &head);
+
+ // Terminate string
+ count += length;
+ count += construct_write("", 1, 1, &head);
+
+ // Write any additional null bytes needed for padding
+ const size_t padded_length = serd_node_pad_length(length);
+ for (size_t p = 0u; p < padded_length - length; ++p) {
+ count += construct_write("", 1, 1, &head);
+ }
-static SerdNode*
-serd_new_custom_literal(const void* const user_data,
- const size_t len,
- const SerdWriteLiteralFunc write,
- const SerdNode* const datatype)
-{
- if (len == 0 || !write) {
- return NULL;
+ if (!buf || count > buf_size) {
+ return result(SERD_ERR_OVERFLOW, count);
}
- const size_t datatype_size = serd_node_total_size(datatype);
- const size_t total_size = serd_node_pad_length(len) + datatype_size;
+ node->length = length;
+ assert(node->length == strlen(serd_node_string(node)));
- SerdNode* const node = serd_node_malloc(
- total_size, datatype ? SERD_HAS_DATATYPE : 0u, SERD_LITERAL);
+ return result(SERD_SUCCESS, count);
+}
- node->length = write(user_data, len + 1, serd_node_buffer(node));
+SerdNode*
+serd_new_file_uri(const SerdStringView path, const SerdStringView hostname)
+{
+ SerdWriteResult r = serd_node_construct_file_uri(0, NULL, path, hostname);
+ SerdNode* const node = serd_node_try_malloc(r);
- if (datatype) {
- memcpy(serd_node_meta(node), datatype, datatype_size);
+ if (node) {
+ r = serd_node_construct_file_uri(r.count, node, path, hostname);
+ MUST_SUCCEED(r.status);
+ assert(serd_node_length(node) == strlen(serd_node_string(node)));
}
serd_node_check_padding(node);
@@ -525,107 +769,97 @@ serd_new_custom_literal(const void* const user_data,
SerdNode*
serd_new_double(const double d)
{
- char buf[EXESS_MAX_DOUBLE_LENGTH + 1] = {0};
+ SerdWriteResult r = serd_node_construct_double(0, NULL, d);
+ SerdNode* const node = serd_node_try_malloc(r);
- const ExessResult r = exess_write_double(d, sizeof(buf), buf);
+ if (node) {
+ r = serd_node_construct_double(r.count, node, d);
+ MUST_SUCCEED(r.status);
+ assert(serd_node_length(node) == strlen(serd_node_string(node)));
+ }
- return r.status ? NULL
- : serd_new_literal(SERD_SUBSTRING(buf, r.count),
- SERD_HAS_DATATYPE,
- SERD_STRING(EXESS_XSD_URI "double"));
+ serd_node_check_padding(node);
+ return node;
}
SerdNode*
serd_new_float(const float f)
{
- char buf[EXESS_MAX_FLOAT_LENGTH + 1] = {0};
+ SerdWriteResult r = serd_node_construct_float(0, NULL, f);
+ SerdNode* const node = serd_node_try_malloc(r);
- const ExessResult r = exess_write_float(f, sizeof(buf), buf);
+ if (node) {
+ r = serd_node_construct_float(r.count, node, f);
+ MUST_SUCCEED(r.status);
+ assert(serd_node_length(node) == strlen(serd_node_string(node)));
+ }
- return r.status ? NULL
- : serd_new_literal(SERD_SUBSTRING(buf, r.count),
- SERD_HAS_DATATYPE,
- SERD_STRING(EXESS_XSD_URI "float"));
+ serd_node_check_padding(node);
+ return node;
}
SerdNode*
serd_new_boolean(bool b)
{
- return serd_new_literal(b ? SERD_STRING("true") : SERD_STRING("false"),
- SERD_HAS_DATATYPE,
- serd_node_string_view(&serd_xsd_boolean.node));
-}
-
-SerdNode*
-serd_new_decimal(const double d, const SerdNode* const datatype)
-{
- // Use given datatype, or xsd:decimal as a default if it is null
- const SerdNode* type = datatype ? datatype : &serd_xsd_decimal.node;
- const size_t type_size = serd_node_total_size(type);
-
- // Measure integer string to know how much space the node will need
- ExessResult r = exess_write_decimal(d, 0, NULL);
- assert(!r.status);
+ SerdWriteResult r = serd_node_construct_boolean(0, NULL, b);
+ SerdNode* const node = serd_node_try_malloc(r);
- // Allocate node with enough space for value and datatype URI
- SerdNode* const node = serd_node_malloc(
- serd_node_pad_length(r.count) + type_size, SERD_HAS_DATATYPE, SERD_LITERAL);
-
- // Write string directly into node
- r = exess_write_decimal(d, r.count + 1, serd_node_buffer(node));
- assert(!r.status);
+ if (node) {
+ r = serd_node_construct_boolean(r.count, node, b);
+ MUST_SUCCEED(r.status);
+ assert(serd_node_length(node) == strlen(serd_node_string(node)));
+ }
- node->length = r.count;
- memcpy(serd_node_meta(node), type, type_size);
serd_node_check_padding(node);
return node;
}
SerdNode*
-serd_new_integer(const int64_t i, const SerdNode* const datatype)
+serd_new_decimal(const double d)
{
- // Use given datatype, or xsd:integer as a default if it is null
- const SerdNode* type = datatype ? datatype : &serd_xsd_integer.node;
- const size_t type_size = serd_node_total_size(type);
-
- // Measure integer string to know how much space the node will need
- ExessResult r = exess_write_long(i, 0, NULL);
- assert(!r.status);
-
- // Allocate node with enough space for value and datatype URI
- SerdNode* const node = serd_node_malloc(
- serd_node_pad_length(r.count) + type_size, SERD_HAS_DATATYPE, SERD_LITERAL);
+ SerdWriteResult r = serd_node_construct_decimal(0, NULL, d);
+ SerdNode* const node = serd_node_try_malloc(r);
- // Write string directly into node
- r = exess_write_long(i, r.count + 1, serd_node_buffer(node));
- assert(!r.status);
+ if (node) {
+ r = serd_node_construct_decimal(r.count, node, d);
+ MUST_SUCCEED(r.status);
+ assert(serd_node_length(node) == strlen(serd_node_string(node)));
+ }
- node->length = r.count;
- memcpy(serd_node_meta(node), type, type_size);
serd_node_check_padding(node);
return node;
}
-static size_t
-write_base64_literal(const void* const user_data,
- const size_t buf_size,
- char* const buf)
+SerdNode*
+serd_new_integer(const int64_t i, const SerdStringView datatype)
{
- const SerdConstBuffer blob = *(const SerdConstBuffer*)user_data;
+ SerdWriteResult r = serd_node_construct_integer(0, NULL, i, datatype);
+ SerdNode* const node = serd_node_try_malloc(r);
- const ExessResult r = exess_write_base64(blob.len, blob.buf, buf_size, buf);
+ if (node) {
+ r = serd_node_construct_integer(r.count, node, i, datatype);
+ MUST_SUCCEED(r.status);
+ assert(serd_node_length(node) == strlen(serd_node_string(node)));
+ }
- return r.status ? 0 : r.count;
+ serd_node_check_padding(node);
+ return node;
}
SerdNode*
-serd_new_base64(const void* buf, size_t size, const SerdNode* datatype)
+serd_new_base64(const void* buf, size_t size, const SerdStringView datatype)
{
- const size_t len = exess_write_base64(size, buf, 0, NULL).count;
- const SerdNode* type = datatype ? datatype : &serd_xsd_base64Binary.node;
- SerdConstBuffer blob = {buf, size};
+ SerdWriteResult r = serd_node_construct_base64(0, NULL, size, buf, datatype);
+ SerdNode* const node = serd_node_try_malloc(r);
+
+ if (node) {
+ r = serd_node_construct_base64(r.count, node, size, buf, datatype);
+ MUST_SUCCEED(r.status);
+ assert(serd_node_length(node) == strlen(serd_node_string(node)));
+ }
- return serd_new_custom_literal(&blob, len, write_base64_literal, type);
+ serd_node_check_padding(node);
+ return node;
}
SerdNodeType
@@ -696,3 +930,5 @@ serd_node_free(SerdNode* const node)
{
serd_free_aligned(node);
}
+
+#undef MUST_SUCCEED
diff --git a/src/node.h b/src/node.h
index affa2efc..ab10a3e7 100644
--- a/src/node.h
+++ b/src/node.h
@@ -20,6 +20,7 @@
#include "exess/exess.h"
#include "serd/serd.h"
+#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -32,6 +33,31 @@ struct SerdNodeImpl {
static const size_t serd_node_align = 2 * sizeof(uint64_t);
+#if SIZE_MAX == UINT64_MAX
+
+static inline size_t
+serd_node_pad_length(const size_t n_bytes)
+{
+ const size_t align = sizeof(SerdNode);
+
+ assert((align & (align - 1u)) == 0u);
+
+ return (n_bytes + align + 2u) & ~(align - 1u);
+}
+
+#else
+
+static inline size_t
+serd_node_pad_length(const size_t n_bytes)
+{
+ const size_t pad = sizeof(SerdNode) - (n_bytes + 2) % sizeof(SerdNode);
+ const size_t size = n_bytes + 2 + pad;
+ assert(size % sizeof(SerdNode) == 0);
+ return size;
+}
+
+#endif
+
static inline char* SERD_NONNULL
serd_node_buffer(SerdNode* SERD_NONNULL node)
{
@@ -44,6 +70,19 @@ serd_node_buffer_c(const SerdNode* SERD_NONNULL node)
return (const char*)(node + 1);
}
+static inline SerdNode* SERD_NONNULL
+serd_node_meta(SerdNode* const SERD_NONNULL node)
+{
+ return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
+}
+
+static inline const SerdNode* SERD_NONNULL
+serd_node_meta_c(const SerdNode* const SERD_NONNULL node)
+{
+ assert(node->flags & (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE));
+ return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
+}
+
static inline const char* SERD_NONNULL
serd_node_string_i(const SerdNode* const SERD_NONNULL node)
{
@@ -57,8 +96,17 @@ serd_node_pattern_match(const SerdNode* SERD_NULLABLE a,
return !a || !b || serd_node_equals(a, b);
}
+SERD_PURE_FUNC
+bool
+is_langtag(SerdStringView string);
+
+SERD_MALLOC_FUNC
+SerdNode* SERD_ALLOCATED
+serd_node_malloc(size_t size);
+
+SERD_MALLOC_FUNC
SerdNode* SERD_ALLOCATED
-serd_node_malloc(size_t length, SerdNodeFlags flags, SerdNodeType type);
+serd_node_try_malloc(SerdWriteResult result);
void
serd_node_set(SerdNode* SERD_NULLABLE* SERD_NONNULL dst,
@@ -66,7 +114,7 @@ serd_node_set(SerdNode* SERD_NULLABLE* SERD_NONNULL dst,
SERD_PURE_FUNC
size_t
-serd_node_total_size(const SerdNode* SERD_NULLABLE node);
+serd_node_total_size(const SerdNode* SERD_NONNULL node);
void
serd_node_zero_pad(SerdNode* SERD_NONNULL node);
diff --git a/src/nodes.c b/src/nodes.c
index 51f354bb..885731cc 100644
--- a/src/nodes.c
+++ b/src/nodes.c
@@ -174,7 +174,7 @@ serd_nodes_uri(SerdNodes* const nodes, const SerdStringView string)
const SerdNode*
serd_nodes_blank(SerdNodes* const nodes, const SerdStringView string)
{
- return serd_nodes_manage(nodes, serd_new_blank(string));
+ return serd_nodes_manage(nodes, serd_new_token(SERD_BLANK, string));
}
void
diff --git a/src/static_nodes.h b/src/static_nodes.h
deleted file mode 100644
index 467d846f..00000000
--- a/src/static_nodes.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- Copyright 2019-2020 David Robillard <d@drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#ifndef SERD_STATIC_NODES_H
-#define SERD_STATIC_NODES_H
-
-#include "serd/serd.h"
-
-#include "namespaces.h"
-#include "node.h"
-
-typedef struct StaticNode {
- SerdNode node;
- char buf[sizeof(NS_XSD "base64Binary") + sizeof(SerdNode)];
-} StaticNode;
-
-#define DEFINE_XSD_NODE(name) \
- static const StaticNode serd_xsd_##name = { \
- {sizeof(NS_XSD #name) - 1, 0, SERD_URI}, NS_XSD #name};
-
-DEFINE_XSD_NODE(base64Binary)
-DEFINE_XSD_NODE(boolean)
-DEFINE_XSD_NODE(decimal)
-DEFINE_XSD_NODE(double)
-DEFINE_XSD_NODE(float)
-DEFINE_XSD_NODE(integer)
-
-#endif // SERD_STATIC_NODES_H
diff --git a/src/world.c b/src/world.c
index d0ad60da..5af8c3d4 100644
--- a/src/world.c
+++ b/src/world.c
@@ -87,7 +87,7 @@ serd_world_new(void)
world->xsd_decimal = serd_nodes_uri(nodes, xsd_decimal);
world->xsd_integer = serd_nodes_uri(nodes, xsd_integer);
- world->blank_node = serd_new_blank(SERD_STRING("b00000000000"));
+ world->blank_node = serd_new_token(SERD_BLANK, SERD_STRING("b00000000000"));
world->nodes = nodes;
world->stderr_color = terminal_supports_color(stderr);