From f601f51f7a0fe9c6ef3ad82cc0718068a398e876 Mon Sep 17 00:00:00 2001 From: kayomn Date: Wed, 22 Feb 2023 20:53:58 +0000 Subject: [PATCH] Improve memory model of coral::stack --- source/coral/sequence.cpp | 75 +++++++++++++++++++++++++++++++-------- source/runtime.cpp | 6 ++-- 2 files changed, 63 insertions(+), 18 deletions(-) diff --git a/source/coral/sequence.cpp b/source/coral/sequence.cpp index 68b8be7..f73a83d 100644 --- a/source/coral/sequence.cpp +++ b/source/coral/sequence.cpp @@ -2,9 +2,10 @@ export module coral.sequence; import coral; +// Collections. export namespace coral { /** - * Result codes used by [sequence]-derived types when they are appended to in any way. + * Result codes used by [contiguous_range]-derived types when they are appended to in any way. * * [append_result::ok] indicates that an append operation was successful. * @@ -17,27 +18,36 @@ export namespace coral { }; /** - * Base type for all sequence-like types. + * Base type for all collections which store their elements as a single block of contiguous + * memory. * * Sequences are any data structure which owns a linear, non-unique set of elements which may * be queried and/or mutated. */ - template struct sequence { - virtual ~sequence() {}; + template struct contiguous_range { + virtual ~contiguous_range() {}; /** - * Attempts to append `source_elements` to the sequence. + * Attempts to append `source_elements` to the contiguous_range. * * The returned [append_result] indicates whether the operation was successful or not. * - * If the returned [append_result] is anything but [append_result::ok], the [sequence] will - * be left in an implementation-defined state. + * If the returned [append_result] is anything but [append_result::ok], the + * [contiguous_range] will be left in an implementation-defined state. */ virtual append_result append(slice const & source_elements) = 0; + + /** + * Returns a read-only [slice] of the current range values. + * + * *Note*: the behavior of retaining the returned value past the scope of the source + * [contiguous_range] or any subsequent modifications to it is implementation-defined. + */ + virtual slice as_slice() = 0; }; /** - * Last-in-first-out linear sequence of `element` values. + * Last-in-first-out contiguous range of `element` values. * * [stack] types will default to using an inline array of `init_capacity` at first. After all * local storage has been exhausted, the [stack] will switch to a dynamic buffer. Because of @@ -48,7 +58,7 @@ export namespace coral { * *Note*: the [allocator] referenced in the stack must remain valid for the duration of the * stack lifetime. */ - template struct stack : public sequence { + template struct stack : public contiguous_range { stack(allocator * dynamic_allocator) { this->dynamic_allocator = dynamic_allocator; } @@ -88,6 +98,16 @@ export namespace coral { return append_result::ok; } + /** + * Returns a read-only [slice] of the current stack values. + * + * *Note*: the returned slice should be considered invalid if any mutable operation is + * performed on the source [stack] or it is no longer in scope. + */ + slice as_slice() override { + return this->elements.sliced(0, this->filled); + } + /** * Returns `true` if the stack is backed by dynamic memory, otherwise `false`. */ @@ -172,17 +192,22 @@ export namespace coral { u8 local_buffer[init_capacity]{0}; }; +} +using contiguous_byte_range = coral::contiguous_range; + +// Reader / writers. +export namespace coral { /** - * Writable type for appending data to a [sequence] containing [u8] values. + * Readable type for streaming data from a [contiguous_range] containing [u8] values. */ - struct sequence_writer : public writer { - sequence_writer(sequence * output_sequence) { - this->output_sequence = output_sequence; + struct contiguous_reader : public reader { + contiguous_reader(contiguous_byte_range * range) { + this->range = range; } expected write(slice const & buffer) { - switch (output_sequence->append(buffer)) { + switch (this->range->append(buffer)) { case append_result::ok: return buffer.length; case append_result::out_of_memory: return io_error::unavailable; default: unreachable(); @@ -190,6 +215,26 @@ export namespace coral { } private: - sequence * output_sequence; + contiguous_byte_range * range; + }; + + /** + * Writable type for appending data to a [contiguous_range] containing [u8] values. + */ + struct contiguous_writer : public writer { + contiguous_writer(contiguous_byte_range * range) { + this->range = range; + } + + expected write(slice const & buffer) { + switch (this->range->append(buffer)) { + case append_result::ok: return buffer.length; + case append_result::out_of_memory: return io_error::unavailable; + default: unreachable(); + } + } + + private: + contiguous_byte_range * range; }; } diff --git a/source/runtime.cpp b/source/runtime.cpp index 29c2cd4..c7e365d 100644 --- a/source/runtime.cpp +++ b/source/runtime.cpp @@ -32,12 +32,12 @@ extern "C" int main(int argc, char const * const * argv) { coral::stack script_source{allocator}; { coral::u8 stream_buffer[1024]{0}; - coral::sequence_writer script_writer{&script_source}; + coral::contiguous_writer script_writer{&script_source}; if (!coral::stream(script_writer, file, stream_buffer).is_ok()) return; } - vm.with_object(vm.compile(coral::slice{script_source.begin(), script_source.end()}.as_chars()), [&](kym::bound_object & script) { + vm.with_object(vm.compile(script_source.as_slice().as_chars()), [&](kym::bound_object & script) { vm.with_object(script.call({}), [&](kym::bound_object & config) { constexpr auto as_u16 = [](coral::i64 value) -> coral::optional { if ((value >= 0) && (value <= coral::u16_max)) @@ -72,7 +72,7 @@ extern "C" int main(int argc, char const * const * argv) { if (!is_config_loaded) { coral::stack error_message{&system.thread_safe_allocator()}; { - coral::sequence_writer error_writer{&error_message}; + coral::contiguous_writer error_writer{&error_message}; if (!error_writer.write(coral::slice{"failed to load "}.as_bytes()).is_ok()) return coral::u8_max;