aboutsummaryrefslogtreecommitdiffstats
path: root/include/serd
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-09-10 15:06:42 -0400
committerDavid Robillard <d@drobilla.net>2023-12-02 18:49:08 -0500
commit248a874d7425749d29cf900a1c3783c624ea8d8c (patch)
treeaed59f5a484a815cd254506866e98a947858904d /include/serd
parent0bd10132c6707353dba80bd89cf0102ee7ca4e34 (diff)
downloadserd-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 'include/serd')
-rw-r--r--include/serd/buffer.h12
-rw-r--r--include/serd/caret.h11
-rw-r--r--include/serd/env.h6
-rw-r--r--include/serd/memory.h96
-rw-r--r--include/serd/node.h60
-rw-r--r--include/serd/sink.h9
-rw-r--r--include/serd/statement.h11
-rw-r--r--include/serd/uri.h8
-rw-r--r--include/serd/world.h7
9 files changed, 182 insertions, 38 deletions
diff --git a/include/serd/buffer.h b/include/serd/buffer.h
index 20abfb29..a56188e7 100644
--- a/include/serd/buffer.h
+++ b/include/serd/buffer.h
@@ -5,6 +5,7 @@
#define SERD_BUFFER_H
#include "serd/attributes.h"
+#include "serd/memory.h"
#include "zix/attributes.h"
#include <stddef.h>
@@ -23,18 +24,19 @@ SERD_BEGIN_DECLS
@{
*/
-/// A mutable buffer in memory
+/// A dynamically resizable mutable buffer in memory
typedef struct {
- void* ZIX_NULLABLE buf; ///< Buffer
- size_t len; ///< Size of buffer in bytes
+ SerdAllocator* ZIX_NULLABLE allocator; ///< Allocator for buf
+ void* ZIX_NULLABLE buf; ///< Buffer
+ size_t len; ///< Size of buffer in bytes
} SerdBuffer;
/**
A function for writing to a buffer, resizing it if necessary.
This function can be used as a #SerdWriteFunc to write to a #SerdBuffer
- which is resized as necessary with realloc(). The `stream` parameter must
- point to an initialized #SerdBuffer.
+ which is reallocated as necessary. The `stream` parameter must point to an
+ initialized #SerdBuffer.
Note that when writing a string, the string in the buffer will not be
null-terminated until serd_buffer_close() is called.
diff --git a/include/serd/caret.h b/include/serd/caret.h
index 429a6fcd..54df0932 100644
--- a/include/serd/caret.h
+++ b/include/serd/caret.h
@@ -5,6 +5,7 @@
#define SERD_CARET_H
#include "serd/attributes.h"
+#include "serd/memory.h"
#include "serd/node.h"
#include "zix/attributes.h"
@@ -29,23 +30,27 @@ typedef struct SerdCaretImpl SerdCaret;
valid. That is, serd_caret_document() will return exactly the pointer
`document`, not a copy.
+ @param allocator Allocator to use for caret memory.
@param document The document or the caret refers to (usually a file URI)
@param line The line number in the document (1-based)
@param column The column number in the document (1-based)
@return A new caret that must be freed with serd_caret_free()
*/
SERD_API SerdCaret* ZIX_ALLOCATED
-serd_caret_new(const SerdNode* ZIX_NONNULL document,
+serd_caret_new(SerdAllocator* ZIX_NULLABLE allocator,
+ const SerdNode* ZIX_NONNULL document,
unsigned line,
unsigned column);
/// Return a copy of `caret`
SERD_API SerdCaret* ZIX_ALLOCATED
-serd_caret_copy(const SerdCaret* ZIX_NULLABLE caret);
+serd_caret_copy(SerdAllocator* ZIX_NULLABLE allocator,
+ const SerdCaret* ZIX_NULLABLE caret);
/// Free `caret`
SERD_API void
-serd_caret_free(SerdCaret* ZIX_NULLABLE caret);
+serd_caret_free(SerdAllocator* ZIX_NULLABLE allocator,
+ SerdCaret* ZIX_NULLABLE caret);
/// Return true iff `lhs` is equal to `rhs`
SERD_PURE_API bool
diff --git a/include/serd/env.h b/include/serd/env.h
index b4f908a9..a0c47997 100644
--- a/include/serd/env.h
+++ b/include/serd/env.h
@@ -5,6 +5,7 @@
#define SERD_ENV_H
#include "serd/attributes.h"
+#include "serd/memory.h"
#include "serd/node.h"
#include "serd/sink.h"
#include "serd/status.h"
@@ -26,11 +27,12 @@ typedef struct SerdEnvImpl SerdEnv;
/// Create a new environment
SERD_API SerdEnv* ZIX_ALLOCATED
-serd_env_new(SerdStringView base_uri);
+serd_env_new(SerdAllocator* ZIX_NULLABLE allocator, SerdStringView base_uri);
/// Copy an environment
SERD_API SerdEnv* ZIX_ALLOCATED
-serd_env_copy(const SerdEnv* ZIX_NULLABLE env);
+serd_env_copy(SerdAllocator* ZIX_NULLABLE allocator,
+ const SerdEnv* ZIX_NULLABLE env);
/// Return true iff `a` is equal to `b`
SERD_PURE_API bool
diff --git a/include/serd/memory.h b/include/serd/memory.h
index 050b7597..4a653349 100644
--- a/include/serd/memory.h
+++ b/include/serd/memory.h
@@ -7,6 +7,8 @@
#include "serd/attributes.h"
#include "zix/attributes.h"
+#include <stddef.h>
+
SERD_BEGIN_DECLS
/**
@@ -16,14 +18,106 @@ SERD_BEGIN_DECLS
*/
/**
+ A memory allocator.
+
+ This object-like structure provides an interface like the standard C
+ functions malloc(), calloc(), realloc(), free(), and aligned_alloc(). It
+ contains function pointers that differ from their standard counterparts by
+ taking a context parameter (a pointer to this struct), which allows the user
+ to implement custom stateful allocators.
+*/
+typedef struct SerdAllocatorImpl SerdAllocator;
+
+/**
+ General malloc-like memory allocation function.
+
+ This works like the standard C malloc(), except has an additional handle
+ parameter for implementing stateful allocators without static data.
+*/
+typedef void* ZIX_ALLOCATED (*SerdAllocatorMallocFunc)( //
+ SerdAllocator* ZIX_NULLABLE allocator,
+ size_t size);
+
+/**
+ General calloc-like memory allocation function.
+
+ This works like the standard C calloc(), except has an additional handle
+ parameter for implementing stateful allocators without static data.
+*/
+typedef void* ZIX_ALLOCATED (*SerdAllocatorCallocFunc)( //
+ SerdAllocator* ZIX_NULLABLE allocator,
+ size_t nmemb,
+ size_t size);
+
+/**
+ General realloc-like memory reallocation function.
+
+ This works like the standard C remalloc(), except has an additional handle
+ parameter for implementing stateful allocators without static data.
+*/
+typedef void* ZIX_ALLOCATED (*SerdAllocatorReallocFunc)( //
+ SerdAllocator* ZIX_NULLABLE allocator,
+ void* ZIX_NULLABLE ptr,
+ size_t size);
+
+/**
+ General free-like memory deallocation function.
+
+ This works like the standard C remalloc(), except has an additional handle
+ parameter for implementing stateful allocators without static data.
+*/
+typedef void (*SerdAllocatorFreeFunc)( //
+ SerdAllocator* ZIX_NULLABLE allocator,
+ void* ZIX_NULLABLE ptr);
+
+/**
+ General aligned_alloc-like memory deallocation function.
+
+ This works like the standard C aligned_alloc(), except has an additional
+ handle parameter for implementing stateful allocators without static data.
+*/
+typedef void* ZIX_ALLOCATED (*SerdAllocatorAlignedAllocFunc)( //
+ SerdAllocator* ZIX_NULLABLE allocator,
+ size_t alignment,
+ size_t size);
+
+/**
+ General aligned memory deallocation function.
+
+ This works like the standard C free(), but must be used to free memory
+ allocated with the aligned_alloc() method of the allocator. This allows
+ portability to systems (like Windows) that can not use the same free function
+ in these cases.
+*/
+typedef void (*SerdAllocatorAlignedFreeFunc)( //
+ SerdAllocator* ZIX_NULLABLE allocator,
+ void* ZIX_NULLABLE ptr);
+
+/// Definition of SerdAllocator
+struct SerdAllocatorImpl {
+ SerdAllocatorMallocFunc ZIX_ALLOCATED malloc;
+ SerdAllocatorCallocFunc ZIX_ALLOCATED calloc;
+ SerdAllocatorReallocFunc ZIX_ALLOCATED realloc;
+ SerdAllocatorFreeFunc ZIX_ALLOCATED free;
+ SerdAllocatorAlignedAllocFunc ZIX_ALLOCATED aligned_alloc;
+ SerdAllocatorAlignedFreeFunc ZIX_ALLOCATED aligned_free;
+};
+
+/// Return the default allocator which simply uses the system allocator
+SERD_CONST_API SerdAllocator* ZIX_NONNULL
+serd_default_allocator(void);
+
+/**
Free memory allocated by Serd.
This function exists because some systems require memory allocated by a
library to be freed by code in the same library. It is otherwise equivalent
to the standard C free() function.
+
+ This may be used to free memory allocated using serd_default_allocator().
*/
SERD_API void
-serd_free(void* ZIX_NULLABLE ptr);
+serd_free(SerdAllocator* ZIX_NULLABLE allocator, void* ZIX_NULLABLE ptr);
/**
@}
diff --git a/include/serd/node.h b/include/serd/node.h
index b0b14a24..f42f07f1 100644
--- a/include/serd/node.h
+++ b/include/serd/node.h
@@ -5,6 +5,7 @@
#define SERD_NODE_H
#include "serd/attributes.h"
+#include "serd/memory.h"
#include "serd/string_view.h"
#include "serd/uri.h"
#include "serd/write_result.h"
@@ -117,13 +118,15 @@ typedef uint32_t SerdNodeFlags;
to create URIs, blank nodes, CURIEs, and simple string literals.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_token(SerdNodeType type, SerdStringView string);
+serd_new_token(SerdAllocator* ZIX_NULLABLE allocator,
+ SerdNodeType type,
+ SerdStringView string);
/**
Create a new string literal node.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_string(SerdStringView string);
+serd_new_string(SerdAllocator* ZIX_NULLABLE allocator, SerdStringView string);
/**
Create a new literal node with optional datatype or language.
@@ -132,6 +135,8 @@ serd_new_string(SerdStringView string);
associated datatype URI or language tag, as well as control whether a
literal should be written as a short or long (triple-quoted) string.
+ @param allocator Allocator for the returned node.
+
@param string The string value of the literal.
@param flags Flags to describe the literal and its metadata. This must be a
@@ -147,27 +152,28 @@ serd_new_string(SerdStringView string);
serd_node_free(), or null if the arguments are invalid or allocation failed.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_literal(SerdStringView string,
- SerdNodeFlags flags,
- SerdStringView meta);
+serd_new_literal(SerdAllocator* ZIX_NULLABLE allocator,
+ SerdStringView string,
+ SerdNodeFlags flags,
+ SerdStringView meta);
/**
Create a new node from a blank node label.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_blank(SerdStringView string);
+serd_new_blank(SerdAllocator* ZIX_NULLABLE allocator, SerdStringView string);
/**
Create a new URI node from a parsed URI.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_parsed_uri(SerdURIView uri);
+serd_new_parsed_uri(SerdAllocator* ZIX_NULLABLE allocator, SerdURIView uri);
/**
Create a new URI node from a string.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_uri(SerdStringView string);
+serd_new_uri(SerdAllocator* ZIX_NULLABLE allocator, SerdStringView string);
/**
Create a new file URI node from a file system path and optional hostname.
@@ -178,13 +184,15 @@ serd_new_uri(SerdStringView string);
If `path` is relative, `hostname` is ignored.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_file_uri(SerdStringView path, SerdStringView hostname);
+serd_new_file_uri(SerdAllocator* ZIX_NULLABLE allocator,
+ SerdStringView path,
+ SerdStringView hostname);
/**
Create a new canonical xsd:boolean node.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_boolean(bool b);
+serd_new_boolean(SerdAllocator* ZIX_NULLABLE allocator, bool b);
/**
Create a new canonical xsd:decimal literal.
@@ -196,11 +204,14 @@ serd_new_boolean(bool b);
(a leading and/or trailing '0' will be added if necessary), for example,
"1.0". It will never be in scientific notation.
+ @param allocator Allocator for the returned node.
@param d The value for the new node.
@param datatype Datatype of node, or NULL for xsd:decimal.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_decimal(double d, const SerdNode* ZIX_NULLABLE datatype);
+serd_new_decimal(SerdAllocator* ZIX_NULLABLE allocator,
+ double d,
+ const SerdNode* ZIX_NULLABLE datatype);
/**
Create a new canonical xsd:double literal.
@@ -212,11 +223,12 @@ serd_new_decimal(double d, const SerdNode* ZIX_NULLABLE datatype);
Uses the shortest possible representation that precisely describes the
value, which has at most 17 significant digits (under 24 characters total).
+ @param allocator Allocator for the returned node.
@param d Double value to write.
@return A literal node with datatype xsd:double.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_double(double d);
+serd_new_double(SerdAllocator* ZIX_NULLABLE allocator, double d);
/**
Create a new canonical xsd:float literal.
@@ -224,11 +236,12 @@ serd_new_double(double d);
Uses identical formatting to serd_new_double(), except with at most 9
significant digits (under 14 characters total).
+ @param allocator Allocator for the returned node.
@param f Float value of literal.
@return A literal node with datatype xsd:float.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_float(float f);
+serd_new_float(SerdAllocator* ZIX_NULLABLE allocator, float f);
/**
Create a new canonical xsd:integer literal.
@@ -236,10 +249,11 @@ serd_new_float(float f);
The node will be an xsd:integer literal like "1234", with datatype
xsd:integer.
+ @param allocator Allocator for the returned node.
@param i Integer value of literal.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_integer(int64_t i);
+serd_new_integer(SerdAllocator* ZIX_NULLABLE allocator, int64_t i);
/**
Create a new canonical xsd:base64Binary literal.
@@ -247,21 +261,31 @@ serd_new_integer(int64_t i);
This function can be used to make a node out of arbitrary binary data, which
can be decoded using serd_base64_decode().
+ @param allocator Allocator for the returned node.
@param buf Raw binary data to encode in node.
@param size Size of `buf` in bytes.
*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_new_base64(const void* ZIX_NONNULL buf, size_t size);
+serd_new_base64(SerdAllocator* ZIX_NULLABLE allocator,
+ const void* ZIX_NONNULL buf,
+ size_t size);
+
+/**
+ Return a deep copy of `node`.
-/// Return a deep copy of `node`
+ @param allocator Allocator for the returned node.
+ @param node The node to copyl
+*/
SERD_API SerdNode* ZIX_ALLOCATED
-serd_node_copy(const SerdNode* ZIX_NULLABLE node);
+serd_node_copy(SerdAllocator* ZIX_NULLABLE allocator,
+ const SerdNode* ZIX_NULLABLE node);
/**
Free any data owned by `node`.
*/
SERD_API void
-serd_node_free(SerdNode* ZIX_NULLABLE node);
+serd_node_free(SerdAllocator* ZIX_NULLABLE allocator,
+ SerdNode* ZIX_NULLABLE node);
/**
@}
diff --git a/include/serd/sink.h b/include/serd/sink.h
index 291e8d3f..e34ce941 100644
--- a/include/serd/sink.h
+++ b/include/serd/sink.h
@@ -6,6 +6,7 @@
#include "serd/attributes.h"
#include "serd/event.h"
+#include "serd/memory.h"
#include "serd/node.h"
#include "serd/statement.h"
#include "serd/status.h"
@@ -65,14 +66,16 @@ typedef void (*SerdFreeFunc)(void* ZIX_NULLABLE ptr);
/**
Create a new sink.
+ @param allocator Allocator to use for the returned sink.
@param handle Opaque handle that will be passed to sink functions.
@param event_func Function that will be called for every event.
@param free_handle Free function to call on handle in serd_sink_free().
*/
SERD_API SerdSink* ZIX_ALLOCATED
-serd_sink_new(void* ZIX_NULLABLE handle,
- SerdEventFunc ZIX_NULLABLE event_func,
- SerdFreeFunc ZIX_NULLABLE free_handle);
+serd_sink_new(SerdAllocator* ZIX_NULLABLE allocator,
+ void* ZIX_NULLABLE handle,
+ SerdEventFunc ZIX_NULLABLE event_func,
+ SerdFreeFunc ZIX_NULLABLE free_handle);
/// Free `sink`
SERD_API void
diff --git a/include/serd/statement.h b/include/serd/statement.h
index a4109958..03d7ae6d 100644
--- a/include/serd/statement.h
+++ b/include/serd/statement.h
@@ -6,6 +6,7 @@
#include "serd/attributes.h"
#include "serd/caret.h"
+#include "serd/memory.h"
#include "serd/node.h"
#include "zix/attributes.h"
@@ -55,6 +56,7 @@ typedef struct SerdStatementImpl SerdStatement;
statements in models, this is the lifetime of the model. For user-created
statements, the simplest way to handle this is to use `SerdNodes`.
+ @param allocator Allocator for the returned statement.
@param s The subject
@param p The predicate ("key")
@param o The object ("value")
@@ -63,7 +65,8 @@ typedef struct SerdStatementImpl SerdStatement;
@return A new statement that must be freed with serd_statement_free()
*/
SERD_API SerdStatement* ZIX_ALLOCATED
-serd_statement_new(const SerdNode* ZIX_NONNULL s,
+serd_statement_new(SerdAllocator* ZIX_NULLABLE allocator,
+ const SerdNode* ZIX_NONNULL s,
const SerdNode* ZIX_NONNULL p,
const SerdNode* ZIX_NONNULL o,
const SerdNode* ZIX_NULLABLE g,
@@ -71,11 +74,13 @@ serd_statement_new(const SerdNode* ZIX_NONNULL s,
/// Return a copy of `statement`
SERD_API SerdStatement* ZIX_ALLOCATED
-serd_statement_copy(const SerdStatement* ZIX_NULLABLE statement);
+serd_statement_copy(SerdAllocator* ZIX_NULLABLE allocator,
+ const SerdStatement* ZIX_NULLABLE statement);
/// Free `statement`
SERD_API void
-serd_statement_free(SerdStatement* ZIX_NULLABLE statement);
+serd_statement_free(SerdAllocator* ZIX_NULLABLE allocator,
+ SerdStatement* ZIX_NULLABLE statement);
/// Return the given node of the statement
SERD_PURE_API const SerdNode* ZIX_NULLABLE
diff --git a/include/serd/uri.h b/include/serd/uri.h
index 7a63f183..c978782f 100644
--- a/include/serd/uri.h
+++ b/include/serd/uri.h
@@ -5,6 +5,7 @@
#define SERD_URI_H
#include "serd/attributes.h"
+#include "serd/memory.h"
#include "serd/stream.h"
#include "serd/string_view.h"
#include "zix/attributes.h"
@@ -55,12 +56,15 @@ static const SerdURIView SERD_URI_NULL =
The returned path and `*hostname` must be freed with serd_free().
+ @param allocator Allocator for the returned string.
@param uri A file URI.
@param hostname If non-NULL, set to the hostname, if present.
- @return A newly-allocated filesystem path.
+
+ @return A newly allocated path string that must be freed with serd_free().
*/
SERD_API char* ZIX_ALLOCATED
-serd_parse_file_uri(const char* ZIX_NONNULL uri,
+serd_parse_file_uri(SerdAllocator* ZIX_NULLABLE allocator,
+ const char* ZIX_NONNULL uri,
char* ZIX_NONNULL* ZIX_NULLABLE hostname);
/// Return true iff `string` starts with a valid URI scheme
diff --git a/include/serd/world.h b/include/serd/world.h
index 9440e6eb..dc2b3b83 100644
--- a/include/serd/world.h
+++ b/include/serd/world.h
@@ -5,6 +5,7 @@
#define SERD_WORLD_H
#include "serd/attributes.h"
+#include "serd/memory.h"
#include "serd/node.h"
#include "serd/status.h"
#include "zix/attributes.h"
@@ -35,12 +36,16 @@ typedef struct {
shared between worlds.
*/
SERD_MALLOC_API SerdWorld* ZIX_ALLOCATED
-serd_world_new(void);
+serd_world_new(SerdAllocator* ZIX_NULLABLE allocator);
/// Free `world`
SERD_API void
serd_world_free(SerdWorld* ZIX_NULLABLE world);
+/// Return the allocator used by `world`
+SERD_PURE_API SerdAllocator* ZIX_NONNULL
+serd_world_allocator(const SerdWorld* ZIX_NONNULL world);
+
/**
Return the current resource limits.