From ebe4cb0bdeabd06a31072547af47cacaab7f78c0 Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Wed, 2 Jul 2025 05:49:47 +0100 Subject: replace nihil::generator the new implementation is much simpler and PD-licensed. the only downside is it doesn't support elements_of. while here, move it to nihil.core. --- nihil.generator/CMakeLists.txt | 33 --- nihil.generator/byte_allocator.ccm | 24 --- nihil.generator/coroutine_traits.ccm | 66 ------ nihil.generator/elements_of.ccm | 66 ------ nihil.generator/forward.ccm | 26 --- nihil.generator/generator.ccm | 323 ----------------------------- nihil.generator/generator.test.cc | 91 -------- nihil.generator/generator_promise.ccm | 61 ------ nihil.generator/generator_promise_base.ccm | 200 ------------------ nihil.generator/manual_lifetime.ccm | 114 ---------- nihil.generator/nihil.generator.ccm | 27 --- nihil.generator/promise_base_alloc.ccm | 90 -------- nihil.generator/util.ccm | 34 --- 13 files changed, 1155 deletions(-) delete mode 100644 nihil.generator/CMakeLists.txt delete mode 100644 nihil.generator/byte_allocator.ccm delete mode 100644 nihil.generator/coroutine_traits.ccm delete mode 100644 nihil.generator/elements_of.ccm delete mode 100644 nihil.generator/forward.ccm delete mode 100644 nihil.generator/generator.ccm delete mode 100644 nihil.generator/generator.test.cc delete mode 100644 nihil.generator/generator_promise.ccm delete mode 100644 nihil.generator/generator_promise_base.ccm delete mode 100644 nihil.generator/manual_lifetime.ccm delete mode 100644 nihil.generator/nihil.generator.ccm delete mode 100644 nihil.generator/promise_base_alloc.ccm delete mode 100644 nihil.generator/util.ccm (limited to 'nihil.generator') diff --git a/nihil.generator/CMakeLists.txt b/nihil.generator/CMakeLists.txt deleted file mode 100644 index d9eb854..0000000 --- a/nihil.generator/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# This source code is released into the public domain. - -add_library(nihil.generator STATIC) -target_link_libraries(nihil.generator PRIVATE nihil.std) -target_sources(nihil.generator - PUBLIC FILE_SET modules TYPE CXX_MODULES FILES - nihil.generator.ccm - - generator.ccm - byte_allocator.ccm - coroutine_traits.ccm - elements_of.ccm - forward.ccm - generator_promise_base.ccm - generator_promise.ccm - manual_lifetime.ccm - promise_base_alloc.ccm - util.ccm -) - -if(NIHIL_TESTS) - enable_testing() - - add_executable(nihil.generator.test generator.test.cc) - target_link_libraries(nihil.generator.test PRIVATE - nihil.generator - Catch2::Catch2WithMain - ) - - include(CTest) - include(Catch) - catch_discover_tests(nihil.generator.test) -endif() diff --git a/nihil.generator/byte_allocator.ccm b/nihil.generator/byte_allocator.ccm deleted file mode 100644 index 86b2edf..0000000 --- a/nihil.generator/byte_allocator.ccm +++ /dev/null @@ -1,24 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:byte_allocator; - -import nihil.std; - -namespace nihil { - -template -using byte_allocator_t = typename std::allocator_traits< - std::remove_cvref_t>::template rebind_alloc; - -} // namespace nihil diff --git a/nihil.generator/coroutine_traits.ccm b/nihil.generator/coroutine_traits.ccm deleted file mode 100644 index fde4393..0000000 --- a/nihil.generator/coroutine_traits.ccm +++ /dev/null @@ -1,66 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:coroutine_traits; - -import nihil.std; -import :byte_allocator; -import :forward; -import :generator_promise; - -namespace std { - -// Type-erased allocator with default allocator behaviour. -export template -struct coroutine_traits, Args...> -{ - using promise_type = - nihil::generator_promise, std::allocator>; -}; - -// Type-erased allocator with std::allocator_arg parameter -export template -struct coroutine_traits, allocator_arg_t, Alloc, Args...> -{ -private: - using byte_allocator = nihil::byte_allocator_t; - -public: - using promise_type = nihil::generator_promise, byte_allocator, - true /*explicit Allocator*/>; -}; - -// Type-erased allocator with std::allocator_arg parameter (non-static member functions) -export template -struct coroutine_traits, This, allocator_arg_t, Alloc, Args...> -{ -private: - using byte_allocator = nihil::byte_allocator_t; - -public: - using promise_type = nihil::generator_promise, byte_allocator, - true /*explicit Allocator*/>; -}; - -// Generator with specified allocator type -export template -struct coroutine_traits, Args...> -{ - using byte_allocator = nihil::byte_allocator_t; - -public: - using promise_type = - nihil::generator_promise, byte_allocator>; -}; - -} // namespace std diff --git a/nihil.generator/elements_of.ccm b/nihil.generator/elements_of.ccm deleted file mode 100644 index 74c8b76..0000000 --- a/nihil.generator/elements_of.ccm +++ /dev/null @@ -1,66 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:elements_of; - -import nihil.std; -import :util; - -namespace nihil { - -export template -struct elements_of { - explicit constexpr elements_of(Range &&range) noexcept - requires std::is_default_constructible_v - : m_range(static_cast(range)) - { - } - - constexpr elements_of(Range &&range, Allocator &&alloc) noexcept - : m_range(static_cast(range)) - , m_alloc(static_cast(alloc)) - {} - - constexpr elements_of(elements_of &&) noexcept = default; - - constexpr elements_of(const elements_of &) = delete; - - constexpr auto operator=(this elements_of &, const elements_of &) - -> elements_of & = delete; - constexpr auto operator=(this elements_of &, elements_of &&) noexcept - -> elements_of & = delete; - - [[nodiscard]] constexpr auto - get(this elements_of const &self) noexcept -> Range && - { - return static_cast(self.m_range); - } - - [[nodiscard]] constexpr auto - get_allocator(this elements_of const &self) noexcept -> Allocator - { - return self.m_alloc; - } - -private: - [[no_unique_address]] Allocator m_alloc; - Range &&m_range; -}; - -export template -elements_of(Range &&) -> elements_of; - -export template -elements_of(Range &&, Allocator &&) -> elements_of; - -} // namespace nihil diff --git a/nihil.generator/forward.ccm b/nihil.generator/forward.ccm deleted file mode 100644 index 2aa2448..0000000 --- a/nihil.generator/forward.ccm +++ /dev/null @@ -1,26 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:forward; - -import nihil.std; -import :util; - -namespace nihil { - -export template , - typename Allocator = use_allocator_arg> -struct generator; - -} // namespace nihil diff --git a/nihil.generator/generator.ccm b/nihil.generator/generator.ccm deleted file mode 100644 index a2fcafb..0000000 --- a/nihil.generator/generator.ccm +++ /dev/null @@ -1,323 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -module; - -#include - -export module nihil.generator:generator; - -import nihil.std; -import :byte_allocator; -import :coroutine_traits; -import :elements_of; -import :forward; -import :generator_promise_base; -import :generator_promise; -import :manual_lifetime; -import :promise_base_alloc; -import :util; - -namespace nihil { - -// TODO : make layout compatible promise casts possible -export template -struct generator -{ - using byte_allocator = byte_allocator_t; - -public: - using promise_type = generator_promise, byte_allocator>; - friend promise_type; - -private: - using coroutine_handle = std::coroutine_handle; - -public: - generator() noexcept = default; - - generator(generator &&other) noexcept - : m_coro(std::exchange(other.m_coro, {})) - , m_started(std::exchange(other.m_started, false)) - { - } - - ~generator() noexcept - { - if (m_coro) { - if (m_started && !m_coro.done()) { - m_coro.promise().__value_.destruct(); - } - m_coro.destroy(); - } - } - - auto operator=(generator &&g) noexcept -> generator & - { - swap(g); - return *this; - } - - void swap(generator &other) noexcept - { - std::swap(m_coro, other.m_coro); - std::swap(m_started, other.m_started); - } - - struct sentinel - { - }; - - struct iterator - { - using iterator_category = std::input_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = Value; - using reference = Ref; - using pointer = std::add_pointer_t; - - iterator() noexcept = default; - iterator(const iterator &) = delete; - - iterator(iterator &&other) noexcept - : m_coro(std::exchange(other.m_coro, {})) - { - } - - auto operator=(iterator &&other) noexcept -> iterator & - { - std::swap(m_coro, other.m_coro); - return *this; - } - - ~iterator() = default; - - friend auto operator==(const iterator &it, sentinel) noexcept -> bool - { - return it.m_coro.done(); - } - - auto operator++() -> iterator & - { - m_coro.promise().m_value.destruct(); - m_coro.promise().resume(); - return *this; - } - - void operator++(int) - { - (void)operator++(); - } - - auto operator*() const noexcept -> reference - { - return static_cast(m_coro.promise().m_value.get()); - } - - private: - friend generator; - - explicit iterator(coroutine_handle coro) noexcept - : m_coro(coro) - { - } - - coroutine_handle m_coro; - }; - - auto begin() -> iterator - { - assert(m_coro); - assert(!m_started); - m_started = true; - m_coro.resume(); - return iterator{m_coro}; - } - - auto end() noexcept -> sentinel - { - return {}; - } - -private: - explicit generator(coroutine_handle coro) noexcept - : m_coro(coro) - { - } - -public: // to get around access restrictions for __yield_sequence_awaitable - auto get_coro() noexcept -> std::coroutine_handle<> - { - return m_coro; - } - auto get_promise() noexcept -> promise_type * - { - return std::addressof(m_coro.promise()); - } - -private: - coroutine_handle m_coro; - bool m_started = false; -}; - -// Specialisation for type-erased allocator implementation. -export template -class generator -{ - using promise_base = generator_promise_base; - -public: - generator() noexcept - : m_promise(nullptr) - { - } - - generator(generator &&other) noexcept - : m_promise(std::exchange(other.m_promise, nullptr)) - , m_coro(std::exchange(other.m_coro, {})) - , m_started(std::exchange(other.m_started, false)) - { - } - - ~generator() noexcept - { - if (m_coro) { - if (m_started && !m_coro.done()) { - m_promise->m_value.destruct(); - } - m_coro.destroy(); - } - } - - auto operator=(generator g) noexcept -> generator & - { - swap(g); - return *this; - } - - void swap(generator &other) noexcept - { - std::swap(m_promise, other.m_promise); - std::swap(m_coro, other.m_coro); - std::swap(m_started, other.m_started); - } - - struct sentinel - { - }; - - struct iterator - { - using iterator_category = std::input_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = Value; - using reference = Ref; - using pointer = std::add_pointer_t; - - iterator() noexcept = default; - iterator(const iterator &) = delete; - - iterator(iterator &&other) noexcept - : m_promise(std::exchange(other.m_promise, nullptr)) - , m_coro(std::exchange(other.m_coro, {})) - { - } - - auto operator=(iterator &&other) noexcept -> iterator & - { - m_promise = std::exchange(other.m_promise, nullptr); - m_coro = std::exchange(other.m_coro, {}); - return *this; - } - - ~iterator() = default; - - friend auto operator==(const iterator &it, sentinel) noexcept -> bool - { - return it.m_coro.done(); - } - - auto operator++() -> iterator & - { - m_promise->m_value.destruct(); - m_promise->resume(); - return *this; - } - - void operator++(int) - { - (void)operator++(); - } - - auto operator*() const noexcept -> reference - { - return static_cast(m_promise->m_value.get()); - } - - private: - friend generator; - - explicit iterator(promise_base *promise, - std::coroutine_handle<> coro) noexcept - : m_promise(promise) - , m_coro(coro) - { - } - - promise_base *m_promise; - std::coroutine_handle<> m_coro; - }; - - auto begin() -> iterator - { - assert(m_coro); - assert(!m_started); - m_started = true; - m_coro.resume(); - return iterator{m_promise, m_coro}; - } - - auto end() noexcept -> sentinel - { - return {}; - } - -private: - template - friend struct generator_promise; - - template - explicit generator(std::coroutine_handle coro) noexcept - : m_promise(std::addressof(coro.promise())) - , m_coro(coro) - { - } - -public: // to get around access restrictions for __yield_sequence_awaitable - auto get_coro() noexcept -> std::coroutine_handle<> - { - return m_coro; - } - - auto get_promise() noexcept -> promise_base * - { - return m_promise; - } - -private: - promise_base *m_promise; - std::coroutine_handle<> m_coro; - bool m_started = false; -}; - -} // namespace nihil diff --git a/nihil.generator/generator.test.cc b/nihil.generator/generator.test.cc deleted file mode 100644 index 1782dfb..0000000 --- a/nihil.generator/generator.test.cc +++ /dev/null @@ -1,91 +0,0 @@ -// This source code is released into the public domain. - -#include - -import nihil.std; -import nihil.generator; - -namespace { -inline auto constexpr test_tags = "[nihil][nihil.generator]"; - -SCENARIO("A generator that yields values", test_tags) -{ - GIVEN ("A generator that yields values") { - auto fn = [&]() -> nihil::generator { - co_yield 1; - co_yield 2; - }; - - THEN ("The generator yields the original values") { - REQUIRE(std::ranges::equal(fn(), std::vector{1, 2})); - } - } -} - -SCENARIO("A generator that yields references", test_tags) -{ - GIVEN ("A generator that yields references") { - auto one = 1, two = 2; - auto fn = [&]() -> nihil::generator { - co_yield one; - co_yield two; - }; - auto range = fn(); - - THEN ("The references refer to the original values") { - auto it = std::ranges::begin(range); - REQUIRE(&*it == &one); - ++it; - REQUIRE(&*it == &two); - ++it; - REQUIRE(it == std::ranges::end(range)); - } - } -} - -SCENARIO("A generator that yields pointers", test_tags) -{ - GIVEN ("A generator that yields pointers") { - auto one = 1, two = 2; - auto fn = [&]() -> nihil::generator { - co_yield &one; - co_yield &two; - }; - - THEN ("The pointers point to the original values") { - REQUIRE(std::ranges::equal(fn(), std::vector{&one, &two})); - } - } -} - -TEST_CASE("generator: exceptions", "[generator]") -{ - auto fn = []() -> nihil::generator { - co_yield 1; - throw std::runtime_error("test"); - }; - - auto range = fn(); - auto it = std::ranges::begin(range); - REQUIRE(*it == 1); - REQUIRE_THROWS_AS(it++, std::runtime_error); -} - -TEST_CASE("generator: elements_of", "[generator]") -{ - auto fn1 = [] -> nihil::generator { - co_yield 1; - co_yield 2; - co_yield 3; - }; - - auto fn2 = [&fn1] -> nihil::generator { - co_yield nihil::elements_of(fn1()); - }; - - auto values = std::vector(); - std::ranges::copy(fn2(), std::back_inserter(values)); - - REQUIRE(values == std::vector{1, 2, 3}); -} -} // anonymous namespace diff --git a/nihil.generator/generator_promise.ccm b/nihil.generator/generator_promise.ccm deleted file mode 100644 index 3e8aa8c..0000000 --- a/nihil.generator/generator_promise.ccm +++ /dev/null @@ -1,61 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:generator_promise; - -import nihil.std; -import :forward; -import :generator_promise_base; -import :promise_base_alloc; - -namespace nihil { - -export template -struct generator_promise; - -export template -struct generator_promise, ByteAllocator, ExplicitAllocator> final - : public generator_promise_base, - public promise_base_alloc -{ - generator_promise() noexcept - : generator_promise_base( - std::coroutine_handle::from_promise(*this)) - { - } - - auto get_return_object() noexcept -> generator - { - return generator{ - std::coroutine_handle::from_promise(*this)}; - } - - using generator_promise_base::yield_value; - - template - auto yield_value(nihil::elements_of &&x) -> typename generator_promise_base< - Ref>::template yield_sequence_awaiter> - { - static_assert(!ExplicitAllocator, - "This coroutine has an explicit allocator specified with " - "std::allocator_arg so an allocator needs to be passed " - "explicitely to std::elements_of"); - return [](auto &&rng) -> generator { - for (auto &&e : rng) - co_yield static_cast(e); - }(std::forward(x.get())); - } -}; - -} // namespace nihil diff --git a/nihil.generator/generator_promise_base.ccm b/nihil.generator/generator_promise_base.ccm deleted file mode 100644 index 6b11b40..0000000 --- a/nihil.generator/generator_promise_base.ccm +++ /dev/null @@ -1,200 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:generator_promise_base; - -import nihil.std; -import :elements_of; -import :forward; -import :manual_lifetime; - -namespace nihil { - -template -struct generator_promise_base -{ - template - friend struct generator; - - generator_promise_base *m_root; - std::coroutine_handle<> m_parent_or_leaf; - - // Note: Using manual_lifetime here to avoid extra calls to exception_ptr - // constructor/destructor in cases where it is not needed (i.e. where this - // generator coroutine is not used as a nested coroutine). - // This member is lazily constructed by the __yield_sequence_awaiter::await_suspend() - // method if this generator is used as a nested generator. - manual_lifetime m_exception; - manual_lifetime m_value; - - explicit generator_promise_base(std::coroutine_handle<> this_coro) noexcept - : m_root(this) - , m_parent_or_leaf(this_coro) - { - } - - ~generator_promise_base() - { - if (m_root != this) { - // This coroutine was used as a nested generator and so will - // have constructed its __exception_ member which needs to be - // destroyed here. - m_exception.destruct(); - } - } - - auto initial_suspend() noexcept -> std::suspend_always - { - return {}; - } - - auto return_void() noexcept -> void - { - } - - auto unhandled_exception() -> void - { - if (m_root != this) - m_exception.get() = std::current_exception(); - else - throw; - } - - // Transfers control back to the parent of a nested coroutine - struct final_awaiter - { - auto await_ready() noexcept -> bool - { - return false; - } - - template - auto - await_suspend(std::coroutine_handle h) noexcept -> std::coroutine_handle<> - { - Promise &promise = h.promise(); - generator_promise_base &root = *promise.m_root; - if (&root != &promise) { - auto parent = promise.m_parent_or_leaf; - root.m_parent_or_leaf = parent; - return parent; - } - return std::noop_coroutine(); - } - - void await_resume() noexcept - { - } - }; - - auto final_suspend() noexcept -> final_awaiter - { - return {}; - } - - auto yield_value(Ref &&x) noexcept(std::is_nothrow_move_constructible_v) - -> std::suspend_always - { - m_root->m_value.construct((Ref &&)x); - return {}; - } - - template - requires(!std::is_reference_v) && std::is_convertible_v - auto - yield_value(T &&x) noexcept(std::is_nothrow_constructible_v) -> std::suspend_always - { - m_root->m_value.construct((T &&)x); - return {}; - } - - template - struct yield_sequence_awaiter - { - Gen m_gen; - - yield_sequence_awaiter(Gen &&g) noexcept - // Taking ownership of the generator ensures frame are destroyed - // in the reverse order of their execution. - : m_gen((Gen &&)g) - { - } - - auto await_ready() noexcept -> bool - { - return false; - } - - // set the parent, root and exceptions pointer and - // resume the nested - template - auto - await_suspend(std::coroutine_handle h) noexcept -> std::coroutine_handle<> - { - generator_promise_base ¤t = h.promise(); - generator_promise_base &nested = *m_gen.get_promise(); - generator_promise_base &root = *current.m_root; - - nested.m_root = current.m_root; - nested.m_parent_or_leaf = h; - - // Lazily construct the __exception_ member here now that we - // know it will be used as a nested generator. This will be - // destroyed by the promise destructor. - nested.m_exception.construct(); - root.m_parent_or_leaf = m_gen.get_coro(); - - // Immediately resume the nested coroutine (nested generator) - return m_gen.get_coro(); - } - - void await_resume() - { - generator_promise_base &nested_promise = *m_gen.get_promise(); - - if (nested_promise.m_exception.get()) { - std::rethrow_exception(nested_promise.m_exception.get()); - } - } - }; - - template - auto yield_value(nihil::elements_of> g) noexcept - -> yield_sequence_awaiter> - - { - return std::move(g).get(); - } - - template - auto yield_value(nihil::elements_of &&x) - -> yield_sequence_awaiter, Allocator>> - - { - return [](std::allocator_arg_t, Allocator, - auto &&rng) -> generator, Allocator> { - for (auto &&e : rng) - co_yield static_cast(e); - }(std::allocator_arg, x.get_allocator(), std::forward(x.get())); - } - - void resume() - { - m_parent_or_leaf.resume(); - } - - // Disable use of co_await within this coroutine. - void await_transform() = delete; -}; - -} // namespace nihil diff --git a/nihil.generator/manual_lifetime.ccm b/nihil.generator/manual_lifetime.ccm deleted file mode 100644 index 44bc0a8..0000000 --- a/nihil.generator/manual_lifetime.ccm +++ /dev/null @@ -1,114 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:manual_lifetime; - -import nihil.std; - -namespace nihil { - -template -struct manual_lifetime { - manual_lifetime() noexcept {} - ~manual_lifetime() {} - - template - auto construct(this manual_lifetime &self, Args && ...args) - noexcept(std::is_nothrow_constructible_v) - -> T & - { - return *::new (static_cast(std::addressof(self.m_value))) - T(static_cast(args)...); - } - - void destruct(this manual_lifetime &self) - noexcept(std::is_nothrow_destructible_v) - { - self.m_value.~T(); - } - - auto get(this manual_lifetime &self) noexcept -> T & - { - return self.m_value; - } - - auto get(this manual_lifetime &&self) noexcept -> T && - { - return static_cast(self.m_value); - } - - auto get(this manual_lifetime const &self) noexcept -> T const & - { - return self.m_value; - } - - auto get(this manual_lifetime const &&self) noexcept -> T const && - { - return static_cast(self.m_value); - } - -private: - union { - std::remove_const_t m_value; - }; -}; - -template -struct manual_lifetime { - manual_lifetime() noexcept = default; - ~manual_lifetime() = default; - - auto construct(this manual_lifetime &self, T &value) noexcept -> T & - { - self.m_value = std::addressof(value); - return value; - } - - auto destruct(this manual_lifetime &) noexcept -> void - { - } - - auto get(this manual_lifetime const &self) noexcept -> T & - { - return *self.m_value; - } - -private: - T *m_value = nullptr; -}; - -template -struct manual_lifetime { - manual_lifetime() noexcept = default; - ~manual_lifetime() = default; - - auto construct(this manual_lifetime &self, T &&value) noexcept -> T && - { - self.m_value = std::addressof(value); - return static_cast(value); - } - - void destruct(this manual_lifetime &) noexcept - { - } - - auto get(this manual_lifetime const &self) noexcept -> T && - { - return static_cast(*self.m_value); - } - -private: - T* m_value = nullptr; -}; - -} diff --git a/nihil.generator/nihil.generator.ccm b/nihil.generator/nihil.generator.ccm deleted file mode 100644 index fc6a097..0000000 --- a/nihil.generator/nihil.generator.ccm +++ /dev/null @@ -1,27 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator; - -import nihil.std; - -export import :coroutine_traits; -export import :elements_of; -export import :generator; - -export namespace std::ranges { // NOLINT - -template -constexpr inline bool enable_view> = true; - -} // namespace std::ranges diff --git a/nihil.generator/promise_base_alloc.ccm b/nihil.generator/promise_base_alloc.ccm deleted file mode 100644 index 7fd544b..0000000 --- a/nihil.generator/promise_base_alloc.ccm +++ /dev/null @@ -1,90 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:promise_base_alloc; - -import nihil.std; -import :util; - -namespace nihil { - -template -struct promise_base_alloc -{ - template - static void* operator new(std::size_t frame_size, std::allocator_arg_t, Alloc alloc, Args &...) - { - void* frame = alloc.allocate(padded_frame_size(frame_size)); - - // Store allocator at end of the coroutine frame. Assuming the - // allocator's move constructor is non-throwing (a requirement - // for allocators) - auto *alloc_address = static_cast(std::addressof(get_allocator(frame, frame_size))); - ::new (alloc_address) Alloc(std::move(alloc)); - - return frame; - } - - template - static void* operator new(std::size_t frame_size, This &, std::allocator_arg_t, Alloc alloc, Args &...) - { - return promise_base_alloc::operator new(frame_size, std::allocator_arg, std::move(alloc)); - } - - static void operator delete(void* ptr, std::size_t frame_size) noexcept - { - auto &alloc = get_allocator(ptr, frame_size); - auto local_alloc = Alloc(std::move(alloc)); - - alloc.~Alloc(); - - local_alloc.deallocate(static_cast(ptr), padded_frame_size(frame_size)); - } - -private: - [[nodiscard]] static constexpr auto offset_of_allocator(std::size_t frame_size) noexcept -> std::size_t - { - return aligned_allocation_size(frame_size, alignof(Alloc)); - } - - [[nodiscard]] static constexpr auto padded_frame_size(std::size_t frame_size) noexcept -> std::size_t - { - return offset_of_allocator(frame_size) + sizeof(Alloc); - } - - [[nodiscard]] static auto get_allocator(void* frame, std::size_t frame_size) noexcept -> Alloc & - { - return *reinterpret_cast( - static_cast(frame) + offset_of_allocator(frame_size)); - } - -}; - -template -requires (!allocator_needs_to_be_stored) -struct promise_base_alloc -{ - static void* operator new(std::size_t size) - { - auto alloc = Alloc(); - return alloc.allocate(size); - } - - static void operator delete(void *ptr, std::size_t size) noexcept - { - auto alloc = Alloc(); - alloc.deallocate(static_cast(ptr), size); - } -}; - -} // namespace nihil diff --git a/nihil.generator/util.ccm b/nihil.generator/util.ccm deleted file mode 100644 index 259499a..0000000 --- a/nihil.generator/util.ccm +++ /dev/null @@ -1,34 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Reference implementation of std::generator proposal P2168. -// -// See https://wg21.link/P2168 for details. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright Lewis Baker, Corentin Jabot -// -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. -// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt) -/////////////////////////////////////////////////////////////////////////////// - -export module nihil.generator:util; - -import nihil.std; - -namespace nihil { - -export struct use_allocator_arg {}; - -template -constexpr bool allocator_needs_to_be_stored = - !std::allocator_traits::is_always_equal::value || - !std::is_default_constructible_v; - -// Round s up to next multiple of a. -[[nodiscard]] constexpr auto -aligned_allocation_size(std::size_t s, std::size_t a) -> std::size_t -{ - return (s + a - 1) & ~(a - 1); -} - -} // namespace nihil -- cgit v1.2.3