Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/allocator_of.hpp -*-C++-*-
// include/beman/execution/detail/task/allocator_of.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ALLOCATOR_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_ALLOCATOR_OF
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_OF

#include <concepts>
#include <cstddef>
Expand Down
149 changes: 149 additions & 0 deletions include/beman/execution/detail/task/allocator_support.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// include/beman/execution/detail/task/allocator_support.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_SUPPORT
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_SUPPORT

#include <concepts>
#include <cstddef>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>

// ----------------------------------------------------------------------------

namespace beman::execution::detail {
struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) allocator_support_allocation_unit {
std::byte bytes[__STDCPP_DEFAULT_NEW_ALIGNMENT__];
};

static_assert(sizeof(allocator_support_allocation_unit) == __STDCPP_DEFAULT_NEW_ALIGNMENT__);
static_assert(alignof(allocator_support_allocation_unit) == __STDCPP_DEFAULT_NEW_ALIGNMENT__);

struct allocator_support_header {
void (*deallocate)(void*, std::size_t) noexcept;
std::size_t count;
std::size_t palloc_offset;
};

template <typename Alloc>
using allocator_support_alloc_t = std::remove_cvref_t<Alloc>;

template <typename Alloc>
using allocator_support_palloc_t = typename std::allocator_traits<
allocator_support_alloc_t<Alloc>>::template rebind_alloc<allocator_support_allocation_unit>;

template <typename Alloc>
concept allocator_support_allocator_like = requires { typename allocator_support_alloc_t<Alloc>::value_type; };

template <typename Allocator, typename Alloc>
concept allocator_support_allocator_arg =
allocator_support_allocator_like<Alloc> && requires(allocator_support_alloc_t<Alloc>& alloc, std::size_t size) {
typename allocator_support_palloc_t<Alloc>;
typename std::allocator_traits<allocator_support_palloc_t<Alloc>>::pointer;
requires std::same_as<typename std::allocator_traits<allocator_support_palloc_t<Alloc>>::pointer,
allocator_support_allocation_unit*>;
requires(alignof(allocator_support_palloc_t<Alloc>) <= alignof(allocator_support_allocation_unit));
allocator_support_palloc_t<Alloc>(alloc);
std::allocator_traits<allocator_support_palloc_t<Alloc>>::allocate(
std::declval<allocator_support_palloc_t<Alloc>&>(), size);
};

/*!
* \brief Utility adding allocator support to type by embedding the allocator
* \headerfile beman/execution/task.hpp <beman/execution/task.hpp>
*
* To add allocator support using this class just publicly inherit from
* allocator_support<Allocator, YourPromiseType>. This utility is probably
* only useful for coroutine promise types.
*
* This struct is a massive hack, primarily support allocators for coroutines.
* The memory for coroutines is implicitly managed and there isn't a way to
* provide the memory directly. Instead, the promise_type can overload an
* operator new and use a leading std::allocator_arg/allocator pair when it
* is present. Even worse, the operator delete only gets passed a pointer to
* delete and a size. To determine the correct allocator the operator delete
* stores a type-erased deallocation header and the rebound allocator in the
* allocation block.
*/
template <typename Allocator>
struct allocator_support {
static std::size_t align_up(std::size_t value, std::size_t alignment) {
return ((value + alignment - 1u) / alignment) * alignment;
}

static std::size_t header_offset(std::size_t size) {
return allocator_support::align_up(size, alignof(allocator_support_header));
}

static allocator_support_header* get_header(void* ptr, std::size_t size) {
ptr = static_cast<std::byte*>(ptr) + allocator_support::header_offset(size);
return ::std::launder(reinterpret_cast<allocator_support_header*>(ptr));
}

template <typename PAlloc>
static void deallocate_with(void* ptr, std::size_t size) noexcept {
using palloc_traits = std::allocator_traits<PAlloc>;

allocator_support_header* header{allocator_support::get_header(ptr, size)};
auto* palloc_ptr{
::std::launder(reinterpret_cast<PAlloc*>(static_cast<std::byte*>(ptr) + header->palloc_offset))};
PAlloc palloc{*palloc_ptr};
std::size_t count{header->count};
palloc_ptr->~PAlloc();
palloc_traits::deallocate(palloc, static_cast<allocator_support_allocation_unit*>(ptr), count);
}

template <typename Alloc>
requires allocator_support_allocator_arg<Allocator, Alloc>
static void* allocate(std::size_t size, Alloc alloc) {
using palloc_t = allocator_support_palloc_t<Alloc>;
using palloc_traits = std::allocator_traits<palloc_t>;

palloc_t palloc{alloc};
std::size_t header_offset{allocator_support::header_offset(size)};
std::size_t palloc_offset{
allocator_support::align_up(header_offset + sizeof(allocator_support_header), alignof(palloc_t))};
std::size_t count{(palloc_offset + sizeof(palloc_t) + sizeof(allocator_support_allocation_unit) - 1u) /
sizeof(allocator_support_allocation_unit)};

allocator_support_allocation_unit* ptr{palloc_traits::allocate(palloc, count)};
try {
new (static_cast<std::byte*>(static_cast<void*>(ptr)) + header_offset)
allocator_support_header{&allocator_support::deallocate_with<palloc_t>, count, palloc_offset};
new (static_cast<std::byte*>(static_cast<void*>(ptr)) + palloc_offset) palloc_t(palloc);
} catch (...) {
palloc_traits::deallocate(palloc, ptr, count);
throw;
}
return ptr;
}

static void* operator new(std::size_t size) { return allocator_support::allocate(size, Allocator{}); }

template <typename Alloc, typename... A>
requires allocator_support_allocator_arg<Allocator, Alloc>
static void* operator new(std::size_t size, std::allocator_arg_t, Alloc alloc, A&&...) {
return allocator_support::allocate(size, alloc);
}

template <typename This, typename Alloc, typename... A>
requires allocator_support_allocator_arg<Allocator, Alloc>
static void* operator new(std::size_t size, const This&, std::allocator_arg_t, Alloc alloc, A&&...) {
return allocator_support::allocate(size, alloc);
}

template <typename... A>
static void operator delete(void* ptr, std::size_t size, const A&...) noexcept {
allocator_support::operator delete(ptr, size);
}
static void operator delete(void* ptr, std::size_t size) noexcept {
allocator_support::get_header(ptr, size)->deallocate(ptr, size);
}
};
} // namespace beman::execution::detail

// ----------------------------------------------------------------------------

#endif
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/completion.hpp -*-C++-*-
// include/beman/execution/detail/task/completion.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION
#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_COMPLETION
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_COMPLETION

#include <beman/execution/execution.hpp>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/error_types_of.hpp -*-C++-*-
// include/beman/execution/detail/task/error_types_of.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CONTEXT_ERROR_TYPES_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_CONTEXT_ERROR_TYPES_OF
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ERROR_TYPES_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ERROR_TYPES_OF

#include <beman/execution/execution.hpp>
#include <exception>
Expand All @@ -25,4 +25,4 @@ using error_types_of_t = typename error_types_of<Context>::type;

// ----------------------------------------------------------------------------

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CONTEXT_ERROR_TYPES_OF
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ERROR_TYPES_OF
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/find_allocator.hpp -*-C++-*-
// include/beman/execution/detail/task/find_allocator.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_FIND_ALLOCATOR
#define INCLUDED_BEMAN_EXECUTION_DETAIL_FIND_ALLOCATOR
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_FIND_ALLOCATOR
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_FIND_ALLOCATOR

#include <concepts>
#include <memory>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/handle.hpp -*-C++-*-
// include/beman/execution/detail/task/handle.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_HANDLE
#define INCLUDED_BEMAN_EXECUTION_DETAIL_HANDLE
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_HANDLE
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_HANDLE

#include <beman/execution/execution.hpp>
#include <cassert>
Expand Down
58 changes: 58 additions & 0 deletions include/beman/execution/detail/task/infallible_scheduler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// include/beman/execution/detail/task/infallible_scheduler.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_INFALLIBLE_SCHEDULER
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_INFALLIBLE_SCHEDULER

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
import std;
#else
#include <concepts>
#include <utility>
#endif
#ifdef BEMAN_HAS_MODULES
import beman.execution.detail.completion_signatures;
import beman.execution.detail.completion_signatures_of_t;
import beman.execution.detail.env;
import beman.execution.detail.schedule;
import beman.execution.detail.scheduler;
import beman.execution.detail.set_stopped;
import beman.execution.detail.set_value;
import beman.execution.detail.stop_token_of_t;
import beman.execution.detail.unstoppable_token;
#else
#include <beman/execution/detail/completion_signatures.hpp>
#include <beman/execution/detail/completion_signatures_of_t.hpp>
#include <beman/execution/detail/env.hpp>
#include <beman/execution/detail/schedule.hpp>
#include <beman/execution/detail/scheduler.hpp>
#include <beman/execution/detail/set_stopped.hpp>
#include <beman/execution/detail/set_value.hpp>
#include <beman/execution/detail/stop_token_of_t.hpp>
#include <beman/execution/detail/unstoppable_token.hpp>
#endif

// ----------------------------------------------------------------------------

namespace beman::execution::detail {
template <class Sch, class Env, class... Comp>
concept completes_with =
::std::same_as<::beman::execution::completion_signatures<Comp...>,
::beman::execution::
completion_signatures_of_t<decltype(::beman::execution::schedule(::std::declval<Sch>())), Env>>;

template <class Sch, class Env>
concept infallible_scheduler =
(::beman::execution::scheduler<Sch>) &&
(::beman::execution::detail::completes_with<Sch, Env, ::beman::execution::set_value_t()> ||
(!::beman::execution::unstoppable_token<::beman::execution::stop_token_of_t<Env>> &&
(::beman::execution::detail::
completes_with<Sch, Env, ::beman::execution::set_value_t(), ::beman::execution::set_stopped_t()> ||
::beman::execution::detail::
completes_with<Sch, Env, ::beman::execution::set_stopped_t(), ::beman::execution::set_value_t()>)));
} // namespace beman::execution::detail

// ----------------------------------------------------------------------------

#endif
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/logger.hpp -*-C++-*-
// include/beman/execution/detail/task/logger.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_LOGGER
#define INCLUDED_BEMAN_EXECUTION_DETAIL_LOGGER
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_LOGGER
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_LOGGER

#include <algorithm>
#include <iterator>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
// include/beman/execution/detail/poly.hpp -*-C++-*-
// include/beman/execution/detail/task/poly.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_POLY
#define INCLUDED_BEMAN_EXECUTION_DETAIL_POLY
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_POLY
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_POLY

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
import std;
#else
#include <array>
#include <concepts>
#include <cstddef>
#include <new>
#include <utility>
#endif

// ----------------------------------------------------------------------------

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/promise_env.hpp -*-C++-*-
// include/beman/execution/detail/task/promise_env.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_PROMISE_ENV
#define INCLUDED_BEMAN_EXECUTION_DETAIL_PROMISE_ENV
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_PROMISE_ENV
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_PROMISE_ENV

#include <beman/execution/execution.hpp>
#include <utility>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/state_rep.hpp -*-C++-*-
// include/beman/execution/detail/task/state_rep.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_STATE_REP
#define INCLUDED_BEMAN_EXECUTION_DETAIL_STATE_REP
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STATE_REP
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STATE_REP

#include <beman/execution/execution.hpp>
#include <type_traits>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/stop_source_of.hpp -*-C++-*-
// include/beman/execution/detail/task/stop_source.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_STOP_SOURCE_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_STOP_SOURCE_OF
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STOP_SOURCE
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STOP_SOURCE

#include <beman/execution/stop_token.hpp>

Expand All @@ -24,4 +24,4 @@ using stop_source_of_t = typename stop_source_of<Context>::type;

// ----------------------------------------------------------------------------

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_STOP_SOURCE_OF
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STOP_SOURCE
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// include/beman/execution/detail/sub_visit.hpp -*-C++-*-
// include/beman/execution/detail/task/sub_visit.hpp -*-C++-*-
// ----------------------------------------------------------------------------
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_SUB_VISIT
#define INCLUDED_BEMAN_EXECUTION_DETAIL_SUB_VISIT
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SUB_VISIT
#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SUB_VISIT

#include <utility>
#include <variant>
Expand Down
Loading
Loading