From 30487c277ac5d4be5786733ca7b98adb4c810ae9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 27 Oct 2021 14:15:31 -0400 Subject: Add custom allocator support --- src/block_dumper.c | 9 ++-- src/block_dumper.h | 5 +- src/buffer.c | 14 ++--- src/byte_source.c | 51 ++++++++++++------ src/byte_source.h | 5 +- src/canon.c | 51 +++++++++++++----- src/caret.c | 34 ++++++++---- src/cursor.c | 17 ++++-- src/describe.c | 17 +++--- src/env.c | 100 ++++++++++++++++++++++++++---------- src/filter.c | 56 +++++++++++++++----- src/inserter.c | 42 +++++++++++---- src/memory.c | 30 +++++++++++ src/memory.h | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/model.c | 101 ++++++++++++++++++++++++++---------- src/model.h | 1 + src/node.c | 125 ++++++++++++++++++++++++++------------------ src/node.h | 10 ++-- src/node_syntax.c | 127 ++++++++++++++++++++++++++------------------- src/nodes.c | 103 +++++++++++++++++++++++-------------- src/reader.c | 31 +++++++---- src/sink.c | 16 +++--- src/sink.h | 7 +-- src/stack.h | 12 +++-- src/statement.c | 55 +++++++++++++++----- src/string.c | 5 +- src/system.c | 96 +++++++++++++++------------------- src/system.h | 23 +-------- src/uri.c | 35 ++++++++++--- src/world.c | 70 +++++++++++++++++-------- src/world.h | 2 + src/writer.c | 76 ++++++++++++++++----------- 32 files changed, 1011 insertions(+), 463 deletions(-) create mode 100644 src/memory.c create mode 100644 src/memory.h (limited to 'src') diff --git a/src/block_dumper.c b/src/block_dumper.c index 201b5dbf..6545d69c 100644 --- a/src/block_dumper.c +++ b/src/block_dumper.c @@ -15,6 +15,8 @@ */ #include "block_dumper.h" + +#include "memory.h" #include "system.h" #include "serd/serd.h" @@ -22,7 +24,8 @@ #include 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) { @@ -39,7 +42,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; } @@ -55,5 +58,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 7c718566..4581de42 100644 --- a/src/block_dumper.h +++ b/src/block_dumper.h @@ -23,6 +23,8 @@ #include typedef struct { + SerdAllocator* SERD_NONNULL allocator; ///< Buffer allocator + SerdOutputStream* SERD_ALLOCATED out; ///< Output stream to write to char* SERD_ALLOCATED buf; ///< Local buffer if needed size_t size; ///< Bytes pending for this block @@ -36,7 +38,8 @@ typedef struct { calling serd_block_dumper_close(). */ SerdStatus -serd_block_dumper_open(SerdBlockDumper* SERD_NONNULL dumper, +serd_block_dumper_open(const SerdWorld* SERD_NONNULL world, + SerdBlockDumper* SERD_NONNULL dumper, SerdOutputStream* SERD_NONNULL output, size_t block_size); diff --git a/src/buffer.c b/src/buffer.c index 85ec09de..8d9eb95d 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -14,11 +14,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "memory.h" + #include "serd/serd.h" #include #include -#include #include size_t @@ -33,20 +34,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 396e16d0..e4a82d6a 100644 --- a/src/byte_source.c +++ b/src/byte_source.c @@ -17,6 +17,7 @@ #include "byte_source.h" #include "caret.h" +#include "memory.h" #include "system.h" #include "serd/serd.h" @@ -24,7 +25,6 @@ #include #include #include -#include #include SerdStatus @@ -53,33 +53,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; @@ -87,21 +102,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 2bd06bdf..8246b581 100644 --- a/src/byte_source.h +++ b/src/byte_source.h @@ -41,12 +41,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/canon.c b/src/canon.c index f8f1d8f0..a02d9a29 100644 --- a/src/canon.c +++ b/src/canon.c @@ -15,6 +15,7 @@ */ #include "caret.h" +#include "memory.h" #include "namespaces.h" #include "node.h" #include "statement.h" @@ -35,7 +36,8 @@ typedef struct { } SerdCanonData; static ExessResult -build_typed(SerdNode** const out, +build_typed(SerdAllocator* const SERD_NONNULL allocator, + SerdNode** const out, const SerdNode* const SERD_NONNULL node, const SerdNode* const SERD_NONNULL datatype) { @@ -46,7 +48,7 @@ build_typed(SerdNode** const out, ExessResult r = {EXESS_SUCCESS, 0}; if (!strcmp(datatype_uri, NS_RDF "langString")) { - *out = serd_new_string(serd_node_string_view(node)); + *out = serd_new_string(allocator, serd_node_string_view(node)); return r; } @@ -65,7 +67,11 @@ build_typed(SerdNode** const out, const size_t datatype_size = serd_node_total_size(datatype); const size_t len = serd_node_pad_length(r.count); const size_t total_len = sizeof(SerdNode) + len + datatype_size; - SerdNode* const result = serd_node_malloc(total_len); + SerdNode* const result = serd_node_malloc(allocator, total_len); + if (!result) { + r.status = EXESS_NO_SPACE; + return r; + } result->length = r.count; result->flags = SERD_HAS_DATATYPE; @@ -86,7 +92,8 @@ build_typed(SerdNode** const out, } static ExessResult -build_tagged(SerdNode** const out, +build_tagged(SerdAllocator* const SERD_NONNULL allocator, + SerdNode** const out, const SerdNode* const SERD_NONNULL node, const SerdNode* const SERD_NONNULL language) { @@ -107,7 +114,8 @@ build_tagged(SerdNode** const out, } // Make a new literal that is otherwise identical - *out = serd_new_literal(serd_node_string_view(node), + *out = serd_new_literal(allocator, + serd_node_string_view(node), serd_node_flags(node), SERD_SUBSTRING(canonical_lang, lang_len)); @@ -122,16 +130,18 @@ serd_canon_on_statement(SerdCanonData* const data, const SerdStatementFlags flags, const SerdStatement* const statement) { - const SerdNode* const object = serd_statement_object(statement); - const SerdNode* const datatype = serd_node_datatype(object); - const SerdNode* const language = serd_node_language(object); + SerdAllocator* const allocator = serd_world_allocator(data->world); + const SerdNode* const object = serd_statement_object(statement); + const SerdNode* const datatype = serd_node_datatype(object); + const SerdNode* const language = serd_node_language(object); if (!datatype && !language) { return serd_sink_write_statement(data->target, flags, statement); } SerdNode* normo = NULL; - const ExessResult r = datatype ? build_typed(&normo, object, datatype) - : build_tagged(&normo, object, language); + const ExessResult r = datatype + ? build_typed(allocator, &normo, object, datatype) + : build_tagged(allocator, &normo, object, language); if (r.status) { SerdCaret caret = {NULL, 0u, 0u}; @@ -151,7 +161,7 @@ serd_canon_on_statement(SerdCanonData* const data, exess_strerror(r.status)); if (!lax) { - return SERD_BAD_LITERAL; + return r.status == EXESS_NO_SPACE ? SERD_BAD_ALLOC : SERD_BAD_LITERAL; } } @@ -165,7 +175,7 @@ serd_canon_on_statement(SerdCanonData* const data, statement->nodes[1], normo, statement->nodes[3]); - serd_node_free(normo); + serd_node_free(allocator, normo); return st; } @@ -183,13 +193,26 @@ serd_canon_new(const SerdWorld* const world, const SerdSink* const target, const SerdCanonFlags flags) { + assert(world); assert(target); - SerdCanonData* const data = (SerdCanonData*)calloc(1, sizeof(SerdCanonData)); + SerdCanonData* const data = + (SerdCanonData*)serd_wcalloc(world, 1, sizeof(SerdCanonData)); + + if (!data) { + return NULL; + } data->world = world; data->target = target; data->flags = flags; - return serd_sink_new(world, data, (SerdEventFunc)serd_canon_on_event, free); + SerdSink* const sink = + serd_sink_new(world, data, (SerdEventFunc)serd_canon_on_event, free); + + if (!sink) { + serd_wfree(world, data); + } + + return sink; } diff --git a/src/caret.c b/src/caret.c index b6911468..67abbadb 100644 --- a/src/caret.c +++ b/src/caret.c @@ -16,40 +16,54 @@ #include "caret.h" +#include "memory.h" + #include #include #include #include SerdCaret* -serd_caret_new(const SerdNode* name, unsigned line, unsigned col) +serd_caret_new(SerdAllocator* const allocator, + const SerdNode* const name, + const unsigned line, + const unsigned col) { assert(name); - SerdCaret* caret = (SerdCaret*)malloc(sizeof(SerdCaret)); + SerdCaret* const caret = + (SerdCaret*)serd_amalloc(allocator, sizeof(SerdCaret)); + + if (caret) { + caret->file = name; + caret->line = line; + caret->col = col; + } - caret->file = name; - caret->line = line; - caret->col = col; return caret; } SerdCaret* -serd_caret_copy(const SerdCaret* caret) +serd_caret_copy(SerdAllocator* const allocator, const SerdCaret* 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* caret) +serd_caret_free(SerdAllocator* const allocator, SerdCaret* caret) { - free(caret); + serd_afree(allocator, caret); } bool diff --git a/src/cursor.c b/src/cursor.c index 1a94142e..e3d7e35f 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -16,6 +16,7 @@ #include "cursor.h" +#include "memory.h" #include "model.h" #include "node.h" @@ -25,7 +26,6 @@ #include #include -#include #include static inline bool @@ -132,14 +132,19 @@ serd_cursor_make(const SerdModel* const model, } SerdCursor* -serd_cursor_copy(const SerdCursor* const cursor) +serd_cursor_copy(SerdAllocator* const allocator, const SerdCursor* const cursor) { if (!cursor) { return NULL; } - SerdCursor* const copy = (SerdCursor* const)malloc(sizeof(SerdCursor)); - memcpy(copy, cursor, sizeof(SerdCursor)); + SerdCursor* const copy = + (SerdCursor* const)serd_amalloc(allocator, sizeof(SerdCursor)); + + if (copy) { + memcpy(copy, cursor, sizeof(SerdCursor)); + } + return copy; } @@ -223,5 +228,7 @@ serd_cursor_equals(const SerdCursor* const lhs, const SerdCursor* const rhs) void serd_cursor_free(SerdCursor* const cursor) { - free(cursor); + if (cursor) { + serd_afree(cursor->model->allocator, cursor); + } } diff --git a/src/describe.c b/src/describe.c index 695217fd..92750363 100644 --- a/src/describe.c +++ b/src/describe.c @@ -23,6 +23,7 @@ #define ZIX_HASH_RECORD_TYPE const SerdNode #include "serd/serd.h" +#include "zix/allocator.h" #include "zix/common.h" #include "zix/digest.h" #include "zix/hash.h" @@ -295,16 +296,18 @@ serd_describe_range(const SerdCursor* const range, assert(sink); - SerdStatus st = SERD_SUCCESS; - SerdCursor copy = *range; - ZixHash* const list_subjects = - zix_hash_new(NULL, identity, ptr_hash, ptr_equals); + SerdCursor copy = *range; - DescribeContext ctx = {range->model, sink, list_subjects, flags}; + ZixHash* const list_subjects = zix_hash_new( + (ZixAllocator*)range->model->allocator, identity, ptr_hash, ptr_equals); - st = write_pretty_range(&ctx, 0, ©, NULL, (flags & SERD_NO_TYPE_FIRST)); + SerdStatus st = SERD_BAD_ALLOC; + if (list_subjects) { + DescribeContext ctx = {range->model, sink, list_subjects, flags}; - zix_hash_free(list_subjects); + st = write_pretty_range(&ctx, 0, ©, NULL, (flags & SERD_NO_TYPE_FIRST)); + } + zix_hash_free(list_subjects); return st; } diff --git a/src/env.c b/src/env.c index df82381c..67d77cab 100644 --- a/src/env.c +++ b/src/env.c @@ -16,14 +16,14 @@ #include "env.h" +#include "memory.h" #include "node.h" +#include "world.h" #include "serd/serd.h" #include #include -#include -#include #include typedef struct { @@ -46,32 +46,53 @@ serd_env_new(SerdWorld* const world, const SerdStringView base_uri) assert(world); (void)world; - SerdEnv* env = (SerdEnv*)calloc(1, sizeof(struct SerdEnvImpl)); + SerdEnv* env = (SerdEnv*)serd_wcalloc(world, 1, sizeof(struct SerdEnvImpl)); - env->world = world; - env->nodes = serd_nodes_new(); + if (env) { + env->world = world; + if (!(env->nodes = serd_nodes_new(world->allocator))) { + serd_wfree(world, env); + return NULL; + } - if (env && base_uri.len) { - serd_env_set_base_uri(env, base_uri); + if (base_uri.len) { + if (serd_env_set_base_uri(env, base_uri)) { + serd_nodes_free(env->nodes); + serd_wfree(world, 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* copy = + (SerdEnv*)serd_acalloc(allocator, 1, sizeof(struct SerdEnvImpl)); + if (copy) { copy->world = env->world; - copy->nodes = serd_nodes_new(); copy->n_prefixes = env->n_prefixes; - copy->prefixes = (SerdPrefix*)malloc(copy->n_prefixes * sizeof(SerdPrefix)); + if (!(copy->nodes = serd_nodes_new(allocator))) { + serd_wfree(env->world, copy); + return NULL; + } + + if (!(copy->prefixes = (SerdPrefix*)serd_amalloc( + allocator, copy->n_prefixes * sizeof(SerdPrefix)))) { + serd_nodes_free(copy->nodes); + serd_wfree(env->world, copy); + return NULL; + } + for (size_t i = 0; i < copy->n_prefixes; ++i) { copy->prefixes[i].name = serd_nodes_intern(copy->nodes, env->prefixes[i].name); @@ -93,9 +114,9 @@ void serd_env_free(SerdEnv* const env) { if (env) { - free(env->prefixes); + serd_wfree(env->world, env->prefixes); serd_nodes_free(env->nodes); - free(env); + serd_wfree(env->world, env); } } @@ -158,8 +179,11 @@ serd_env_set_base_uri(SerdEnv* const env, const SerdStringView uri) serd_resolve_uri(serd_parse_uri(uri.buf), env->base_uri); // Replace the current base URI - env->base_uri_node = serd_nodes_parsed_uri(env->nodes, new_base_uri); - env->base_uri = serd_node_uri_view(env->base_uri_node); + if ((env->base_uri_node = serd_nodes_parsed_uri(env->nodes, new_base_uri))) { + env->base_uri = serd_node_uri_view(env->base_uri_node); + } else { + return SERD_BAD_ALLOC; + } serd_nodes_deref(env->nodes, old_base_uri); return SERD_SUCCESS; @@ -182,7 +206,7 @@ serd_env_find(const SerdEnv* const env, return NULL; } -static void +static SerdStatus serd_env_add(SerdEnv* const env, const SerdStringView name, const SerdNode* const uri) @@ -194,14 +218,25 @@ serd_env_add(SerdEnv* const env, prefix->uri = uri; } } else { - env->prefixes = (SerdPrefix*)realloc( - env->prefixes, (++env->n_prefixes) * sizeof(SerdPrefix)); + const SerdNode* const name_node = serd_nodes_string(env->nodes, name); + if (!name_node) { + return SERD_BAD_ALLOC; + } - env->prefixes[env->n_prefixes - 1].name = - serd_nodes_string(env->nodes, name); + SerdPrefix* const new_prefixes = (SerdPrefix*)serd_wrealloc( + env->world, env->prefixes, (env->n_prefixes + 1) * sizeof(SerdPrefix)); - env->prefixes[env->n_prefixes - 1].uri = uri; + if (!new_prefixes) { + return SERD_BAD_ALLOC; + } + + new_prefixes[env->n_prefixes].name = name_node; + new_prefixes[env->n_prefixes].uri = uri; + env->prefixes = new_prefixes; + ++env->n_prefixes; } + + return SERD_SUCCESS; } SerdStatus @@ -213,8 +248,12 @@ serd_env_set_prefix(SerdEnv* const env, if (serd_uri_string_has_scheme(uri.buf)) { // Set prefix to absolute URI - serd_env_add(env, name, serd_nodes_uri(env->nodes, uri)); - return SERD_SUCCESS; + const SerdNode* const abs_uri = serd_nodes_uri(env->nodes, uri); + if (!abs_uri) { + return SERD_BAD_ALLOC; + } + + return serd_env_add(env, name, abs_uri); } if (!env->base_uri_node) { @@ -230,11 +269,14 @@ serd_env_set_prefix(SerdEnv* const env, const SerdNode* const abs_uri = serd_nodes_parsed_uri(env->nodes, 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, abs_uri); - return SERD_SUCCESS; + return serd_env_add(env, name, abs_uri); } SerdStatus @@ -303,7 +345,9 @@ serd_env_expand_curie(const SerdEnv* const env, const SerdStringView curie) } const size_t len = prefix.len + suffix.len; - SerdNode* ret = serd_node_malloc(sizeof(SerdNode) + len + 1); + SerdNode* ret = + serd_node_malloc(env->world->allocator, sizeof(SerdNode) + len + 1); + if (ret) { ret->length = len; ret->flags = 0u; @@ -331,8 +375,8 @@ serd_env_expand_node(const SerdEnv* const env, const SerdNode* const node) return NULL; } - const SerdWriteResult r = serd_node_construct_uri(0u, NULL, abs_uri); - SerdNode* const expanded = serd_node_try_malloc(r); + const SerdWriteResult r = serd_node_construct_uri(0u, NULL, abs_uri); + SerdNode* const expanded = serd_node_try_malloc(env->world->allocator, r); if (expanded) { serd_node_construct_uri(r.count, expanded, abs_uri); } diff --git a/src/filter.c b/src/filter.c index 8efe1e91..8e0f5731 100644 --- a/src/filter.c +++ b/src/filter.c @@ -16,6 +16,9 @@ #include "serd/serd.h" +#include "memory.h" +#include "sink.h" + #include #include #include @@ -33,13 +36,15 @@ static void free_data(void* const handle) { if (handle) { - SerdFilterData* data = (SerdFilterData*)handle; - - serd_node_free(data->subject); - serd_node_free(data->predicate); - serd_node_free(data->object); - serd_node_free(data->graph); - free(data); + SerdFilterData* const data = (SerdFilterData*)handle; + const SerdWorld* const world = data->target->world; + SerdAllocator* const allocator = serd_world_allocator(world); + + serd_node_free(allocator, data->subject); + serd_node_free(allocator, data->predicate); + serd_node_free(allocator, data->object); + serd_node_free(allocator, data->graph); + serd_wfree(data->target->world, data); } } @@ -80,28 +85,53 @@ serd_filter_new(const SerdWorld* const world, { assert(world); assert(target); + assert(target->world == world); + SerdAllocator* const allocator = serd_world_allocator(world); SerdFilterData* const data = - (SerdFilterData*)calloc(1, sizeof(SerdFilterData)); + (SerdFilterData*)serd_wcalloc(world, 1, sizeof(SerdFilterData)); + + if (!data) { + return NULL; + } data->target = target; data->inclusive = inclusive; if (subject && serd_node_type(subject) != SERD_VARIABLE) { - data->subject = serd_node_copy(subject); + if (!(data->subject = serd_node_copy(allocator, subject))) { + free_data(data); + return NULL; + } } if (predicate && serd_node_type(predicate) != SERD_VARIABLE) { - data->predicate = serd_node_copy(predicate); + if (!(data->predicate = serd_node_copy(allocator, predicate))) { + free_data(data); + return NULL; + } } if (object && serd_node_type(object) != SERD_VARIABLE) { - data->object = serd_node_copy(object); + if (!(data->object = serd_node_copy(allocator, object))) { + free_data(data); + return NULL; + } } if (graph && serd_node_type(graph) != SERD_VARIABLE) { - data->graph = serd_node_copy(graph); + if (!(data->graph = serd_node_copy(allocator, graph))) { + free_data(data); + return NULL; + } + } + + SerdSink* const sink = + serd_sink_new(world, data, serd_filter_on_event, free_data); + + if (!sink) { + free_data(data); } - return serd_sink_new(world, data, serd_filter_on_event, free_data); + return sink; } diff --git a/src/inserter.c b/src/inserter.c index 9f388921..f5419b81 100644 --- a/src/inserter.c +++ b/src/inserter.c @@ -14,6 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "memory.h" #include "model.h" #include "statement.h" @@ -24,8 +25,8 @@ #include typedef struct { - SerdModel* model; - const SerdNode* default_graph; + SerdModel* model; + SerdNode* default_graph; } SerdInserterData; static bool @@ -107,19 +108,38 @@ serd_inserter_on_event(SerdInserterData* const data, return SERD_SUCCESS; } +static SerdInserterData* +serd_inserter_data_new(SerdModel* const model, + const SerdNode* const default_graph) +{ + SerdInserterData* const data = + (SerdInserterData*)serd_wcalloc(model->world, 1, sizeof(SerdInserterData)); + + if (data) { + data->model = model; + data->default_graph = serd_node_copy(model->allocator, default_graph); + } + + return data; +} + +static void +serd_inserter_data_free(SerdInserterData* const data) +{ + serd_node_free(data->model->allocator, data->default_graph); + serd_wfree(data->model->world, data); +} + SerdSink* serd_inserter_new(SerdModel* const model, const SerdNode* const default_graph) { assert(model); - SerdInserterData* const data = - (SerdInserterData*)calloc(1, sizeof(SerdInserterData)); - - data->model = model; - data->default_graph = serd_node_copy(default_graph); - - SerdSink* const sink = serd_sink_new( - model->world, data, (SerdEventFunc)serd_inserter_on_event, free); + SerdEventFunc func = (SerdEventFunc)serd_inserter_on_event; + SerdInserterData* const data = serd_inserter_data_new(model, default_graph); - return sink; + return data + ? serd_sink_new( + model->world, data, func, (SerdFreeFunc)serd_inserter_data_free) + : NULL; } diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 00000000..a46319fb --- /dev/null +++ b/src/memory.c @@ -0,0 +1,30 @@ +/* + Copyright 2011-2021 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "memory.h" + +#include "serd/serd.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..e0cd4dff --- /dev/null +++ b/src/memory.h @@ -0,0 +1,148 @@ +/* + Copyright 2011-2021 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef SERD_MEMORY_H +#define SERD_MEMORY_H + +#include "serd/serd.h" + +#include +#include + +// 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_MEMORY_H diff --git a/src/model.c b/src/model.c index 4e79fa77..1b1c144a 100644 --- a/src/model.c +++ b/src/model.c @@ -19,15 +19,16 @@ #include "caret.h" #include "compare.h" #include "cursor.h" +#include "memory.h" #include "statement.h" +#include "zix/allocator.h" #include "zix/btree.h" #include "zix/common.h" #include #include #include -#include static const SerdQuad everything_pattern = {0, 0, 0, 0}; @@ -73,11 +74,15 @@ serd_model_add_index(SerdModel* const model, const SerdStatementOrder order) const unsigned* const ordering = orderings[order]; const ZixComparator comparator = serd_model_index_comparator(model, order); - model->indices[order] = zix_btree_new(NULL, comparator, ordering); + model->indices[order] = + zix_btree_new((ZixAllocator*)model->allocator, comparator, ordering); - ZixStatus zst = model->indices[order] ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; + if (!model->indices[order]) { + return SERD_BAD_ALLOC; + } // Insert statements from the default index + ZixStatus zst = ZIX_STATUS_SUCCESS; if (order != model->default_order) { ZixBTree* const default_index = model->indices[model->default_order]; for (ZixBTreeIter i = zix_btree_begin(default_index); @@ -108,21 +113,38 @@ serd_model_drop_index(SerdModel* const model, const SerdStatementOrder order) return SERD_SUCCESS; } -SerdModel* -serd_model_new(SerdWorld* const world, - const SerdStatementOrder default_order, - const SerdModelFlags flags) +static SerdModel* +serd_model_new_with_allocator(SerdAllocator* const allocator, + SerdWorld* const world, + const SerdStatementOrder default_order, + const SerdModelFlags flags) { assert(world); - SerdModel* model = (SerdModel*)calloc(1, sizeof(struct SerdModelImpl)); + SerdNodes* const nodes = serd_nodes_new(allocator); + if (!nodes) { + return NULL; + } + + SerdModel* model = + (SerdModel*)serd_acalloc(allocator, 1, sizeof(struct SerdModelImpl)); + if (!model) { + serd_nodes_free(nodes); + return NULL; + } + + model->allocator = allocator; model->world = world; - model->nodes = serd_nodes_new(); + model->nodes = nodes; model->default_order = default_order; model->flags = flags; - serd_model_add_index(model, default_order); + if (serd_model_add_index(model, default_order)) { + serd_nodes_free(nodes); + serd_wfree(world, model); + return NULL; + } const ScanStrategy end_strategy = {SCAN_EVERYTHING, 0u, default_order}; @@ -135,12 +157,21 @@ serd_model_new(SerdWorld* const world, } SerdModel* -serd_model_copy(const SerdModel* const model) +serd_model_new(SerdWorld* const world, + const SerdStatementOrder default_order, + const SerdModelFlags flags) +{ + return serd_model_new_with_allocator( + serd_world_allocator(world), world, default_order, flags); +} + +SerdModel* +serd_model_copy(SerdAllocator* const allocator, const SerdModel* const model) { assert(model); - SerdModel* copy = - serd_model_new(model->world, model->default_order, model->flags); + SerdModel* copy = serd_model_new_with_allocator( + allocator, model->world, model->default_order, model->flags); SerdCursor* cursor = serd_model_begin(model); serd_model_insert_statements(copy, cursor); @@ -239,18 +270,23 @@ serd_model_drop_statement(SerdModel* const model, } } - if (statement->caret && statement->caret->file) { - serd_nodes_deref(model->nodes, statement->caret->file); + if (statement->caret && serd_caret_name(statement->caret)) { + serd_nodes_deref(model->nodes, serd_caret_name(statement->caret)); } - serd_statement_free(statement); + serd_statement_free(model->allocator, statement); } +typedef struct { + SerdAllocator* allocator; +} DestroyContext; + static void destroy_tree_statement(void* ptr, const void* user_data) { - (void)user_data; - serd_statement_free((SerdStatement*)ptr); + const DestroyContext* const ctx = (const DestroyContext*)user_data; + + serd_statement_free(ctx->allocator, (SerdStatement*)ptr); } void @@ -261,8 +297,9 @@ serd_model_free(SerdModel* const model) } // Free all statements (which are owned by the default index) - ZixBTree* const default_index = model->indices[model->default_order]; - zix_btree_clear(default_index, destroy_tree_statement, NULL); + ZixBTree* const default_index = model->indices[model->default_order]; + const DestroyContext ctx = {model->allocator}; + zix_btree_clear(default_index, destroy_tree_statement, &ctx); // Free indices themselves for (unsigned i = 0u; i < N_STATEMENT_ORDERS; ++i) { @@ -270,7 +307,7 @@ serd_model_free(SerdModel* const model) } serd_nodes_free(model->nodes); - free(model); + serd_wfree(model->world, model); } SerdWorld* @@ -323,7 +360,7 @@ serd_model_begin_ordered(const SerdModel* const model, const SerdCursor cursor = make_begin_cursor(model, order); - return serd_cursor_copy(&cursor); + return serd_cursor_copy(model->allocator, &cursor); } SerdCursor* @@ -524,7 +561,9 @@ serd_model_find(const SerdModel* const model, const SerdCursor cursor = serd_model_search(model, s, p, o, g); - return zix_btree_iter_is_end(cursor.iter) ? NULL : serd_cursor_copy(&cursor); + return zix_btree_iter_is_end(cursor.iter) + ? NULL + : serd_cursor_copy(model->allocator, &cursor); } const SerdNode* @@ -602,16 +641,20 @@ serd_model_ask(const SerdModel* const model, static SerdCaret* serd_model_intern_caret(SerdModel* const model, const SerdCaret* const caret) { - if (caret) { - SerdCaret* copy = (SerdCaret*)calloc(1, sizeof(SerdCaret)); + if (!caret) { + return NULL; + } + SerdCaret* const copy = + (SerdCaret*)serd_acalloc(model->allocator, 1, sizeof(SerdCaret)); + + if (copy) { copy->file = serd_nodes_intern(model->nodes, caret->file); copy->line = caret->line; copy->col = caret->col; - return copy; } - return NULL; + return copy; } SerdStatus @@ -624,7 +667,9 @@ serd_model_add_with_caret(SerdModel* const model, { assert(model); - SerdStatement* const statement = serd_statement_new(s, p, o, g, NULL); + SerdStatement* const statement = + serd_statement_new(model->allocator, s, p, o, g, NULL); + if (!statement) { return SERD_BAD_ALLOC; } diff --git a/src/model.h b/src/model.h index 5fbf6209..7c4816a4 100644 --- a/src/model.h +++ b/src/model.h @@ -25,6 +25,7 @@ #include struct SerdModelImpl { + SerdAllocator* allocator; ///< Allocator for everything in this model SerdWorld* world; ///< World this model is a part of SerdNodes* nodes; ///< Interned nodes in this model ZixBTree* indices[12]; ///< Trees of SerdStatement pointers diff --git a/src/node.c b/src/node.c index 61a45a03..0436c4fb 100644 --- a/src/node.c +++ b/src/node.c @@ -16,9 +16,9 @@ #include "node.h" +#include "memory.h" #include "namespaces.h" #include "string_utils.h" -#include "system.h" #include "exess/exess.h" #include "serd/serd.h" @@ -81,39 +81,46 @@ serd_node_total_size(const SerdNode* const node) } SerdNode* -serd_node_malloc(const size_t size) +serd_node_malloc(SerdAllocator* const allocator, const size_t size) { - SerdNode* const node = - (SerdNode*)serd_calloc_aligned(serd_node_align, serd_node_pad_size(size)); + SerdNode* const node = (SerdNode*)serd_aaligned_calloc( + allocator, serd_node_align, serd_node_pad_size(size)); assert((uintptr_t)node % serd_node_align == 0); return node; } SerdNode* -serd_node_try_malloc(const SerdWriteResult r) +serd_node_try_malloc(SerdAllocator* const allocator, const SerdWriteResult r) { - return (r.status && r.status != SERD_OVERFLOW) ? NULL - : serd_node_malloc(r.count); + return (r.status && r.status != SERD_OVERFLOW) + ? NULL + : serd_node_malloc(allocator, r.count); } -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) { if (!src) { - serd_free_aligned(*dst); + serd_aaligned_free(allocator, *dst); *dst = NULL; - return; + return SERD_SUCCESS; } 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; } /** @@ -457,7 +464,8 @@ serd_node_construct_uri(const size_t buf_size, } SerdNode* -serd_node_new(const SerdNodeType type, +serd_node_new(SerdAllocator* const allocator, + const SerdNodeType type, const SerdStringView string, const SerdNodeFlags flags, const SerdStringView meta) @@ -469,7 +477,8 @@ serd_node_new(const SerdNodeType type, assert(r.count % sizeof(SerdNode) == 0); - SerdNode* const node = serd_node_malloc(sizeof(SerdNode) + r.count + 1); + SerdNode* const node = + serd_node_malloc(allocator, sizeof(SerdNode) + r.count + 1); if (node) { r = serd_node_construct(r.count, node, type, string, flags, meta); @@ -480,23 +489,26 @@ serd_node_new(const SerdNodeType type, } SerdNode* -serd_new_token(const SerdNodeType type, const SerdStringView string) +serd_new_token(SerdAllocator* const allocator, + const SerdNodeType type, + const SerdStringView string) { - return serd_node_new(type, string, 0u, SERD_EMPTY_STRING()); + return serd_node_new(allocator, type, string, 0u, SERD_EMPTY_STRING()); } SerdNode* -serd_new_string(const SerdStringView str) +serd_new_string(SerdAllocator* const allocator, const SerdStringView str) { - return serd_node_new(SERD_LITERAL, str, 0u, SERD_EMPTY_STRING()); + return serd_node_new(allocator, SERD_LITERAL, str, 0u, SERD_EMPTY_STRING()); } SerdNode* -serd_new_literal(const SerdStringView str, +serd_new_literal(SerdAllocator* const allocator, + const SerdStringView str, const SerdNodeFlags flags, const SerdStringView meta) { - return serd_node_new(SERD_LITERAL, str, flags, meta); + return serd_node_new(allocator, SERD_LITERAL, str, flags, meta); } ExessResult @@ -607,16 +619,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; } @@ -677,16 +693,16 @@ 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) { SerdWriteResult r = serd_node_construct_uri(0u, NULL, uri); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_uri(r.count, node, uri); @@ -758,114 +774,121 @@ serd_node_construct_file_uri(const size_t buf_size, } SerdNode* -serd_new_file_uri(const SerdStringView path, const SerdStringView hostname) +serd_new_file_uri(SerdAllocator* const allocator, + const SerdStringView path, + const SerdStringView hostname) { SerdWriteResult r = serd_node_construct_file_uri(0, NULL, path, hostname); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_file_uri(r.count, node, path, hostname); MUST_SUCCEED(r.status); assert(serd_node_length(node) == strlen(serd_node_string(node))); + serd_node_check_padding(node); } - serd_node_check_padding(node); return node; } SerdNode* -serd_new_double(const double d) +serd_new_double(SerdAllocator* const allocator, const double d) { SerdWriteResult r = serd_node_construct_double(0, NULL, d); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_double(r.count, node, d); MUST_SUCCEED(r.status); assert(serd_node_length(node) == strlen(serd_node_string(node))); + serd_node_check_padding(node); } - serd_node_check_padding(node); return node; } SerdNode* -serd_new_float(const float f) +serd_new_float(SerdAllocator* const allocator, const float f) { SerdWriteResult r = serd_node_construct_float(0, NULL, f); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_float(r.count, node, f); MUST_SUCCEED(r.status); assert(serd_node_length(node) == strlen(serd_node_string(node))); + serd_node_check_padding(node); } - serd_node_check_padding(node); return node; } SerdNode* -serd_new_boolean(bool b) +serd_new_boolean(SerdAllocator* const allocator, bool b) { SerdWriteResult r = serd_node_construct_boolean(0, NULL, b); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_boolean(r.count, node, b); MUST_SUCCEED(r.status); assert(serd_node_length(node) == strlen(serd_node_string(node))); + serd_node_check_padding(node); } - serd_node_check_padding(node); return node; } SerdNode* -serd_new_decimal(const double d) +serd_new_decimal(SerdAllocator* const allocator, const double d) { SerdWriteResult r = serd_node_construct_decimal(0, NULL, d); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_decimal(r.count, node, d); MUST_SUCCEED(r.status); assert(serd_node_length(node) == strlen(serd_node_string(node))); + serd_node_check_padding(node); } - serd_node_check_padding(node); return node; } SerdNode* -serd_new_integer(const int64_t i, const SerdStringView datatype) +serd_new_integer(SerdAllocator* const allocator, + const int64_t i, + const SerdStringView datatype) { SerdWriteResult r = serd_node_construct_integer(0, NULL, i, datatype); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_integer(r.count, node, i, datatype); MUST_SUCCEED(r.status); assert(serd_node_length(node) == strlen(serd_node_string(node))); + serd_node_check_padding(node); } - serd_node_check_padding(node); return node; } SerdNode* -serd_new_base64(const void* buf, size_t size, const SerdStringView datatype) +serd_new_base64(SerdAllocator* const allocator, + const void* buf, + size_t size, + const SerdStringView datatype) { SerdWriteResult r = serd_node_construct_base64(0, NULL, size, buf, datatype); - SerdNode* const node = serd_node_try_malloc(r); + SerdNode* const node = serd_node_try_malloc(allocator, r); if (node) { r = serd_node_construct_base64(r.count, node, size, buf, datatype); MUST_SUCCEED(r.status); assert(serd_node_length(node) == strlen(serd_node_string(node))); + serd_node_check_padding(node); } - serd_node_check_padding(node); return node; } @@ -947,9 +970,9 @@ 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); } #undef MUST_SUCCEED diff --git a/src/node.h b/src/node.h index ab10a3e7..751b827a 100644 --- a/src/node.h +++ b/src/node.h @@ -102,14 +102,16 @@ is_langtag(SerdStringView string); SERD_MALLOC_FUNC SerdNode* SERD_ALLOCATED -serd_node_malloc(size_t size); +serd_node_malloc(SerdAllocator* SERD_NULLABLE allocator, size_t size); SERD_MALLOC_FUNC SerdNode* SERD_ALLOCATED -serd_node_try_malloc(SerdWriteResult result); +serd_node_try_malloc(SerdAllocator* SERD_NULLABLE allocator, + SerdWriteResult result); -void -serd_node_set(SerdNode* SERD_NULLABLE* SERD_NONNULL dst, +SerdStatus +serd_node_set(SerdAllocator* SERD_NULLABLE allocator, + SerdNode* SERD_NULLABLE* SERD_NONNULL dst, const SerdNode* SERD_NULLABLE src); SERD_PURE_FUNC diff --git a/src/node_syntax.c b/src/node_syntax.c index 261d4b03..166fad0e 100644 --- a/src/node_syntax.c +++ b/src/node_syntax.c @@ -15,21 +15,28 @@ */ #include "env.h" +#include "memory.h" #include "writer.h" #include "serd/serd.h" #include #include -#include #include +typedef struct { + SerdAllocator* allocator; + SerdNode* object; +} NodeSyntaxContext; + static SerdStatus -on_node_string_event(void* const handle, const SerdEvent* const event) +on_syntax_event(void* const handle, const SerdEvent* const event) { + NodeSyntaxContext* const ctx = (NodeSyntaxContext*)handle; + if (event->type == SERD_STATEMENT) { - *(SerdNode**)handle = - serd_node_copy(serd_statement_object(event->statement.statement)); + ctx->object = serd_node_copy( + ctx->allocator, serd_statement_object(event->statement.statement)); } return SERD_SUCCESS; @@ -46,44 +53,46 @@ serd_node_from_syntax_in(SerdWorld* const world, static const char* const prelude = "_:s "; - const size_t str_len = strlen(str); - const size_t doc_len = strlen(prelude) + str_len + 4; - char* const doc = (char*)calloc(doc_len + 1, 1); - - snprintf(doc, doc_len + 1, "%s %s .", prelude, str); - - SerdNode* object = NULL; - SerdSink* const sink = - serd_sink_new(world, &object, on_node_string_event, NULL); - - SerdReader* const reader = - serd_reader_new(world, - syntax, - SERD_READ_RELATIVE | SERD_READ_GLOBAL | SERD_READ_GENERATED, - env, - sink, - 1024 + doc_len); - - const SerdNode* string_name = - serd_nodes_string(serd_world_nodes(world), SERD_STRING("string")); - - const char* position = doc; - SerdInputStream in = serd_open_input_string(&position); - serd_reader_start(reader, &in, string_name, 1); - serd_reader_read_document(reader); - serd_reader_finish(reader); - serd_close_input(&in); - serd_reader_free(reader); + const size_t str_len = strlen(str); + const size_t doc_len = strlen(prelude) + str_len + 4; + NodeSyntaxContext ctx = {serd_world_allocator(world), NULL}; + char* const doc = (char*)serd_wcalloc(world, doc_len + 1, 1); + SerdSink* const sink = serd_sink_new(world, &ctx, on_syntax_event, NULL); + + if (doc && sink) { + snprintf(doc, doc_len + 1, "%s %s .", prelude, str); + + SerdReader* const reader = serd_reader_new( + world, + syntax, + SERD_READ_RELATIVE | SERD_READ_GLOBAL | SERD_READ_GENERATED, + env, + sink, + 1024 + doc_len); + + if (reader) { + const char* position = doc; + SerdInputStream in = serd_open_input_string(&position); + serd_reader_start(reader, &in, NULL, 1); + serd_reader_read_document(reader); + serd_reader_finish(reader); + serd_close_input(&in); + } + + serd_reader_free(reader); + } + serd_sink_free(sink); - free(doc); + serd_wfree(world, doc); - return object; + return ctx.object; } SerdNode* -serd_node_from_syntax(const char* const str, - const SerdSyntax syntax, - SerdEnv* const env) +serd_node_from_syntax(SerdAllocator* const allocator, + const char* const str, + const SerdSyntax syntax, + SerdEnv* const env) { assert(str); @@ -91,7 +100,7 @@ serd_node_from_syntax(const char* const str, return serd_node_from_syntax_in(serd_env_world(env), str, syntax, env); } - SerdWorld* const temp_world = serd_world_new(); + SerdWorld* const temp_world = serd_world_new(allocator); if (!temp_world) { return NULL; } @@ -116,27 +125,34 @@ serd_node_to_syntax_in(SerdWorld* const world, const SerdSyntax syntax, const SerdEnv* const env) { - SerdBuffer buffer = {NULL, 0}; + SerdBuffer buffer = {serd_world_allocator(world), NULL, 0}; SerdOutputStream out = serd_open_output_buffer(&buffer); SerdWriter* const writer = serd_writer_new(world, syntax, 0, env, &out, 1); + if (!writer) { + return NULL; + } char* result = NULL; - if (!serd_writer_write_node(writer, node) && !serd_writer_finish(writer) && - !serd_close_output(&out)) { - result = (char*)buffer.buf; + if (!serd_writer_write_node(writer, node) && !serd_writer_finish(writer)) { + if (!serd_close_output(&out)) { + result = (char*)buffer.buf; + } } else { serd_close_output(&out); - free(buffer.buf); } serd_writer_free(writer); - serd_close_output(&out); + + if (!result) { + serd_wfree(world, buffer.buf); + } return result; } char* -serd_node_to_syntax(const SerdNode* const node, +serd_node_to_syntax(SerdAllocator* const allocator, + const SerdNode* const node, const SerdSyntax syntax, const SerdEnv* const env) { @@ -146,16 +162,21 @@ serd_node_to_syntax(const SerdNode* const node, return serd_node_to_syntax_in(serd_env_world(env), node, syntax, env); } - SerdWorld* const temp_world = serd_world_new(); - SerdEnv* const temp_env = serd_env_new(temp_world, SERD_EMPTY_STRING()); - if (temp_env) { - char* const string = - serd_node_to_syntax_in(temp_world, node, syntax, temp_env); + SerdWorld* const temp_world = serd_world_new(allocator); + if (!temp_world) { + return NULL; + } - serd_env_free(temp_env); + SerdEnv* const temp_env = serd_env_new(temp_world, SERD_EMPTY_STRING()); + if (!temp_env) { serd_world_free(temp_world); - return string; + return NULL; } - return NULL; + char* const string = + serd_node_to_syntax_in(temp_world, node, syntax, temp_env); + + serd_env_free(temp_env); + serd_world_free(temp_world); + return string; } diff --git a/src/nodes.c b/src/nodes.c index 529af688..09b63f2a 100644 --- a/src/nodes.c +++ b/src/nodes.c @@ -16,9 +16,9 @@ #include "nodes.h" +#include "memory.h" #include "node.h" #include "node_spec.h" -#include "system.h" // Define the types used in the hash interface for more type safety #define ZIX_HASH_KEY_TYPE SerdNode @@ -26,13 +26,13 @@ #define ZIX_HASH_SEARCH_DATA_TYPE NodeSpec #include "serd/serd.h" +#include "zix/allocator.h" #include "zix/digest.h" #include "zix/hash.h" #include #include #include -#include #include #if ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112l) || \ @@ -76,7 +76,8 @@ typedef struct { } StaticNode; struct SerdNodesImpl { - ZixHash* hash; + SerdAllocator* allocator; + ZixHash* hash; }; static const StaticNode empty_static_node = {{0u, 0u, SERD_LITERAL}, {'\0'}}; @@ -185,10 +186,10 @@ nodes_equal(const SerdNode* const a, const SerdNode* const b) } static NodesEntry* -new_entry(const size_t node_size) +new_entry(SerdAllocator* const allocator, const size_t node_size) { - NodesEntry* const entry = (NodesEntry*)serd_calloc_aligned( - serd_node_align, sizeof(NodesEntryHead) + node_size); + NodesEntry* const entry = (NodesEntry*)serd_aaligned_calloc( + allocator, serd_node_align, sizeof(NodesEntryHead) + node_size); if (entry) { entry->head.refs = 1u; @@ -198,11 +199,20 @@ new_entry(const size_t node_size) } SerdNodes* -serd_nodes_new(void) +serd_nodes_new(SerdAllocator* const allocator) { - SerdNodes* const nodes = (SerdNodes*)calloc(1, sizeof(SerdNodes)); + SerdNodes* const nodes = + (SerdNodes*)serd_acalloc(allocator, 1, sizeof(SerdNodes)); - nodes->hash = zix_hash_new(NULL, nodes_key, nodes_hash, nodes_equal); + if (nodes) { + nodes->allocator = allocator; + + if (!(nodes->hash = zix_hash_new( + (ZixAllocator*)allocator, nodes_key, nodes_hash, nodes_equal))) { + serd_afree(allocator, nodes); + return NULL; + } + } return nodes; } @@ -214,11 +224,11 @@ serd_nodes_free(SerdNodes* nodes) for (ZixHashIter i = zix_hash_begin(nodes->hash); i != zix_hash_end(nodes->hash); i = zix_hash_next(nodes->hash, i)) { - serd_free_aligned(zix_hash_get(nodes->hash, i)); + serd_aaligned_free(nodes->allocator, zix_hash_get(nodes->hash, i)); } zix_hash_free(nodes->hash); - free(nodes); + serd_afree(nodes->allocator, nodes); } } @@ -247,7 +257,10 @@ serd_nodes_intern(SerdNodes* nodes, const SerdNode* node) } const size_t node_size = serd_node_total_size(node); - NodesEntry* const entry = new_entry(node_size); + NodesEntry* const entry = new_entry(nodes->allocator, node_size); + if (!entry) { + return NULL; + } memcpy(&entry->node, node, node_size); @@ -273,6 +286,10 @@ serd_nodes_get(const SerdNodes* const nodes, const SerdNode* const node) static const SerdNode* serd_nodes_manage_entry(SerdNodes* const nodes, NodesEntry* const entry) { + if (!entry) { + return NULL; + } + const SerdNode* const node = &entry->node; const ZixHashInsertPlan plan = zix_hash_plan_insert(nodes->hash, node); NodesEntry* const existing = zix_hash_record_at(nodes->hash, plan); @@ -280,12 +297,16 @@ serd_nodes_manage_entry(SerdNodes* const nodes, NodesEntry* const entry) assert(serd_node_equals(&existing->node, node)); assert(nodes_hash(&existing->node) == plan.code); ++existing->head.refs; - serd_free_aligned(entry); + serd_aaligned_free(nodes->allocator, entry); return &existing->node; } - // Insert the entry (blissfully ignoring a failed hash size increase) - zix_hash_insert_at(nodes->hash, plan, entry); + // Insert the entry (or fail and free it on a failed hash size increase) + if (zix_hash_insert_at(nodes->hash, plan, entry)) { + serd_aaligned_free(nodes->allocator, entry); + return NULL; + } + assert(nodes_hash(&entry->node) == plan.code); return &entry->node; } @@ -309,22 +330,27 @@ serd_nodes_token(SerdNodes* const nodes, const size_t padded_length = serd_node_pad_length(string.len); const size_t node_size = sizeof(SerdNode) + padded_length; - NodesEntry* const entry = new_entry(node_size); + NodesEntry* const entry = new_entry(nodes->allocator, node_size); SerdNode* const node = entry ? &entry->node : NULL; + if (!node) { + return NULL; + } - if (node) { - // Construct the token directly into the node in the new entry - const SerdWriteResult r = - serd_node_construct_token(node_size, &entry->node, type, string); + // Construct the token directly into the node in the new entry + const SerdWriteResult r = + serd_node_construct_token(node_size, &entry->node, type, string); - assert(!r.status); // Never fails with sufficient space - (void)r; + assert(!r.status); // Never fails with sufficient space + (void)r; - // Insert the entry (blissfully ignoring a failed hash size increase) - zix_hash_insert_at(nodes->hash, plan, entry); - assert(nodes_hash(node) == code); + // Insert the entry (blissfully ignoring a failed hash size increase) + if (zix_hash_insert_at(nodes->hash, plan, entry)) { + serd_aaligned_free(nodes->allocator, entry); + return NULL; } + assert(nodes_hash(node) == code); + return node; } @@ -357,7 +383,7 @@ serd_nodes_literal(SerdNodes* const nodes, } // Allocate a new entry with enough space for the node - NodesEntry* const entry = new_entry(r.count); + NodesEntry* const entry = new_entry(nodes->allocator, r.count); SerdNode* const node = entry ? &entry->node : NULL; if (node) { @@ -460,13 +486,15 @@ serd_nodes_base64(SerdNodes* const nodes, serd_node_construct_base64(0, NULL, value_size, value, datatype); // Allocate a new entry to and construct the node into it - NodesEntry* const entry = new_entry(r.count); + NodesEntry* const entry = new_entry(nodes->allocator, r.count); + if (entry) { + r = serd_node_construct_base64( + r.count, &entry->node, value_size, value, datatype); - r = serd_node_construct_base64( - r.count, &entry->node, value_size, value, datatype); + assert(!r.status); + (void)r; + } - assert(!r.status); - (void)r; return serd_nodes_manage_entry(nodes, entry); } @@ -490,11 +518,12 @@ serd_nodes_parsed_uri(SerdNodes* const nodes, const SerdURIView uri) assert(r.status == SERD_OVERFLOW); // Currently no other errors // Allocate a new entry to write the URI node into - NodesEntry* const entry = new_entry(r.count); - - r = serd_node_construct_uri(r.count, &entry->node, uri); - assert(!r.status); - (void)r; + NodesEntry* const entry = new_entry(nodes->allocator, r.count); + if (entry) { + r = serd_node_construct_uri(r.count, &entry->node, uri); + assert(!r.status); + (void)r; + } return serd_nodes_manage_entry(nodes, entry); } @@ -522,6 +551,6 @@ serd_nodes_deref(SerdNodes* const nodes, const SerdNode* const node) NodesEntry* removed = NULL; zix_hash_erase(nodes->hash, i, &removed); assert(removed == entry); - serd_free_aligned(removed); + serd_aaligned_free(nodes->allocator, removed); } } diff --git a/src/reader.c b/src/reader.c index 985a9fd2..46390192 100644 --- a/src/reader.c +++ b/src/reader.c @@ -17,19 +17,18 @@ #include "reader.h" #include "byte_source.h" +#include "memory.h" #include "namespaces.h" #include "node.h" #include "read_nquads.h" #include "read_ntriples.h" #include "stack.h" #include "statement.h" -#include "system.h" #include "world.h" #include #include #include -#include #include static SerdStatus @@ -247,17 +246,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; @@ -288,8 +295,8 @@ serd_reader_free(SerdReader* const reader) serd_reader_finish(reader); - serd_free_aligned(reader->stack.buf); - free(reader); + serd_aaligned_free(reader->world->allocator, reader->stack.buf); + serd_wfree(reader->world, reader); } static SerdStatus @@ -318,11 +325,17 @@ serd_reader_start(SerdReader* const reader, assert(reader); assert(input); + if (!block_size || !input->stream) { + return SERD_BAD_ARG; + } + serd_reader_finish(reader); - reader->source = serd_byte_source_new_input(input, input_name, block_size); + assert(!reader->source); + 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 @@ -361,7 +374,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/sink.c b/src/sink.c index 3e22f11c..f9c46f09 100644 --- a/src/sink.c +++ b/src/sink.c @@ -16,6 +16,7 @@ #include "sink.h" +#include "memory.h" #include "statement.h" #include "serd/serd.h" @@ -29,13 +30,16 @@ serd_sink_new(const SerdWorld* const world, SerdEventFunc event_func, SerdFreeFunc free_handle) { - (void)world; + assert(world); - SerdSink* sink = (SerdSink*)calloc(1, sizeof(SerdSink)); + SerdSink* sink = (SerdSink*)serd_wcalloc(world, 1, sizeof(SerdSink)); - sink->handle = handle; - sink->on_event = event_func; - sink->free_handle = free_handle; + if (sink) { + sink->world = world; + sink->handle = handle; + sink->on_event = event_func; + sink->free_handle = free_handle; + } return sink; } @@ -48,7 +52,7 @@ serd_sink_free(SerdSink* sink) sink->free_handle(sink->handle); } - free(sink); + serd_wfree(sink->world, sink); } } diff --git a/src/sink.h b/src/sink.h index 6e8dffe3..1f7df534 100644 --- a/src/sink.h +++ b/src/sink.h @@ -23,9 +23,10 @@ An interface that receives a stream of RDF data. */ struct SerdSinkImpl { - void* handle; - SerdFreeFunc free_handle; - SerdEventFunc on_event; + const SerdWorld* world; + void* handle; + SerdFreeFunc free_handle; + SerdEventFunc on_event; }; #endif // SERD_SINK_H diff --git a/src/stack.h b/src/stack.h index f94730c3..3b53ac88 100644 --- a/src/stack.h +++ b/src/stack.h @@ -17,7 +17,9 @@ #ifndef SERD_STACK_H #define SERD_STACK_H -#include "system.h" +#include "memory.h" + +#include "serd/serd.h" #include #include @@ -38,12 +40,12 @@ typedef struct { #define SERD_STACK_BOTTOM sizeof(void*) 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 = SERD_STACK_BOTTOM; return stack; @@ -62,9 +64,9 @@ serd_stack_is_empty(const SerdStack* 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 8ca0d8ee..d407ad76 100644 --- a/src/statement.c +++ b/src/statement.c @@ -17,6 +17,7 @@ #include "statement.h" #include "caret.h" +#include "memory.h" #include "node.h" #include @@ -38,13 +39,16 @@ serd_statement_is_valid(const SerdNode* const subject, const SerdNode* const object, const SerdNode* const graph) { - return subject && predicate && object && is_resource(subject) && - is_resource(predicate) && serd_node_type(predicate) != SERD_BLANK && + (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, @@ -58,39 +62,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 136cb09c..1b9bb64a 100644 --- a/src/string.c +++ b/src/string.c @@ -14,6 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "memory.h" #include "string_utils.h" #include "serd/serd.h" @@ -22,9 +23,9 @@ #include 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 cb6ceb6d..2ebca97c 100644 --- a/src/system.c +++ b/src/system.c @@ -16,17 +16,23 @@ #include "system.h" -#include "serd/serd.h" +#include "memory.h" #include "serd_config.h" +#include "serd/serd.h" + #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN 1 # include # include +#else +# include +# ifndef PATH_MAX +# include +# endif #endif #include -#include #include #include @@ -44,72 +50,52 @@ serd_system_strerror(const int errnum, char* const buf, const size_t buflen) #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 -} - char* -serd_canonical_path(const char* const path) +serd_canonical_path(SerdAllocator* const allocator, const char* const path) { assert(path); -#ifdef _WIN32 +#if defined(_WIN32) + // Microsoft got this one right: measure, allocate, resolve const DWORD size = GetFullPathName(path, 0, NULL, NULL); if (size == 0) { return NULL; } - char* const out = (char*)calloc(size, 1); - const DWORD ret = GetFullPathName(path, MAX_PATH, out, NULL); - if (ret == 0 || ret >= size) { - free(out); + char* const out = (char*)serd_acalloc(allocator, size, 1); + if (out) { + const DWORD ret = GetFullPathName(path, MAX_PATH, out, NULL); + if (ret == 0 || ret >= size) { + serd_afree(allocator, out); + return NULL; + } + } + + return out; + +#elif defined(PATH_MAX) + // Some POSIX systems have a static PATH_MAX so we can resolve on the stack + char result[PATH_MAX] = {0}; + char* resolved_path = realpath(path, result); + if (!resolved_path) { return NULL; } + const size_t len = strlen(resolved_path); + char* const out = (char*)serd_acalloc(allocator, len + 1, 1); + if (out) { + memcpy(out, resolved_path, len + 1); + } return out; + #else - return path ? realpath(path, NULL) : NULL; + // Others don't so we have to query PATH_MAX at runtime to allocate the result + long path_max = pathconf(path, _PC_PATH_MAX); + if (path_max <= 0) { + path_max = SERD_PAGE_SIZE; + } + + char* const out = (char*)serd_acalloc(allocator, path_max, 1); + return out ? realpath(path, out) : NULL; #endif } diff --git a/src/system.h b/src/system.h index 184e1aae..9ef0b142 100644 --- a/src/system.h +++ b/src/system.h @@ -17,9 +17,7 @@ #ifndef SERD_SYSTEM_H #define SERD_SYSTEM_H -#include "attributes.h" - -#include +#include #define SERD_PAGE_SIZE 4096 @@ -27,23 +25,4 @@ int serd_system_strerror(int errnum, char* buf, size_t buflen); -/// Allocate a buffer aligned to `alignment` bytes -SERD_I_MALLOC_FUNC -void* -serd_malloc_aligned(size_t alignment, size_t size); - -/// Allocate a zeroed buffer aligned to `alignment` bytes -SERD_I_MALLOC_FUNC -void* -serd_calloc_aligned(size_t alignment, size_t size); - -/// Allocate an aligned buffer for I/O -SERD_I_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_SYSTEM_H diff --git a/src/uri.c b/src/uri.c index bbd53ca3..fad1d188 100644 --- a/src/uri.c +++ b/src/uri.c @@ -14,6 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "memory.h" #include "string_utils.h" #include "uri_utils.h" @@ -26,7 +27,9 @@ #include 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); @@ -46,7 +49,10 @@ serd_parse_file_uri(const char* const uri, char** const hostname) if (hostname) { const size_t len = (size_t)(path - auth); - *hostname = (char*)calloc(len + 1, 1); + if (!(*hostname = (char*)serd_acalloc(allocator, len + 1, 1))) { + return NULL; + } + memcpy(*hostname, auth, len); } } @@ -56,26 +62,39 @@ 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; *s; ++s) { if (*s == '%') { if (*(s + 1) == '%') { - serd_buffer_write("%", 1, 1, &buffer); + if (serd_buffer_write("%", 1, 1, &buffer) != 1) { + serd_afree(allocator, buffer.buf); + return NULL; + } + ++s; } else if (is_hexdig(*(s + 1)) && is_hexdig(*(s + 2))) { const char code[3] = {*(s + 1), *(s + 2), 0}; const char c = (char)strtoul(code, NULL, 16); - serd_buffer_write(&c, 1, 1, &buffer); + if (serd_buffer_write(&c, 1, 1, &buffer) != 1) { + serd_afree(allocator, buffer.buf); + return NULL; + } + s += 2; } else { s += 2; // Junk escape, ignore } - } else { - serd_buffer_write(s, 1, 1, &buffer); + } else if (serd_buffer_write(s, 1, 1, &buffer) != 1) { + serd_afree(allocator, buffer.buf); + return NULL; } } - serd_buffer_close(&buffer); + if (serd_buffer_close(&buffer)) { + serd_afree(allocator, buffer.buf); + return NULL; + } + return (char*)buffer.buf; } diff --git a/src/world.c b/src/world.c index 39eeaec3..5b5cb900 100644 --- a/src/world.c +++ b/src/world.c @@ -16,6 +16,7 @@ #include "world.h" +#include "memory.h" #include "namespaces.h" #include "node.h" #include "serd_config.h" @@ -67,27 +68,46 @@ terminal_supports_color(FILE* const stream) } SerdWorld* -serd_world_new(void) +serd_world_new(SerdAllocator* const allocator) { - SerdWorld* world = (SerdWorld*)calloc(1, sizeof(SerdWorld)); - SerdNodes* nodes = serd_nodes_new(); - - const SerdStringView rdf_first = SERD_STRING(NS_RDF "first"); - const SerdStringView rdf_nil = SERD_STRING(NS_RDF "nil"); - const SerdStringView rdf_rest = SERD_STRING(NS_RDF "rest"); - const SerdStringView rdf_type = SERD_STRING(NS_RDF "type"); - const SerdStringView xsd_boolean = SERD_STRING(NS_XSD "boolean"); - const SerdStringView xsd_decimal = SERD_STRING(NS_XSD "decimal"); - const SerdStringView xsd_integer = SERD_STRING(NS_XSD "integer"); - - world->nodes = nodes; - world->rdf_first = serd_nodes_uri(nodes, rdf_first); - world->rdf_nil = serd_nodes_uri(nodes, rdf_nil); - world->rdf_rest = serd_nodes_uri(nodes, rdf_rest); - world->rdf_type = serd_nodes_uri(nodes, rdf_type); - world->xsd_boolean = serd_nodes_uri(nodes, xsd_boolean); - world->xsd_decimal = serd_nodes_uri(nodes, xsd_decimal); - world->xsd_integer = serd_nodes_uri(nodes, xsd_integer); + SerdAllocator* const actual = + allocator ? allocator : serd_default_allocator(); + + SerdWorld* const world = + (SerdWorld*)serd_acalloc(actual, 1, sizeof(SerdWorld)); + + if (!world) { + return NULL; + } + + SerdNodes* const nodes = serd_nodes_new(actual); + if (!nodes) { + serd_afree(actual, world); + return NULL; + } + + static const SerdStringView rdf_first = SERD_STRING(NS_RDF "first"); + static const SerdStringView rdf_nil = SERD_STRING(NS_RDF "nil"); + static const SerdStringView rdf_rest = SERD_STRING(NS_RDF "rest"); + static const SerdStringView rdf_type = SERD_STRING(NS_RDF "type"); + static const SerdStringView xsd_boolean = SERD_STRING(NS_XSD "boolean"); + static const SerdStringView xsd_decimal = SERD_STRING(NS_XSD "decimal"); + static const SerdStringView xsd_integer = SERD_STRING(NS_XSD "integer"); + + world->allocator = actual; + world->nodes = nodes; + + if (!(world->rdf_first = serd_nodes_uri(nodes, rdf_first)) || + !(world->rdf_nil = serd_nodes_uri(nodes, rdf_nil)) || + !(world->rdf_rest = serd_nodes_uri(nodes, rdf_rest)) || + !(world->rdf_type = serd_nodes_uri(nodes, rdf_type)) || + !(world->xsd_boolean = serd_nodes_uri(nodes, xsd_boolean)) || + !(world->xsd_decimal = serd_nodes_uri(nodes, xsd_decimal)) || + !(world->xsd_integer = serd_nodes_uri(nodes, xsd_integer))) { + serd_nodes_free(nodes); + serd_afree(actual, world); + return NULL; + } serd_node_construct_token(sizeof(world->blank), &world->blank, @@ -104,10 +124,18 @@ serd_world_free(SerdWorld* const world) { if (world) { serd_nodes_free(world->nodes); - free(world); + serd_afree(world->allocator, world); } } +SerdAllocator* +serd_world_allocator(const SerdWorld* const world) +{ + assert(world); + assert(world->allocator); + return world->allocator; +} + SerdNodes* serd_world_nodes(SerdWorld* const world) { diff --git a/src/world.h b/src/world.h index f1124023..5e8adaeb 100644 --- a/src/world.h +++ b/src/world.h @@ -43,6 +43,8 @@ struct SerdWorldImpl { uint32_t next_blank_id; uint32_t next_document_id; + SerdAllocator* allocator; + bool stderr_color; }; diff --git a/src/writer.c b/src/writer.c index e19518e4..db69b9ed 100644 --- a/src/writer.c +++ b/src/writer.c @@ -18,6 +18,7 @@ #include "block_dumper.h" #include "env.h" +#include "memory.h" #include "node.h" #include "sink.h" #include "string_utils.h" @@ -35,7 +36,6 @@ #include #include #include -#include #include #ifndef _MSC_VER @@ -176,9 +176,9 @@ supports_uriref(const SerdWriter* writer) static SerdStatus free_context(SerdWriter* writer) { - serd_node_free(writer->context.graph); - serd_node_free(writer->context.subject); - serd_node_free(writer->context.predicate); + 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; } @@ -196,9 +196,9 @@ push_context(SerdWriter* const writer, const WriteContext new_context = {type, flags, - serd_node_copy(g), - serd_node_copy(s), - serd_node_copy(p), + serd_node_copy(writer->world->allocator, g), + serd_node_copy(writer->world->allocator, s), + serd_node_copy(writer->world->allocator, p), false}; writer->anon_stack[writer->anon_stack_size++] = writer->context; @@ -951,8 +951,9 @@ write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred) SerdStatus st = SERD_SUCCESS; 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); - return st; + + return serd_node_set( + writer->world->allocator, &writer->context.predicate, pred); } SERD_WARN_UNUSED_RESULT static SerdStatus @@ -1028,12 +1029,10 @@ update_abbreviation_context(SerdWriter* const writer, SerdStatus st = SERD_SUCCESS; // Push context for list or anonymous subject if necessary - if (!st) { - if (flags & SERD_ANON_S) { - st = push_context(writer, CTX_BLANK, flags, graph, subject, predicate); - } else if (flags & SERD_LIST_S) { - st = push_context(writer, CTX_LIST, flags, graph, subject, NULL); - } + if (flags & SERD_ANON_S) { + st = push_context(writer, CTX_BLANK, flags, graph, subject, predicate); + } else if (flags & SERD_LIST_S) { + st = push_context(writer, CTX_LIST, flags, graph, subject, NULL); } // Push context for list or anonymous object if necessary @@ -1048,9 +1047,10 @@ update_abbreviation_context(SerdWriter* const writer, // Update current context to this statement if this isn't a new context if (!st) { if (!(flags & (SERD_ANON_S | SERD_LIST_S | SERD_ANON_O | SERD_LIST_O))) { - serd_node_set(&writer->context.graph, graph); - serd_node_set(&writer->context.subject, subject); - serd_node_set(&writer->context.predicate, predicate); + SerdAllocator* const allocator = writer->world->allocator; + TRY(st, serd_node_set(allocator, &writer->context.graph, graph)); + TRY(st, serd_node_set(allocator, &writer->context.subject, subject)); + TRY(st, serd_node_set(allocator, &writer->context.predicate, predicate)); } } @@ -1126,11 +1126,16 @@ write_turtle_trig_statement(SerdWriter* const writer, } // Write new subject + if (!ctx(writer, SERD_GRAPH)) { TRY(st, write_top_level_sep(writer)); } + reset_context(writer, false); - serd_node_set(&writer->context.subject, subject); + TRY(st, + serd_node_set( + writer->world->allocator, &writer->context.subject, subject)); + TRY(st, write_node(writer, subject, SERD_SUBJECT, flags)); // Write appropriate S,P separator based on the context @@ -1187,7 +1192,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); } } @@ -1327,13 +1332,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 WriteContext context = WRITE_CONTEXT_NULL; - SerdWriter* writer = (SerdWriter*)calloc(1, sizeof(SerdWriter)); + + SerdWriter* writer = (SerdWriter*)serd_wcalloc(world, 1, sizeof(SerdWriter)); + if (!writer) { + serd_block_dumper_close(&dumper); + return NULL; + } writer->world = world; writer->syntax = syntax; @@ -1345,9 +1355,15 @@ serd_writer_new(SerdWorld* world, writer->context = context; writer->empty = true; - writer->anon_stack = - (WriteContext*)calloc(anon_stack_capacity, sizeof(WriteContext)); + writer->anon_stack = (WriteContext*)serd_wcalloc( + world, anon_stack_capacity, sizeof(WriteContext)); + + if (!writer->anon_stack) { + serd_wfree(world, writer); + return NULL; + } + writer->iface.world = world; writer->iface.handle = writer; writer->iface.on_event = (SerdEventFunc)serd_writer_on_event; @@ -1386,12 +1402,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.len) { - 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); } @@ -1439,9 +1455,9 @@ serd_writer_free(SerdWriter* writer) serd_writer_finish(writer); serd_block_dumper_close(&writer->output); - free(writer->anon_stack); - serd_node_free(writer->root_node); - free(writer); + serd_wfree(writer->world, writer->anon_stack); + serd_node_free(writer->world->allocator, writer->root_node); + serd_wfree(writer->world, writer); } const SerdSink* -- cgit v1.2.1