From c564145e6f9aebabb5dfe0896e36d2bb6bc8b6b9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 4 Feb 2018 18:35:41 +0100 Subject: Make nodes opaque --- src/node.c | 168 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 97 insertions(+), 71 deletions(-) (limited to 'src/node.c') diff --git a/src/node.c b/src/node.c index 65a2172b..e7e18533 100644 --- a/src/node.c +++ b/src/node.c @@ -31,52 +31,79 @@ # 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); } +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; + } +} + SERD_API -SerdNode -serd_node_from_string(SerdType type, const char* str) +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; } SERD_API -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; } SERD_API -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; } @@ -84,12 +111,11 @@ SERD_API 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 @@ -119,7 +145,7 @@ string_sink(const void* buf, size_t len, void* stream) } SERD_API -SerdNode +SerdNode* serd_node_new_uri_from_node(const SerdNode* uri_node, const SerdURI* base, SerdURI* out) @@ -127,18 +153,18 @@ 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; } SERD_API -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; @@ -166,7 +192,7 @@ is_uri_path_char(const char c) } SERD_API -SerdNode +SerdNode* serd_node_new_file_uri(const char* path, const char* hostname, SerdURI* out, @@ -201,16 +227,18 @@ 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; } SERD_API -SerdNode +SerdNode* serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out) { SerdURI abs_uri = *uri; @@ -219,23 +247,22 @@ 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; } SERD_API -SerdNode +SerdNode* serd_node_new_relative_uri(const SerdURI* uri, const SerdURI* base, const SerdURI* root, @@ -243,17 +270,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; @@ -267,18 +293,19 @@ serd_digits(double abs) } SERD_API -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; @@ -294,13 +321,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; @@ -309,7 +337,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) { @@ -322,13 +350,13 @@ serd_node_new_decimal(double d, unsigned frac_digits) } SERD_API -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; @@ -337,7 +365,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 { @@ -369,12 +397,12 @@ encode_chunk(uint8_t out[4], const uint8_t in[3], size_t n_in) } SERD_API -SerdNode +SerdNode* serd_node_new_blob(const void* buf, size_t size, bool wrap_lines) { const size_t len = ((size + 2) / 3) * 4 + (wrap_lines ? (size / 57) : 0); - uint8_t* str = (uint8_t*)calloc(1, len + 2); - 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); @@ -382,11 +410,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 + 1; return node; } @@ -401,7 +430,7 @@ SERD_API const char* serd_node_get_string(const SerdNode* node) { - return node ? node->buf : NULL; + return node ? (const char*)(node + 1) : NULL; } SERD_API @@ -422,8 +451,5 @@ SERD_API void serd_node_free(SerdNode* node) { - if (node && node->buf) { - free((char*)node->buf); - node->buf = NULL; - } + free(node); } -- cgit v1.2.1