unified single-type interface for channels

master
Daniel Kolesa 2017-03-23 02:44:45 +01:00
parent 0e24dcd1c4
commit 45e65d7ec7
3 changed files with 70 additions and 23 deletions

View File

@ -6,7 +6,8 @@
#ifndef OSTD_CHANNEL_HH
#define OSTD_CHANNEL_HH
#include <stdio.h>
#include <type_traits>
#include <algorithm>
#include <list>
#include <mutex>
#include <condition_variable>
@ -19,10 +20,8 @@ struct channel_error: std::logic_error {
using std::logic_error::logic_error;
};
template<typename T, typename C = std::condition_variable>
template<typename T>
struct channel {
using condition_variable_type = C;
/* default ctor works for default C */
channel(): p_state(new impl) {}
@ -67,11 +66,68 @@ struct channel {
}
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 {
impl() {}
impl() {
}
template<typename F>
impl(F &func): p_lock(), p_cond(func()) {}
impl(F &func): p_lock(), p_cond(func) {}
template<typename U>
void put(U &&val) {
@ -118,7 +174,7 @@ private:
std::list<T> p_messages;
mutable std::mutex p_lock;
C p_cond;
cond p_cond;
bool p_closed = false;
};

View File

@ -19,9 +19,6 @@
namespace ostd {
struct thread_scheduler {
template<typename T>
using channel_type = channel<T>;
~thread_scheduler() {
join_all();
}
@ -174,9 +171,6 @@ private:
};
public:
template<typename T>
using channel_type = channel<T, coro_cond>;
basic_simple_coroutine_scheduler(
size_t ss = TR::default_size(),
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
@ -228,8 +222,8 @@ public:
}
template<typename T>
channel<T, coro_cond> make_channel() {
return channel<T, coro_cond>{[this]() {
channel<T> make_channel() {
return channel<T>{[this]() {
return coro_cond{*this};
}};
}
@ -354,9 +348,6 @@ private:
};
public:
template<typename T>
using channel_type = channel<T, task_cond>;
basic_coroutine_scheduler(
size_t ss = TR::default_size(),
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
@ -409,8 +400,8 @@ public:
}
template<typename T>
channel<T, task_cond> make_channel() {
return channel<T, task_cond>{[this]() {
channel<T> make_channel() {
return channel<T>{[this]() {
return task_cond{*this};
}};
}
@ -551,7 +542,7 @@ inline void yield(S &sched) {
}
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>();
}

View File

@ -60,7 +60,7 @@ namespace detail {
template<typename F>
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))
tpool_func_impl<F>{std::move(func)};
} else {
@ -81,7 +81,7 @@ namespace detail {
}
private:
std::aligned_storage_t<
sizeof(std::packaged_task<void()>) + sizeof(void *)
sizeof(tpool_func_impl<std::packaged_task<void()>>)
> p_buf;
tpool_func_base *p_func;
};