Reformat coral library

This commit is contained in:
kayomn 2023-02-26 01:19:16 +00:00
parent 3c44a6c0f3
commit 98fb389ff0

View File

@ -12,8 +12,8 @@ export namespace coral {
/** /**
* Triggers safety-checked behavior in debug mode. * Triggers safety-checked behavior in debug mode.
* *
* In release mode, the compiler can use this function as a marker to optimize out safety- * In release mode, the compiler can use this function as a marker to optimize out safety-checked logic branches
* checked logic branches that should never be executed. * that should never be executed.
*/ */
[[noreturn]] void unreachable() { [[noreturn]] void unreachable() {
__builtin_unreachable(); __builtin_unreachable();
@ -59,37 +59,38 @@ export namespace coral {
virtual ~allocator() {}; virtual ~allocator() {};
/** /**
* If `allocation` is `nullptr`, the allocator will attempt to allocate a new memory block * If `allocation` is `nullptr`, the allocator will attempt to allocate a new memory block of `requested_size`
* of `requested_size` bytes. Otherwise, the allocator will attempt to reallocate * bytes. Otherwise, the allocator will attempt to reallocate `allocation` to be `request_size` bytes in size.
* `allocation` to be `request_size` bytes in size.
* *
* The returned address will point to a dynamically allocated buffer of `requested_size` if * The returned address will point to a dynamically allocated buffer of `requested_size` if the operation was
* the operation was successful, otherwise `nullptr`. * successful, otherwise `nullptr`.
* *
* *Note*: If the returned address is a non-`nullptr`, it should be deallocated prior to * *Note*: If the returned address is a non-`nullptr`, it should be deallocated prior to program exit. This may
* program exit. This may be achieved through either [deallocate] or implementation- * be achieved through either [deallocate] or implementation-specific allocator functionality.
* specific allocator functionality.
* *
* *Note*: Attempting to pass a non-`nullptr` `allocation` address not allocated by the * *Note*: Attempting to pass a non-`nullptr` `allocation` address not allocated by the allocator *will* result
* allocator *will* result in erroneous implementation-behavior. * in erroneous implementation-behavior.
* *
* *Note*: After invocation, `allocation` should be considered an invalid memory address. * *Note*: After invocation, `allocation` should be considered an invalid memory address.
*/ */
[[nodiscard]] virtual u8 * reallocate(u8 * allocation, usize requested_size) = 0; [[nodiscard]] virtual u8 * reallocate(u8 * allocation, usize requested_size) = 0;
/** /**
* If `allocation` points to a non-`nullptr` address, the allocator will deallocate it. * If `allocation` points to a non-`nullptr` address, the allocator will deallocate it. Otherwise, the function
* Otherwise, the function has no side-effects. * has no side-effects.
* *
* *Note* that attempting to pass a non-`nullptr` `allocation` address not allocated by the * *Note* that attempting to pass a non-`nullptr` `allocation` address not allocated by the allocator *will*
* allocator *will* result in erroneous implementation-behavior. * result in erroneous implementation-behavior.
*/ */
virtual void deallocate(void * allocation) = 0; virtual void deallocate(void * allocation) = 0;
}; };
/** /**
* Length-signed pointer type that describes how many elements of `type` it references, * Length-signed pointer type that describes how many elements of `type` it references, providing a type-safe
* providing a type-safe wrapper for passing arrays and zero-terminated strings to functions. * wrapper for passing arrays and zero-terminated strings to functions.
*
* **Note**: slices take no ownership of their data, making it the responsibility of the caller to manage the
* lifetime of any data referenced by it.
*/ */
template<typename type> struct slice { template<typename type> struct slice {
/** /**
@ -140,8 +141,7 @@ export namespace coral {
* *
* The returned view is constant to protect against inadvertant memory corruption. * The returned view is constant to protect against inadvertant memory corruption.
* *
* *Note* the returned value has no guarantees about the validity of any specific character * *Note* the returned value has no guarantees about the validity of any specific character encoding set.
* encoding set.
*/ */
slice<char const> as_chars() const { slice<char const> as_chars() const {
return {reinterpret_cast<char const *>(this->pointer), this->length * sizeof(type)}; return {reinterpret_cast<char const *>(this->pointer), this->length * sizeof(type)};
@ -162,11 +162,11 @@ export namespace coral {
} }
/** /**
* Returns a new slice with the base-pointer offset by `index` elements and a length of * Returns a new slice with the base-pointer offset by `index` elements and a length of `range` elements from
* `range` elements from `index`. * `index`.
* *
* *Note* that attempting to slice with an `index` or `range` outside of the existing slice * *Note* that attempting to slice with an `index` or `range` outside of the existing slice bounds will result
* bounds will result in safety-checked behavior. * in safety-checked behavior.
*/ */
constexpr slice sliced(usize index, usize range) const { constexpr slice sliced(usize index, usize range) const {
if ((this->length <= index) || ((range + index) > this->length)) unreachable(); if ((this->length <= index) || ((range + index) > this->length)) unreachable();
@ -205,7 +205,9 @@ export namespace coral {
/** /**
* Returns `value` clamped between the range of `min_value` and `max_value` (inclusive). * Returns `value` clamped between the range of `min_value` and `max_value` (inclusive).
*/ */
template<typename scalar> constexpr scalar clamp(scalar const & value, scalar const & min_value, scalar const & max_value) { template<typename scalar> constexpr scalar clamp(scalar const & value,
scalar const & min_value, scalar const & max_value) {
return max(min_value, min(max_value, value)); return max(min_value, min(max_value, value));
} }
@ -218,11 +220,10 @@ export namespace coral {
} }
/** /**
* Allocates and initializes a type of `requested_size` in `buffer`, returning its base pointer. As * Allocates and initializes a type of `requested_size` in `buffer`, returning its base pointer. As a result of
* a result of accepting a pre-allocated buffer, invocation does not allocate any dynamic memory. * accepting a pre-allocated buffer, invocation does not allocate any dynamic memory.
* *
* *Note*: passing an `buffer` smaller than `requested_size` will result in safety-checked * *Note*: passing an `buffer` smaller than `requested_size` will result in safety-checked behavior.
* behavior.
*/ */
export void * operator new(coral::usize requested_size, coral::slice<coral::u8> const & buffer) { export void * operator new(coral::usize requested_size, coral::slice<coral::u8> const & buffer) {
if (buffer.length < requested_size) coral::unreachable(); if (buffer.length < requested_size) coral::unreachable();
@ -231,12 +232,10 @@ export void * operator new(coral::usize requested_size, coral::slice<coral::u8>
} }
/** /**
* Allocates and initializes a series of types at `requested_size` in `buffer`, returning the base * Allocates and initializes a series of types at `requested_size` in `buffer`, returning the base pointer. As a result
* pointer. As a result of accepting a pre-allocated buffer, invocation does not allocate any * of accepting a pre-allocated buffer, invocation does not allocate any dynamic memory.
* dynamic memory.
* *
* *Note*: passing an `buffer` smaller than `requested_size` will result in safety-checked * *Note*: passing an `buffer` smaller than `requested_size` will result in safety-checked behavior.
* behavior.
*/ */
export void * operator new[](coral::usize requested_size, coral::slice<coral::u8> const & buffer) { export void * operator new[](coral::usize requested_size, coral::slice<coral::u8> const & buffer) {
if (buffer.length < requested_size) coral::unreachable(); if (buffer.length < requested_size) coral::unreachable();
@ -247,9 +246,8 @@ export void * operator new[](coral::usize requested_size, coral::slice<coral::u8
/** /**
* Attempts to allocate and initialize a type of `requested_size` using `allocator`. * Attempts to allocate and initialize a type of `requested_size` using `allocator`.
* *
* *Note*: If the returned address is a non-`nullptr`, it should be deallocated prior to program * *Note*: If the returned address is a non-`nullptr`, it should be deallocated prior to program exit. This may be
* exit. This may be achieved through either [coral::allocator::deallocate] or implementation- * achieved through either [coral::allocator::deallocate] or implementation-specific allocator functionality.
* specific allocator functionality.
*/ */
export [[nodiscard]] void * operator new(coral::usize requested_size, coral::allocator & allocator) { export [[nodiscard]] void * operator new(coral::usize requested_size, coral::allocator & allocator) {
return allocator.reallocate(nullptr, requested_size); return allocator.reallocate(nullptr, requested_size);
@ -258,31 +256,30 @@ export [[nodiscard]] void * operator new(coral::usize requested_size, coral::all
/** /**
* Attempts to allocate and initialize a series of types of `requested_size` using `allocator`. * Attempts to allocate and initialize a series of types of `requested_size` using `allocator`.
* *
* *Note*: If the returned address is a non-`nullptr`, it should be deallocated prior to program * *Note*: If the returned address is a non-`nullptr`, it should be deallocated prior to program exit. This may be
* exit. This may be achieved through either [coral::allocator::deallocate] or implementation- * achieved through either [coral::allocator::deallocate] or implementation-specific allocator functionality.
* specific allocator functionality.
*/ */
export [[nodiscard]] void * operator new[](coral::usize requested_size, coral::allocator & allocator) { export [[nodiscard]] void * operator new[](coral::usize requested_size, coral::allocator & allocator) {
return allocator.reallocate(nullptr, requested_size); return allocator.reallocate(nullptr, requested_size);
} }
/** /**
* If `pointer` is a non-`nullptr` value, the referenced memory will be deallocated using * If `pointer` is a non-`nullptr` value, the referenced memory will be deallocated using `allocator`. Otherwise, the
* `allocator`. Otherwise, the function has no side-effects. * function has no side-effects.
* *
* *Note*: passing a `pointer` value that was not allocated by `allocator` will result in erroneous * *Note*: passing a `pointer` value that was not allocated by `allocator` will result in erroneous behavior defined by
* behavior defined by the [coral::allocator] implementation. * the [coral::allocator] implementation.
*/ */
export void operator delete(void * pointer, coral::allocator & allocator) { export void operator delete(void * pointer, coral::allocator & allocator) {
return allocator.deallocate(pointer); return allocator.deallocate(pointer);
} }
/** /**
* If `pointer` is a non-`nullptr` value, the referenced memory block will be deallocated using * If `pointer` is a non-`nullptr` value, the referenced memory block will be deallocated using `allocator`. Otherwise,
* `allocator`. Otherwise, the function has no side-effects. * the function has no side-effects.
* *
* *Note*: passing a `pointer` value that was not allocated by `allocator` will result in erroneous * *Note*: passing a `pointer` value that was not allocated by `allocator` will result in erroneous behavior defined by
* behavior defined by the [coral::allocator] implementation. * the [coral::allocator] implementation.
*/ */
export void operator delete[](void * pointer, coral::allocator & allocator) { export void operator delete[](void * pointer, coral::allocator & allocator) {
return allocator.deallocate(pointer); return allocator.deallocate(pointer);
@ -290,22 +287,22 @@ export void operator delete[](void * pointer, coral::allocator & allocator) {
// Wrapper types. // Wrapper types.
export namespace coral { export namespace coral {
template<typename type, typename... arguments> concept function_pointer = template<typename callable, typename... arguments> concept function_pointer =
requires (type value, arguments... value_arguments) { requires (callable callable_value, arguments... value_arguments) {
{*value}; {*callable_value};
{value(value_arguments...)}; {callable_value(value_arguments...)};
}; };
template<typename type, typename... arguments> concept functor = template<typename callable, typename... arguments> concept functor =
requires (type value, arguments... value_arguments) { requires (callable callable_value, arguments... value_arguments) {
{value.operator()(value_arguments...)}; {callable_value.operator()(value_arguments...)};
}; };
template<typename> struct closure; template<typename> struct closure;
/** /**
* Type-erasing view wrapper for both function and functor types that have a call operator with * Type-erasing view wrapper for both function and functor types that have a call operator with a return value
* a return value matching `return_value` and arguments matching `argument_values`. * matching `result` and arguments matching `arguments`.
* *
* A closure may be constructed from either of the following inputs: * A closure may be constructed from either of the following inputs:
* *
@ -314,12 +311,12 @@ export namespace coral {
* *
* * An L or R-value functor reference. * * An L or R-value functor reference.
* *
* **Note**: closures take no ownership of allocated memory, making it the responsibility of * **Note**: closures take no ownership of their data, making it the responsibility of the caller to manage the
* the caller to manage the lifetime of any functor assigned to it. * lifetime of any functor assigned to it.
*/ */
template<typename returns, typename... arguments> struct closure<returns(arguments...)> { template<typename result, typename... arguments> struct closure<result(arguments...)> {
template<typename callable> closure(callable call) requires function_pointer<callable, arguments...> { template<typename callable> closure(callable call) requires function_pointer<callable, arguments...> {
this->dispatch = [](void * context, arguments... dispatch_arguments) -> returns { this->dispatch = [](void * context, arguments... dispatch_arguments) -> result {
return (reinterpret_cast<callable>(context))(dispatch_arguments...); return (reinterpret_cast<callable>(context))(dispatch_arguments...);
}; };
@ -327,7 +324,7 @@ export namespace coral {
} }
template<typename callable> closure(callable && call) requires functor<callable, arguments...> { template<typename callable> closure(callable && call) requires functor<callable, arguments...> {
this->dispatch = [](void * context, arguments... dispatch_arguments) -> returns { this->dispatch = [](void * context, arguments... dispatch_arguments) -> result {
return (*reinterpret_cast<callable *>(context))(dispatch_arguments...); return (*reinterpret_cast<callable *>(context))(dispatch_arguments...);
}; };
@ -335,7 +332,7 @@ export namespace coral {
} }
template<typename callable> closure(callable & call) requires functor<callable, arguments...> { template<typename callable> closure(callable & call) requires functor<callable, arguments...> {
this->dispatch = [](void * context, arguments... dispatch_arguments) -> returns { this->dispatch = [](void * context, arguments... dispatch_arguments) -> result {
return (*reinterpret_cast<callable *>(context))(dispatch_arguments...); return (*reinterpret_cast<callable *>(context))(dispatch_arguments...);
}; };
@ -344,31 +341,31 @@ export namespace coral {
closure(closure const &) = delete; closure(closure const &) = delete;
returns operator()(arguments const &... call_arguments) const { result operator()(arguments const &... call_arguments) const {
return this->dispatch(this->context, call_arguments...); return this->dispatch(this->context, call_arguments...);
} }
private: private:
void * context; void * context;
returns(* dispatch)(void *, arguments...); result(* dispatch)(void *, arguments...);
}; };
/** /**
* Monadic container for a descriminating union of either `value_element` or `error_element`. * Monadic container for a descriminating union of either `expects` or `errors`.
*/ */
template<typename value_element, typename error_element> struct [[nodiscard]] expected { template<typename expects, typename errors> struct [[nodiscard]] expected {
expected(value_element const & value) : buffer{0} { expected(expects const & value) : buffer{0} {
(*reinterpret_cast<value_element *>(this->buffer)) = value; (*reinterpret_cast<expects *>(this->buffer)) = value;
this->buffer[buffer_size] = 1; this->buffer[buffer_size] = 1;
} }
expected(error_element const & error) : buffer{0} { expected(errors const & error) : buffer{0} {
(*reinterpret_cast<error_element *>(this->buffer)) = error; (*reinterpret_cast<errors *>(this->buffer)) = error;
} }
/** /**
* Returns `true` if the optional contains a value, otherwise `false` if it holds an error. * Returns `true` if the optional contains the expected value, otherwise `false` if it holds an error.
*/ */
bool is_ok() const { bool is_ok() const {
return this->buffer[buffer_size]; return this->buffer[buffer_size];
@ -377,66 +374,64 @@ export namespace coral {
/** /**
* Returns a reference to the contained value. * Returns a reference to the contained value.
* *
* *Note*: attempting to access the value of an erroneous expected will trigger safety- * *Note*: attempting to access the value of an erroneous expected will trigger safety-checked behavior.
* checked behavior.
*/ */
value_element & value() { expects & value() {
if (!this->is_ok()) unreachable(); if (!this->is_ok()) unreachable();
return *reinterpret_cast<value_element *>(this->buffer); return *reinterpret_cast<expects *>(this->buffer);
} }
/** /**
* Returns the contained value. * Returns the contained value.
* *
* *Note*: attempting to access the value of an erroneous expected will trigger safety- * *Note*: attempting to access the value of an erroneous expected will trigger safety-checked behavior.
* checked behavior.
*/ */
value_element const & value() const { expects const & value() const {
if (!this->is_ok()) unreachable(); if (!this->is_ok()) unreachable();
return *reinterpret_cast<value_element const *>(this->buffer); return *reinterpret_cast<expects const *>(this->buffer);
} }
/** /**
* Returns a reference to the contained error. * Returns a reference to the contained error.
* *
* *Note*: attempting to access the error of a non-erroneous expected will trigger safety- * *Note*: attempting to access the error of a non-erroneous expected will trigger safety-checked behavior.
* checked behavior.
*/ */
error_element & error() { errors & error() {
if (this->is_ok()) unreachable(); if (this->is_ok()) unreachable();
return *reinterpret_cast<error_element *>(this->buffer); return *reinterpret_cast<errors *>(this->buffer);
} }
/** /**
* Returns the contained error. * Returns the contained error.
* *
* *Note*: attempting to access the error of a non-erroneous expected will trigger safety- * *Note*: attempting to access the error of a non-erroneous expected will trigger safety-checked behavior.
* checked behavior.
*/ */
error_element const & error() const { errors const & error() const {
if (this->is_ok()) unreachable(); if (this->is_ok()) unreachable();
return *reinterpret_cast<error_element const *>(this->buffer); return *reinterpret_cast<errors const *>(this->buffer);
} }
template<typename returns> expected<returns, error_element> map(closure<returns(value_element const &)> const & apply) const { /**
*
*/
template<typename result> expected<result, errors> map(closure<result(expects const &)> const & apply) const {
if (this->is_ok()) return apply(this->value()); if (this->is_ok()) return apply(this->value());
return this->error(); return this->error();
} }
private: private:
static constexpr usize buffer_size = max(sizeof(value_element), sizeof(error_element)); static constexpr usize buffer_size = max(sizeof(expects), sizeof(errors));
u8 buffer[buffer_size + 1]; u8 buffer[buffer_size + 1];
}; };
/** /**
* Errors that may occur while executing an opaque I/O operation via the `readable` and * Errors that may occur while executing an opaque I/O operation via the `readable` and `writable` type aliases.
* `writable` type aliases.
*/ */
enum class io_error { enum class io_error {
unavailable, unavailable,
@ -449,8 +444,7 @@ export namespace coral {
virtual ~reader() {} virtual ~reader() {}
/** /**
* Attempts to fill `data` with whatever data the reader has to offer, returning the number * Attempts to fill `data` with whatever the reader has to offer, returning the number of bytes actually read.
* of bytes actually read.
* *
* Should the read operation fail for any reason, a [io_error] is returned instead. * Should the read operation fail for any reason, a [io_error] is returned instead.
*/ */
@ -464,8 +458,7 @@ export namespace coral {
virtual ~writer() {} virtual ~writer() {}
/** /**
* Attempts to write `data` out to the writer, returning the number of bytes actually * Attempts to write `data` out to the writer, returning the number of bytes actually written.
* written.
* *
* Should the write operation fail for any reason, a [io_error] is returned instead. * Should the write operation fail for any reason, a [io_error] is returned instead.
*/ */
@ -516,8 +509,7 @@ export namespace coral {
} }
/** /**
* Tests the equality of `a` against `b`, returning `true` if they contain identical bytes, * Tests the equality of `a` against `b`, returning `true` if they contain identical bytes, otherwise `false`.
* otherwise `false`.
*/ */
constexpr bool equals(slice<u8 const> const & a, slice<u8 const> const & b) { constexpr bool equals(slice<u8 const> const & a, slice<u8 const> const & b) {
if (a.length != b.length) return false; if (a.length != b.length) return false;