diff options
author | David Robillard <d@drobilla.net> | 2017-07-09 14:59:05 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2017-07-09 14:59:05 +0200 |
commit | 4d535bbe0390ed4f03c611e433145c9e49cbf3ad (patch) | |
tree | 3ec86327944909c214dabe419ef67c3400fb1aec | |
parent | 4270fbbc761e4d36e9fc28a361b7e8d7c21166d2 (diff) | |
download | serd-4d535bbe0390ed4f03c611e433145c9e49cbf3ad.tar.gz serd-4d535bbe0390ed4f03c611e433145c9e49cbf3ad.tar.bz2 serd-4d535bbe0390ed4f03c611e433145c9e49cbf3ad.zip |
Add serd_node_from_substring()
This allows creating nodes in-place from substrings of other strings to allow
zero-copy serialization from existing delimited buffers.
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | serd/serd.h | 10 | ||||
-rw-r--r-- | src/node.c | 18 | ||||
-rw-r--r-- | src/serd_internal.h | 6 | ||||
-rw-r--r-- | src/string.c | 47 | ||||
-rw-r--r-- | tests/serd_test.c | 21 | ||||
-rw-r--r-- | wscript | 2 |
7 files changed, 97 insertions, 13 deletions
@@ -1,9 +1,11 @@ -serd (0.27.1) unstable; +serd (0.27.2) unstable; * Add support for reading from a user provided callback + * Add serd_node_from_substring() * Fix strict parsing of abolute URI schemes + * Fix parsing of hex escapes in file URIs (thanks Johannes Mueller) - -- David Robillard <d@drobilla.net> Thu, 29 Jun 2017 12:20:40 -0400 + -- David Robillard <d@drobilla.net> Sun, 09 Jul 2017 14:58:47 +0200 serd (0.26.0) stable; diff --git a/serd/serd.h b/serd/serd.h index ca72a232..027c4e20 100644 --- a/serd/serd.h +++ b/serd/serd.h @@ -449,6 +449,16 @@ SerdNode serd_node_from_string(SerdType type, const uint8_t* str); /** + Make a (shallow) node from a prefix of `str`. + + This measures, but does not copy, `str`. No memory is allocated. + Note that the returned node may not be null terminated. +*/ +SERD_API +SerdNode +serd_node_from_substring(SerdType type, const uint8_t* str, size_t len); + +/** Make a deep copy of `node`. @return a node that the caller must free with serd_node_free(). @@ -48,6 +48,22 @@ serd_node_from_string(SerdType type, const uint8_t* str) SERD_API SerdNode +serd_node_from_substring(SerdType type, const uint8_t* str, const size_t len) +{ + if (!str) { + return SERD_NODE_NULL; + } + + uint32_t flags = 0; + size_t buf_n_bytes = 0; + const size_t buf_n_chars = serd_substrlen(str, len, &buf_n_bytes, &flags); + assert(buf_n_bytes <= len); + SerdNode ret = { str, buf_n_bytes, buf_n_chars, flags, type }; + return ret; +} + +SERD_API +SerdNode serd_node_copy(const SerdNode* node) { if (!node || !node->buf) { @@ -187,7 +203,7 @@ serd_node_new_file_uri(const uint8_t* path, serd_uri_parse(chunk.buf, out); } - return serd_node_from_string(SERD_URI, chunk.buf); + return serd_node_from_substring(SERD_URI, chunk.buf, chunk.len); } SERD_API diff --git a/src/serd_internal.h b/src/serd_internal.h index afbea5fb..55f6a6b6 100644 --- a/src/serd_internal.h +++ b/src/serd_internal.h @@ -325,6 +325,12 @@ is_windows_path(const uint8_t* path) && (path[2] == '/' || path[2] == '\\'); } +size_t +serd_substrlen(const uint8_t* str, + const size_t len, + size_t* n_bytes, + SerdNodeFlags* flags); + /* URI utilities */ static inline bool diff --git a/src/string.c b/src/string.c index 9381015d..dedd0713 100644 --- a/src/string.c +++ b/src/string.c @@ -36,6 +36,42 @@ serd_strerror(SerdStatus status) return (const uint8_t*)"Unknown error"; // never reached } +static inline void +serd_update_flags(const uint8_t c, SerdNodeFlags* const flags) +{ + switch (c) { + case '\r': case '\n': + *flags |= SERD_HAS_NEWLINE; + break; + case '"': + *flags |= SERD_HAS_QUOTE; + } +} + +size_t +serd_substrlen(const uint8_t* const str, + const size_t len, + size_t* const n_bytes, + SerdNodeFlags* const flags) +{ + size_t n_chars = 0; + size_t i = 0; + SerdNodeFlags f = 0; + for (; i < len && str[i]; ++i) { + if ((str[i] & 0xC0) != 0x80) { // Start of new character + ++n_chars; + serd_update_flags(str[i], &f); + } + } + if (n_bytes) { + *n_bytes = i; + } + if (flags) { + *flags = f; + } + return n_chars; +} + SERD_API size_t serd_strlen(const uint8_t* str, size_t* n_bytes, SerdNodeFlags* flags) @@ -44,16 +80,9 @@ serd_strlen(const uint8_t* str, size_t* n_bytes, SerdNodeFlags* flags) size_t i = 0; SerdNodeFlags f = 0; for (; str[i]; ++i) { - if ((str[i] & 0xC0) != 0x80) { - // Does not start with `10', start of a new character + if ((str[i] & 0xC0) != 0x80) { // Start of new character ++n_chars; - switch (str[i]) { - case '\r': case '\n': - f |= SERD_HAS_NEWLINE; - break; - case '"': - f |= SERD_HAS_QUOTE; - } + serd_update_flags(str[i], &f); } } if (n_bytes) { diff --git a/tests/serd_test.c b/tests/serd_test.c index 39ebc117..1eace3fd 100644 --- a/tests/serd_test.c +++ b/tests/serd_test.c @@ -366,6 +366,27 @@ main(void) return failure("Creating node from NULL string failed\n"); } + // Test serd_node_from_substring + + SerdNode empty = serd_node_from_substring(SERD_LITERAL, NULL, 32); + if (empty.buf || empty.n_bytes || empty.n_chars || empty.flags || empty.type) { + return failure("Successfully created node from NULL substring\n"); + } + + SerdNode a_b = serd_node_from_substring(SERD_LITERAL, USTR("a\"bc"), 3); + if (a_b.n_bytes != 3 || a_b.n_chars != 3 || a_b.flags != SERD_HAS_QUOTE + || strncmp((const char*)a_b.buf, "a\"b", 3)) { + return failure("Bad node %s %zu %zu %d %d\n", + a_b.buf, a_b.n_bytes, a_b.n_chars, a_b.flags, a_b.type); + } + + a_b = serd_node_from_substring(SERD_LITERAL, USTR("a\"bc"), 10); + if (a_b.n_bytes != 4 || a_b.n_chars != 4 || a_b.flags != SERD_HAS_QUOTE + || strncmp((const char*)a_b.buf, "a\"bc", 4)) { + return failure("Bad node %s %zu %zu %d %d\n", + a_b.buf, a_b.n_bytes, a_b.n_chars, a_b.flags, a_b.type); + } + // Test serd_node_new_uri_from_string SerdNode nonsense = serd_node_new_uri_from_string(NULL, NULL, NULL); @@ -11,7 +11,7 @@ import waflib.extras.autowaf as autowaf # major increment <=> incompatible changes # minor increment <=> compatible changes (additions) # micro increment <=> no interface changes -SERD_VERSION = '0.27.1' +SERD_VERSION = '0.27.2' SERD_MAJOR_VERSION = '0' # Mandatory waf variables |