diff options
author | David Robillard <d@drobilla.net> | 2023-09-10 15:06:42 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2023-12-02 18:49:08 -0500 |
commit | 248a874d7425749d29cf900a1c3783c624ea8d8c (patch) | |
tree | aed59f5a484a815cd254506866e98a947858904d /src | |
parent | 0bd10132c6707353dba80bd89cf0102ee7ca4e34 (diff) | |
download | serd-248a874d7425749d29cf900a1c3783c624ea8d8c.tar.gz serd-248a874d7425749d29cf900a1c3783c624ea8d8c.tar.bz2 serd-248a874d7425749d29cf900a1c3783c624ea8d8c.zip |
Add support for custom allocators
This makes it explicit in the API where memory is allocated, and allows the
user to provide a custom allocator to avoid the use of the default system
allocator for whatever reason.
Diffstat (limited to 'src')
-rw-r--r-- | src/block_dumper.c | 9 | ||||
-rw-r--r-- | src/block_dumper.h | 7 | ||||
-rw-r--r-- | src/buffer.c | 14 | ||||
-rw-r--r-- | src/byte_source.c | 51 | ||||
-rw-r--r-- | src/byte_source.h | 6 | ||||
-rw-r--r-- | src/caret.c | 24 | ||||
-rw-r--r-- | src/env.c | 134 | ||||
-rw-r--r-- | src/memory.c | 17 | ||||
-rw-r--r-- | src/memory.h | 136 | ||||
-rw-r--r-- | src/node.c | 145 | ||||
-rw-r--r-- | src/node.h | 12 | ||||
-rw-r--r-- | src/reader.c | 37 | ||||
-rw-r--r-- | src/serd_config.h | 13 | ||||
-rw-r--r-- | src/sink.c | 21 | ||||
-rw-r--r-- | src/sink.h | 8 | ||||
-rw-r--r-- | src/stack.h | 10 | ||||
-rw-r--r-- | src/statement.c | 56 | ||||
-rw-r--r-- | src/string.c | 8 | ||||
-rw-r--r-- | src/system.c | 48 | ||||
-rw-r--r-- | src/system.h | 20 | ||||
-rw-r--r-- | src/uri.c | 19 | ||||
-rw-r--r-- | src/world.c | 28 | ||||
-rw-r--r-- | src/world.h | 13 | ||||
-rw-r--r-- | src/writer.c | 95 |
24 files changed, 611 insertions, 320 deletions
diff --git a/src/block_dumper.c b/src/block_dumper.c index 174f0215..21a10fcc 100644 --- a/src/block_dumper.c +++ b/src/block_dumper.c @@ -2,12 +2,15 @@ // SPDX-License-Identifier: ISC #include "block_dumper.h" + +#include "memory.h" #include "system.h" #include <stddef.h> SerdStatus -serd_block_dumper_open(SerdBlockDumper* const dumper, +serd_block_dumper_open(const SerdWorld* const world, + SerdBlockDumper* const dumper, SerdOutputStream* const output, const size_t block_size) { @@ -24,7 +27,7 @@ serd_block_dumper_open(SerdBlockDumper* const dumper, return SERD_SUCCESS; } - dumper->buf = (char*)serd_allocate_buffer(block_size); + dumper->buf = (char*)serd_waligned_alloc(world, SERD_PAGE_SIZE, block_size); return dumper->buf ? SERD_SUCCESS : SERD_BAD_ALLOC; } @@ -50,5 +53,5 @@ serd_block_dumper_flush(SerdBlockDumper* const dumper) void serd_block_dumper_close(SerdBlockDumper* const dumper) { - serd_free_aligned(dumper->buf); + serd_aaligned_free(dumper->allocator, dumper->buf); } diff --git a/src/block_dumper.h b/src/block_dumper.h index 24fb977c..e5a2c318 100644 --- a/src/block_dumper.h +++ b/src/block_dumper.h @@ -4,14 +4,18 @@ #ifndef SERD_SRC_BLOCK_DUMPER_H #define SERD_SRC_BLOCK_DUMPER_H +#include "serd/memory.h" #include "serd/output_stream.h" #include "serd/status.h" +#include "serd/world.h" #include "zix/attributes.h" #include <stddef.h> #include <string.h> typedef struct { + SerdAllocator* ZIX_NONNULL allocator; ///< Buffer allocator + SerdOutputStream* ZIX_ALLOCATED out; ///< Output stream to write to char* ZIX_ALLOCATED buf; ///< Local buffer if needed size_t size; ///< Bytes pending for this block @@ -25,7 +29,8 @@ typedef struct { calling serd_block_dumper_close(). */ SerdStatus -serd_block_dumper_open(SerdBlockDumper* ZIX_NONNULL dumper, +serd_block_dumper_open(const SerdWorld* ZIX_NONNULL world, + SerdBlockDumper* ZIX_NONNULL dumper, SerdOutputStream* ZIX_NONNULL output, size_t block_size); diff --git a/src/buffer.c b/src/buffer.c index befa3943..c16a0ad6 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,11 +1,12 @@ // Copyright 2011-2021 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC +#include "memory.h" + #include "serd/buffer.h" #include <assert.h> #include <stddef.h> -#include <stdlib.h> #include <string.h> size_t @@ -20,20 +21,21 @@ serd_buffer_write(const void* const buf, SerdBuffer* const buffer = (SerdBuffer*)stream; const size_t n_bytes = size * nmemb; - char* const new_buf = (char*)realloc(buffer->buf, buffer->len + n_bytes); + char* const new_buf = + (char*)serd_arealloc(buffer->allocator, buffer->buf, buffer->len + n_bytes); + if (new_buf) { memcpy(new_buf + buffer->len, buf, n_bytes); buffer->buf = new_buf; buffer->len += nmemb; + return n_bytes; } - return new_buf ? nmemb : 0; + return 0; } int serd_buffer_close(void* const stream) { - serd_buffer_write("", 1, 1, stream); // Write null terminator - - return 0; + return serd_buffer_write("", 1, 1, stream) != 1; // Write null terminator } diff --git a/src/byte_source.c b/src/byte_source.c index e4810b60..cf9a2466 100644 --- a/src/byte_source.c +++ b/src/byte_source.c @@ -3,6 +3,7 @@ #include "byte_source.h" +#include "memory.h" #include "system.h" #include "serd/node.h" @@ -11,7 +12,6 @@ #include <assert.h> #include <stdbool.h> #include <stdint.h> -#include <stdlib.h> #include <string.h> SerdStatus @@ -40,33 +40,48 @@ serd_byte_source_page(SerdByteSource* const source) } static void -serd_byte_source_init_buffer(SerdByteSource* const source) +serd_byte_source_init_buffer(SerdAllocator* const allocator, + SerdByteSource* const source) { if (source->block_size > 1) { - source->block = (uint8_t*)serd_allocate_buffer(source->block_size); - source->read_buf = source->block; - memset(source->block, '\0', source->block_size); + source->block = (uint8_t*)serd_aaligned_alloc( + allocator, SERD_PAGE_SIZE, source->block_size); + + if ((source->read_buf = source->block)) { + memset(source->block, '\0', source->block_size); + } } else { source->read_buf = &source->read_byte; } } SerdByteSource* -serd_byte_source_new_input(SerdInputStream* const input, +serd_byte_source_new_input(SerdAllocator* const allocator, + SerdInputStream* const input, const SerdNode* const name, const size_t block_size) { assert(input); + assert(block_size); + assert(input->stream); - if (!block_size || !input->stream) { + SerdNode* const source_name = + name ? serd_node_copy(allocator, name) + : serd_new_string(allocator, serd_string("input")); + + if (!source_name) { return NULL; } - SerdByteSource* source = (SerdByteSource*)calloc(1, sizeof(SerdByteSource)); + SerdByteSource* source = + (SerdByteSource*)serd_acalloc(allocator, 1, sizeof(SerdByteSource)); - source->name = - name ? serd_node_copy(name) : serd_new_string(serd_string("input")); + if (!source) { + serd_node_free(allocator, source_name); + return NULL; + } + source->name = source_name; source->in = input; source->block_size = block_size; source->buf_size = block_size; @@ -74,21 +89,27 @@ serd_byte_source_new_input(SerdInputStream* const input, source->caret.line = 1U; source->caret.col = 1U; - serd_byte_source_init_buffer(source); + serd_byte_source_init_buffer(allocator, source); + if (block_size > 1 && !source->block) { + serd_node_free(allocator, source_name); + serd_afree(allocator, source); + return NULL; + } return source; } void -serd_byte_source_free(SerdByteSource* const source) +serd_byte_source_free(SerdAllocator* const allocator, + SerdByteSource* const source) { if (source) { if (source->block_size > 1) { - serd_free_aligned(source->block); + serd_aaligned_free(allocator, source->block); } - serd_node_free(source->name); - free(source); + serd_node_free(allocator, source->name); + serd_afree(allocator, source); } } diff --git a/src/byte_source.h b/src/byte_source.h index 3a16a7c6..ba63e794 100644 --- a/src/byte_source.h +++ b/src/byte_source.h @@ -8,6 +8,7 @@ #include "serd/caret.h" #include "serd/input_stream.h" +#include "serd/memory.h" #include "serd/node.h" #include "serd/status.h" #include "zix/attributes.h" @@ -32,12 +33,13 @@ typedef struct { } SerdByteSource; SerdByteSource* -serd_byte_source_new_input(SerdInputStream* input, +serd_byte_source_new_input(SerdAllocator* allocator, + SerdInputStream* input, const SerdNode* name, size_t block_size); void -serd_byte_source_free(SerdByteSource* source); +serd_byte_source_free(SerdAllocator* allocator, SerdByteSource* source); SerdStatus serd_byte_source_prepare(SerdByteSource* source); diff --git a/src/caret.c b/src/caret.c index 02d5b94b..2d7e9a8e 100644 --- a/src/caret.c +++ b/src/caret.c @@ -3,7 +3,10 @@ #include "caret.h" +#include "memory.h" + #include "serd/caret.h" +#include "serd/memory.h" #include <assert.h> #include <stdbool.h> @@ -11,13 +14,15 @@ #include <string.h> SerdCaret* -serd_caret_new(const SerdNode* const document, +serd_caret_new(SerdAllocator* const allocator, + const SerdNode* const document, const unsigned line, const unsigned column) { assert(document); - SerdCaret* caret = (SerdCaret*)malloc(sizeof(SerdCaret)); + SerdCaret* const caret = + (SerdCaret*)serd_amalloc(allocator, sizeof(SerdCaret)); if (caret) { caret->document = document; @@ -29,21 +34,26 @@ serd_caret_new(const SerdNode* const document, } SerdCaret* -serd_caret_copy(const SerdCaret* const caret) +serd_caret_copy(SerdAllocator* const allocator, const SerdCaret* const caret) { if (!caret) { return NULL; } - SerdCaret* copy = (SerdCaret*)malloc(sizeof(SerdCaret)); - memcpy(copy, caret, sizeof(SerdCaret)); + SerdCaret* const copy = + (SerdCaret*)serd_amalloc(allocator, sizeof(SerdCaret)); + + if (copy) { + memcpy(copy, caret, sizeof(SerdCaret)); + } + return copy; } void -serd_caret_free(SerdCaret* const caret) +serd_caret_free(SerdAllocator* const allocator, SerdCaret* const caret) { - free(caret); + serd_afree(allocator, caret); } bool @@ -4,6 +4,7 @@ #include "serd/env.h" #include "env.h" +#include "memory.h" #include "node.h" #include "serd/node.h" @@ -11,8 +12,6 @@ #include <assert.h> #include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> #include <string.h> typedef struct { @@ -21,42 +20,69 @@ typedef struct { } SerdPrefix; struct SerdEnvImpl { - SerdPrefix* prefixes; - size_t n_prefixes; - SerdNode* base_uri_node; - SerdURIView base_uri; + SerdAllocator* allocator; + SerdPrefix* prefixes; + size_t n_prefixes; + SerdNode* base_uri_node; + SerdURIView base_uri; }; SerdEnv* -serd_env_new(const SerdStringView base_uri) +serd_env_new(SerdAllocator* const allocator, const SerdStringView base_uri) { - SerdEnv* env = (SerdEnv*)calloc(1, sizeof(struct SerdEnvImpl)); - if (env && base_uri.length) { - serd_env_set_base_uri(env, base_uri); + SerdEnv* env = + (SerdEnv*)serd_acalloc(allocator, 1, sizeof(struct SerdEnvImpl)); + + if (env) { + env->allocator = allocator; + + if (base_uri.length) { + if (serd_env_set_base_uri(env, base_uri)) { + serd_afree(allocator, env); + return NULL; + } + } } return env; } SerdEnv* -serd_env_copy(const SerdEnv* const env) +serd_env_copy(SerdAllocator* const allocator, const SerdEnv* const env) { if (!env) { return NULL; } - SerdEnv* copy = (SerdEnv*)calloc(1, sizeof(struct SerdEnvImpl)); + SerdEnv* const copy = + (SerdEnv*)serd_acalloc(allocator, 1, sizeof(struct SerdEnvImpl)); + if (copy) { + copy->allocator = allocator; copy->n_prefixes = env->n_prefixes; - copy->prefixes = (SerdPrefix*)malloc(copy->n_prefixes * sizeof(SerdPrefix)); + + if (!(copy->prefixes = (SerdPrefix*)serd_acalloc( + allocator, copy->n_prefixes, sizeof(SerdPrefix)))) { + serd_afree(allocator, copy); + return NULL; + } + for (size_t i = 0; i < copy->n_prefixes; ++i) { - copy->prefixes[i].name = serd_node_copy(env->prefixes[i].name); - copy->prefixes[i].uri = serd_node_copy(env->prefixes[i].uri); + if (!(copy->prefixes[i].name = + serd_node_copy(allocator, env->prefixes[i].name)) || + !(copy->prefixes[i].uri = + serd_node_copy(allocator, env->prefixes[i].uri))) { + serd_env_free(copy); + return NULL; + } } const SerdNode* const base = serd_env_base_uri(env); if (base) { - serd_env_set_base_uri(copy, serd_node_string_view(base)); + if (serd_env_set_base_uri(copy, serd_node_string_view(base))) { + serd_env_free(copy); + return NULL; + } } } @@ -71,12 +97,12 @@ serd_env_free(SerdEnv* const env) } for (size_t i = 0; i < env->n_prefixes; ++i) { - serd_node_free(env->prefixes[i].name); - serd_node_free(env->prefixes[i].uri); + serd_node_free(env->allocator, env->prefixes[i].name); + serd_node_free(env->allocator, env->prefixes[i].uri); } - free(env->prefixes); - serd_node_free(env->base_uri_node); - free(env); + serd_afree(env->allocator, env->prefixes); + serd_node_free(env->allocator, env->base_uri_node); + serd_afree(env->allocator, env); } bool @@ -119,7 +145,7 @@ serd_env_set_base_uri(SerdEnv* const env, const SerdStringView uri) assert(env); if (!uri.length) { - serd_node_free(env->base_uri_node); + serd_node_free(env->allocator, env->base_uri_node); env->base_uri_node = NULL; env->base_uri = SERD_URI_NULL; return SERD_SUCCESS; @@ -132,10 +158,14 @@ serd_env_set_base_uri(SerdEnv* const env, const SerdStringView uri) serd_resolve_uri(serd_parse_uri(uri.data), env->base_uri); // Replace the current base URI - env->base_uri_node = serd_new_parsed_uri(new_base_uri); - env->base_uri = serd_node_uri_view(env->base_uri_node); + if ((env->base_uri_node = + serd_new_parsed_uri(env->allocator, new_base_uri))) { + env->base_uri = serd_node_uri_view(env->base_uri_node); + } else { + return SERD_BAD_ALLOC; + } - serd_node_free(old_base_uri); + serd_node_free(env->allocator, old_base_uri); return SERD_SUCCESS; } @@ -170,7 +200,7 @@ serd_env_find(const SerdEnv* const env, return NULL; } -static void +static SerdStatus serd_env_add(SerdEnv* const env, const SerdStringView name, const SerdStringView uri) @@ -178,18 +208,34 @@ serd_env_add(SerdEnv* const env, SerdPrefix* const prefix = serd_env_find(env, name.data, name.length); if (prefix) { if (!!strcmp(serd_node_string(prefix->uri), uri.data)) { - serd_node_free(prefix->uri); - prefix->uri = serd_new_uri(uri); + serd_node_free(env->allocator, prefix->uri); + prefix->uri = serd_new_uri(env->allocator, uri); } } else { - SerdPrefix* const new_prefixes = (SerdPrefix*)realloc( - env->prefixes, (++env->n_prefixes) * sizeof(SerdPrefix)); - if (new_prefixes) { - env->prefixes = new_prefixes; - env->prefixes[env->n_prefixes - 1].name = serd_new_string(name); - env->prefixes[env->n_prefixes - 1].uri = serd_new_uri(uri); + SerdPrefix* const new_prefixes = + (SerdPrefix*)serd_arealloc(env->allocator, + env->prefixes, + (env->n_prefixes + 1) * sizeof(SerdPrefix)); + if (!new_prefixes) { + return SERD_BAD_ALLOC; } + + env->prefixes = new_prefixes; + + SerdNode* const name_node = serd_new_string(env->allocator, name); + SerdNode* const uri_node = serd_new_uri(env->allocator, uri); + if (!name_node || !uri_node) { + serd_node_free(env->allocator, uri_node); + serd_node_free(env->allocator, name_node); + return SERD_BAD_ALLOC; + } + + new_prefixes[env->n_prefixes].name = name_node; + new_prefixes[env->n_prefixes].uri = uri_node; + ++env->n_prefixes; } + + return SERD_SUCCESS; } SerdStatus @@ -201,8 +247,7 @@ serd_env_set_prefix(SerdEnv* const env, if (serd_uri_string_has_scheme(uri.data)) { // Set prefix to absolute URI - serd_env_add(env, name, uri); - return SERD_SUCCESS; + return serd_env_add(env, name, uri); } if (!env->base_uri_node) { @@ -215,13 +260,17 @@ serd_env_set_prefix(SerdEnv* const env, assert(abs_uri_view.scheme.length); // Create a new node for the absolute URI - SerdNode* const abs_uri = serd_new_parsed_uri(abs_uri_view); + SerdNode* const abs_uri = serd_new_parsed_uri(env->allocator, abs_uri_view); + if (!abs_uri) { + return SERD_BAD_ALLOC; + } + assert(serd_uri_string_has_scheme(serd_node_string(abs_uri))); // Set prefix to resolved (absolute) URI - serd_env_add(env, name, serd_node_string_view(abs_uri)); - serd_node_free(abs_uri); - return SERD_SUCCESS; + const SerdStatus st = serd_env_add(env, name, serd_node_string_view(abs_uri)); + serd_node_free(env->allocator, abs_uri); + return st; } SerdStatus @@ -290,7 +339,7 @@ serd_env_expand_curie(const SerdEnv* const env, const SerdStringView curie) } const size_t len = prefix.length + suffix.length; - SerdNode* const ret = serd_node_malloc(len, 0U, SERD_URI); + SerdNode* const ret = serd_node_malloc(env->allocator, len, 0U, SERD_URI); if (ret) { char* const string = serd_node_buffer(ret); memcpy(string, prefix.data, prefix.length); @@ -310,7 +359,8 @@ serd_env_expand_node(const SerdEnv* const env, const SerdNode* const node) const SerdURIView uri = serd_node_uri_view(node); const SerdURIView abs_uri = serd_resolve_uri(uri, env->base_uri); - return abs_uri.scheme.length ? serd_new_parsed_uri(abs_uri) : NULL; + return abs_uri.scheme.length ? serd_new_parsed_uri(env->allocator, abs_uri) + : NULL; } SerdStatus diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 00000000..74694c14 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,17 @@ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#include "memory.h" + +#include "serd/memory.h" +#include "zix/allocator.h" + +SerdAllocator* +serd_default_allocator(void) +{ + /* Note that SerdAllocator is intentionally the same as ZixAllocator. It + only exists to avoid exposing the zix API in the public serd API, which + I'm not sure would be appropriate. */ + + return (SerdAllocator*)zix_default_allocator(); +} diff --git a/src/memory.h b/src/memory.h new file mode 100644 index 00000000..80c60724 --- /dev/null +++ b/src/memory.h @@ -0,0 +1,136 @@ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#ifndef SERD_SRC_MEMORY_H +#define SERD_SRC_MEMORY_H + +#include "serd/memory.h" +#include "serd/world.h" + +#include <stddef.h> +#include <string.h> + +// Allocator convenience wrappers that fall back to the default for NULL + +/// Convenience wrapper that defers to malloc() if allocator is null +static inline void* +serd_amalloc(SerdAllocator* const allocator, const size_t size) +{ + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + return actual->malloc(actual, size); +} + +/// Convenience wrapper that defers to calloc() if allocator is null +static inline void* +serd_acalloc(SerdAllocator* const allocator, + const size_t nmemb, + const size_t size) +{ + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + return actual->calloc(actual, nmemb, size); +} + +/// Convenience wrapper that defers to realloc() if allocator is null +static inline void* +serd_arealloc(SerdAllocator* const allocator, + void* const ptr, + const size_t size) +{ + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + return actual->realloc(actual, ptr, size); +} + +/// Convenience wrapper that defers to free() if allocator is null +static inline void +serd_afree(SerdAllocator* const allocator, void* const ptr) +{ + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + actual->free(actual, ptr); +} + +/// Convenience wrapper that defers to the system allocator if allocator is null +static inline void* +serd_aaligned_alloc(SerdAllocator* const allocator, + const size_t alignment, + const size_t size) +{ + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + return actual->aligned_alloc(actual, alignment, size); +} + +/// Convenience wrapper for serd_aaligned_alloc that zeros memory +static inline void* +serd_aaligned_calloc(SerdAllocator* const allocator, + const size_t alignment, + const size_t size) +{ + void* const ptr = serd_aaligned_alloc(allocator, alignment, size); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; +} + +/// Convenience wrapper that defers to the system allocator if allocator is null +static inline void +serd_aaligned_free(SerdAllocator* const allocator, void* const ptr) +{ + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + actual->aligned_free(actual, ptr); +} + +// World convenience wrappers + +static inline void* +serd_wmalloc(const SerdWorld* const world, const size_t size) +{ + return serd_amalloc(serd_world_allocator(world), size); +} + +static inline void* +serd_wcalloc(const SerdWorld* const world, + const size_t nmemb, + const size_t size) +{ + return serd_acalloc(serd_world_allocator(world), nmemb, size); +} + +static inline void* +serd_wrealloc(const SerdWorld* const world, void* const ptr, const size_t size) +{ + return serd_arealloc(serd_world_allocator(world), ptr, size); +} + +static inline void +serd_wfree(const SerdWorld* const world, void* const ptr) +{ + serd_afree(serd_world_allocator(world), ptr); +} + +static inline void* +serd_waligned_alloc(const SerdWorld* const world, + const size_t alignment, + const size_t size) +{ + return serd_aaligned_alloc(serd_world_allocator(world), alignment, size); +} + +static inline void +serd_waligned_free(const SerdWorld* const world, void* const ptr) +{ + serd_aaligned_free(serd_world_allocator(world), ptr); +} + +#endif // SERD_SRC_MEMORY_H @@ -3,9 +3,9 @@ #include "node.h" +#include "memory.h" #include "namespaces.h" #include "string_utils.h" -#include "system.h" #include "exess/exess.h" #include "serd/buffer.h" @@ -110,35 +110,46 @@ serd_node_total_size(const SerdNode* const node) } SerdNode* -serd_node_malloc(const size_t length, - const SerdNodeFlags flags, - const SerdNodeType type) +serd_node_malloc(SerdAllocator* const allocator, + const size_t length, + const SerdNodeFlags flags, + const SerdNodeType type) { const size_t size = sizeof(SerdNode) + serd_node_pad_length(length); - SerdNode* node = (SerdNode*)serd_calloc_aligned(serd_node_align, size); - node->length = 0; - node->flags = flags; - node->type = type; + SerdNode* const node = + (SerdNode*)serd_aaligned_calloc(allocator, serd_node_align, size); + + if (node) { + node->length = 0; + node->flags = flags; + node->type = type; + } assert((uintptr_t)node % serd_node_align == 0U); return node; } -void -serd_node_set(SerdNode** const dst, const SerdNode* const src) +SerdStatus +serd_node_set(SerdAllocator* const allocator, + SerdNode** const dst, + const SerdNode* const src) { assert(dst); assert(src); const size_t size = serd_node_total_size(src); if (!*dst || serd_node_total_size(*dst) < size) { - serd_free_aligned(*dst); - *dst = (SerdNode*)serd_calloc_aligned(serd_node_align, size); + serd_aaligned_free(allocator, *dst); + if (!(*dst = (SerdNode*)serd_aaligned_calloc( + allocator, serd_node_align, size))) { + return SERD_BAD_ALLOC; + } } assert(*dst); memcpy(*dst, src, size); + return SERD_SUCCESS; } /** @@ -169,11 +180,13 @@ result(const SerdStatus status, const size_t count) } SerdNode* -serd_new_token(const SerdNodeType type, const SerdStringView str) +serd_new_token(SerdAllocator* const allocator, + const SerdNodeType type, + const SerdStringView str) { SerdNodeFlags flags = 0U; const size_t length = str.data ? str.length : 0U; - SerdNode* node = serd_node_malloc(length, flags, type); + SerdNode* node = serd_node_malloc(allocator, length, flags, type); if (node) { if (str.data) { @@ -189,10 +202,10 @@ serd_new_token(const SerdNodeType type, const SerdStringView str) } SerdNode* -serd_new_string(const SerdStringView str) +serd_new_string(SerdAllocator* const allocator, const SerdStringView str) { SerdNodeFlags flags = 0U; - SerdNode* node = serd_node_malloc(str.length, flags, SERD_LITERAL); + SerdNode* node = serd_node_malloc(allocator, str.length, flags, SERD_LITERAL); if (node) { if (str.data && str.length) { @@ -236,12 +249,14 @@ is_langtag(const SerdStringView string) } SerdNode* -serd_new_literal(const SerdStringView string, +serd_new_literal(SerdAllocator* const allocator, + const SerdStringView string, const SerdNodeFlags flags, const SerdStringView meta) { if (!(flags & (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE))) { - SerdNode* node = serd_node_malloc(string.length, flags, SERD_LITERAL); + SerdNode* node = + serd_node_malloc(allocator, string.length, flags, SERD_LITERAL); memcpy(serd_node_buffer(node), string.data, string.length); node->length = string.length; @@ -268,7 +283,8 @@ serd_new_literal(const SerdStringView string, const size_t meta_len = serd_node_pad_length(meta.length); const size_t meta_size = sizeof(SerdNode) + meta_len; - SerdNode* node = serd_node_malloc(len + meta_size, flags, SERD_LITERAL); + SerdNode* node = + serd_node_malloc(allocator, len + meta_size, flags, SERD_LITERAL); memcpy(serd_node_buffer(node), string.data, string.length); node->length = string.length; @@ -283,9 +299,9 @@ serd_new_literal(const SerdStringView string, } SerdNode* -serd_new_blank(const SerdStringView str) +serd_new_blank(SerdAllocator* const allocator, const SerdStringView str) { - return serd_new_token(SERD_BLANK, str); + return serd_new_token(allocator, SERD_BLANK, str); } ExessResult @@ -396,16 +412,20 @@ serd_get_base64(const SerdNode* const node, } SerdNode* -serd_node_copy(const SerdNode* node) +serd_node_copy(SerdAllocator* const allocator, const SerdNode* node) { if (!node) { return NULL; } const size_t size = serd_node_total_size(node); - SerdNode* copy = (SerdNode*)serd_calloc_aligned(serd_node_align, size); + SerdNode* copy = + (SerdNode*)serd_aaligned_alloc(allocator, serd_node_align, size); + + if (copy) { + memcpy(copy, node, size); + } - memcpy(copy, node, size); return copy; } @@ -466,39 +486,45 @@ serd_node_compare(const SerdNode* const a, const SerdNode* const b) } SerdNode* -serd_new_uri(const SerdStringView string) +serd_new_uri(SerdAllocator* const allocator, const SerdStringView string) { - return serd_new_token(SERD_URI, string); + return serd_new_token(allocator, SERD_URI, string); } SerdNode* -serd_new_parsed_uri(const SerdURIView uri) +serd_new_parsed_uri(SerdAllocator* const allocator, const SerdURIView uri) { - const size_t len = serd_uri_string_length(uri); - SerdNode* const node = serd_node_malloc(len, 0, SERD_URI); - char* ptr = serd_node_buffer(node); - const size_t actual_len = serd_write_uri(uri, string_sink, &ptr); + const size_t len = serd_uri_string_length(uri); + SerdNode* const node = serd_node_malloc(allocator, len, 0, SERD_URI); - assert(actual_len == len); + if (node) { + char* ptr = serd_node_buffer(node); + const size_t actual_len = serd_write_uri(uri, string_sink, &ptr); + + assert(actual_len == len); - serd_node_buffer(node)[actual_len] = '\0'; - node->length = actual_len; + serd_node_buffer(node)[actual_len] = '\0'; + node->length = actual_len; + } serd_node_check_padding(node); return node; } SerdNode* -serd_new_file_uri(const SerdStringView path, const SerdStringView hostname) +serd_new_file_uri(SerdAllocator* const allocator, + const SerdStringView path, + const SerdStringView hostname) { - SerdBuffer buffer = {NULL, 0U}; + SerdBuffer buffer = {NULL, NULL, 0U}; serd_write_file_uri(path, hostname, serd_buffer_write, &buffer); serd_buffer_close(&buffer); const size_t length = buffer.len; const char* const string = (char*)buffer.buf; - SerdNode* const node = serd_new_string(serd_substring(string, length)); + SerdNode* const node = + serd_new_string(allocator, serd_substring(string, length)); free(buffer.buf); serd_node_check_padding(node); @@ -510,7 +536,8 @@ typedef size_t (*SerdWriteLiteralFunc)(const void* user_data, char* buf); static SerdNode* -serd_new_custom_literal(const void* const user_data, +serd_new_custom_literal(SerdAllocator* const allocator, + const void* const user_data, const size_t len, const SerdWriteLiteralFunc write, const SerdNode* const datatype) @@ -523,7 +550,7 @@ serd_new_custom_literal(const void* const user_data, const size_t total_size = serd_node_pad_length(len) + datatype_size; SerdNode* const node = serd_node_malloc( - total_size, datatype ? SERD_HAS_DATATYPE : 0U, SERD_LITERAL); + allocator, total_size, datatype ? SERD_HAS_DATATYPE : 0U, SERD_LITERAL); node->length = write(user_data, len + 1, serd_node_buffer(node)); @@ -531,46 +558,50 @@ serd_new_custom_literal(const void* const user_data, memcpy(serd_node_meta(node), datatype, datatype_size); } - serd_node_check_padding(node); return node; } SerdNode* -serd_new_double(const double d) +serd_new_double(SerdAllocator* const allocator, const double d) { char buf[EXESS_MAX_DOUBLE_LENGTH + 1] = {0}; const ExessResult r = exess_write_double(d, sizeof(buf), buf); return r.status ? NULL - : serd_new_literal(serd_substring(buf, r.count), + : serd_new_literal(allocator, + serd_substring(buf, r.count), SERD_HAS_DATATYPE, serd_string(EXESS_XSD_URI "double")); } SerdNode* -serd_new_float(const float f) +serd_new_float(SerdAllocator* const allocator, const float f) { char buf[EXESS_MAX_FLOAT_LENGTH + 1] = {0}; const ExessResult r = exess_write_float(f, sizeof(buf), buf); return r.status ? NULL - : serd_new_literal(serd_substring(buf, r.count), + : serd_new_literal(allocator, + serd_substring(buf, r.count), SERD_HAS_DATATYPE, serd_string(EXESS_XSD_URI "float")); } SerdNode* -serd_new_boolean(bool b) +serd_new_boolean(SerdAllocator* const allocator, bool b) { - return serd_new_literal(b ? serd_string("true") : serd_string("false"), + return serd_new_literal(allocator, + b ? serd_string("true") : serd_string("false"), SERD_HAS_DATATYPE, serd_node_string_view(&serd_xsd_boolean.node)); } SerdNode* -serd_new_decimal(const double d, const SerdNode* const datatype) +serd_new_decimal(SerdAllocator* const allocator, + const double d, + const SerdNode* const datatype) { // Use given datatype, or xsd:decimal as a default if it is null const SerdNode* type = datatype ? datatype : &serd_xsd_decimal.node; @@ -581,8 +612,11 @@ serd_new_decimal(const double d, const SerdNode* const datatype) assert(!r.status); // Allocate node with enough space for value and datatype URI - SerdNode* const node = serd_node_malloc( - serd_node_pad_length(r.count) + type_size, SERD_HAS_DATATYPE, SERD_LITERAL); + SerdNode* const node = + serd_node_malloc(allocator, + serd_node_pad_length(r.count) + type_size, + SERD_HAS_DATATYPE, + SERD_LITERAL); // Write string directly into node r = exess_write_decimal(d, r.count + 1, serd_node_buffer(node)); @@ -595,7 +629,7 @@ serd_new_decimal(const double d, const SerdNode* const datatype) } SerdNode* -serd_new_integer(const int64_t i) +serd_new_integer(SerdAllocator* const allocator, const int64_t i) { // Use given datatype, or xsd:integer as a default if it is null const SerdNode* datatype = &serd_xsd_integer.node; @@ -607,7 +641,8 @@ serd_new_integer(const int64_t i) // Allocate node with enough space for value and datatype URI SerdNode* const node = - serd_node_malloc(serd_node_pad_length(r.count) + datatype_size, + serd_node_malloc(allocator, + serd_node_pad_length(r.count) + datatype_size, SERD_HAS_DATATYPE, SERD_LITERAL); @@ -634,13 +669,13 @@ write_base64_literal(const void* const user_data, } SerdNode* -serd_new_base64(const void* buf, size_t size) +serd_new_base64(SerdAllocator* const allocator, const void* buf, size_t size) { const size_t len = exess_write_base64(size, buf, 0, NULL).count; SerdConstBuffer blob = {buf, size}; return serd_new_custom_literal( - &blob, len, write_base64_literal, &serd_xsd_base64Binary.node); + allocator, &blob, len, write_base64_literal, &serd_xsd_base64Binary.node); } SerdNodeType @@ -721,7 +756,7 @@ serd_node_flags(const SerdNode* const node) } void -serd_node_free(SerdNode* const node) +serd_node_free(SerdAllocator* const allocator, SerdNode* const node) { - serd_free_aligned(node); + serd_aaligned_free(allocator, node); } @@ -5,7 +5,9 @@ #define SERD_SRC_NODE_H #include "exess/exess.h" +#include "serd/memory.h" #include "serd/node.h" +#include "serd/status.h" #include "zix/attributes.h" #include <stdbool.h> @@ -46,10 +48,14 @@ serd_node_pattern_match(const SerdNode* ZIX_NULLABLE a, } SerdNode* ZIX_ALLOCATED -serd_node_malloc(size_t length, SerdNodeFlags flags, SerdNodeType type); +serd_node_malloc(SerdAllocator* ZIX_NULLABLE allocator, + size_t length, + SerdNodeFlags flags, + SerdNodeType type); -void -serd_node_set(SerdNode* ZIX_NONNULL* ZIX_NONNULL dst, +SerdStatus +serd_node_set(SerdAllocator* ZIX_NULLABLE allocator, + SerdNode* ZIX_NONNULL* ZIX_NONNULL dst, const SerdNode* ZIX_NONNULL src); ZIX_PURE_FUNC size_t diff --git a/src/reader.c b/src/reader.c index 8b74836f..bbb1325b 100644 --- a/src/reader.c +++ b/src/reader.c @@ -4,6 +4,7 @@ #include "reader.h" #include "byte_source.h" +#include "memory.h" #include "namespaces.h" #include "node.h" #include "read_nquads.h" @@ -13,7 +14,6 @@ #include "stack.h" #include "statement.h" #include "string_utils.h" -#include "system.h" #include "world.h" #include "serd/input_stream.h" @@ -22,7 +22,6 @@ #include <assert.h> #include <stdarg.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> static SerdStatus @@ -241,17 +240,25 @@ serd_reader_new(SerdWorld* const world, return NULL; } - SerdReader* me = (SerdReader*)calloc(1, sizeof(SerdReader)); + SerdReader* me = (SerdReader*)serd_wcalloc(world, 1, sizeof(SerdReader)); + if (!me) { + return NULL; + } me->world = world; me->sink = sink; me->env = env; - me->stack = serd_stack_new(stack_size, serd_node_align); + me->stack = serd_stack_new(world->allocator, stack_size, serd_node_align); me->syntax = syntax; me->flags = flags; me->next_id = 1; me->strict = !(flags & SERD_READ_LAX); + if (!me->stack.buf) { + serd_wfree(world, me); + return NULL; + } + // Reserve a bit of space at the end of the stack to zero pad nodes me->stack.buf_size -= serd_node_align; @@ -278,9 +285,9 @@ serd_reader_free(SerdReader* const reader) serd_reader_finish(reader); } - serd_free_aligned(reader->stack.buf); - free(reader->bprefix); - free(reader); + serd_aaligned_free(reader->world->allocator, reader->stack.buf); + serd_wfree(reader->world, reader->bprefix); + serd_wfree(reader->world, reader); } void @@ -288,14 +295,15 @@ serd_reader_add_blank_prefix(SerdReader* const reader, const char* const prefix) { assert(reader); - free(reader->bprefix); + serd_wfree(reader->world, reader->bprefix); reader->bprefix_len = 0; reader->bprefix = NULL; const size_t prefix_len = prefix ? strlen(prefix) : 0; if (prefix_len) { reader->bprefix_len = prefix_len; - reader->bprefix = (char*)malloc(reader->bprefix_len + 1); + reader->bprefix = + (char*)serd_wmalloc(reader->world, reader->bprefix_len + 1); memcpy(reader->bprefix, prefix, reader->bprefix_len + 1); } } @@ -326,13 +334,18 @@ serd_reader_start(SerdReader* const reader, assert(reader); assert(input); + if (!block_size || !input->stream) { + return SERD_BAD_ARG; + } + if (reader->source) { return SERD_BAD_CALL; } - reader->source = serd_byte_source_new_input(input, input_name, block_size); + reader->source = serd_byte_source_new_input( + reader->world->allocator, input, input_name, block_size); - return reader->source ? SERD_SUCCESS : SERD_BAD_ARG; + return reader->source ? SERD_SUCCESS : SERD_BAD_ALLOC; } static SerdStatus @@ -393,7 +406,7 @@ serd_reader_finish(SerdReader* const reader) { assert(reader); - serd_byte_source_free(reader->source); + serd_byte_source_free(reader->world->allocator, reader->source); reader->source = NULL; return SERD_SUCCESS; } diff --git a/src/serd_config.h b/src/serd_config.h index 0bd9b5ac..0146c181 100644 --- a/src/serd_config.h +++ b/src/serd_config.h @@ -74,13 +74,6 @@ # endif # endif -// POSIX.1-2001: posix_memalign() -# ifndef HAVE_POSIX_MEMALIGN -# if SERD_POSIX_VERSION >= 200112L -# define HAVE_POSIX_MEMALIGN 1 -# endif -# endif - // POSIX.1-2001: strerror_r() # ifndef HAVE_STRERROR_R # if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L @@ -116,12 +109,6 @@ # define USE_POSIX_FADVISE 0 #endif -#if defined(HAVE_POSIX_MEMALIGN) && HAVE_POSIX_MEMALIGN -# define USE_POSIX_MEMALIGN 1 -#else -# define USE_POSIX_MEMALIGN 0 -#endif - #ifdef HAVE_STRERROR_R # define USE_STRERROR_R 1 #else @@ -3,6 +3,7 @@ #include "sink.h" +#include "memory.h" #include "statement.h" #include "serd/node.h" @@ -14,15 +15,19 @@ #include <stdlib.h> SerdSink* -serd_sink_new(void* const handle, - SerdEventFunc event_func, - SerdFreeFunc free_handle) +serd_sink_new(SerdAllocator* const allocator, + void* const handle, + SerdEventFunc event_func, + SerdFreeFunc free_handle) { - SerdSink* sink = (SerdSink*)calloc(1, sizeof(SerdSink)); + SerdSink* sink = (SerdSink*)serd_acalloc(allocator, 1, sizeof(SerdSink)); - sink->handle = handle; - sink->on_event = event_func; - sink->free_handle = free_handle; + if (sink) { + sink->allocator = allocator; + sink->handle = handle; + sink->on_event = event_func; + sink->free_handle = free_handle; + } return sink; } @@ -35,7 +40,7 @@ serd_sink_free(SerdSink* sink) sink->free_handle(sink->handle); } - free(sink); + serd_afree(sink->allocator, sink); } } @@ -5,15 +5,17 @@ #define SERD_SRC_SINK_H #include "serd/event.h" +#include "serd/memory.h" #include "serd/sink.h" /** An interface that receives a stream of RDF data. */ struct SerdSinkImpl { - void* handle; - SerdFreeFunc free_handle; - SerdEventFunc on_event; + SerdAllocator* allocator; + void* handle; + SerdFreeFunc free_handle; + SerdEventFunc on_event; }; #endif // SERD_SRC_SINK_H diff --git a/src/stack.h b/src/stack.h index 20bd561b..40e8065d 100644 --- a/src/stack.h +++ b/src/stack.h @@ -4,7 +4,7 @@ #ifndef SERD_SRC_STACK_H #define SERD_SRC_STACK_H -#include "system.h" +#include "memory.h" #include <assert.h> #include <stdbool.h> @@ -19,21 +19,21 @@ typedef struct { } SerdStack; static inline SerdStack -serd_stack_new(size_t size, size_t align) +serd_stack_new(SerdAllocator* const allocator, size_t size, size_t align) { const size_t aligned_size = (size + (align - 1)) / align * align; SerdStack stack; - stack.buf = (char*)serd_calloc_aligned(align, aligned_size); + stack.buf = (char*)serd_aaligned_calloc(allocator, align, aligned_size); stack.buf_size = size; stack.size = align; // 0 is reserved for null return stack; } static inline void -serd_stack_free(SerdStack* stack) +serd_stack_free(SerdAllocator* const allocator, SerdStack* stack) { - serd_free_aligned(stack->buf); + serd_aaligned_free(allocator, stack->buf); stack->buf = NULL; stack->buf_size = 0; stack->size = 0; diff --git a/src/statement.c b/src/statement.c index 418e999e..5ea14910 100644 --- a/src/statement.c +++ b/src/statement.c @@ -4,8 +4,10 @@ #include "statement.h" #include "caret.h" +#include "memory.h" #include "node.h" +#include "serd/memory.h" #include "serd/statement.h" #include <assert.h> @@ -16,7 +18,7 @@ static bool is_resource(const SerdNode* const node) { - const SerdNodeType type = node ? serd_node_type(node) : (SerdNodeType)0; + const SerdNodeType type = serd_node_type(node); return type == SERD_URI || type == SERD_BLANK || type == SERD_VARIABLE; } @@ -26,13 +28,16 @@ serd_statement_is_valid(const SerdNode* const subject, const SerdNode* const object, const SerdNode* const graph) { - return is_resource(subject) && is_resource(predicate) && object && + (void)object; + + return is_resource(subject) && is_resource(predicate) && serd_node_type(predicate) != SERD_BLANK && (!graph || is_resource(graph)); } SerdStatement* -serd_statement_new(const SerdNode* const s, +serd_statement_new(SerdAllocator* const allocator, + const SerdNode* const s, const SerdNode* const p, const SerdNode* const o, const SerdNode* const g, @@ -46,39 +51,62 @@ serd_statement_new(const SerdNode* const s, return NULL; } - SerdStatement* statement = (SerdStatement*)malloc(sizeof(SerdStatement)); + SerdStatement* statement = + (SerdStatement*)serd_amalloc(allocator, sizeof(SerdStatement)); + if (statement) { statement->nodes[0] = s; statement->nodes[1] = p; statement->nodes[2] = o; statement->nodes[3] = g; - statement->caret = serd_caret_copy(caret); + statement->caret = NULL; + + if (caret) { + if (!(statement->caret = serd_caret_copy(allocator, caret))) { + serd_afree(allocator, statement); + return NULL; + } + } } + return statement; } SerdStatement* -serd_statement_copy(const SerdStatement* const statement) +serd_statement_copy(SerdAllocator* const allocator, + const SerdStatement* const statement) { if (!statement) { return NULL; } - SerdStatement* copy = (SerdStatement*)malloc(sizeof(SerdStatement)); - memcpy(copy, statement, sizeof(SerdStatement)); - if (statement->caret) { - copy->caret = (SerdCaret*)malloc(sizeof(SerdCaret)); - memcpy(copy->caret, statement->caret, sizeof(SerdCaret)); + SerdStatement* copy = + (SerdStatement*)serd_amalloc(allocator, sizeof(SerdStatement)); + + if (copy) { + memcpy(copy, statement, sizeof(SerdStatement)); + + if (statement->caret) { + if (!(copy->caret = + (SerdCaret*)serd_amalloc(allocator, sizeof(SerdCaret)))) { + serd_afree(allocator, copy); + return NULL; + } + + memcpy(copy->caret, statement->caret, sizeof(SerdCaret)); + } } + return copy; } void -serd_statement_free(SerdStatement* const statement) +serd_statement_free(SerdAllocator* const allocator, + SerdStatement* const statement) { if (statement) { - free(statement->caret); - free(statement); + serd_afree(allocator, statement->caret); + serd_afree(allocator, statement); } } diff --git a/src/string.c b/src/string.c index ed3149d0..46f8ff9a 100644 --- a/src/string.c +++ b/src/string.c @@ -1,15 +1,15 @@ // Copyright 2011-2020 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC +#include "memory.h" + #include "serd/memory.h" #include "serd/status.h" -#include <stdlib.h> - void -serd_free(void* const ptr) +serd_free(SerdAllocator* const allocator, void* const ptr) { - free(ptr); + serd_afree(allocator, ptr); } const char* diff --git a/src/system.c b/src/system.c index 16a292f5..4c29f7a1 100644 --- a/src/system.c +++ b/src/system.c @@ -9,8 +9,6 @@ # include <malloc.h> #endif -#include <stdio.h> -#include <stdlib.h> #include <string.h> int @@ -26,49 +24,3 @@ serd_system_strerror(const int errnum, char* const buf, const size_t buflen) return 0; #endif } - -void* -serd_malloc_aligned(const size_t alignment, const size_t size) -{ -#if defined(_WIN32) - return _aligned_malloc(size, alignment); -#elif USE_POSIX_MEMALIGN - void* ptr = NULL; - const int ret = posix_memalign(&ptr, alignment, size); - return ret ? NULL : ptr; -#else - (void)alignment; - return malloc(size); -#endif -} - -void* -serd_calloc_aligned(const size_t alignment, const size_t size) -{ -#if defined(_WIN32) || defined(USE_POSIX_MEMALIGN) - void* const ptr = serd_malloc_aligned(alignment, size); - if (ptr) { - memset(ptr, 0, size); - } - return ptr; -#else - (void)alignment; - return calloc(1, size); -#endif -} - -void* -serd_allocate_buffer(const size_t size) -{ - return serd_malloc_aligned(SERD_PAGE_SIZE, size); -} - -void -serd_free_aligned(void* const ptr) -{ -#ifdef _WIN32 - _aligned_free(ptr); -#else - free(ptr); -#endif -} diff --git a/src/system.h b/src/system.h index a0ec05dc..b606744b 100644 --- a/src/system.h +++ b/src/system.h @@ -4,9 +4,7 @@ #ifndef SERD_SRC_SYSTEM_H #define SERD_SRC_SYSTEM_H -#include "zix/attributes.h" - -#include <stdio.h> +#include <stddef.h> #define SERD_PAGE_SIZE 4096 @@ -14,20 +12,4 @@ int serd_system_strerror(int errnum, char* buf, size_t buflen); -/// Allocate a buffer aligned to `alignment` bytes -ZIX_MALLOC_FUNC void* -serd_malloc_aligned(size_t alignment, size_t size); - -/// Allocate a zeroed buffer aligned to `alignment` bytes -ZIX_MALLOC_FUNC void* -serd_calloc_aligned(size_t alignment, size_t size); - -/// Allocate an aligned buffer for I/O -ZIX_MALLOC_FUNC void* -serd_allocate_buffer(size_t size); - -/// Free a buffer allocated with an aligned allocation function -void -serd_free_aligned(void* ptr); - #endif // SERD_SRC_SYSTEM_H @@ -1,10 +1,12 @@ // Copyright 2011-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC +#include "memory.h" #include "string_utils.h" #include "uri_utils.h" #include "serd/buffer.h" +#include "serd/memory.h" #include "serd/status.h" #include "serd/stream.h" #include "serd/string_view.h" @@ -14,7 +16,6 @@ #include <stdbool.h> #include <stdint.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> static SerdStatus @@ -25,7 +26,9 @@ write_file_uri_char(const char c, void* const stream) } static char* -parse_hostname(const char* const authority, char** const hostname) +parse_hostname(SerdAllocator* const allocator, + const char* const authority, + char** const hostname) { char* const path = strchr(authority, '/'); if (!path) { @@ -34,7 +37,7 @@ parse_hostname(const char* const authority, char** const hostname) if (hostname) { const size_t len = (size_t)(path - authority); - if (!(*hostname = (char*)calloc(len + 1, 1))) { + if (!(*hostname = (char*)serd_acalloc(allocator, len + 1, 1))) { return NULL; } @@ -45,7 +48,9 @@ parse_hostname(const char* const authority, char** const hostname) } char* -serd_parse_file_uri(const char* const uri, char** const hostname) +serd_parse_file_uri(SerdAllocator* const allocator, + const char* const uri, + char** const hostname) { assert(uri); @@ -60,7 +65,7 @@ serd_parse_file_uri(const char* const uri, char** const hostname) const char* auth = uri + 7; if (*auth == '/') { // No hostname path = auth; - } else if (!(path = parse_hostname(auth, hostname))) { + } else if (!(path = parse_hostname(allocator, auth, hostname))) { return NULL; } } @@ -69,7 +74,7 @@ serd_parse_file_uri(const char* const uri, char** const hostname) ++path; } - SerdBuffer buffer = {NULL, 0}; + SerdBuffer buffer = {allocator, NULL, 0}; for (const char* s = path; !st && *s; ++s) { if (*s != '%') { st = write_file_uri_char(*s, &buffer); @@ -90,7 +95,7 @@ serd_parse_file_uri(const char* const uri, char** const hostname) } if (st || serd_buffer_close(&buffer)) { - free(buffer.buf); + serd_free(allocator, buffer.buf); return NULL; } diff --git a/src/world.c b/src/world.c index f5ab2f19..2c563f15 100644 --- a/src/world.c +++ b/src/world.c @@ -4,6 +4,7 @@ #include "world.h" #include "log.h" +#include "memory.h" #include "node.h" #include "serd/node.h" @@ -13,23 +14,26 @@ #include <assert.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> SerdWorld* -serd_world_new(void) +serd_world_new(SerdAllocator* const allocator) { - SerdWorld* world = (SerdWorld*)calloc(1, sizeof(SerdWorld)); - SerdNode* blank_node = serd_new_blank(serd_string("b00000000000")); + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + SerdWorld* world = (SerdWorld*)serd_acalloc(actual, 1, sizeof(SerdWorld)); + SerdNode* blank_node = serd_new_blank(actual, serd_string("b00000000000")); if (!world || !blank_node) { - serd_node_free(blank_node); - free(world); + serd_node_free(actual, blank_node); + serd_afree(actual, world); return NULL; } world->limits.reader_stack_size = 1048576U; world->limits.writer_max_depth = 128U; + world->allocator = actual; world->blank_node = blank_node; serd_log_init(&world->log); @@ -41,8 +45,8 @@ void serd_world_free(SerdWorld* const world) { if (world) { - serd_node_free(world->blank_node); - free(world); + serd_node_free(world->allocator, world->blank_node); + serd_afree(world->allocator, world); } } @@ -78,3 +82,11 @@ serd_world_get_blank(SerdWorld* const world) #undef BLANK_CHARS } + +SerdAllocator* +serd_world_allocator(const SerdWorld* const world) +{ + assert(world); + assert(world->allocator); + return world->allocator; +} diff --git a/src/world.h b/src/world.h index af6281d4..2499b761 100644 --- a/src/world.h +++ b/src/world.h @@ -6,16 +6,21 @@ #include "log.h" +#include "serd/memory.h" #include "serd/node.h" #include "serd/world.h" +#include <stdbool.h> #include <stdint.h> struct SerdWorldImpl { - SerdLimits limits; - SerdLog log; - uint32_t next_blank_id; - SerdNode* blank_node; + SerdLimits limits; + SerdAllocator* allocator; + SerdLog log; + uint32_t next_blank_id; + SerdNode* blank_node; + + bool stderr_color; }; #endif // SERD_SRC_WORLD_H diff --git a/src/writer.c b/src/writer.c index fa1abd9f..6d52b4e6 100644 --- a/src/writer.c +++ b/src/writer.c @@ -3,6 +3,7 @@ #include "block_dumper.h" #include "env.h" +#include "memory.h" #include "namespaces.h" #include "node.h" #include "sink.h" @@ -34,7 +35,6 @@ #include <stdbool.h> #include <stdint.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> typedef enum { @@ -175,14 +175,11 @@ supports_uriref(const SerdWriter* writer) } static SerdStatus -free_context(WriteContext* const ctx) +free_context(SerdWriter* const writer) { - serd_node_free(ctx->graph); - serd_node_free(ctx->subject); - serd_node_free(ctx->predicate); - ctx->graph = NULL; - ctx->subject = NULL; - ctx->predicate = NULL; + serd_node_free(writer->world->allocator, writer->context.graph); + serd_node_free(writer->world->allocator, writer->context.subject); + serd_node_free(writer->world->allocator, writer->context.predicate); return SERD_SUCCESS; } @@ -234,13 +231,14 @@ push_context(SerdWriter* const writer, // Update the current context - const WriteContext current = {type, - flags, - serd_node_copy(graph), - serd_node_copy(subject), - serd_node_copy(predicate), - 0U, - 0U}; + const WriteContext current = { + type, + flags, + serd_node_copy(writer->world->allocator, graph), + serd_node_copy(writer->world->allocator, subject), + serd_node_copy(writer->world->allocator, predicate), + 0U, + 0U}; writer->context = current; return SERD_SUCCESS; @@ -251,7 +249,7 @@ pop_context(SerdWriter* writer) { assert(writer->anon_stack_size > 0); - free_context(&writer->context); + free_context(writer); writer->context = writer->anon_stack[--writer->anon_stack_size]; } @@ -971,10 +969,10 @@ write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred) TRY(st, write_node(writer, pred, SERD_PREDICATE, flags)); TRY(st, write_sep(writer, flags, SEP_P_O)); - serd_node_set(&writer->context.predicate, pred); writer->context.predicates = true; writer->context.comma_indented = false; - return st; + return serd_node_set( + writer->world->allocator, &writer->context.predicate, pred); } SERD_NODISCARD static SerdStatus @@ -1068,7 +1066,7 @@ update_abbreviation_context(SerdWriter* const writer, { SerdStatus st = SERD_SUCCESS; - // Push context for anonymous or list subject if necessary + // Push context for list or anonymous subject if necessary if (flags & SERD_ANON_S) { st = push_context(writer, CTX_BLANK, flags, graph, subject, predicate); } else if (flags & SERD_LIST_S) { @@ -1175,9 +1173,13 @@ write_turtle_trig_statement(SerdWriter* const writer, TRY(st, write_sep(writer, flags, SEP_ANON_S_P)); } - // Set context to new subject and write predicate + // Set context to new subject reset_context(writer, 0U); - serd_node_set(&writer->context.subject, subject); + TRY(st, + serd_node_set( + writer->world->allocator, &writer->context.subject, subject)); + + // Write predicate if (!(flags & SERD_LIST_S)) { TRY(st, write_pred(writer, flags, predicate)); } @@ -1218,7 +1220,7 @@ write_trig_statement(SerdWriter* const writer, if (graph) { TRY(st, write_node(writer, graph, SERD_GRAPH, flags)); TRY(st, write_sep(writer, flags, SEP_GRAPH_BEGIN)); - serd_node_set(&writer->context.graph, graph); + serd_node_set(writer->world->allocator, &writer->context.graph, graph); } } @@ -1340,14 +1342,18 @@ serd_writer_new(SerdWorld* world, assert(env); assert(output); - SerdBlockDumper dumper = {NULL, NULL, 0U, 0U}; - if (serd_block_dumper_open(&dumper, output, block_size)) { + SerdBlockDumper dumper = {world->allocator, NULL, NULL, 0U, 0U}; + if (serd_block_dumper_open(world, &dumper, output, block_size)) { return NULL; } - const size_t max_depth = world->limits.writer_max_depth; - const WriteContext context = WRITE_CONTEXT_NULL; - SerdWriter* writer = (SerdWriter*)calloc(1, sizeof(SerdWriter)); + const WriteContext context = WRITE_CONTEXT_NULL; + + SerdWriter* writer = (SerdWriter*)serd_wcalloc(world, 1, sizeof(SerdWriter)); + if (!writer) { + serd_block_dumper_close(&dumper); + return NULL; + } writer->world = world; writer->syntax = syntax; @@ -1358,13 +1364,19 @@ serd_writer_new(SerdWorld* world, writer->output = dumper; writer->context = context; - if (max_depth) { - writer->max_depth = max_depth; - writer->anon_stack = (WriteContext*)calloc(max_depth, sizeof(WriteContext)); + if (world->limits.writer_max_depth) { + writer->max_depth = world->limits.writer_max_depth; + writer->anon_stack = (WriteContext*)serd_wcalloc( + world, world->limits.writer_max_depth, sizeof(WriteContext)); + if (!writer->anon_stack) { + serd_wfree(world, writer); + return NULL; + } } - writer->iface.handle = writer; - writer->iface.on_event = (SerdEventFunc)serd_writer_on_event; + writer->iface.allocator = world->allocator; + writer->iface.handle = writer; + writer->iface.on_event = (SerdEventFunc)serd_writer_on_event; return writer; } @@ -1374,14 +1386,15 @@ serd_writer_chop_blank_prefix(SerdWriter* writer, const char* prefix) { assert(writer); - free(writer->bprefix); + serd_wfree(writer->world, writer->bprefix); writer->bprefix_len = 0; writer->bprefix = NULL; const size_t prefix_len = prefix ? strlen(prefix) : 0; if (prefix_len) { writer->bprefix_len = prefix_len; - writer->bprefix = (char*)malloc(writer->bprefix_len + 1); + writer->bprefix = + (char*)serd_wmalloc(writer->world, writer->bprefix_len + 1); memcpy(writer->bprefix, prefix, writer->bprefix_len + 1); } } @@ -1417,12 +1430,12 @@ serd_writer_set_root_uri(SerdWriter* writer, const SerdStringView uri) { assert(writer); - serd_node_free(writer->root_node); + serd_node_free(writer->world->allocator, writer->root_node); writer->root_node = NULL; writer->root_uri = SERD_URI_NULL; if (uri.length) { - writer->root_node = serd_new_uri(uri); + writer->root_node = serd_new_uri(writer->world->allocator, uri); writer->root_uri = serd_node_uri_view(writer->root_node); } @@ -1462,13 +1475,13 @@ serd_writer_free(SerdWriter* writer) } serd_writer_finish(writer); - free_context(&writer->context); + free_context(writer); free_anon_stack(writer); serd_block_dumper_close(&writer->output); - free(writer->anon_stack); - free(writer->bprefix); - serd_node_free(writer->root_node); - free(writer); + serd_wfree(writer->world, writer->anon_stack); + serd_wfree(writer->world, writer->bprefix); + serd_node_free(writer->world->allocator, writer->root_node); + serd_wfree(writer->world, writer); } const SerdSink* |