diff options
author | David Robillard <d@drobilla.net> | 2021-07-22 23:39:39 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2022-01-14 19:37:51 -0500 |
commit | a63a8f19c54dfee75e092819d6622b8d36fe1d39 (patch) | |
tree | 3c2fe49c257e27d369365a0c08c1524baaf74a4c /src | |
parent | 64e81dfd6ec04995fd396269deb6b32fe2d1192d (diff) | |
download | serd-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.c | 28 | ||||
-rw-r--r-- | src/n3.c | 5 | ||||
-rw-r--r-- | src/node.c | 660 | ||||
-rw-r--r-- | src/node.h | 52 | ||||
-rw-r--r-- | src/nodes.c | 2 | ||||
-rw-r--r-- | src/static_nodes.h | 41 | ||||
-rw-r--r-- | src/world.c | 2 |
7 files changed, 519 insertions, 271 deletions
@@ -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* @@ -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); @@ -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 @@ -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); |