aboutsummaryrefslogtreecommitdiffstats
path: root/src/node.c
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-02-04 18:35:41 +0100
committerDavid Robillard <d@drobilla.net>2018-11-25 09:21:03 +0100
commit43e4cba8561d332cdc0fa9d257008dc68bb65a96 (patch)
tree7c4c773414bdda0e9c008e6c157f4bd88cd77cdf /src/node.c
parent7519da91b22e5c5898f522b897e1e77e7f0734b3 (diff)
downloadserd-43e4cba8561d332cdc0fa9d257008dc68bb65a96.tar.gz
serd-43e4cba8561d332cdc0fa9d257008dc68bb65a96.tar.bz2
serd-43e4cba8561d332cdc0fa9d257008dc68bb65a96.zip
Make nodes opaque
Diffstat (limited to 'src/node.c')
-rw-r--r--src/node.c172
1 files changed, 101 insertions, 71 deletions
diff --git a/src/node.c b/src/node.c
index 8b846aab..d32a0832 100644
--- a/src/node.c
+++ b/src/node.c
@@ -31,61 +31,87 @@
# endif
#endif
+SerdNode*
+serd_node_malloc(size_t n_bytes, SerdNodeFlags flags, SerdType type)
+{
+ SerdNode* node = (SerdNode*)calloc(1, sizeof(SerdNode) + n_bytes + 1);
+ node->n_bytes = 0;
+ node->flags = flags;
+ node->type = type;
+ return node;
+}
+
char*
serd_node_buffer(SerdNode* node)
{
return (char*)(node + 1);
}
-SerdNode
-serd_node_from_string(SerdType type, const char* str)
+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) {
+ (*dst)->type = SERD_NOTHING;
+ }
+}
+
+SerdNode*
+serd_node_new_string(SerdType type, const char* str)
{
if (!str) {
- return SERD_NODE_NULL;
+ return NULL;
}
- uint32_t flags = 0;
- const size_t n_bytes = serd_strlen(str, &flags);
- const SerdNode ret = { str, n_bytes, flags, type };
- return ret;
+ uint32_t 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;
}
-SerdNode
-serd_node_from_substring(SerdType type, const char* str, const size_t len)
+SerdNode*
+serd_node_new_substring(SerdType type, const char* str, const size_t len)
{
if (!str) {
- return SERD_NODE_NULL;
+ return NULL;
}
- uint32_t flags = 0;
- const size_t n_bytes = serd_substrlen(str, len, &flags);
- const SerdNode ret = { str, n_bytes, flags, type };
- return ret;
+ uint32_t flags = 0;
+ const size_t n_bytes = serd_substrlen(str, len, &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;
}
-SerdNode
+SerdNode*
serd_node_copy(const SerdNode* node)
{
- if (!node || !node->buf) {
- return SERD_NODE_NULL;
+ if (!node) {
+ return NULL;
}
- SerdNode copy = *node;
- char* buf = (char*)malloc(copy.n_bytes + 1);
- memcpy(buf, node->buf, copy.n_bytes + 1);
- copy.buf = buf;
+ const size_t size = sizeof(SerdNode) + node->n_bytes + 1;
+ SerdNode* copy = (SerdNode*)malloc(size);
+ memcpy(copy, node, size);
return copy;
}
bool
serd_node_equals(const SerdNode* a, const SerdNode* b)
{
- return (a == b)
- || (a->type == b->type
- && a->n_bytes == b->n_bytes
- && ((a->buf == b->buf) || !memcmp((const char*)a->buf,
- (const char*)b->buf,
- a->n_bytes + 1)));
+ return (a == b) ||
+ (a && b && a->type == b->type && a->n_bytes == b->n_bytes &&
+ !memcmp(serd_node_get_string(a),
+ serd_node_get_string(b),
+ a->n_bytes));
}
static size_t
@@ -114,7 +140,7 @@ string_sink(const void* buf, size_t len, void* stream)
return len;
}
-SerdNode
+SerdNode*
serd_node_new_uri_from_node(const SerdNode* uri_node,
const SerdURI* base,
SerdURI* out)
@@ -122,17 +148,17 @@ serd_node_new_uri_from_node(const SerdNode* uri_node,
const char* uri_str = serd_node_get_string(uri_node);
return (uri_node->type == SERD_URI && uri_str)
? serd_node_new_uri_from_string(uri_str, base, out)
- : SERD_NODE_NULL;
+ : NULL;
}
-SerdNode
+SerdNode*
serd_node_new_uri_from_string(const char* str,
const SerdURI* base,
SerdURI* out)
{
if (!str || str[0] == '\0') {
// Empty URI => Base URI, or nothing if no base is given
- return base ? serd_node_new_uri(base, NULL, out) : SERD_NODE_NULL;
+ return base ? serd_node_new_uri(base, NULL, out) : NULL;
}
SerdURI uri;
@@ -159,7 +185,7 @@ is_uri_path_char(const char c)
}
}
-SerdNode
+SerdNode*
serd_node_new_file_uri(const char* path,
const char* hostname,
SerdURI* out,
@@ -194,15 +220,17 @@ serd_node_new_file_uri(const char* path,
}
serd_buffer_sink_finish(&buffer);
+ SerdNode* node = serd_node_new_substring(
+ SERD_URI, (const char*)buffer.buf, buffer.len);
if (out) {
- serd_uri_parse((const char*)buffer.buf, out);
+ serd_uri_parse(serd_node_buffer(node), out);
}
- return serd_node_from_substring(
- SERD_URI, (const char*)buffer.buf, buffer.len);
+ free(buffer.buf);
+ return node;
}
-SerdNode
+SerdNode*
serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out)
{
SerdURI abs_uri = *uri;
@@ -211,22 +239,21 @@ serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out)
}
const size_t len = serd_uri_string_length(&abs_uri);
- char* buf = (char*)malloc(len + 1);
- SerdNode node = { buf, len, 0, SERD_URI };
- char* ptr = buf;
+ SerdNode* node = serd_node_malloc(len, 0, SERD_URI);
+ char* ptr = serd_node_buffer(node);
const size_t actual_len = serd_uri_serialise(&abs_uri, string_sink, &ptr);
- buf[actual_len] = '\0';
- node.n_bytes = actual_len;
+ serd_node_buffer(node)[actual_len] = '\0';
+ node->n_bytes = actual_len;
if (out) {
- serd_uri_parse(buf, out); // TODO: cleverly avoid double parse
+ serd_uri_parse(serd_node_buffer(node), out); // TODO: avoid double parse
}
return node;
}
-SerdNode
+SerdNode*
serd_node_new_relative_uri(const SerdURI* uri,
const SerdURI* base,
const SerdURI* root,
@@ -234,17 +261,16 @@ serd_node_new_relative_uri(const SerdURI* uri,
{
const size_t uri_len = serd_uri_string_length(uri);
const size_t base_len = serd_uri_string_length(base);
- char* buf = (char*)malloc(uri_len + base_len + 1);
- SerdNode node = { buf, 0, 0, SERD_URI };
- char* ptr = buf;
+ SerdNode* node = serd_node_malloc(uri_len + base_len, 0, SERD_URI);
+ char* ptr = serd_node_buffer(node);
const size_t actual_len = serd_uri_serialise_relative(
uri, base, root, string_sink, &ptr);
- buf[actual_len] = '\0';
- node.n_bytes = actual_len;
+ serd_node_buffer(node)[actual_len] = '\0';
+ node->n_bytes = actual_len;
if (out) {
- serd_uri_parse(buf, out); // TODO: cleverly avoid double parse
+ serd_uri_parse(serd_node_buffer(node), out); // TODO: avoid double parse
}
return node;
@@ -257,18 +283,19 @@ serd_digits(double abs)
return lg < 1.0 ? 1U : (unsigned)lg;
}
-SerdNode
+SerdNode*
serd_node_new_decimal(double d, unsigned frac_digits)
{
if (isnan(d) || isinf(d)) {
- return SERD_NODE_NULL;
+ return NULL;
}
- const double abs_d = fabs(d);
- const unsigned int_digits = serd_digits(abs_d);
- char* buf = (char*)calloc(int_digits + frac_digits + 3, 1);
- SerdNode node = { buf, 0, 0, SERD_LITERAL };
- const double int_part = floor(abs_d);
+ const double abs_d = fabs(d);
+ const unsigned int_digits = serd_digits(abs_d);
+ const size_t len = int_digits + frac_digits + 3;
+ SerdNode* const node = serd_node_malloc(len, 0, SERD_LITERAL);
+ char* const buf = serd_node_buffer(node);
+ const double int_part = floor(abs_d);
// Point s to decimal point location
char* s = buf + int_digits;
@@ -284,13 +311,14 @@ serd_node_new_decimal(double d, unsigned frac_digits)
*t-- = '0' + (dec % 10);
} while ((dec /= 10) > 0);
+
*s++ = '.';
// Write fractional part (right to left)
double frac_part = fabs(d - int_part);
if (frac_part < DBL_EPSILON) {
*s++ = '0';
- node.n_bytes = (s - buf);
+ node->n_bytes = (s - buf);
} else {
uint64_t frac = frac_part * pow(10.0, (int)frac_digits) + 0.5;
s += frac_digits - 1;
@@ -299,7 +327,7 @@ serd_node_new_decimal(double d, unsigned frac_digits)
// Skip trailing zeros
for (; i < frac_digits - 1 && !(frac % 10); ++i, --s, frac /= 10) {}
- node.n_bytes = (s - buf) + 1;
+ node->n_bytes = (s - buf) + 1;
// Write digits from last trailing zero to decimal point
for (; i < frac_digits; ++i) {
@@ -311,13 +339,13 @@ serd_node_new_decimal(double d, unsigned frac_digits)
return node;
}
-SerdNode
+SerdNode*
serd_node_new_integer(int64_t i)
{
int64_t abs_i = (i < 0) ? -i : i;
const unsigned digits = serd_digits(abs_i);
- char* buf = (char*)calloc(digits + 2, 1);
- SerdNode node = { (const char*)buf, 0, 0, SERD_LITERAL };
+ SerdNode* node = serd_node_malloc(digits + 2, 0, SERD_LITERAL);
+ char* buf = serd_node_buffer(node);
// Point s to the end
char* s = buf + digits - 1;
@@ -326,7 +354,7 @@ serd_node_new_integer(int64_t i)
++s;
}
- node.n_bytes = (s - buf) + 1;
+ node->n_bytes = (s - buf) + 1;
// Write integer part (right to left)
do {
@@ -357,12 +385,16 @@ encode_chunk(uint8_t out[4], const uint8_t in[3], size_t n_in)
out[3] = ((n_in > 2) ? b64_map[in[2] & 0x3F] : (uint8_t)'=');
}
-SerdNode
+SerdNode*
serd_node_new_blob(const void* buf, size_t size, bool wrap_lines)
{
+ if (!buf || !size) {
+ return NULL;
+ }
+
const size_t len = (size + 2) / 3 * 4 + (wrap_lines * ((size - 1) / 57));
- uint8_t* str = (uint8_t*)calloc(len + 2, 1);
- SerdNode node = { (const char*)str, len, 0, SERD_LITERAL };
+ SerdNode* node = serd_node_malloc(len + 1, 0, SERD_LITERAL);
+ uint8_t* str = (uint8_t*)serd_node_buffer(node);
for (size_t i = 0, j = 0; i < size; i += 3, j += 4) {
uint8_t in[4] = { 0, 0, 0, 0 };
size_t n_in = MIN(3, size - i);
@@ -370,11 +402,12 @@ serd_node_new_blob(const void* buf, size_t size, bool wrap_lines)
if (wrap_lines && i > 0 && (i % 57) == 0) {
str[j++] = '\n';
- node.flags |= SERD_HAS_NEWLINE;
+ node->flags |= SERD_HAS_NEWLINE;
}
encode_chunk(str + j, in, n_in);
}
+ node->n_bytes = len;
return node;
}
@@ -387,7 +420,7 @@ serd_node_get_type(const SerdNode* node)
const char*
serd_node_get_string(const SerdNode* node)
{
- return node ? node->buf : NULL;
+ return node ? (const char*)(node + 1) : NULL;
}
size_t
@@ -405,8 +438,5 @@ serd_node_get_flags(const SerdNode* node)
void
serd_node_free(SerdNode* node)
{
- if (node && node->buf) {
- free((char*)node->buf);
- node->buf = NULL;
- }
+ free(node);
}