diff options
Diffstat (limited to 'nihil.monad')
| -rw-r--r-- | nihil.monad/CMakeLists.txt | 22 | ||||
| -rw-r--r-- | nihil.monad/monad.ccm | 282 | ||||
| -rw-r--r-- | nihil.monad/test.cc | 64 |
3 files changed, 0 insertions, 368 deletions
diff --git a/nihil.monad/CMakeLists.txt b/nihil.monad/CMakeLists.txt deleted file mode 100644 index f82e464..0000000 --- a/nihil.monad/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# This source code is released into the public domain. - -add_library(nihil.monad STATIC) -target_link_libraries(nihil.monad PRIVATE nihil.std nihil.error) -target_sources(nihil.monad - PUBLIC FILE_SET modules TYPE CXX_MODULES FILES - monad.ccm -) - -if(NIHIL_TESTS) - enable_testing() - - add_executable(nihil.monad.test test.cc) - target_link_libraries(nihil.monad.test PRIVATE - nihil.monad - Catch2::Catch2WithMain - ) - - include(CTest) - include(Catch) - catch_discover_tests(nihil.monad.test) -endif() diff --git a/nihil.monad/monad.ccm b/nihil.monad/monad.ccm deleted file mode 100644 index cd17e0f..0000000 --- a/nihil.monad/monad.ccm +++ /dev/null @@ -1,282 +0,0 @@ -/* - * From https://github.com/toby-allsopp/coroutine_monad - * - * Copyright (c) 2017 Toby Allsopp - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -export module nihil.monad; - -import nihil.std; - -namespace nihil { - -/********************************************************************** - * return_object_holder - */ - -// An object that starts out unitialized. Initialized by a call to emplace. -export template <typename T> -using deferred = std::optional<T>; - -export template <typename T> -struct return_object_holder { - // The staging object that is returned (by copy/move) to the caller of - // the coroutine. - deferred<T> stage; - return_object_holder*& p; - - // When constructed, we assign a pointer to ourselves to the supplied - // reference to pointer. - return_object_holder(return_object_holder*& p) - : stage{} - , p(p) - { - p = this; - } - - // Copying doesn't make any sense (which copy should the pointer refer - // to?). - return_object_holder(return_object_holder const&) = delete; - - // To move, we just update the pointer to point at the new object. - return_object_holder(return_object_holder&& other) - : stage(std::move(other.stage)) - , p(other.p) - { - p = this; - } - - // Assignment doesn't make sense. - void operator=(return_object_holder const&) = delete; - void operator=(return_object_holder&&) = delete; - - // A non-trivial destructor is required until - // https://bugs.llvm.org//show_bug.cgi?id=28593 is fixed. - ~return_object_holder() {} - - // Construct the staging value; arguments are perfect forwarded to T's - // constructor. - template <typename... Args> - void emplace(Args&&... args) - { - stage.emplace(std::forward<Args>(args)...); - } - - // We assume that we will be converted only once, so we can move from - // the staging object. We also assume that `emplace` has been called - // at least once. - operator T() - { - return std::move(*stage); - } -}; - -export template <typename T> -auto make_return_object_holder(return_object_holder<T>*& p) -{ - return return_object_holder<T>{p}; -} - -/********************************************************************** - * std::optional - */ - -template <typename T> -struct optional_promise { - return_object_holder<std::optional<T>>* data; - - auto get_return_object() - { - return make_return_object_holder(data); - } - - auto initial_suspend() noexcept -> std::suspend_never - { - return {}; - } - - auto final_suspend() noexcept -> std::suspend_never - { - return {}; - } - - void return_value(T x) - { - data->emplace(std::move(x)); - } - - void unhandled_exception() - { - std::rethrow_exception(std::current_exception()); - } -}; - -} // namespace nihil - -export template <typename T, typename... Args> -struct std::coroutine_traits<std::optional<T>, Args...> { - using promise_type = nihil::optional_promise<T>; -}; - -namespace nihil { - -template <typename T> -struct optional_awaitable { - std::optional<T> o; - - auto await_ready() - { - return o.has_value(); - } - - auto await_resume() - { - return *o; - } - - template <typename U> - void await_suspend(std::coroutine_handle<optional_promise<U>> h) - { - h.promise().data->emplace(std::nullopt); - h.destroy(); - } -}; - -} // namespace nihil - -namespace std { - -export template <typename T> -auto operator co_await(std::optional<T> o) { - return nihil::optional_awaitable<T>{std::move(o)}; -} - -} // namespace std - -/********************************************************************** - * std::expected - */ - -namespace nihil { - -export template <typename T, typename E> -struct expected_promise_base { - return_object_holder<std::expected<T, E>>* data; - - auto get_return_object() - { - return make_return_object_holder(data); - } - - auto initial_suspend() noexcept -> std::suspend_never - { - return {}; - } - - auto final_suspend() noexcept -> std::suspend_never - { - return {}; - } - - void unhandled_exception() - { - std::rethrow_exception(std::current_exception()); - } -}; - -export template <typename T, typename E> -struct expected_promise : expected_promise_base<T, E> { - void return_value(this expected_promise &self, std::unexpected<E> err) - { - self.data->emplace(std::move(err)); - } - - void return_value(this expected_promise &self, T o) - { - self.data->emplace(std::move(o)); - } -}; - -export template <typename E> -struct expected_promise<void, E> : expected_promise_base<void, E> { - void return_value(this expected_promise &self, std::unexpected<E> err) - { - self.data->emplace(std::move(err)); - } - - void return_value(this expected_promise &self, std::expected<void, E> o) - { - self.data->emplace(std::move(o)); - } -}; - -} // namespace nihil - -export template <typename T, typename E, typename... Args> -struct std::coroutine_traits<std::expected<T, E>, Args...> { - using promise_type = nihil::expected_promise<T, E>; -}; - -namespace nihil { - -export template<typename T, typename E> -struct expected_awaitable_base { - std::expected<T, E> o; - - auto await_ready() - { - return o.has_value(); - } - - template <typename P> - void await_suspend(std::coroutine_handle<P> h) - { - h.promise().data->emplace(std::unexpected(o.error())); - h.destroy(); - } -}; - -export template <typename T, typename E> -struct expected_awaitable : expected_awaitable_base<T, E> { - auto await_resume(this expected_awaitable &self) - { - return std::move(*self.o); - } -}; - -export template <typename E> -struct expected_awaitable<void, E> : expected_awaitable_base<void, E> { - auto await_resume(this expected_awaitable &) - { - return std::expected<void, E>(); - } -}; - -} // namespace nihil - -namespace std { - -export template <typename T, typename E> -auto operator co_await(std::expected<T, E> o) { - return nihil::expected_awaitable<T, E>{std::move(o)}; -} - -} // namespace std diff --git a/nihil.monad/test.cc b/nihil.monad/test.cc deleted file mode 100644 index 2cc743c..0000000 --- a/nihil.monad/test.cc +++ /dev/null @@ -1,64 +0,0 @@ -// This source code is released into the public domain. - -#include <catch2/catch_test_macros.hpp> - -import nihil.std; -import nihil.error; -import nihil.monad; - -TEST_CASE("monad: co_await std::optional<> with value", "[nihil]") -{ - auto get_value = [] -> std::optional<int> { - return 42; - }; - - auto try_get_value = [&get_value] -> std::optional<int> { - co_return co_await get_value(); - }; - - auto o = try_get_value(); - REQUIRE(o == 42); -} - -TEST_CASE("monad: co_await std::optional<> without value", "[nihil]") -{ - auto get_value = [] -> std::optional<int> { - return {}; - }; - - auto try_get_value = [&get_value] -> std::optional<int> { - co_return co_await get_value(); - }; - - auto o = try_get_value(); - REQUIRE(!o.has_value()); -} - -TEST_CASE("monad: co_await std::expected<> with value", "[nihil]") -{ - auto get_value = [] -> std::expected<int, std::string> { - return 42; - }; - - auto try_get_value = [&get_value] -> std::expected<int, std::string> { - co_return co_await get_value(); - }; - - auto o = try_get_value(); - REQUIRE(o == 42); -} - -TEST_CASE("monad: co_await std::expected<> with error", "[nihil]") -{ - auto get_value = [] -> std::expected<int, std::string> { - return std::unexpected("error"); - }; - - auto try_get_value = [&get_value] -> std::expected<int, std::string> { - co_return co_await get_value(); - }; - - auto o = try_get_value(); - REQUIRE(!o); - REQUIRE(o.error() == "error"); -} |
