aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-07-02 05:49:47 +0100
committerLexi Winter <lexi@le-fay.org>2025-07-02 05:49:47 +0100
commitebe4cb0bdeabd06a31072547af47cacaab7f78c0 (patch)
tree65a81c2c86260b595107ee6c5505583f9afaf39d
parent5adeb648f74c1771164c0686d6e0fc584cf36d9e (diff)
downloadnihil-ebe4cb0bdeabd06a31072547af47cacaab7f78c0.tar.gz
nihil-ebe4cb0bdeabd06a31072547af47cacaab7f78c0.tar.bz2
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.
-rw-r--r--CMakeLists.txt1
-rw-r--r--README5
-rw-r--r--nihil.cli/CMakeLists.txt1
-rw-r--r--nihil.cli/command_tree.ccm4
-rw-r--r--nihil.config/CMakeLists.txt6
-rw-r--r--nihil.config/store.cc1
-rw-r--r--nihil.config/store.ccm1
-rw-r--r--nihil.core/CMakeLists.txt29
-rw-r--r--nihil.core/error.test.cc1
-rw-r--r--nihil.core/generator.ccm240
-rw-r--r--nihil.core/generator.test.cc (renamed from nihil.generator/generator.test.cc)20
-rw-r--r--nihil.core/nihil.core.ccm1
-rw-r--r--nihil.generator/CMakeLists.txt33
-rw-r--r--nihil.generator/byte_allocator.ccm24
-rw-r--r--nihil.generator/coroutine_traits.ccm66
-rw-r--r--nihil.generator/elements_of.ccm66
-rw-r--r--nihil.generator/forward.ccm26
-rw-r--r--nihil.generator/generator.ccm323
-rw-r--r--nihil.generator/generator_promise.ccm61
-rw-r--r--nihil.generator/generator_promise_base.ccm200
-rw-r--r--nihil.generator/manual_lifetime.ccm114
-rw-r--r--nihil.generator/nihil.generator.ccm27
-rw-r--r--nihil.generator/promise_base_alloc.ccm90
-rw-r--r--nihil.generator/util.ccm34
-rw-r--r--nihil.std/nihil.std.ccm7
25 files changed, 305 insertions, 1076 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af2bb8c..b51f7b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,7 +64,6 @@ endif()
add_subdirectory(nihil.std)
add_subdirectory(nihil.cli)
add_subdirectory(nihil.core)
-add_subdirectory(nihil.generator)
add_subdirectory(nihil.posix)
if(NIHIL_UCL)
diff --git a/README b/README
index 42471d0..ed52cf9 100644
--- a/README
+++ b/README
@@ -11,9 +11,8 @@ license
all of nihil is in the public domain, with the exception of:
-- nihil/generator.ccm (BSL)
-- nihil/monad.ccm (MIT)
-- nihil/uuid.ccm (MIT)
+- nihil.core/monad.ccm (MIT)
+- nihil.core/uuid.ccm (MIT)
requirements
------------
diff --git a/nihil.cli/CMakeLists.txt b/nihil.cli/CMakeLists.txt
index e87d3d4..8f4d1ea 100644
--- a/nihil.cli/CMakeLists.txt
+++ b/nihil.cli/CMakeLists.txt
@@ -5,7 +5,6 @@ add_library(nihil.cli STATIC)
target_link_libraries(nihil.cli PRIVATE
nihil.std
nihil.core
- nihil.generator
nihil.posix
)
diff --git a/nihil.cli/command_tree.ccm b/nihil.cli/command_tree.ccm
index 844b2cf..4c341b7 100644
--- a/nihil.cli/command_tree.ccm
+++ b/nihil.cli/command_tree.ccm
@@ -2,7 +2,6 @@
export module nihil.cli:command_tree;
import nihil.std;
-import nihil.generator;
import nihil.core;
import :command;
@@ -103,7 +102,8 @@ struct command_tree_node final
{
for (auto &&node : self.m_children | std::views::values) {
co_yield node;
- co_yield elements_of(node.all_children());
+ for (auto &&child : node.all_children())
+ co_yield child;
}
}
diff --git a/nihil.config/CMakeLists.txt b/nihil.config/CMakeLists.txt
index 0d8ffee..95b3fdb 100644
--- a/nihil.config/CMakeLists.txt
+++ b/nihil.config/CMakeLists.txt
@@ -1,12 +1,14 @@
# This source code is released into the public domain.
add_library(nihil.config STATIC)
+
target_link_libraries(nihil.config PRIVATE
nihil.std
- nihil.generator
+ nihil.core
nihil.posix
nihil.ucl
)
+
target_sources(nihil.config
PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
nihil.config.ccm
@@ -28,6 +30,8 @@ if(NIHIL_TESTS)
)
target_link_libraries(nihil.config.test PRIVATE
+ nihil.std
+ nihil.core
nihil.config
Catch2::Catch2WithMain)
diff --git a/nihil.config/store.cc b/nihil.config/store.cc
index 08850c4..06c2035 100644
--- a/nihil.config/store.cc
+++ b/nihil.config/store.cc
@@ -3,7 +3,6 @@ module nihil.config;
import nihil.std;
import nihil.core;
-import nihil.generator;
namespace nihil::config {
diff --git a/nihil.config/store.ccm b/nihil.config/store.ccm
index 2ceb52b..45de35e 100644
--- a/nihil.config/store.ccm
+++ b/nihil.config/store.ccm
@@ -4,7 +4,6 @@ export module nihil.config:store;
// The configuration store. There should only be one of these.
import nihil.std;
-import nihil.generator;
import nihil.core;
namespace nihil::config {
diff --git a/nihil.core/CMakeLists.txt b/nihil.core/CMakeLists.txt
index e9998a3..d0713ce 100644
--- a/nihil.core/CMakeLists.txt
+++ b/nihil.core/CMakeLists.txt
@@ -14,6 +14,7 @@ target_sources(nihil.core
error.ccm
features.ccm
flagset.ccm
+ generator.ccm
guard.ccm
match.ccm
monad.ccm
@@ -25,3 +26,31 @@ target_sources(nihil.core
tabulate.ccm
uuid.ccm
)
+
+if (NIHIL_TESTS)
+ add_executable(nihil.core.test
+ capture_stream.test.cc
+ ctype.test.cc
+ error.test.cc
+ flagset.test.cc
+ generator.test.cc
+ guard.test.cc
+ match.test.cc
+ monad.test.cc
+ next_word.test.cc
+ parse_size.test.cc
+ skipws.test.cc
+ tabulate.test.cc
+ )
+
+ target_link_libraries(nihil.core.test PRIVATE
+ nihil.std
+ nihil.core
+ Catch2::Catch2WithMain)
+
+ include(CTest)
+ include(Catch)
+ catch_discover_tests(nihil.core.test)
+
+ enable_testing()
+endif ()
diff --git a/nihil.core/error.test.cc b/nihil.core/error.test.cc
index f4ec1ee..7a923e4 100644
--- a/nihil.core/error.test.cc
+++ b/nihil.core/error.test.cc
@@ -4,7 +4,6 @@
import nihil.std;
import nihil.core;
-import nihil.util;
namespace {
inline constexpr auto *test_tags = "[nihil][nihil.error]";
diff --git a/nihil.core/generator.ccm b/nihil.core/generator.ccm
new file mode 100644
index 0000000..4d2bfe3
--- /dev/null
+++ b/nihil.core/generator.ccm
@@ -0,0 +1,240 @@
+// generator - Single-header, ranges-compatible generator type built
+// on C++20 coroutines
+// Written in 2021 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
+//
+// Documentation available at https://tl.tartanllama.xyz/
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this software to the
+// public domain worldwide. This software is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication
+// along with this software. If not, see
+// <http://creativecommons.org/publicdomain/zero/1.0/>.
+export module nihil.core:generator;
+
+import nihil.std;
+
+namespace nihil {
+
+export template <typename T>
+struct generator
+{
+private:
+ struct promise
+ {
+ using value_type = std::remove_reference_t<T>;
+ using reference_type =
+ std::conditional_t<std::is_pointer_v<value_type>, value_type, value_type &>;
+ using pointer_type =
+ std::conditional_t<std::is_pointer_v<value_type>, value_type, value_type *>;
+
+ promise() = default;
+
+ [[nodiscard]] auto get_return_object() -> generator
+ {
+ return generator(std::coroutine_handle<promise>::from_promise(*this));
+ }
+
+ [[nodiscard]] auto initial_suspend() const -> std::suspend_always
+ {
+ return {};
+ }
+
+ [[nodiscard]] auto final_suspend() const noexcept -> std::suspend_always
+ {
+ return {};
+ }
+
+ void return_void() const noexcept
+ {
+ }
+
+ void unhandled_exception() noexcept
+ {
+ exception_ = std::current_exception();
+ }
+
+ void rethrow_if_exception()
+ {
+ if (exception_) {
+ std::rethrow_exception(exception_);
+ }
+ }
+
+ std::suspend_always yield_value(value_type &&v) noexcept
+ {
+ value_ = std::move(v);
+ return {};
+ }
+
+ std::suspend_always yield_value(value_type const &v) noexcept
+ requires(!std::is_reference_v<T>)
+ {
+ value_ = v;
+ return {};
+ }
+
+ std::suspend_always yield_value(value_type &v) noexcept
+ requires(std::is_reference_v<T>)
+ {
+ value_ = &v;
+ return {};
+ }
+
+ std::exception_ptr exception_;
+ std::variant<std::monostate, value_type, value_type *> value_;
+ };
+
+public:
+ using promise_type = promise;
+ class sentinel
+ {
+ };
+
+ class iterator
+ {
+ using handle_type = std::coroutine_handle<promise_type>;
+
+ public:
+ using value_type = typename promise_type::value_type;
+ using reference_type = typename promise_type::reference_type;
+ using pointer_type = typename promise_type::pointer_type;
+ using difference_type = std::ptrdiff_t;
+
+ iterator() = default;
+ ~iterator()
+ {
+ if (handle_)
+ handle_.destroy();
+ }
+
+ // Non-copyable because coroutine handles point to a unique resource
+ iterator(iterator const &) = delete;
+ iterator(iterator &&rhs) noexcept
+ : handle_(std::exchange(rhs.handle_, nullptr))
+ {
+ }
+
+ auto operator=(iterator const &) -> iterator & = delete;
+
+ auto operator=(iterator &&rhs) noexcept -> iterator &
+ {
+ handle_ = std::exchange(rhs.handle_, nullptr);
+ return *this;
+ }
+
+ friend auto operator==(iterator const &it, sentinel) noexcept -> bool
+ {
+ return (!it.handle_ || it.handle_.done());
+ }
+
+ auto operator++() -> iterator &
+ {
+ handle_.resume();
+ if (handle_.done()) {
+ handle_.promise().rethrow_if_exception();
+ }
+ return *this;
+ }
+
+ void operator++(int)
+ {
+ (void)this->operator++();
+ }
+
+ reference_type operator*() const
+ noexcept(noexcept(std::is_nothrow_copy_constructible_v<reference_type>))
+ requires(std::is_reference_v<T>)
+ {
+ return *std::get<value_type *>(handle_.promise().value_);
+ }
+
+ reference_type operator*() const
+ noexcept(noexcept(std::is_nothrow_copy_constructible_v<reference_type>))
+ requires(!std::is_reference_v<T>)
+ {
+ return std::get<value_type>(handle_.promise().value_);
+ }
+
+ value_type *operator->() const
+ noexcept(noexcept(std::is_nothrow_copy_constructible_v<reference_type>))
+ requires(std::is_reference_v<T>)
+ {
+ return std::get<value_type *>(handle_.promise().value_);
+ }
+
+ value_type *operator->() const
+ noexcept(noexcept(std::is_nothrow_copy_constructible_v<reference_type>))
+ requires(!std::is_reference_v<T>)
+ {
+ return &std::get<value_type>(handle_.promise().value_);
+ }
+
+ private:
+ friend struct generator;
+
+ explicit iterator(handle_type handle)
+ : handle_(handle)
+ {
+ }
+
+ handle_type handle_;
+ };
+
+ using handle_type = std::coroutine_handle<promise_type>;
+
+ generator() noexcept = default;
+ ~generator()
+ {
+ if (handle_)
+ handle_.destroy();
+ }
+
+ generator(generator const &) = delete;
+
+ generator(generator &&rhs) noexcept
+ : handle_(std::exchange(rhs.handle_, nullptr))
+ {
+ }
+
+ auto operator=(generator const &) -> generator & = delete;
+
+ auto operator=(generator &&rhs) noexcept -> generator &
+ {
+ swap(rhs);
+ return *this;
+ }
+
+ auto begin() -> iterator
+ {
+ handle_.resume();
+ if (handle_.done()) {
+ handle_.promise().rethrow_if_exception();
+ }
+ return iterator(std::exchange(handle_, nullptr));
+ }
+
+ auto end() const noexcept -> sentinel
+ {
+ return {};
+ }
+
+ void swap(generator &other) noexcept
+ {
+ std::swap(handle_, other.handle_);
+ }
+
+private:
+ friend class iterator;
+ explicit generator(handle_type handle) noexcept
+ : handle_(handle)
+ {
+ }
+
+ handle_type handle_ = nullptr;
+};
+} // namespace nihil
+
+export template <typename T>
+inline constexpr bool std::ranges::enable_view<nihil::generator<T>> = true;
diff --git a/nihil.generator/generator.test.cc b/nihil.core/generator.test.cc
index 1782dfb..1fc0f22 100644
--- a/nihil.generator/generator.test.cc
+++ b/nihil.core/generator.test.cc
@@ -3,7 +3,7 @@
#include <catch2/catch_test_macros.hpp>
import nihil.std;
-import nihil.generator;
+import nihil.core;
namespace {
inline auto constexpr test_tags = "[nihil][nihil.generator]";
@@ -58,6 +58,21 @@ SCENARIO("A generator that yields pointers", test_tags)
}
}
+SCENARIO("A generator that yields lvalues", test_tags)
+{
+ GIVEN ("A generator that yields pointers") {
+ auto one = 1, two = 2;
+ auto fn = [&]() -> nihil::generator<int> {
+ co_yield one;
+ co_yield two;
+ };
+
+ THEN ("The pointers point to the original values") {
+ REQUIRE(std::ranges::equal(fn(), std::vector{1, 2}));
+ }
+ }
+}
+
TEST_CASE("generator: exceptions", "[generator]")
{
auto fn = []() -> nihil::generator<int> {
@@ -71,6 +86,8 @@ TEST_CASE("generator: exceptions", "[generator]")
REQUIRE_THROWS_AS(it++, std::runtime_error);
}
+#if 0
+// TODO: Re-enable this test once we have a standard-compliant generator.
TEST_CASE("generator: elements_of", "[generator]")
{
auto fn1 = [] -> nihil::generator<int> {
@@ -88,4 +105,5 @@ TEST_CASE("generator: elements_of", "[generator]")
REQUIRE(values == std::vector{1, 2, 3});
}
+#endif
} // anonymous namespace
diff --git a/nihil.core/nihil.core.ccm b/nihil.core/nihil.core.ccm
index 37ad032..7634026 100644
--- a/nihil.core/nihil.core.ccm
+++ b/nihil.core/nihil.core.ccm
@@ -8,6 +8,7 @@ export import :errc;
export import :error;
export import :features;
export import :flagset;
+export import :generator;
export import :guard;
export import :match;
export import :monad;
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 <typename Alloc>
-using byte_allocator_t = typename std::allocator_traits<
- std::remove_cvref_t<Alloc>>::template rebind_alloc<std::byte>;
-
-} // 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 <typename Ref, typename Value, typename... Args>
-struct coroutine_traits<nihil::generator<Ref, Value>, Args...>
-{
- using promise_type =
- nihil::generator_promise<nihil::generator<Ref, Value>, std::allocator<std::byte>>;
-};
-
-// Type-erased allocator with std::allocator_arg parameter
-export template <typename Ref, typename Value, typename Alloc, typename... Args>
-struct coroutine_traits<nihil::generator<Ref, Value>, allocator_arg_t, Alloc, Args...>
-{
-private:
- using byte_allocator = nihil::byte_allocator_t<Alloc>;
-
-public:
- using promise_type = nihil::generator_promise<nihil::generator<Ref, Value>, byte_allocator,
- true /*explicit Allocator*/>;
-};
-
-// Type-erased allocator with std::allocator_arg parameter (non-static member functions)
-export template <typename Ref, typename Value, typename This, typename Alloc, typename... Args>
-struct coroutine_traits<nihil::generator<Ref, Value>, This, allocator_arg_t, Alloc, Args...>
-{
-private:
- using byte_allocator = nihil::byte_allocator_t<Alloc>;
-
-public:
- using promise_type = nihil::generator_promise<nihil::generator<Ref, Value>, byte_allocator,
- true /*explicit Allocator*/>;
-};
-
-// Generator with specified allocator type
-export template <typename Ref, typename Value, typename Alloc, typename... Args>
-struct coroutine_traits<nihil::generator<Ref, Value, Alloc>, Args...>
-{
- using byte_allocator = nihil::byte_allocator_t<Alloc>;
-
-public:
- using promise_type =
- nihil::generator_promise<nihil::generator<Ref, Value, Alloc>, 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 <typename Range, typename Allocator = use_allocator_arg>
-struct elements_of {
- explicit constexpr elements_of(Range &&range) noexcept
- requires std::is_default_constructible_v<Allocator>
- : m_range(static_cast<Range &&>(range))
- {
- }
-
- constexpr elements_of(Range &&range, Allocator &&alloc) noexcept
- : m_range(static_cast<Range &&>(range))
- , m_alloc(static_cast<Allocator &&>(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<Range &&>(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 <typename Range>
-elements_of(Range &&) -> elements_of<Range>;
-
-export template <typename Range, typename Allocator>
-elements_of(Range &&, Allocator &&) -> elements_of<Range, Allocator>;
-
-} // 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 Ref,
- typename Value = std::remove_cvref_t<Ref>,
- 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 <cassert>
-
-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 <typename Ref, typename Value, typename Alloc>
-struct generator
-{
- using byte_allocator = byte_allocator_t<Alloc>;
-
-public:
- using promise_type = generator_promise<generator<Ref, Value, Alloc>, byte_allocator>;
- friend promise_type;
-
-private:
- using coroutine_handle = std::coroutine_handle<promise_type>;
-
-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<Ref>;
-
- 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<reference>(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 <typename Ref, typename Value>
-class generator<Ref, Value, use_allocator_arg>
-{
- using promise_base = generator_promise_base<Ref>;
-
-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<Ref>;
-
- 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<reference>(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 <typename Generator, typename ByteAllocator, bool ExplicitAllocator>
- friend struct generator_promise;
-
- template <typename Promise>
- explicit generator(std::coroutine_handle<Promise> 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_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 <typename Generator, typename ByteAllocator, bool ExplicitAllocator = false>
-struct generator_promise;
-
-export template <typename Ref, typename Value, typename Alloc, typename ByteAllocator,
- bool ExplicitAllocator>
-struct generator_promise<generator<Ref, Value, Alloc>, ByteAllocator, ExplicitAllocator> final
- : public generator_promise_base<Ref>,
- public promise_base_alloc<ByteAllocator>
-{
- generator_promise() noexcept
- : generator_promise_base<Ref>(
- std::coroutine_handle<generator_promise>::from_promise(*this))
- {
- }
-
- auto get_return_object() noexcept -> generator<Ref, Value, Alloc>
- {
- return generator<Ref, Value, Alloc>{
- std::coroutine_handle<generator_promise>::from_promise(*this)};
- }
-
- using generator_promise_base<Ref>::yield_value;
-
- template <std::ranges::range Rng>
- auto yield_value(nihil::elements_of<Rng> &&x) -> typename generator_promise_base<
- Ref>::template yield_sequence_awaiter<generator<Ref, Value, Alloc>>
- {
- 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<Ref, Value, Alloc> {
- for (auto &&e : rng)
- co_yield static_cast<decltype(e)>(e);
- }(std::forward<Rng>(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 <typename Ref>
-struct generator_promise_base
-{
- template <typename Ref2, typename Value, typename Alloc>
- 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<std::exception_ptr> m_exception;
- manual_lifetime<Ref> 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 <typename Promise>
- auto
- await_suspend(std::coroutine_handle<Promise> 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<Ref>)
- -> std::suspend_always
- {
- m_root->m_value.construct((Ref &&)x);
- return {};
- }
-
- template <typename T>
- requires(!std::is_reference_v<Ref>) && std::is_convertible_v<T, Ref>
- auto
- yield_value(T &&x) noexcept(std::is_nothrow_constructible_v<Ref, T>) -> std::suspend_always
- {
- m_root->m_value.construct((T &&)x);
- return {};
- }
-
- template <typename Gen>
- 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 <typename Promise>
- auto
- await_suspend(std::coroutine_handle<Promise> h) noexcept -> std::coroutine_handle<>
- {
- generator_promise_base &current = 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 <typename OValue, typename OAlloc>
- auto yield_value(nihil::elements_of<generator<Ref, OValue, OAlloc>> g) noexcept
- -> yield_sequence_awaiter<generator<Ref, OValue, OAlloc>>
-
- {
- return std::move(g).get();
- }
-
- template <std::ranges::range Rng, typename Allocator>
- auto yield_value(nihil::elements_of<Rng, Allocator> &&x)
- -> yield_sequence_awaiter<generator<Ref, std::remove_cvref_t<Ref>, Allocator>>
-
- {
- return [](std::allocator_arg_t, Allocator,
- auto &&rng) -> generator<Ref, std::remove_cvref_t<Ref>, Allocator> {
- for (auto &&e : rng)
- co_yield static_cast<decltype(e)>(e);
- }(std::allocator_arg, x.get_allocator(), std::forward<Rng>(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 <typename T>
-struct manual_lifetime {
- manual_lifetime() noexcept {}
- ~manual_lifetime() {}
-
- template <typename ...Args>
- auto construct(this manual_lifetime &self, Args && ...args)
- noexcept(std::is_nothrow_constructible_v<T, Args...>)
- -> T &
- {
- return *::new (static_cast<void*>(std::addressof(self.m_value)))
- T(static_cast<Args &&>(args)...);
- }
-
- void destruct(this manual_lifetime &self)
- noexcept(std::is_nothrow_destructible_v<T>)
- {
- 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<T&&>(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<T const &&>(self.m_value);
- }
-
-private:
- union {
- std::remove_const_t<T> m_value;
- };
-};
-
-template <typename T>
-struct manual_lifetime<T &> {
- 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 <typename T>
-struct manual_lifetime<T &&> {
- 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<T &&>(value);
- }
-
- void destruct(this manual_lifetime &) noexcept
- {
- }
-
- auto get(this manual_lifetime const &self) noexcept -> T &&
- {
- return static_cast<T &&>(*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 <typename T, typename U, typename Alloc>
-constexpr inline bool enable_view<nihil::generator<T, U, Alloc>> = 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<typename Alloc>
-struct promise_base_alloc
-{
- template<typename... Args>
- 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<void*>(std::addressof(get_allocator(frame, frame_size)));
- ::new (alloc_address) Alloc(std::move(alloc));
-
- return frame;
- }
-
- template<typename This, typename... Args>
- 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<std::byte*>(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<Alloc*>(
- static_cast<char*>(frame) + offset_of_allocator(frame_size));
- }
-
-};
-
-template<typename Alloc>
-requires (!allocator_needs_to_be_stored<Alloc>)
-struct promise_base_alloc<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<std::byte *>(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 <typename Alloc>
-constexpr bool allocator_needs_to_be_stored =
- !std::allocator_traits<Alloc>::is_always_equal::value ||
- !std::is_default_constructible_v<Alloc>;
-
-// 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
diff --git a/nihil.std/nihil.std.ccm b/nihil.std/nihil.std.ccm
index 349ab95..cb6a46d 100644
--- a/nihil.std/nihil.std.ccm
+++ b/nihil.std/nihil.std.ccm
@@ -421,6 +421,7 @@ using std::system_error;
// <type_traits>
using std::add_pointer_t;
+using std::conditional_t;
using std::false_type;
using std::invoke_result;
using std::is_convertible;
@@ -437,10 +438,14 @@ using std::is_move_assignable;
using std::is_move_assignable_v;
using std::is_nothrow_constructible;
using std::is_nothrow_constructible_v;
+using std::is_nothrow_copy_constructible;
+using std::is_nothrow_copy_constructible_v;
using std::is_nothrow_destructible;
using std::is_nothrow_destructible_v;
using std::is_nothrow_move_constructible;
using std::is_nothrow_move_constructible_v;
+using std::is_pointer;
+using std::is_pointer_v;
using std::is_reference;
using std::is_reference_v;
using std::is_same;
@@ -448,6 +453,7 @@ using std::is_same_v;
using std::remove_const_t;
using std::remove_cv_t;
using std::remove_cvref_t;
+using std::remove_reference_t;
using std::true_type;
// <unordered_set>
@@ -463,6 +469,7 @@ using std::move;
using std::pair;
// <variant>
+using std::get;
using std::get_if;
using std::monostate;
using std::variant;