| enum class construct_type {
none,
copy,
move,
copy_and_move
};
template<construct_type>
struct fixed_function_base;
template<> struct fixed_function_base<construct_type::copy_and_move> {
void(*copy_)(const void*, void*) = nullptr;
void(*move_)(void*, void*) = nullptr;
};
template<> struct fixed_function_base<construct_type::copy> {
void(*copy_)(const void*, void*) = nullptr;
};
template<> struct fixed_function_base<construct_type::move> {
void(*move_)(void*, void*) = nullptr;
};
template<> struct fixed_function_base<construct_type::none> {
};
template<typename Function, size_t MaxSize, construct_type ConstructStrategy>
class fixed_size_function;
template<size_t MaxSize, construct_type ConstructStrategy, typename Ret, typename ...Args>
class fixed_size_function<Ret(Args...), MaxSize, ConstructStrategy>
: fixed_function_base<ConstructStrategy>
{
typedef fixed_function_base<ConstructStrategy> base;
const static bool movable = ConstructStrategy == construct_type::move || ConstructStrategy == construct_type::copy_and_move;
const static bool copyable = ConstructStrategy == construct_type::copy || ConstructStrategy == construct_type::copy_and_move;
template<bool> struct movable_flag{};
typedef movable_flag<movable> is_movable_t;
typedef movable_flag<true> movable_t;
typedef movable_flag<false> non_movable_t;
template<bool> struct copyable_flag{};
typedef copyable_flag<copyable> is_copyable_t;
typedef copyable_flag<true> copyable_t;
typedef copyable_flag<false> non_copyable_t;
public:
template<typename F, size_t S, construct_type C> fixed_size_function(const fixed_size_function<F, S, C>&) = delete;
template<typename F, size_t S, construct_type C> fixed_size_function(fixed_size_function<F, S, C>&) = delete;
template<typename F, size_t S, construct_type C> fixed_size_function(fixed_size_function<F, S, C>&&) = delete;
template<typename F, size_t S, construct_type C> fixed_size_function& operator=(const fixed_size_function<F, S, C>&) = delete;
template<typename F, size_t S, construct_type C> fixed_size_function& operator=(fixed_size_function<F, S, C>&) = delete;
template<typename F, size_t S, construct_type C> fixed_size_function& operator=(const fixed_size_function<F, S, C>&&) = delete;
template<typename F, size_t S, construct_type C> void assign(const fixed_size_function<F, S, C>&) = delete;
template<typename F, size_t S, construct_type C> void assign(fixed_size_function<F, S, C>&) = delete;
template<typename F, size_t S, construct_type C> void assign(fixed_size_function<F, S, C>&&) = delete;
using result_type = Ret;
static const std::size_t arity = sizeof...(Args);
template <std::size_t N>
struct argument
{
static_assert(N < arity, "invalid argument index");
using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
fixed_size_function() = default;
fixed_size_function(std::nullptr_t) {
}
~fixed_size_function() {
reset();
}
fixed_size_function(const fixed_size_function& rhs) {
copy_construct_(rhs);
}
fixed_size_function(fixed_size_function& rhs) {
copy_construct_(rhs);
}
fixed_size_function(fixed_size_function&& rhs) {
move_construct_(std::move(rhs), is_movable_t());
}
fixed_size_function& operator=(const fixed_size_function& rhs) {
assign(rhs);
return *this;
}
fixed_size_function& operator=(fixed_size_function& rhs) {
assign(rhs);
return *this;
}
fixed_size_function& operator=(fixed_size_function&& rhs) {
assign(std::move(rhs));
return *this;
}
void assign(const fixed_size_function& rhs) {
reset();
copy_construct_(rhs);
}
void assign(fixed_size_function& rhs) {
reset();
copy_construct_(rhs);
}
void assign(fixed_size_function&& rhs) {
reset();
move_construct_(std::move(rhs), is_movable_t());
}
template<typename F>
fixed_size_function(F&& f) {
construct_(std::forward<F>(f));
}
template<typename F>
fixed_size_function& operator=(F&& f) {
reset();
construct_(std::forward<F>(f));
return *this;
}
template<typename F>
void assign(F&& f) {
reset();
construct_(std::forward<F>(f));
}
Ret operator()(Args&& ... args) {
if(!call_)
throw std::bad_function_call();
return call_(&storage_, std::forward<Args>(args)...);
}
operator bool() const {
return call_ != nullptr;
}
void reset() {
auto dtor = dtor_;
if(dtor) {
reset_vtable_();
dtor(&storage_);
}
}
void swap(fixed_size_function& rhs) {
fixed_size_function tmp = std::move(rhs);
rhs = std::move(*this);
*this = std::move(tmp);
}
private:
template<typename F> static void dtor_impl_(void* obj) {
static_cast<F*>(obj)->~F();
}
template<typename F> static void move_impl_(void* from, void* to) {
new(to)F(std::move(*static_cast<F*>(from)));
}
template<typename F> static void copy_impl_(const void* from, void* to) {
new(to)F(*static_cast<const F*>(from));
}
template<typename F> static Ret call_impl_(void* f, Args&& ... args) {
return (*static_cast<F*>(f))(std::forward<Args>(args)...);
}
void reset_copy_(copyable_t) { base::copy_ = nullptr; }
void reset_copy_(non_copyable_t) {}
void reset_move_(movable_t) { base::move_ = nullptr; }
void reset_move_(non_movable_t) {}
void reset_vtable_() {
reset_copy_(is_copyable_t());
reset_move_(is_movable_t());
call_ = nullptr;
dtor_ = nullptr;
}
void copy_copy_(const fixed_size_function& rhs, copyable_t) { base::copy_ = rhs.copy_; }
void copy_copy_(const fixed_size_function&, non_copyable_t) {}
void copy_move_(const fixed_size_function& rhs, movable_t) { base::move_ = rhs.move_; }
void copy_move_(const fixed_size_function&, non_movable_t) {}
void copy_vtable_(const fixed_size_function& rhs) {
copy_copy_(rhs, is_copyable_t());
copy_move_(rhs, is_movable_t());
call_ = rhs.call_;
dtor_ = rhs.dtor_;
}
template<typename F> void init_copy_(copyable_t) { base::copy_ = ©_impl_<F>; }
template<typename F> void init_copy_(non_copyable_t) {}
template<typename F> void init_move_(movable_t) { base::move_ = &move_impl_<F>; }
template<typename F> void init_move_(non_movable_t) {}
template<typename F>
void construct_(F&& f) {
typedef typename std::decay<F>::type functor_type;
static_assert(sizeof(functor_type) <= MaxSize
, "non sufficient fixed_size_function storage size");
new (&storage_) functor_type(std::forward<F>(f));
init_copy_<functor_type>(is_copyable_t());
init_move_<functor_type>(is_movable_t());
call_ = &call_impl_<functor_type, Args...>;
dtor_ = &dtor_impl_<functor_type>;
}
void move_construct_(fixed_size_function&& rhs, movable_t) {
if(!rhs.move_) return;
rhs.move_(&rhs.storage_, &storage_);
copy_vtable_(rhs);
rhs.reset();
}
void move_construct_(const fixed_size_function& rhs, non_movable_t) {
copy_construct_(rhs);
}
void copy_construct_(const fixed_size_function& rhs) {
if(!rhs.copy_) return;
rhs.copy_(&rhs.storage_, &storage_);
copy_vtable_(rhs);
}
Ret(*call_)(void*, Args...) = nullptr;
void(*dtor_)(void*) = nullptr;
typename std::aligned_storage<MaxSize>::type storage_;
};
template<typename F, size_t S, construct_type C>
inline void swap(fixed_size_function<F, S, C>& lhs, fixed_size_function<F, S, C>& rhs) {
lhs.swap(rhs);
}
template<typename F, size_t S, construct_type C>
inline bool operator==(std::nullptr_t, fixed_size_function<F, S, C> const& f) {
return !f;
}
template<typename F, size_t S, construct_type C>
inline bool operator==(fixed_size_function<F, S, C> const& f, std::nullptr_t) {
return !f;
}
template<typename F, size_t S, construct_type C>
inline bool operator!=(std::nullptr_t, fixed_size_function<F, S, C> const& f) {
return f;
}
template<typename F, size_t S, construct_type C>
inline bool operator!=(fixed_size_function<F, S, C> const& f, std::nullptr_t) {
return f;
}
|