diff --git a/src/Core/CMakeLists.txt b/src/Core/CMakeLists.txt index 1191bb9e8..d6938ea77 100644 --- a/src/Core/CMakeLists.txt +++ b/src/Core/CMakeLists.txt @@ -17,7 +17,6 @@ CONFIGURE_FILE("core.tmpl" "${CMAKE_CURRENT_BINARY_DIR}/include/litefx/core.h") # Collect header & source files. SET(CORE_HEADERS "include/litefx/containers.hpp" - "include/litefx/generator.hpp" "include/litefx/string.hpp" "include/litefx/traits.hpp" "include/litefx/exceptions.hpp" diff --git a/src/Core/include/litefx/containers.hpp b/src/Core/include/litefx/containers.hpp index 4f096aa6b..e723edb99 100644 --- a/src/Core/include/litefx/containers.hpp +++ b/src/Core/include/litefx/containers.hpp @@ -19,12 +19,7 @@ #include #include #include - -#if __has_include() -#inclue -#else -#include "generator.hpp" -#endif +#include #include "traits.hpp" #include "string.hpp" diff --git a/src/Core/include/litefx/generator.hpp b/src/Core/include/litefx/generator.hpp deleted file mode 100644 index 8b4980713..000000000 --- a/src/Core/include/litefx/generator.hpp +++ /dev/null @@ -1,806 +0,0 @@ -#ifndef __STD_GENERATOR_INCLUDED -#define __STD_GENERATOR_INCLUDED -/////////////////////////////////////////////////////////////////////////////// -// 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) -/////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#if __has_include() -#include -#else -// Fallback for older experimental implementations of coroutines. -#include -namespace std { - using std::experimental::coroutine_handle; - using std::experimental::coroutine_traits; - using std::experimental::noop_coroutine; - using std::experimental::suspend_always; - using std::experimental::suspend_never; -} // namespace std -#endif - -#include -#include -#include -#include -#include -#include -#include - -#if __has_include() -# include -#else - -// Placeholder implementation of the bits we need from header -// when we don't have the header (e.g. Clang 12 and earlier). -namespace std { - - // Don't create naming conflicts with recent libc++ which defines std::iter_reference_t - // in but doesn't yet provide a header. - template - using __iter_reference_t = decltype(*std::declval<_T&>()); - - template - using iter_value_t = - typename std::iterator_traits>::value_type; - - namespace ranges { - - namespace __begin { - void begin(); - - struct _fn { - template - requires requires(_Range& __r) { - __r.begin(); - } - auto operator()(_Range&& __r) const - noexcept(noexcept(__r.begin())) - -> decltype(__r.begin()) { - return __r.begin(); - } - - template - requires - (!requires(_Range& __r) { __r.begin(); }) && - requires(_Range& __r) { begin(__r); } - auto operator()(_Range&& __r) const - noexcept(noexcept(begin(__r))) - -> decltype(begin(__r)) { - return begin(__r); - } - }; - - } // namespace __begin - - inline namespace __begin_cpo { - inline constexpr __begin::_fn begin = {}; - } - - namespace __end { - void end(); - - struct _fn { - template - requires requires(_Range& __r) { __r.end(); } - auto operator()(_Range&& __r) const - noexcept(noexcept(__r.end())) - -> decltype(__r.end()) { - return __r.end(); - } - - template - requires - (!requires(_Range& __r) { __r.end(); }) && - requires(_Range& __r) { end(__r); } - auto operator()(_Range&& __r) const - noexcept(noexcept(end(__r))) - -> decltype(end(__r)) { - return end(__r); - } - }; - } // namespace __end - - inline namespace _end_cpo { - inline constexpr __end::_fn end = {}; - } - - template - using iterator_t = decltype(begin(std::declval<_Range>())); - - template - using sentinel_t = decltype(end(std::declval<_Range>())); - - template - using range_reference_t = __iter_reference_t>; - - template - using range_value_t = iter_value_t>; - - template - concept range = requires(_T & __t) { - ranges::begin(__t); - ranges::end(__t); - }; - - } // namespace ranges -} // namespace std - -#endif // !__has_include() - - -namespace std { - - template - class __manual_lifetime { - public: - __manual_lifetime() noexcept {} - ~__manual_lifetime() {} - - template - _T& construct(_Args&&... __args) noexcept(std::is_nothrow_constructible_v<_T, _Args...>) { - return *::new (static_cast(std::addressof(__value_))) _T((_Args&&)__args...); - } - - void destruct() noexcept(std::is_nothrow_destructible_v<_T>) { - __value_.~_T(); - } - - _T& get() & noexcept { - return __value_; - } - _T&& get() && noexcept { - return static_cast<_T&&>(__value_); - } - const _T& get() const& noexcept { - return __value_; - } - const _T&& get() const&& noexcept { - return static_cast(__value_); - } - - private: - union { - std::remove_const_t<_T> __value_; - }; - }; - - template - class __manual_lifetime<_T&> { - public: - __manual_lifetime() noexcept : __value_(nullptr) {} - ~__manual_lifetime() {} - - _T& construct(_T& __value) noexcept { - __value_ = std::addressof(__value); - return __value; - } - - void destruct() noexcept {} - - _T& get() const noexcept { - return *__value_; - } - - private: - _T* __value_; - }; - - template - class __manual_lifetime<_T&&> { - public: - __manual_lifetime() noexcept : __value_(nullptr) {} - ~__manual_lifetime() {} - - _T&& construct(_T&& __value) noexcept { - __value_ = std::addressof(__value); - return static_cast<_T&&>(__value); - } - - void destruct() noexcept {} - - _T&& get() const noexcept { - return static_cast<_T&&>(*__value_); - } - - private: - _T* __value_; - }; - - struct use_allocator_arg {}; - - namespace ranges { - - template - struct elements_of { - explicit constexpr elements_of(_Rng&& __rng) noexcept - requires std::is_default_constructible_v<_Allocator> - : _range(static_cast<_Rng&&>(__rng)) - {} - - constexpr elements_of(_Rng&& __rng, _Allocator&& __alloc) noexcept - : _range((_Rng&&)__rng), __alloc((_Allocator&&)__alloc) {} - - constexpr elements_of(elements_of&&) noexcept = default; - - constexpr elements_of(const elements_of&) = delete; - constexpr elements_of& operator=(const elements_of&) = delete; - constexpr elements_of& operator=(elements_of&&) = delete; - - constexpr _Rng&& get() noexcept { - return static_cast<_Rng&&>(_range); - } - - constexpr _Allocator get_allocator() const noexcept { - return __alloc; - } - - private: - [[no_unique_address]] _Allocator __alloc; // \expos - _Rng&& _range; // \expos - }; - - template - elements_of(_Rng&&) -> elements_of<_Rng>; - - template - elements_of(_Rng&&, Allocator&&) -> elements_of<_Rng, Allocator>; - - } // namespace ranges - - template - static 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. - constexpr size_t __aligned_allocation_size(size_t s, size_t a) { - return (s + a - 1) & ~(a - 1); - } - - - template , - typename _Allocator = use_allocator_arg> - class generator; - - template - class __promise_base_alloc { - static constexpr std::size_t __offset_of_allocator(std::size_t __frameSize) noexcept { - return __aligned_allocation_size(__frameSize, alignof(_Alloc)); - } - - static constexpr std::size_t __padded_frame_size(std::size_t __frameSize) noexcept { - return __offset_of_allocator(__frameSize) + sizeof(_Alloc); - } - - static _Alloc& __get_allocator(void* __frame, std::size_t __frameSize) noexcept { - return *reinterpret_cast<_Alloc*>( - static_cast(__frame) + __offset_of_allocator(__frameSize)); - } - - public: - template - static void* operator new(std::size_t __frameSize, std::allocator_arg_t, _Alloc __alloc, _Args&...) { - void* __frame = __alloc.allocate(__padded_frame_size(__frameSize)); - - // Store allocator at end of the coroutine frame. - // Assuming the allocator's move constructor is non-throwing (a requirement for allocators) - ::new (static_cast(std::addressof(__get_allocator(__frame, __frameSize)))) _Alloc(std::move(__alloc)); - - return __frame; - } - - template - static void* operator new(std::size_t __frameSize, _This&, std::allocator_arg_t, _Alloc __alloc, _Args&...) { - return __promise_base_alloc::operator new(__frameSize, std::allocator_arg, std::move(__alloc)); - } - - static void operator delete(void* __ptr, std::size_t __frameSize) noexcept { - _Alloc& __alloc = __get_allocator(__ptr, __frameSize); - _Alloc __localAlloc(std::move(__alloc)); - __alloc.~Alloc(); - __localAlloc.deallocate(static_cast(__ptr), __padded_frame_size(__frameSize)); - } - }; - - template - requires (!__allocator_needs_to_be_stored<_Alloc>) - class __promise_base_alloc<_Alloc> { - public: - static void* operator new(std::size_t __size) { - _Alloc __alloc; - return __alloc.allocate(__size); - } - - static void operator delete(void* __ptr, std::size_t __size) noexcept { - _Alloc __alloc; - __alloc.deallocate(static_cast(__ptr), __size); - } - }; - - template - struct __generator_promise_base - { - template - friend class generator; - - __generator_promise_base* __root_; - std::coroutine_handle<> __parentOrLeaf_; - // 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 __exception_; - __manual_lifetime<_Ref> __value_; - - explicit __generator_promise_base(std::coroutine_handle<> thisCoro) noexcept - : __root_(this) - , __parentOrLeaf_(thisCoro) - {} - - ~__generator_promise_base() { - if (__root_ != this) { - // This coroutine was used as a nested generator and so will - // have constructed its __exception_ member which needs to be - // destroyed here. - __exception_.destruct(); - } - } - - std::suspend_always initial_suspend() noexcept { - return {}; - } - - void return_void() noexcept {} - - void unhandled_exception() { - if (__root_ != this) { - __exception_.get() = std::current_exception(); - } - else { - throw; - } - } - - // Transfers control back to the parent of a nested coroutine - struct __final_awaiter { - bool await_ready() noexcept { - return false; - } - - template - std::coroutine_handle<> - await_suspend(std::coroutine_handle<_Promise> __h) noexcept { - _Promise& __promise = __h.promise(); - __generator_promise_base& __root = *__promise.__root_; - if (&__root != &__promise) { - auto __parent = __promise.__parentOrLeaf_; - __root.__parentOrLeaf_ = __parent; - return __parent; - } - return std::noop_coroutine(); - } - - void await_resume() noexcept {} - }; - - __final_awaiter final_suspend() noexcept { - return {}; - } - - std::suspend_always yield_value(_Ref&& __x) - noexcept(std::is_nothrow_move_constructible_v<_Ref>) { - __root_->__value_.construct((_Ref&&)__x); - return {}; - } - - template - requires - (!std::is_reference_v<_Ref>) && - std::is_convertible_v<_T, _Ref> - std::suspend_always yield_value(_T&& __x) - noexcept(std::is_nothrow_constructible_v<_Ref, _T>) { - __root_->__value_.construct((_T&&)__x); - return {}; - } - - template - struct __yield_sequence_awaiter { - _Gen __gen_; - - __yield_sequence_awaiter(_Gen&& __g) noexcept - // Taking ownership of the generator ensures frame are destroyed - // in the reverse order of their execution. - : __gen_((_Gen&&)__g) { - } - - bool await_ready() noexcept { - return false; - } - - // set the parent, root and exceptions pointer and - // resume the nested - template - std::coroutine_handle<> - await_suspend(std::coroutine_handle<_Promise> __h) noexcept { - __generator_promise_base& __current = __h.promise(); - __generator_promise_base& __nested = *__gen_.__get_promise(); - __generator_promise_base& __root = *__current.__root_; - - __nested.__root_ = __current.__root_; - __nested.__parentOrLeaf_ = __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.__exception_.construct(); - __root.__parentOrLeaf_ = __gen_.__get_coro(); - - // Immediately resume the nested coroutine (nested generator) - return __gen_.__get_coro(); - } - - void await_resume() { - __generator_promise_base& __nestedPromise = *__gen_.__get_promise(); - if (__nestedPromise.__exception_.get()) { - std::rethrow_exception(std::move(__nestedPromise.__exception_.get())); - } - } - }; - - template - __yield_sequence_awaiter> - yield_value(std::ranges::elements_of> __g) noexcept { - return std::move(__g).get(); - } - - template - __yield_sequence_awaiter, _Allocator>> - yield_value(std::ranges::elements_of<_Rng, _Allocator>&& __x) { - return [](allocator_arg_t, _Allocator alloc, auto&& __rng) -> generator<_Ref, std::remove_cvref_t<_Ref>, _Allocator> { - for (auto&& e : __rng) - co_yield static_cast(e); - }(std::allocator_arg, __x.get_allocator(), std::forward<_Rng>(__x.get())); - } - - void resume() { - __parentOrLeaf_.resume(); - } - - // Disable use of co_await within this coroutine. - void await_transform() = delete; - }; - - template - struct __generator_promise; - - template - struct __generator_promise, _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)) - {} - - generator<_Ref, _Value, _Alloc> get_return_object() noexcept { - return generator<_Ref, _Value, _Alloc>{ - std::coroutine_handle<__generator_promise>::from_promise(*this) - }; - } - - using __generator_promise_base<_Ref>::yield_value; - - template - typename __generator_promise_base<_Ref>::template __yield_sequence_awaiter> - yield_value(std::ranges::elements_of<_Rng>&& __x) { - 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(e); - }(std::forward<_Rng>(__x.get())); - } - }; - - template - using __byte_allocator_t = typename std::allocator_traits>::template rebind_alloc; - - - // Type-erased allocator with default allocator behaviour. - template - struct coroutine_traits, _Args...> { - using promise_type = __generator_promise, std::allocator>; - }; - - // Type-erased allocator with std::allocator_arg parameter - template - struct coroutine_traits, allocator_arg_t, _Alloc, _Args...> { - private: - using __byte_allocator = __byte_allocator_t<_Alloc>; - public: - using promise_type = __generator_promise, __byte_allocator, true /*explicit Allocator*/>; - }; - - // Type-erased allocator with std::allocator_arg parameter (non-static member functions) - template - struct coroutine_traits, _This, allocator_arg_t, _Alloc, _Args...> { - private: - using __byte_allocator = __byte_allocator_t<_Alloc>; - public: - using promise_type = __generator_promise, __byte_allocator, true /*explicit Allocator*/>; - }; - - // Generator with specified allocator type - template - struct coroutine_traits, _Args...> { - using __byte_allocator = __byte_allocator_t<_Alloc>; - public: - using promise_type = __generator_promise, __byte_allocator>; - }; - - - // TODO : make layout compatible promise casts possible - template - class generator { - using __byte_allocator = __byte_allocator_t<_Alloc>; - 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 - : __coro_(std::exchange(__other.__coro_, {})) - , __started_(std::exchange(__other.__started_, false)) { - } - - ~generator() noexcept { - if (__coro_) { - if (__started_ && !__coro_.done()) { - __coro_.promise().__value_.destruct(); - } - __coro_.destroy(); - } - } - - generator& operator=(generator&& g) noexcept { - swap(g); - return *this; - } - - void swap(generator& __other) noexcept { - std::swap(__coro_, __other.__coro_); - std::swap(__started_, __other.__started_); - } - - struct sentinel {}; - - class iterator { - public: - 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 - : __coro_(std::exchange(__other.__coro_, {})) { - } - - iterator& operator=(iterator&& __other) { - std::swap(__coro_, __other.__coro_); - return *this; - } - - ~iterator() { - } - - friend bool operator==(const iterator& it, sentinel) noexcept { - return it.__coro_.done(); - } - - iterator& operator++() { - __coro_.promise().__value_.destruct(); - __coro_.promise().resume(); - return *this; - } - void operator++(int) { - (void)operator++(); - } - - reference operator*() const noexcept { - return static_cast(__coro_.promise().__value_.get()); - } - - private: - friend generator; - - explicit iterator(__coroutine_handle __coro) noexcept - : __coro_(__coro) {} - - __coroutine_handle __coro_; - }; - - iterator begin() { - assert(__coro_); - assert(!__started_); - __started_ = true; - __coro_.resume(); - return iterator{ __coro_ }; - } - - sentinel end() noexcept { - return {}; - } - - private: - explicit generator(__coroutine_handle __coro) noexcept - : __coro_(__coro) { - } - - public: // to get around access restrictions for __yield_sequence_awaitable - std::coroutine_handle<> __get_coro() noexcept { return __coro_; } - promise_type* __get_promise() noexcept { return std::addressof(__coro_.promise()); } - - private: - __coroutine_handle __coro_; - bool __started_ = false; - }; - - // Specialisation for type-erased allocator implementation. - template - class generator<_Ref, _Value, use_allocator_arg> { - using __promise_base = __generator_promise_base<_Ref>; - public: - - generator() noexcept - : __promise_(nullptr) - , __coro_() - , __started_(false) - {} - - generator(generator&& __other) noexcept - : __promise_(std::exchange(__other.__promise_, nullptr)) - , __coro_(std::exchange(__other.__coro_, {})) - , __started_(std::exchange(__other.__started_, false)) { - } - - ~generator() noexcept { - if (__coro_) { - if (__started_ && !__coro_.done()) { - __promise_->__value_.destruct(); - } - __coro_.destroy(); - } - } - - generator& operator=(generator g) noexcept { - swap(g); - return *this; - } - - void swap(generator& __other) noexcept { - std::swap(__promise_, __other.__promise_); - std::swap(__coro_, __other.__coro_); - std::swap(__started_, __other.__started_); - } - - struct sentinel {}; - - class iterator { - public: - 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 - : __promise_(std::exchange(__other.__promise_, nullptr)) - , __coro_(std::exchange(__other.__coro_, {})) - {} - - iterator& operator=(iterator&& __other) { - __promise_ = std::exchange(__other.__promise_, nullptr); - __coro_ = std::exchange(__other.__coro_, {}); - return *this; - } - - ~iterator() = default; - - friend bool operator==(const iterator& it, sentinel) noexcept { - return it.__coro_.done(); - } - - iterator& operator++() { - __promise_->__value_.destruct(); - __promise_->resume(); - return *this; - } - - void operator++(int) { - (void)operator++(); - } - - reference operator*() const noexcept { - return static_cast(__promise_->__value_.get()); - } - - private: - friend generator; - - explicit iterator(__promise_base* __promise, std::coroutine_handle<> __coro) noexcept - : __promise_(__promise) - , __coro_(__coro) - {} - - __promise_base* __promise_; - std::coroutine_handle<> __coro_; - }; - - iterator begin() { - assert(__coro_); - assert(!__started_); - __started_ = true; - __coro_.resume(); - return iterator{ __promise_, __coro_ }; - } - - sentinel end() noexcept { - return {}; - } - - private: - template - friend struct __generator_promise; - - template - explicit generator(std::coroutine_handle<_Promise> __coro) noexcept - : __promise_(std::addressof(__coro.promise())) - , __coro_(__coro) - {} - - public: // to get around access restrictions for __yield_sequence_awaitable - std::coroutine_handle<> __get_coro() noexcept { return __coro_; } - __promise_base* __get_promise() noexcept { return __promise_; } - - private: - __promise_base* __promise_; - std::coroutine_handle<> __coro_; - bool __started_ = false; - }; - -#if __has_include() - namespace ranges { - - template - constexpr inline bool enable_view> = true; - - } // namespace ranges -#endif - -} // namespace std - -#endif // __STD_GENERATOR_INCLUDED \ No newline at end of file