diff --git a/hyper.h b/hyper.h index 1e746907..923239da 100644 --- a/hyper.h +++ b/hyper.h @@ -7,6 +7,7 @@ #define VERNUM_HEX 0xA505 #include +#include "hyper_function.h" namespace hr { @@ -15,6 +16,8 @@ void ignore(T&&) { // placate GCC's overzealous -Wunused-result } +template using function = hyper_function; + // functions and types used from the standard library using std::vector; using std::map; @@ -24,7 +27,6 @@ using std::sort; using std::multimap; using std::set; using std::string; -using std::function; using std::pair; using std::tuple; using std::shared_ptr; diff --git a/hyper_function.h b/hyper_function.h new file mode 100644 index 00000000..9a64e57c --- /dev/null +++ b/hyper_function.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +template +class hyper_function; + +template +struct hyper_function_state_base { + virtual R call(Args...) const = 0; + virtual hyper_function_state_base *clone() const = 0; + virtual ~hyper_function_state_base() = default; +}; + +template +struct hyper_function_state : hyper_function_state_base { + using Self = hyper_function_state; + T t_; + explicit hyper_function_state(T t) : t_(std::move(t)) {} + R call(Args... args) const override { + return const_cast(t_)(static_cast(args)...); + } + hyper_function_state_base *clone() const override { + return new Self(*this); + } +}; + +template +class hyper_function +{ + hyper_function_state_base *ptr_ = nullptr; +public: + hyper_function() = default; + + template::type>()(std::declval()...)))> + hyper_function(Callable&& t) : + ptr_(new hyper_function_state::type, R, Args...>(static_cast(t))) + {} + + ~hyper_function() { + delete ptr_; + } + + hyper_function(hyper_function& rhs) : ptr_(rhs.ptr_ ? rhs.ptr_->clone() : nullptr) {} + hyper_function(const hyper_function& rhs) : ptr_(rhs.ptr_ ? rhs.ptr_->clone() : nullptr) {} + hyper_function(hyper_function&& rhs) noexcept : ptr_(rhs.ptr_) { rhs.ptr_ = nullptr; } + hyper_function(const hyper_function&& rhs) = delete; + + void operator=(hyper_function rhs) noexcept { + std::swap(ptr_, rhs.ptr_); + } + + R operator()(Args... args) const { + return ptr_->call(static_cast(args)...); + } + + explicit operator bool() const noexcept { + return ptr_ != nullptr; + } +};