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 /src | |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/node.c | 18 | ||||
-rw-r--r-- | src/serd_internal.h | 6 | ||||
-rw-r--r-- | src/string.c | 47 |
3 files changed, 61 insertions, 10 deletions
@@ -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) { |