gnss-sim/3rdparty/boost/cobalt/unique_handle.hpp

307 lines
8.2 KiB
C++

//
// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_COBALT_HANDLE_HPP
#define BOOST_COBALT_HANDLE_HPP
#include <boost/asio/associator.hpp>
#include <coroutine>
#include <memory>
namespace boost::cobalt
{
template<typename T>
struct unique_handle
{
unique_handle() noexcept = default;
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
explicit unique_handle(T * promise,
const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(promise), loc_(loc) {}
#else
explicit unique_handle(T * promise) noexcept : handle_(promise) {}
#endif
unique_handle(std::nullptr_t) noexcept {}
std::coroutine_handle<T> release()
{
return std::coroutine_handle<T>::from_promise(*handle_.release());
}
void* address() const noexcept { return get_handle_().address(); }
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
static unique_handle from_address(
void* a,
const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
{
unique_handle res;
res.loc_ = loc;
res.handle_.reset(&std::coroutine_handle<T>::from_address(a).promise());
return res;
}
#else
static unique_handle from_address(void* a) noexcept
{
unique_handle res;
res.handle_.reset(&std::coroutine_handle<T>::from_address(a).promise());
return res;
}
#endif
bool done() const noexcept { return get_handle_().done(); }
explicit operator bool() const { return static_cast<bool>(handle_); }
void destroy() { handle_.reset(); }
void operator()() const &
{
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
#endif
resume();
}
void resume() const & { get_handle_().resume(); }
void operator()() &&
{
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
#endif
release().resume();
}
void resume() && { release().resume(); }
T & promise() {return *handle_;}
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
constexpr static unique_handle from_promise(
T &p,
const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
{
unique_handle res;
res.loc_ = loc;
res.handle_.reset(&p);
return res;
}
#else
constexpr static unique_handle from_promise(T &p) noexcept
{
unique_handle res;
res.handle_.reset(&p);
return res;
}
#endif
T & operator*() {return *handle_;}
const T & operator*() const {return *handle_;}
T * operator->() {return handle_.get();}
const T * operator->() const {return handle_.get();}
T * get() {return handle_.get();}
const T * get() const {return handle_.get();}
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
void reset(T * handle = nullptr,
const boost::source_location & loc = BOOST_CURRENT_LOCATION)
{
loc_ = loc; handle_.reset(handle);
}
#else
void reset(T * handle = nullptr) {handle_.reset(handle);}
#endif
friend
auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;}
friend
auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;}
private:
struct deleter_
{
void operator()(T * p)
{
std::coroutine_handle<T>::from_promise(*p).destroy();
}
};
std::coroutine_handle<T> get_handle_() const
{
return std::coroutine_handle<T>::from_promise(*handle_);
}
std::unique_ptr<T, deleter_> handle_;
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
boost::source_location loc_;
#endif
};
template<>
struct unique_handle<void>
{
unique_handle() noexcept = default;
unique_handle(std::nullptr_t) noexcept {}
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
explicit unique_handle(void * handle,
const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(handle), loc_(loc) {}
#else
explicit unique_handle(void * handle) noexcept : handle_(handle) {}
#endif
std::coroutine_handle<void> release()
{
return std::coroutine_handle<void>::from_address(handle_.release());
}
void* address() const noexcept { return get_handle_().address(); }
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
static unique_handle<void> from_address(void* a,
const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
{
unique_handle res;
res.loc_ = loc;
res.handle_.reset(std::coroutine_handle<void>::from_address(a).address());
return res;
}
#else
static unique_handle<void> from_address(void* a) noexcept
{
unique_handle res;
res.handle_.reset(std::coroutine_handle<void>::from_address(a).address());
return res;
}
#endif
explicit operator bool() const { return static_cast<bool>(handle_); }
bool done() const noexcept { return get_handle_().done(); }
void operator()() const &
{
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
#endif
resume();
}
void resume() const & { get_handle_().resume(); }
void operator()() &&
{
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
#endif
release().resume();
}
void resume() && { release().resume(); }
void destroy() { handle_.reset(); }
void * get() { return handle_.get(); }
const void * get() const { return handle_.get(); }
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
void reset(void * handle = nullptr,
const boost::source_location & loc = BOOST_CURRENT_LOCATION)
{
loc_ = loc;
handle_.reset(handle);
}
#else
void reset(void * handle = nullptr) {handle_.reset(handle);}
#endif
friend
auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;}
friend
auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;}
private:
struct deleter_
{
void operator()(void * p)
{
std::coroutine_handle<void>::from_address(p).destroy();
}
};
std::coroutine_handle<void> get_handle_() const
{
return std::coroutine_handle<void>::from_address(handle_.get());
}
std::unique_ptr<void, deleter_> handle_;
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
boost::source_location loc_;
#endif
};
template<>
struct unique_handle<std::noop_coroutine_promise>
{
unique_handle() noexcept = default;
unique_handle(std::nullptr_t) noexcept {}
std::coroutine_handle<void> release()
{
return std::noop_coroutine();
}
void* address() const noexcept { return std::noop_coroutine().address(); }
bool done() const noexcept { return true;}
void operator()() const {}
void resume() const {}
void destroy() {}
explicit operator bool() const { return true; }
struct executor_type
{
template<typename Fn>
void execute(Fn &&) const {}
};
executor_type get_executor() const {return {}; }
friend
auto operator==(const unique_handle &, std::nullptr_t) {return false;}
friend
auto operator!=(const unique_handle &, std::nullptr_t) {return true;}
};
}
namespace boost::asio
{
template <template <typename, typename> class Associator,
typename Promise, typename DefaultCandidate>
requires (!std::is_void_v<Promise>)
struct associator<Associator,
boost::cobalt::unique_handle<Promise>, DefaultCandidate>
: Associator<Promise, DefaultCandidate>
{
static typename Associator<Promise, DefaultCandidate>::type
get(const boost::cobalt::unique_handle<Promise>& h) BOOST_ASIO_NOEXCEPT
{
return Associator<Promise, DefaultCandidate>::get(*h);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const boost::cobalt::unique_handle<Promise>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Promise, DefaultCandidate>::get(*h, c)))
{
return Associator<Promise, DefaultCandidate>::get(*h, c);
}
};
}
#endif //BOOST_COBALT_HANDLE_HPP