Skip to content
Open
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
39 changes: 39 additions & 0 deletions include/beman/execution/detail/allocator_of.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// include/beman/execution/detail/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

#include <concepts>
#include <cstddef>
#include <memory>

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

namespace beman::execution::detail {
/*!
* \brief Utility to get an allocator type from a context
* \headerfile beman/execution/task.hpp <beman/execution/task.hpp>
* \internal
*/
template <typename>
struct allocator_of {
using type = std::allocator<std::byte>;
};
template <typename Context>
requires requires { typename Context::allocator_type; }
struct allocator_of<Context> {
using type = typename Context::allocator_type;
static_assert(
requires(type& a, std::size_t s, std::byte* ptr) {
{ a.allocate(s) } -> std::same_as<std::byte*>;
a.deallocate(ptr, s);
}, "The allocator_type needs to be an allocator of std::byte");
};
template <typename Context>
using allocator_of_t = typename allocator_of<Context>::type;
} // namespace beman::execution::detail

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

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

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION
#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION

#include <beman/execution/execution.hpp>

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

namespace beman::execution::detail {
template <typename R>
struct completion {
using type = ::beman::execution::set_value_t(R);
};
template <>
struct completion<void> {
using type = ::beman::execution::set_value_t();
};

template <typename R>
using completion_t = typename beman::execution::detail::completion<R>::type;

} // namespace beman::execution::detail

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

#endif
28 changes: 28 additions & 0 deletions include/beman/execution/detail/error_types_of.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// include/beman/execution/detail/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

#include <beman/execution/execution.hpp>
#include <exception>

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

namespace beman::execution::detail {
template <typename>
struct error_types_of {
using type = ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>;
};
template <typename Context>
requires requires { typename Context::error_types; }
struct error_types_of<Context> {
using type = typename Context::error_types;
};
template <typename Context>
using error_types_of_t = typename error_types_of<Context>::type;
} // namespace beman::execution::detail

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

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CONTEXT_ERROR_TYPES_OF
47 changes: 47 additions & 0 deletions include/beman/execution/detail/find_allocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// include/beman/execution/detail/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

#include <concepts>
#include <memory>

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

namespace beman::execution::detail {
/*!
* \brief Utility locating an allocator_arg/allocator pair
* \headerfile beman/execution/task.hpp <beman/execution/task.hpp>
* \internal
*/
template <typename Allocator>
Allocator find_allocator() {
return Allocator();
}
template <typename Allocator>
Allocator find_allocator(const std::allocator_arg_t&) {
static_assert(
requires {
{ Allocator() } -> std::same_as<void>;
}, "There needs to be an allocator argument following std::allocator_arg");
return Allocator();
}

template <typename Allocator, typename Alloc, typename... A>
Allocator find_allocator(const std::allocator_arg_t&, const Alloc& alloc, const A&...) {
static_assert(
requires(const Alloc& a) { Allocator(a); },
"The allocator needs to be constructible from the argument following std::allocator");
return Allocator(alloc);
}
template <typename Allocator, typename A0, typename... A>
Allocator find_allocator(A0 const&, const A&... a) {
return ::beman::execution::detail::find_allocator<Allocator>(a...);
}

} // namespace beman::execution::detail

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

#endif
49 changes: 49 additions & 0 deletions include/beman/execution/detail/handle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// include/beman/execution/detail/handle.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_HANDLE
#define INCLUDED_BEMAN_EXECUTION_DETAIL_HANDLE

#include <beman/execution/execution.hpp>
#include <cassert>
#include <coroutine>
#include <memory>
#include <utility>

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

namespace beman::execution::detail {
template <typename P>
class handle {
private:
struct deleter {
auto operator()(P* p) noexcept -> void {
if (p) {
std::coroutine_handle<P>::from_promise(*p).destroy();
}
}
};
std::unique_ptr<P, deleter> h;

public:
explicit handle(P* p) : h(p) {}
auto reset() -> void { this->h.reset(); }
template <typename... A>
auto start(A&&... a) noexcept -> auto {
return this->h->start(::std::forward<A>(a)...);
}
auto release() -> ::std::coroutine_handle<P> {
return ::std::coroutine_handle<P>::from_promise(*this->h.release());
}
P* get() const noexcept { return this->h.get(); }
auto get_env() const noexcept {
assert(this->h.get());
return ::beman::execution::get_env(*this->h);
}
};

} // namespace beman::execution::detail

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

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

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_LOGGER
#define INCLUDED_BEMAN_EXECUTION_DETAIL_LOGGER

#include <algorithm>
#include <iterator>
#include <iostream>

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

namespace beman::execution::detail {
struct logger {
static auto level(int i) -> int {
static int rc{};
return rc += i;
}
::std::ostream& log(const char* pre, const char* msg) {
::std::fill_n(::std::ostreambuf_iterator<char>(std::cout.rdbuf()), level(0), ' ');
std::cout << pre;
return std::cout << msg << "\n";
}
::std::ostream& log(const char* msg) { return log("| ", msg); }
const char* msg;
explicit logger(const char* m) : msg(m) {
level(1);
log("\\ ", this->msg);
}
logger(logger&&) = delete;
~logger() {
log("/ ", this->msg);
level(-1);
}
};
} // namespace beman::execution::detail

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

#endif
79 changes: 79 additions & 0 deletions include/beman/execution/detail/poly.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// include/beman/execution/detail/poly.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_POLY
#define INCLUDED_BEMAN_EXECUTION_DETAIL_POLY

#include <array>
#include <concepts>
#include <cstddef>
#include <new>
#include <utility>

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

namespace beman::execution::detail {
/*!
* \brief Utility providing small object optimization and type erasure.
* \headerfile beman/execution/task.hpp <beman/execution/task.hpp>
* \internal
*/
template <typename Base, std::size_t Size = 4u * sizeof(void*)>
class alignas(sizeof(double)) poly {
private:
std::array<std::byte, Size> buf{};

Base* pointer() { return static_cast<Base*>(static_cast<void*>(buf.data())); }
const Base* pointer() const { return static_cast<const Base*>(static_cast<const void*>(buf.data())); }

public:
template <typename T, typename... Args>
requires(sizeof(T) <= Size)
poly(T*, Args&&... args) {
new (this->buf.data()) T(::std::forward<Args>(args)...);
static_assert(sizeof(T) <= Size);
}
poly(poly&& other)
requires requires(Base* b, void* t) { b->move(t); }
{
other.pointer()->move(this->buf.data());
}
poly& operator=(poly&& other)
requires requires(Base* b, void* t) { b->move(t); }
{
if (this != &other) {
this->pointer()->~Base();
other.pointer()->move(this->buf.data());
}
return *this;
}
poly& operator=(const poly& other)
requires requires(Base* b, void* t) { b->clone(t); }
{
if (this != &other) {
this->pointer()->~Base();
other.pointer()->clone(this->buf.data());
}
return *this;
}
poly(const poly& other)
requires requires(Base* b, void* t) { b->clone(t); }
{
other.pointer()->clone(this->buf.data());
}
~poly() { this->pointer()->~Base(); }
bool operator==(const poly& other) const
requires requires(const Base& b) {
{ b.equals(&b) } -> std::same_as<bool>;
}
{
return other.pointer()->equals(this->pointer());
}
Base* operator->() { return this->pointer(); }
const Base* operator->() const { return this->pointer(); }
};
} // namespace beman::execution::detail

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

#endif
40 changes: 40 additions & 0 deletions include/beman/execution/detail/promise_env.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// include/beman/execution/detail/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

#include <beman/execution/execution.hpp>
#include <utility>

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

namespace beman::execution::detail {
template <typename Promise>
struct promise_env {
const Promise* promise;

auto query(const ::beman::execution::get_scheduler_t&) const noexcept -> typename Promise::scheduler_type {
return this->promise->get_scheduler();
}
auto query(const ::beman::execution::get_allocator_t&) const noexcept -> typename Promise::allocator_type {
return this->promise->get_allocator();
}
auto query(const ::beman::execution::get_stop_token_t&) const noexcept -> typename Promise::stop_token_type {
return this->promise->get_stop_token();
}

template <typename Q, typename... A>
requires requires(const Promise* p, Q q, A&&... a) {
::beman::execution::forwarding_query(q);
q(p->get_environment(), std::forward<A>(a)...);
}
auto query(Q q, A&&... a) const noexcept {
return q(promise->get_environment(), std::forward<A>(a)...);
}
};
} // namespace beman::execution::detail

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

#endif
Loading
Loading