From 0e739f34801ff6810064a8fac570f6be2b61ae70 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 13 Aug 2021 20:31:57 -0400 Subject: Simplify output stream API This makes the paging mechanism an internal detail once again. While it's conceptually elegant to simply have a single write interface and have the block dumper just be another implementation of that, unfortunately it is not practical. The inlining of serd_block_dumper_write() is a significant performance boost, because it avoids a non-inlinable function call of overhead per character. Compared to the SerdByteSink approach, this removes the burden and overhead of needing to dynamically allocate the structure itself. --- include/serd/serd.h | 101 +++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 52 deletions(-) (limited to 'include') diff --git a/include/serd/serd.h b/include/serd/serd.h index c3b674b7..db7520d9 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -2427,78 +2427,74 @@ serd_buffer_close(void* SERD_NONNULL stream); /** @} - @defgroup serd_byte_sink Byte Sink + @defgroup serd_output_stream Output Streams + + An output stream is used for writing output as a raw stream of bytes. It is + compatible with standard C `FILE` streams, but allows different functions to + be provided for things like writing to a buffer or a socket. + @{ */ -/// A sink for bytes that receives text output -typedef struct SerdByteSinkImpl SerdByteSink; +/// An output stream that receives bytes +typedef struct { + void* SERD_NULLABLE stream; ///< Opaque parameter for functions + SerdWriteFunc SERD_NULLABLE write; ///< Write bytes to output + SerdStreamCloseFunc SERD_NULLABLE close; ///< Close output +} SerdOutputStream; /** - Create a new byte sink that writes to a buffer. + Open a stream that writes to a provided function. - The `buffer` is owned by the caller, but will be expanded as necessary. - Note that the string in the buffer will not be null terminated until the - byte sink is closed. + @param write_func Function to write output. + @param close_func Function to close the stream after writing is done. + @param stream Opaque stream parameter for write_func and close_func. - @param buffer Buffer to write output to. + @return An opened output stream, or all zeros on error. */ -SERD_API -SerdByteSink* SERD_ALLOCATED -serd_byte_sink_new_buffer(SerdBuffer* SERD_NONNULL buffer); +SERD_CONST_API +SerdOutputStream +serd_open_output_stream(SerdWriteFunc SERD_NONNULL write_func, + SerdStreamCloseFunc SERD_NULLABLE close_func, + void* SERD_NULLABLE stream); /** - Create a new byte sink that writes to a file. + Open a stream that writes to a buffer. - An arbitrary `FILE*` can be used via serd_byte_sink_new_function() as well, - this is just a convenience function that opens the file properly and sets - flags for optimized I/O if possible. + 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. - @param path Path of file to open and write to. - @param block_size Number of bytes to write per call. + @param buffer Buffer to write output to. + @return An opened output stream, or all zeros on error. */ -SERD_API -SerdByteSink* SERD_ALLOCATED -serd_byte_sink_new_filename(const char* SERD_NONNULL path, size_t block_size); +SERD_CONST_API +SerdOutputStream +serd_open_output_buffer(SerdBuffer* SERD_NONNULL buffer); /** - Create a new byte sink that writes to a user-specified function. + Create a new byte sink that writes to a file. - The `stream` will be passed to the `write_func`, which is compatible with - the standard C `fwrite` if `stream` is a `FILE*`. + An arbitrary `FILE*` can be used with serd_open_output_stream() as well, + this convenience function opens the file properly for readingn with serd, + and sets flags for optimized I/O if possible. - @param write_func Stream write function, like `fwrite`. - @param close_func Stream close function, like `fclose`. - @param stream Context parameter passed to `sink`. - @param block_size Number of bytes to write per call. + @param path Path of file to open and write to. */ SERD_API -SerdByteSink* SERD_ALLOCATED -serd_byte_sink_new_function(SerdWriteFunc SERD_NONNULL write_func, - SerdStreamCloseFunc SERD_NULLABLE close_func, - void* SERD_NULLABLE stream, - size_t block_size); - -/// Flush any pending output in `sink` to the underlying write function -SERD_API -void -serd_byte_sink_flush(SerdByteSink* SERD_NONNULL sink); +SerdOutputStream +serd_open_output_file(const char* SERD_NONNULL path); /** - Close `sink`, including the underlying file if necessary. + Close an output stream. - If `sink` was created with serd_byte_sink_new_filename(), then the file is - closed. If there was an error, then SERD_ERR_UNKNOWN is returned and - `errno` is set. + This will call the close function, and reset the stream internally so that + no further writes can be made. For convenience, this is safe to call on + NULL, and safe to call several times on the same output. */ SERD_API SerdStatus -serd_byte_sink_close(SerdByteSink* SERD_NONNULL sink); - -/// Free `sink`, flushing and closing first if necessary -SERD_API -void -serd_byte_sink_free(SerdByteSink* SERD_NULLABLE sink); +serd_close_output(SerdOutputStream* SERD_NULLABLE output); /** @} @@ -2579,11 +2575,12 @@ typedef uint32_t SerdWriterFlags; /// Create a new RDF writer SERD_API SerdWriter* SERD_ALLOCATED -serd_writer_new(SerdWorld* SERD_NONNULL world, - SerdSyntax syntax, - SerdWriterFlags flags, - const SerdEnv* SERD_NONNULL env, - SerdByteSink* SERD_NONNULL byte_sink); +serd_writer_new(SerdWorld* SERD_NONNULL world, + SerdSyntax syntax, + SerdWriterFlags flags, + const SerdEnv* SERD_NONNULL env, + SerdOutputStream* SERD_NONNULL output, + size_t block_size); /// Free `writer` SERD_API -- cgit v1.2.1