diff --git a/source/coral.cpp b/source/coral.cpp index 5c70cc0..27e163e 100644 --- a/source/coral.cpp +++ b/source/coral.cpp @@ -285,6 +285,54 @@ export void operator delete[](void * pointer, coral::allocator & allocator) { // Wrapper types. export namespace coral { + template struct closure; + + /** + * Type-erasing view wrapper for both function and functor types that have a call operator with + * a return value matching `return_value` and arguments matching `argument_values`. + * + * **Note**: closures take no ownership of allocated memory, making it the responsibility of + * the caller to manage the lifetime of any functor assigned to it. + */ + template struct closure { + using function = returns(*)(arguments...); + + closure(function callable_function) { + this->dispatch = [](void const * context, arguments... dispatch_arguments) -> returns { + return (reinterpret_cast(context))(dispatch_arguments...); + }; + + this->context = callable_function; + } + + template closure(functor * callable_functor) { + this->dispatch = [](void const * context, arguments... dispatch_arguments) -> returns { + return (*reinterpret_cast(context))(dispatch_arguments...); + }; + + this->context = callable_functor; + } + + closure(closure const &) = delete; + + template closure(functor && callable_functor) { + this->dispatch = [](void const * context, arguments... dispatch_arguments) -> returns { + return (*reinterpret_cast(context))(dispatch_arguments...); + }; + + this->context = &callable_functor; + } + + returns operator()(arguments const &... call_arguments) const { + return this->dispatch(this->context, call_arguments...); + } + + private: + void const * context; + + returns(* dispatch)(void const *, arguments...); + }; + /** * Monadic container for a single-`element` value or nothing. */ @@ -359,6 +407,17 @@ export namespace coral { (*reinterpret_cast(this->buffer)) = error; } + /** + * Monadic function for calling `predicate` conditionally based on whether the expected is + * ok. If ok, the result of `predicate` is returned, otherwise `false` is always returned. + * + * This function may be used to chain conditional checks that depend on the expected being + * ok without creating a new local variable. + */ + bool and_test(closure const & predicate) const { + return this->is_ok() && predicate(this->value()); + } + /** * Returns `true` if the optional contains a value, otherwise `false` if it holds an error. */ @@ -420,54 +479,6 @@ export namespace coral { u8 buffer[buffer_size + 1]; }; - template struct closure; - - /** - * Type-erasing view wrapper for both function and functor types that have a call operator with - * a return value matching `return_value` and arguments matching `argument_values`. - * - * **Note**: closures take no ownership of allocated memory, making it the responsibility of - * the caller to manage the lifetime of any functor assigned to it. - */ - template struct closure { - using function = returns(*)(arguments...); - - closure(function callable_function) { - this->dispatch = [](void const * context, arguments... dispatch_arguments) -> returns { - return (reinterpret_cast(context))(dispatch_arguments...); - }; - - this->context = callable_function; - } - - template closure(functor * callable_functor) { - this->dispatch = [](void const * context, arguments... dispatch_arguments) -> returns { - return (*reinterpret_cast(context))(dispatch_arguments...); - }; - - this->context = callable_functor; - } - - closure(closure const &) = delete; - - template closure(functor && callable_functor) { - this->dispatch = [](void const * context, arguments... dispatch_arguments) -> returns { - return (*reinterpret_cast(context))(dispatch_arguments...); - }; - - this->context = &callable_functor; - } - - returns operator()(arguments const &... call_arguments) const { - return this->dispatch(this->context, call_arguments...); - } - - private: - void const * context; - - returns(* dispatch)(void const *, arguments...); - }; - /** * Errors that may occur while executing an opaque I/O operation via the `readable` and * `writable` type aliases.