unified single-type interface for channels
This commit is contained in:
parent
0e24dcd1c4
commit
45e65d7ec7
|
@ -6,7 +6,8 @@
|
||||||
#ifndef OSTD_CHANNEL_HH
|
#ifndef OSTD_CHANNEL_HH
|
||||||
#define OSTD_CHANNEL_HH
|
#define OSTD_CHANNEL_HH
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <type_traits>
|
||||||
|
#include <algorithm>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
@ -19,10 +20,8 @@ struct channel_error: std::logic_error {
|
||||||
using std::logic_error::logic_error;
|
using std::logic_error::logic_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename C = std::condition_variable>
|
template<typename T>
|
||||||
struct channel {
|
struct channel {
|
||||||
using condition_variable_type = C;
|
|
||||||
|
|
||||||
/* default ctor works for default C */
|
/* default ctor works for default C */
|
||||||
channel(): p_state(new impl) {}
|
channel(): p_state(new impl) {}
|
||||||
|
|
||||||
|
@ -67,11 +66,68 @@ struct channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct cond_iface {
|
||||||
|
cond_iface() {}
|
||||||
|
virtual ~cond_iface() {}
|
||||||
|
virtual void notify_one() = 0;
|
||||||
|
virtual void notify_all() = 0;
|
||||||
|
virtual void wait(std::unique_lock<std::mutex> &) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
struct cond_impl: cond_iface {
|
||||||
|
cond_impl(): p_cond() {}
|
||||||
|
template<typename F>
|
||||||
|
cond_impl(F &func): p_cond(func()) {}
|
||||||
|
void notify_one() {
|
||||||
|
p_cond.notify_one();
|
||||||
|
}
|
||||||
|
void notify_all() {
|
||||||
|
p_cond.notify_all();
|
||||||
|
}
|
||||||
|
void wait(std::unique_lock<std::mutex> &l) {
|
||||||
|
p_cond.wait(l);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
C p_cond;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cond {
|
||||||
|
cond() {
|
||||||
|
new (reinterpret_cast<void *>(&p_condbuf))
|
||||||
|
cond_impl<std::condition_variable>();
|
||||||
|
}
|
||||||
|
template<typename F>
|
||||||
|
cond(F &func) {
|
||||||
|
new (reinterpret_cast<void *>(&p_condbuf))
|
||||||
|
cond_impl<std::result_of_t<F()>>(func);
|
||||||
|
}
|
||||||
|
~cond() {
|
||||||
|
reinterpret_cast<cond_iface *>(&p_condbuf)->~cond_iface();
|
||||||
|
}
|
||||||
|
|
||||||
|
void notify_one() {
|
||||||
|
reinterpret_cast<cond_iface *>(&p_condbuf)->notify_one();
|
||||||
|
}
|
||||||
|
void notify_all() {
|
||||||
|
reinterpret_cast<cond_iface *>(&p_condbuf)->notify_all();
|
||||||
|
}
|
||||||
|
void wait(std::unique_lock<std::mutex> &l) {
|
||||||
|
reinterpret_cast<cond_iface *>(&p_condbuf)->wait(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::aligned_storage_t<std::max(
|
||||||
|
6 * sizeof(void *), sizeof(cond_impl<std::condition_variable>)
|
||||||
|
), alignof(std::condition_variable)> p_condbuf;
|
||||||
|
};
|
||||||
|
|
||||||
struct impl {
|
struct impl {
|
||||||
impl() {}
|
impl() {
|
||||||
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
impl(F &func): p_lock(), p_cond(func()) {}
|
impl(F &func): p_lock(), p_cond(func) {}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
void put(U &&val) {
|
void put(U &&val) {
|
||||||
|
@ -118,7 +174,7 @@ private:
|
||||||
|
|
||||||
std::list<T> p_messages;
|
std::list<T> p_messages;
|
||||||
mutable std::mutex p_lock;
|
mutable std::mutex p_lock;
|
||||||
C p_cond;
|
cond p_cond;
|
||||||
bool p_closed = false;
|
bool p_closed = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,6 @@
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
|
|
||||||
struct thread_scheduler {
|
struct thread_scheduler {
|
||||||
template<typename T>
|
|
||||||
using channel_type = channel<T>;
|
|
||||||
|
|
||||||
~thread_scheduler() {
|
~thread_scheduler() {
|
||||||
join_all();
|
join_all();
|
||||||
}
|
}
|
||||||
|
@ -174,9 +171,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
|
||||||
using channel_type = channel<T, coro_cond>;
|
|
||||||
|
|
||||||
basic_simple_coroutine_scheduler(
|
basic_simple_coroutine_scheduler(
|
||||||
size_t ss = TR::default_size(),
|
size_t ss = TR::default_size(),
|
||||||
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
|
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
|
||||||
|
@ -228,8 +222,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
channel<T, coro_cond> make_channel() {
|
channel<T> make_channel() {
|
||||||
return channel<T, coro_cond>{[this]() {
|
return channel<T>{[this]() {
|
||||||
return coro_cond{*this};
|
return coro_cond{*this};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
@ -354,9 +348,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
|
||||||
using channel_type = channel<T, task_cond>;
|
|
||||||
|
|
||||||
basic_coroutine_scheduler(
|
basic_coroutine_scheduler(
|
||||||
size_t ss = TR::default_size(),
|
size_t ss = TR::default_size(),
|
||||||
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
|
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
|
||||||
|
@ -409,8 +400,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
channel<T, task_cond> make_channel() {
|
channel<T> make_channel() {
|
||||||
return channel<T, task_cond>{[this]() {
|
return channel<T>{[this]() {
|
||||||
return task_cond{*this};
|
return task_cond{*this};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
@ -551,7 +542,7 @@ inline void yield(S &sched) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename S>
|
template<typename T, typename S>
|
||||||
inline auto make_channel(S &sched) -> typename S::template channel_type<T> {
|
inline channel<T> make_channel(S &sched) {
|
||||||
return sched.template make_channel<T>();
|
return sched.template make_channel<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace detail {
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
tpool_func(F &&func) {
|
tpool_func(F &&func) {
|
||||||
if (sizeof(F) <= sizeof(p_buf)) {
|
if (sizeof(tpool_func_impl<F>) <= sizeof(p_buf)) {
|
||||||
p_func = ::new(reinterpret_cast<void *>(&p_buf))
|
p_func = ::new(reinterpret_cast<void *>(&p_buf))
|
||||||
tpool_func_impl<F>{std::move(func)};
|
tpool_func_impl<F>{std::move(func)};
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,7 +81,7 @@ namespace detail {
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::aligned_storage_t<
|
std::aligned_storage_t<
|
||||||
sizeof(std::packaged_task<void()>) + sizeof(void *)
|
sizeof(tpool_func_impl<std::packaged_task<void()>>)
|
||||||
> p_buf;
|
> p_buf;
|
||||||
tpool_func_base *p_func;
|
tpool_func_base *p_func;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue