diff options
Diffstat (limited to 'include/serd')
-rw-r--r-- | include/serd/serd.h | 262 |
1 files changed, 201 insertions, 61 deletions
diff --git a/include/serd/serd.h b/include/serd/serd.h index 9e322c0d..2300a1a4 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -197,7 +197,102 @@ typedef struct { /** @} + @defgroup serd_memory Memory Management + @{ +*/ + +struct SerdAllocatorImpl; + +/** + 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* SERD_ALLOCATED (*SerdAllocatorMallocFunc)( // + SerdAllocator* SERD_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* SERD_ALLOCATED (*SerdAllocatorCallocFunc)( // + SerdAllocator* SERD_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* SERD_ALLOCATED (*SerdAllocatorReallocFunc)( // + SerdAllocator* SERD_NULLABLE allocator, + void* SERD_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* SERD_NULLABLE allocator, + void* SERD_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* SERD_ALLOCATED (*SerdAllocatorAlignedAllocFunc)( // + SerdAllocator* SERD_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* SERD_NULLABLE allocator, + void* SERD_NULLABLE ptr); + +/// Definition of SerdAllocator +struct SerdAllocatorImpl { + SerdAllocatorMallocFunc SERD_ALLOCATED malloc; + SerdAllocatorCallocFunc SERD_ALLOCATED calloc; + SerdAllocatorReallocFunc SERD_ALLOCATED realloc; + SerdAllocatorFreeFunc SERD_ALLOCATED free; + SerdAllocatorAlignedAllocFunc SERD_ALLOCATED aligned_alloc; + SerdAllocatorAlignedFreeFunc SERD_ALLOCATED aligned_free; +}; + +/// Return the default allocator which simply uses the system allocator +SERD_CONST_API +SerdAllocator* SERD_NONNULL +serd_default_allocator(void); /** Free memory allocated by Serd. @@ -205,12 +300,15 @@ typedef struct { 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* SERD_NULLABLE ptr); +serd_free(SerdAllocator* SERD_NULLABLE allocator, void* SERD_NULLABLE ptr); /** + @} @defgroup serd_status Status Codes @{ */ @@ -283,11 +381,13 @@ serd_strerror(SerdStatus status); directory separators. Null is returned on error, including if the path does not exist. - @return A new string that must be freed with serd_free(), or null. + @return A newly allocated string that must be freed with serd_free() using + the world allocator, or null. */ SERD_API -char* SERD_NULLABLE -serd_canonical_path(const char* SERD_NONNULL path); +char* SERD_ALLOCATED +serd_canonical_path(SerdAllocator* SERD_NULLABLE allocator, + const char* SERD_NONNULL path); /** Compare two strings ignoring case. @@ -462,13 +562,16 @@ serd_parse_uri(const char* SERD_NONNULL string); 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 filesystem path. + + @return A newly allocated path string that must be freed with serd_free(). */ SERD_API char* SERD_NULLABLE -serd_parse_file_uri(const char* SERD_NONNULL uri, +serd_parse_file_uri(SerdAllocator* SERD_NULLABLE allocator, + const char* SERD_NONNULL uri, char* SERD_NONNULL* SERD_NULLABLE hostname); /** @@ -856,7 +959,8 @@ serd_node_construct_base64(size_t buf_size, @defgroup serd_node_allocation Dynamic Allocation This is a convenient higher-level node construction API which allocates - nodes on the heap. The returned nodes must be freed with serd_node_free(). + nodes with an allocator. The returned nodes must be freed with + serd_node_free() using the same allocator. Note that in most cases it is better to use a #SerdNodes instead of managing individual node allocations. @@ -875,10 +979,11 @@ serd_node_construct_base64(size_t buf_size, */ SERD_API SerdNode* SERD_ALLOCATED -serd_node_new(SerdNodeType type, - SerdStringView string, - SerdNodeFlags flags, - SerdStringView meta); +serd_node_new(SerdAllocator* SERD_NULLABLE allocator, + SerdNodeType type, + SerdStringView string, + SerdNodeFlags flags, + SerdStringView meta); /** Create a new simple "token" node. @@ -891,7 +996,9 @@ serd_node_new(SerdNodeType type, */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_token(SerdNodeType type, SerdStringView string); +serd_new_token(SerdAllocator* SERD_NULLABLE allocator, + SerdNodeType type, + SerdStringView string); /** Create a new string literal node. @@ -904,7 +1011,7 @@ serd_new_token(SerdNodeType type, SerdStringView string); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_string(SerdStringView string); +serd_new_string(SerdAllocator* SERD_NULLABLE allocator, SerdStringView string); /** Create a new URI node from a string. @@ -917,7 +1024,7 @@ serd_new_string(SerdStringView string); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_uri(SerdStringView string); +serd_new_uri(SerdAllocator* SERD_NULLABLE allocator, SerdStringView string); /** Create a new URI node from a parsed URI. @@ -930,7 +1037,7 @@ serd_new_uri(SerdStringView string); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_parsed_uri(SerdURIView uri); +serd_new_parsed_uri(SerdAllocator* SERD_NULLABLE allocator, SerdURIView uri); /** Create a new file URI node from a path and optional hostname. @@ -943,7 +1050,9 @@ serd_new_parsed_uri(SerdURIView uri); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_file_uri(SerdStringView path, SerdStringView hostname); +serd_new_file_uri(SerdAllocator* SERD_NULLABLE allocator, + SerdStringView path, + SerdStringView hostname); /** Create a new literal node. @@ -956,9 +1065,10 @@ serd_new_file_uri(SerdStringView path, SerdStringView hostname); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_literal(SerdStringView string, - SerdNodeFlags flags, - SerdStringView meta); +serd_new_literal(SerdAllocator* SERD_NULLABLE allocator, + SerdStringView string, + SerdNodeFlags flags, + SerdStringView meta); /** Create a new canonical xsd:boolean node. @@ -971,7 +1081,7 @@ serd_new_literal(SerdStringView string, */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_boolean(bool b); +serd_new_boolean(SerdAllocator* SERD_NULLABLE allocator, bool b); /** Create a new canonical xsd:decimal literal. @@ -984,7 +1094,7 @@ serd_new_boolean(bool b); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_decimal(double d); +serd_new_decimal(SerdAllocator* SERD_NULLABLE allocator, double d); /** Create a new canonical xsd:double literal. @@ -997,7 +1107,7 @@ serd_new_decimal(double d); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_double(double d); +serd_new_double(SerdAllocator* SERD_NULLABLE allocator, double d); /** Create a new canonical xsd:float literal. @@ -1010,7 +1120,7 @@ serd_new_double(double d); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_float(float f); +serd_new_float(SerdAllocator* SERD_NULLABLE allocator, float f); /** Create a new canonical xsd:integer literal. @@ -1023,7 +1133,9 @@ serd_new_float(float f); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_integer(int64_t i, SerdStringView datatype); +serd_new_integer(SerdAllocator* SERD_NULLABLE allocator, + int64_t i, + SerdStringView datatype); /** Create a new canonical xsd:base64Binary literal. @@ -1036,9 +1148,10 @@ serd_new_integer(int64_t i, SerdStringView datatype); */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_base64(const void* SERD_NONNULL buf, - size_t size, - SerdStringView datatype); +serd_new_base64(SerdAllocator* SERD_NULLABLE allocator, + const void* SERD_NONNULL buf, + size_t size, + SerdStringView datatype); /** @} @@ -1125,12 +1238,14 @@ serd_get_base64(const SerdNode* SERD_NONNULL node, /// Return a deep copy of `node` SERD_API SerdNode* SERD_ALLOCATED -serd_node_copy(const SerdNode* SERD_NULLABLE node); +serd_node_copy(SerdAllocator* SERD_NULLABLE allocator, + const SerdNode* SERD_NULLABLE node); /// Free any data owned by `node` SERD_API void -serd_node_free(SerdNode* SERD_NULLABLE node); +serd_node_free(SerdAllocator* SERD_NULLABLE allocator, + SerdNode* SERD_NULLABLE node); /// Return the type of a node (SERD_URI, SERD_BLANK, or SERD_LITERAL) SERD_PURE_API @@ -1220,7 +1335,7 @@ typedef struct SerdNodesImpl SerdNodes; /// Create a new node set SERD_API SerdNodes* SERD_ALLOCATED -serd_nodes_new(void); +serd_nodes_new(SerdAllocator* SERD_NULLABLE allocator); /** Free `nodes` and all nodes that are stored in it. @@ -1307,9 +1422,6 @@ serd_nodes_parsed_uri(SerdNodes* SERD_NONNULL nodes, SerdURIView uri); #SERD_HAS_DATATYPE is set, then this must be an absolute datatype URI. If #SERD_HAS_LANGUAGE is set, then this must be an RFC 5646 language tag like "en-ca". Otherwise, it is ignored. - - @return A newly allocated literal node that must be freed with - serd_node_free(), or null if the arguments are invalid or allocation failed. */ SERD_API const SerdNode* SERD_ALLOCATED @@ -1422,6 +1534,7 @@ typedef struct SerdCaretImpl SerdCaret; valid. That is, serd_caret_name() will return exactly the pointer `name`, not a copy. + @param allocator Allocator to use for caret memory. @param name The name of the document or stream (usually a file URI) @param line The line number in the document (1-based) @param col The column number in the document (1-based) @@ -1429,17 +1542,22 @@ typedef struct SerdCaretImpl SerdCaret; */ SERD_API SerdCaret* SERD_ALLOCATED -serd_caret_new(const SerdNode* SERD_NONNULL name, unsigned line, unsigned col); +serd_caret_new(SerdAllocator* SERD_NULLABLE allocator, + const SerdNode* SERD_NONNULL name, + unsigned line, + unsigned col); /// Return a copy of `caret` SERD_API SerdCaret* SERD_ALLOCATED -serd_caret_copy(const SerdCaret* SERD_NULLABLE caret); +serd_caret_copy(SerdAllocator* SERD_NULLABLE allocator, + const SerdCaret* SERD_NULLABLE caret); /// Free `caret` SERD_API void -serd_caret_free(SerdCaret* SERD_NULLABLE caret); +serd_caret_free(SerdAllocator* SERD_NULLABLE allocator, + SerdCaret* SERD_NULLABLE caret); /// Return true iff `lhs` is equal to `rhs` SERD_PURE_API @@ -1492,6 +1610,7 @@ typedef enum { 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 to use for statement memory. @param s The subject @param p The predicate ("key") @param o The object ("value") @@ -1501,7 +1620,8 @@ typedef enum { */ SERD_API SerdStatement* SERD_ALLOCATED -serd_statement_new(const SerdNode* SERD_NONNULL s, +serd_statement_new(SerdAllocator* SERD_NULLABLE allocator, + const SerdNode* SERD_NONNULL s, const SerdNode* SERD_NONNULL p, const SerdNode* SERD_NONNULL o, const SerdNode* SERD_NULLABLE g, @@ -1510,12 +1630,14 @@ serd_statement_new(const SerdNode* SERD_NONNULL s, /// Return a copy of `statement` SERD_API SerdStatement* SERD_ALLOCATED -serd_statement_copy(const SerdStatement* SERD_NULLABLE statement); +serd_statement_copy(SerdAllocator* SERD_NULLABLE allocator, + const SerdStatement* SERD_NULLABLE statement); /// Free `statement` SERD_API void -serd_statement_free(SerdStatement* SERD_NULLABLE statement); +serd_statement_free(SerdAllocator* SERD_NULLABLE allocator, + SerdStatement* SERD_NULLABLE statement); /// Return the given node of the statement SERD_PURE_API @@ -1590,13 +1712,18 @@ typedef struct SerdWorldImpl SerdWorld; */ SERD_MALLOC_API SerdWorld* SERD_ALLOCATED -serd_world_new(void); +serd_world_new(SerdAllocator* SERD_NULLABLE allocator); /// Free `world` SERD_API void serd_world_free(SerdWorld* SERD_NULLABLE world); +/// Return the allocator used by `world` +SERD_PURE_API +SerdAllocator* SERD_NONNULL +serd_world_allocator(const SerdWorld* SERD_NONNULL world); + /** Return the nodes cache in `world`. @@ -2057,7 +2184,8 @@ serd_env_new(SerdWorld* SERD_NONNULL world, SerdStringView base_uri); /// Copy an environment SERD_API SerdEnv* SERD_ALLOCATED -serd_env_copy(const SerdEnv* SERD_NULLABLE env); +serd_env_copy(SerdAllocator* SERD_NULLABLE allocator, + const SerdEnv* SERD_NULLABLE env); /// Return true iff `a` is equal to `b` SERD_PURE_API @@ -2152,6 +2280,9 @@ serd_env_write_prefixes(const SerdEnv* SERD_NONNULL env, serd_node_to_syntax(). These two functions, when used with #SERD_TURTLE, can be used to round-trip any node to a string and back. + @param allocator Allocator used for the returned node, and any temporary + objects if `env` is null. + @param str String representation of a node. @param syntax Syntax to use. Should be either SERD_TURTLE or SERD_NTRIPLES @@ -2161,13 +2292,15 @@ serd_env_write_prefixes(const SerdEnv* SERD_NONNULL env, @param env Environment of `str`. This must define any abbreviations needed to parse the string. - @return A newly allocated node that must be freed with serd_node_free(). + @return A newly allocated node that must be freed with serd_node_free() + using the world allocator. */ SERD_API SerdNode* SERD_ALLOCATED -serd_node_from_syntax(const char* SERD_NONNULL str, - SerdSyntax syntax, - SerdEnv* SERD_NULLABLE env); +serd_node_from_syntax(SerdAllocator* SERD_NULLABLE allocator, + const char* SERD_NONNULL str, + SerdSyntax syntax, + SerdEnv* SERD_NULLABLE env); /** Return a string representation of `node` in `syntax`. @@ -2175,6 +2308,9 @@ serd_node_from_syntax(const char* SERD_NONNULL str, The returned string represents that node as if written as an object in the given syntax, without any extra quoting or punctuation. + @param allocator Allocator used for the returned node, and any temporary + objects if `env` is null. + @param node Node to write as a string. @param syntax Syntax to use. Should be either SERD_TURTLE or SERD_NTRIPLES @@ -2184,11 +2320,13 @@ serd_node_from_syntax(const char* SERD_NONNULL str, @param env Environment for the output string. This can be used to abbreviate things nicely by setting namespace prefixes. - @return A newly allocated string that must be freed with serd_free(). + @return A newly allocated string that must be freed with serd_free() using + the world allocator. */ SERD_API char* SERD_ALLOCATED -serd_node_to_syntax(const SerdNode* SERD_NONNULL node, +serd_node_to_syntax(SerdAllocator* SERD_NULLABLE allocator, + const SerdNode* SERD_NONNULL node, SerdSyntax syntax, const SerdEnv* SERD_NULLABLE env); @@ -2418,26 +2556,26 @@ serd_reader_free(SerdReader* SERD_NULLABLE reader); @defgroup serd_buffer Buffer The #SerdBuffer type represents a writable area of memory with a known size. - An implementation of #SerdWriteFunc, #SerdErrorFunc, and - #SerdCloseFunc are provided which allow output to be written to a - buffer in memory instead of to a file as with `fwrite`, `ferror`, and - `fclose`. + An implementation of #SerdWriteFunc, #SerdErrorFunc, and #SerdCloseFunc are + provided which allow output to be written to a buffer in memory instead of + to a file as with `fwrite`, `ferror`, and `fclose`. @{ */ -/// A mutable buffer in memory +/// A dynamically resizable mutable buffer in memory typedef struct { - void* SERD_NULLABLE buf; ///< Buffer - size_t len; ///< Size of buffer in bytes + SerdAllocator* SERD_NULLABLE allocator; ///< Allocator for buf + void* SERD_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. @@ -2498,9 +2636,9 @@ serd_open_output_stream(SerdWriteFunc SERD_NONNULL write_func, /** Open a stream that writes to a buffer. - The `buffer` is owned by the caller, but will be expanded using `realloc` as - necessary. Note that the string in the buffer will not be null terminated - until the stream is closed. + The `buffer` is owned by the caller, but will be reallocated using the + buffer's allocator as necessary. Note that the string in the buffer will + not be null terminated until the stream is closed. @param buffer Buffer to write output to. @return An opened output stream, or all zeros on error. @@ -2690,7 +2828,8 @@ typedef struct SerdCursorImpl SerdCursor; /// Return a new copy of `cursor` SERD_API SerdCursor* SERD_ALLOCATED -serd_cursor_copy(const SerdCursor* SERD_NULLABLE cursor); +serd_cursor_copy(SerdAllocator* SERD_NULLABLE allocator, + const SerdCursor* SERD_NULLABLE cursor); /// Return the statement pointed to by `cursor` SERD_API @@ -2826,7 +2965,8 @@ serd_model_new(SerdWorld* SERD_NONNULL world, /// Return a deep copy of `model` SERD_API SerdModel* SERD_ALLOCATED -serd_model_copy(const SerdModel* SERD_NONNULL model); +serd_model_copy(SerdAllocator* SERD_NULLABLE allocator, + const SerdModel* SERD_NONNULL model); /// Return true iff `a` is equal to `b`, ignoring statement cursor metadata SERD_API |