aboutsummaryrefslogtreecommitdiffstats
path: root/src/node.c
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-08-14 16:05:10 +0200
committerDavid Robillard <d@drobilla.net>2021-03-07 15:32:24 -0500
commit6f03ae92415a7758fdc74f6720ec4955bc67fc0c (patch)
tree027582bca0844f8fe650db707eb14dc3b46c7598 /src/node.c
parent194d6f42583745c3fde6387b14abab2311b4f0b7 (diff)
downloadserd-6f03ae92415a7758fdc74f6720ec4955bc67fc0c.tar.gz
serd-6f03ae92415a7758fdc74f6720ec4955bc67fc0c.tar.bz2
serd-6f03ae92415a7758fdc74f6720ec4955bc67fc0c.zip
Merge datatype/language into node
This moves closer to the sord API, and is more convenient in most cases.
Diffstat (limited to 'src/node.c')
-rw-r--r--src/node.c149
1 files changed, 132 insertions, 17 deletions
diff --git a/src/node.c b/src/node.c
index b11625aa..14efddd3 100644
--- a/src/node.c
+++ b/src/node.c
@@ -17,10 +17,12 @@
#include "node.h"
#include "base64.h"
+#include "serd_internal.h"
#include "string_utils.h"
#include "serd/serd.h"
+#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdbool.h>
@@ -38,28 +40,55 @@
# endif
#endif
+static const size_t serd_node_align = sizeof(SerdNode);
+
+static size_t
+serd_node_pad_size(const size_t n_bytes)
+{
+ const size_t pad = serd_node_align - (n_bytes + 2) % serd_node_align;
+ return n_bytes + 2 + pad;
+}
+
+static const SerdNode*
+serd_node_maybe_get_meta_c(const SerdNode* node)
+{
+ return (node->flags & (SERD_HAS_LANGUAGE | SERD_HAS_DATATYPE))
+ ? (node + 1 + (serd_node_pad_size(node->n_bytes) / serd_node_align))
+ : NULL;
+}
+
+static SERD_PURE_FUNC
+size_t
+serd_node_total_size(const SerdNode* node)
+{
+ return node ? (sizeof(SerdNode) + serd_node_pad_size(node->n_bytes) +
+ serd_node_total_size(serd_node_maybe_get_meta_c(node)))
+ : 0;
+}
+
SerdNode*
serd_node_malloc(size_t n_bytes, SerdNodeFlags flags, SerdNodeType type)
{
- SerdNode* node = (SerdNode*)calloc(1, sizeof(SerdNode) + n_bytes + 1);
- node->n_bytes = 0;
- node->flags = flags;
- node->type = type;
+ const size_t size = sizeof(SerdNode) + serd_node_pad_size(n_bytes);
+ SerdNode* node = (SerdNode*)calloc(1, size);
+
+ node->n_bytes = 0;
+ node->flags = flags;
+ node->type = type;
+
+ assert((intptr_t)node % serd_node_align == 0);
return node;
}
void
serd_node_set(SerdNode** dst, const SerdNode* src)
{
- if (src) {
- if (!(*dst) || (*dst)->n_bytes < src->n_bytes) {
- (*dst) = (SerdNode*)realloc(*dst, sizeof(SerdNode) + src->n_bytes + 1);
- }
-
- memcpy(*dst, src, sizeof(SerdNode) + src->n_bytes + 1);
- } else if (*dst) {
- memset(*dst, 0, sizeof(SerdNode));
+ const size_t size = serd_node_total_size(src);
+ if (serd_node_total_size(*dst) < size) {
+ (*dst) = (SerdNode*)realloc(*dst, size);
}
+
+ memcpy(*dst, src, size);
}
SerdNode*
@@ -68,8 +97,10 @@ serd_new_string(SerdNodeType type, const char* str)
SerdNodeFlags flags = 0;
const size_t n_bytes = serd_strlen(str, &flags);
SerdNode* node = serd_node_malloc(n_bytes, flags, type);
+
memcpy(serd_node_buffer(node), str, n_bytes);
node->n_bytes = n_bytes;
+
return node;
}
@@ -85,14 +116,59 @@ serd_new_substring(SerdNodeType type, const char* str, const size_t len)
}
SerdNode*
+serd_new_literal(const char* str, const char* datatype, const char* lang)
+{
+ if (!str || (lang && datatype && strcmp(datatype, NS_RDF "#langString"))) {
+ return NULL;
+ }
+
+ SerdNodeFlags flags = 0;
+ const size_t n_bytes = serd_strlen(str, &flags);
+ const size_t len = serd_node_pad_size(n_bytes);
+
+ SerdNode* node = NULL;
+ if (lang) {
+ flags |= SERD_HAS_LANGUAGE;
+ const size_t lang_len = strlen(lang);
+ const size_t total_len = len + sizeof(SerdNode) + lang_len;
+ node = serd_node_malloc(total_len, flags, SERD_LITERAL);
+ memcpy(serd_node_buffer(node), str, n_bytes);
+ node->n_bytes = n_bytes;
+
+ 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, lang_len);
+ } else if (datatype) {
+ flags |= SERD_HAS_DATATYPE;
+ const size_t datatype_len = strlen(datatype);
+ const size_t total_len = len + sizeof(SerdNode) + datatype_len;
+ node = serd_node_malloc(total_len, flags, SERD_LITERAL);
+ memcpy(serd_node_buffer(node), str, n_bytes);
+ node->n_bytes = n_bytes;
+
+ SerdNode* datatype_node = node + 1 + (len / serd_node_align);
+ datatype_node->type = SERD_URI;
+ datatype_node->n_bytes = datatype_len;
+ memcpy(serd_node_buffer(datatype_node), datatype, datatype_len);
+ } else {
+ node = serd_node_malloc(n_bytes, flags, SERD_LITERAL);
+ memcpy(serd_node_buffer(node), str, n_bytes);
+ node->n_bytes = n_bytes;
+ }
+
+ return node;
+}
+
+SerdNode*
serd_node_copy(const SerdNode* node)
{
if (!node) {
return NULL;
}
- const size_t size = sizeof(SerdNode) + node->n_bytes + 1;
- SerdNode* copy = (SerdNode*)malloc(size);
+ const size_t size = serd_node_total_size(node);
+ SerdNode* copy = (SerdNode*)calloc(1, size + 3);
memcpy(copy, node, size);
return copy;
}
@@ -100,9 +176,16 @@ serd_node_copy(const SerdNode* node)
bool
serd_node_equals(const SerdNode* a, const SerdNode* b)
{
- return (a == b) ||
- (a && b && a->type == b->type && a->n_bytes == b->n_bytes &&
- !memcmp(serd_node_string(a), serd_node_string(b), a->n_bytes));
+ if (a == b) {
+ return true;
+ }
+
+ if (!a || !b) {
+ return false;
+ }
+
+ const size_t a_size = serd_node_total_size(a);
+ return serd_node_total_size(b) == a_size && !memcmp(a, b, a_size);
}
static size_t
@@ -416,6 +499,38 @@ serd_node_length(const SerdNode* node)
return node->n_bytes;
}
+const SerdNode*
+serd_node_datatype(const SerdNode* node)
+{
+ if (!node || !(node->flags & SERD_HAS_DATATYPE)) {
+ return NULL;
+ }
+
+ const size_t len = serd_node_pad_size(node->n_bytes);
+ assert((intptr_t)node % serd_node_align == 0);
+ assert(len % serd_node_align == 0);
+
+ const SerdNode* const datatype = node + 1 + (len / serd_node_align);
+ assert(datatype->type == SERD_URI || datatype->type == SERD_CURIE);
+ return datatype;
+}
+
+const SerdNode*
+serd_node_language(const SerdNode* node)
+{
+ if (!node || !(node->flags & SERD_HAS_LANGUAGE)) {
+ return NULL;
+ }
+
+ const size_t len = serd_node_pad_size(node->n_bytes);
+ assert((intptr_t)node % serd_node_align == 0);
+ assert(len % serd_node_align == 0);
+
+ const SerdNode* const lang = node + 1 + (len / serd_node_align);
+ assert(lang->type == SERD_LITERAL);
+ return lang;
+}
+
SerdNodeFlags
serd_node_flags(const SerdNode* node)
{