Commit ed3ab09c authored by Eric Niebler's avatar Eric Niebler Committed by Facebook Github Bot

clean-up the type-erasing single<>

fbshipit-source-id: 4eeda45c9b4bb8256f71c9e644cd70f83b539fd0
parent 38a4477a
...@@ -84,7 +84,7 @@ public: ...@@ -84,7 +84,7 @@ public:
template <class E> template <class E>
constexpr typename none<E>::vtable const none<E>::vtable::noop_; constexpr typename none<E>::vtable const none<E>::vtable::noop_;
template <class E> template <class E>
template <class Wrapped, bool Big> template <class Wrapped, bool InSitu>
constexpr typename none<E>::vtable const none<E>::vtable_v; constexpr typename none<E>::vtable const none<E>::vtable_v;
template <class E> template <class E>
template <class Wrapped> template <class Wrapped>
......
...@@ -9,77 +9,6 @@ ...@@ -9,77 +9,6 @@
namespace pushmi { namespace pushmi {
namespace detail {
template<class data, class V, class E>
struct single_vtable {
void (*op_)(data&, data*) = +[](data&, data*) {};
void (*done_)(data&) = +[](data&) {};
void (*error_)(data&, E) noexcept = +[](data&, E) noexcept {
std::terminate();
};
void (*rvalue_)(data&, V&&) = +[](data&, V&&) {};
void (*lvalue_)(data&, V&) = +[](data&, V&) {};
static constexpr single_vtable const noop_ = {};
};
template <class data, class V, class E, class Wrapped, bool insitu>
struct single_vtable_v;
template <class data, class V, class E, class Wrapped>
struct single_vtable_v<data, V, E, Wrapped, false> {
static constexpr single_vtable<data, V, E> const vtable_v = {
+[](data& src, data* dst) {
if (dst)
dst->pobj_ = std::exchange(src.pobj_, nullptr);
delete static_cast<Wrapped const*>(src.pobj_);
},
+[](data& src) { ::pushmi::set_done(*static_cast<Wrapped*>(src.pobj_)); },
+[](data& src, E e) noexcept {
::pushmi::set_error(*static_cast<Wrapped*>(src.pobj_), std::move(e));
},
+[](data& src, V&& v) {
::pushmi::set_value(*static_cast<Wrapped*>(src.pobj_), (V&&) v);
},
+[](data& src, V& v) {
::pushmi::set_value(*static_cast<Wrapped*>(src.pobj_), v);
}
};
};
template <class data, class V, class E, class Wrapped>
struct single_vtable_v<data, V, E, Wrapped, true> {
static constexpr single_vtable<data, V, E> const vtable_v = {
+[](data& src, data* dst) {
if (dst)
new (dst->buffer_) Wrapped(
std::move(*static_cast<Wrapped*>((void*)src.buffer_)));
static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped();
},
+[](data& src) {
::pushmi::set_done(*static_cast<Wrapped*>((void*)src.buffer_));
},
+[](data& src, E e) noexcept {
::pushmi::set_error(
*static_cast<Wrapped*>((void*)src.buffer_),
std::move(e));
},
+[](data& src, V&& v) {
::pushmi::set_value(*static_cast<Wrapped*>((void*)src.buffer_), (V&&) v);
},
+[](data& src, V& v) {
::pushmi::set_value(*static_cast<Wrapped*>((void*)src.buffer_), v);
}
};
};
// Class static definitions:
template<class data, class V, class E>
constexpr single_vtable<data, V, E> const single_vtable<data, V, E>::noop_;
} // namespace detail
template <class V, class E> template <class V, class E>
class single<V, E> { class single<V, E> {
bool done_ = false; bool done_ = false;
...@@ -92,9 +21,18 @@ class single<V, E> { ...@@ -92,9 +21,18 @@ class single<V, E> {
return sizeof(Wrapped) <= sizeof(data::buffer_) && return sizeof(Wrapped) <= sizeof(data::buffer_) &&
std::is_nothrow_move_constructible_v<Wrapped>; std::is_nothrow_move_constructible_v<Wrapped>;
} }
using vtable = detail::single_vtable<data, V, E>; struct vtable {
vtable const* vptr_ = &vtable::noop_; void (*op_)(data&, data*) = +[](data&, data*) {};
void (*done_)(data&) = +[](data&) {};
void (*error_)(data&, E) noexcept = +[](data&, E) noexcept {
std::terminate();
};
void (*rvalue_)(data&, V&&) = +[](data&, V&&) {};
void (*lvalue_)(data&, V&) = +[](data&, V&) {};
static constexpr vtable const noop_ = {};
} const* vptr_ = &vtable::noop_;
template <class Wrapped>
static constexpr vtable vtable_v() noexcept;
template <class T, class U = std::decay_t<T>> template <class T, class U = std::decay_t<T>>
using wrapped_t = using wrapped_t =
std::enable_if_t<!std::is_same_v<U, single>, U>; std::enable_if_t<!std::is_same_v<U, single>, U>;
...@@ -116,11 +54,11 @@ public: ...@@ -116,11 +54,11 @@ public:
static_assert(NothrowInvocable<decltype(::pushmi::set_error), Wrapped, E>, static_assert(NothrowInvocable<decltype(::pushmi::set_error), Wrapped, E>,
"Wrapped single must support E and be noexcept"); "Wrapped single must support E and be noexcept");
if constexpr (insitu<Wrapped>()) if constexpr (insitu<Wrapped>())
new (data_.buffer_) Wrapped(std::move(obj)); new ((void*)data_.buffer_) Wrapped(std::move(obj));
else else
data_.pobj_ = new Wrapped(std::move(obj)); data_.pobj_ = new Wrapped(std::move(obj));
vptr_ = static constexpr auto vtbl = vtable_v<Wrapped>();
&detail::single_vtable_v<data, V, E, Wrapped, insitu<Wrapped>()>::vtable_v; vptr_ = &vtbl;
} }
~single() { ~single() {
vptr_->op_(data_, nullptr); vptr_->op_(data_, nullptr);
...@@ -160,6 +98,54 @@ public: ...@@ -160,6 +98,54 @@ public:
} }
}; };
// Class static definitions:
template <class V, class E>
constexpr typename single<V, E>::vtable const single<V, E>::vtable::noop_;
template <class V, class E>
template <class Wrapped>
constexpr typename single<V, E>::vtable single<V, E>::vtable_v() noexcept {
if constexpr (insitu<Wrapped>())
return {
+[](data& src, data* dst) {
if (dst)
new (dst->buffer_) Wrapped(
std::move(*static_cast<Wrapped*>((void*)src.buffer_)));
static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped();
},
+[](data& src) {
::pushmi::set_done(*static_cast<Wrapped*>((void*)src.buffer_));
},
+[](data& src, E e) noexcept {
::pushmi::set_error(
*static_cast<Wrapped*>((void*)src.buffer_),
std::move(e));
},
+[](data& src, V&& v) {
::pushmi::set_value(*static_cast<Wrapped*>((void*)src.buffer_), (V&&) v);
},
+[](data& src, V& v) {
::pushmi::set_value(*static_cast<Wrapped*>((void*)src.buffer_), v);
}
};
else
return {
+[](data& src, data* dst) {
if (dst)
dst->pobj_ = std::exchange(src.pobj_, nullptr);
delete static_cast<Wrapped const*>(src.pobj_);
},
+[](data& src) { ::pushmi::set_done(*static_cast<Wrapped*>(src.pobj_)); },
+[](data& src, E e) noexcept {
::pushmi::set_error(*static_cast<Wrapped*>(src.pobj_), std::move(e));
},
+[](data& src, V&& v) {
::pushmi::set_value(*static_cast<Wrapped*>(src.pobj_), (V&&) v);
},
+[](data& src, V& v) {
::pushmi::set_value(*static_cast<Wrapped*>(src.pobj_), v);
}
};
}
template <class VF, class EF, class DF> template <class VF, class EF, class DF>
requires Invocable<DF&> requires Invocable<DF&>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment