如本文标题所示,是为了进行优化,才进行重写的,并且砍掉了标准库 std::function 实现的自身提供的固态大小BUFF缓冲区,因为没有必要了,该实现是复制共享指针的引用,而不是像官版实现需要复制BUFF并重新构造,如果结构超过BUFF大小还会从STL运行时从系统分配堆内存,该版本使用自己希望使用的方式进行堆内存分配。
支援特性:
1、NULL(宏)
2、nullptr(C++11引入的空指针关键字)
3、Lambda 普通函数
4、Lambda 闭包函数
5、普通 C/C++ 函数绑定
6、对于闭包结构仅单次复制,减少内存复制问题
7、EMC-MCx 多线程安全支援
8、高效率简介的模板源代码实现
9、C++ 11、14 标准编译器支援
10、可允许派生子类,按L原则里氏代换重写基类函数,可用于AOP切面编程处理事务日志等
11、支援Void无返回值类型返回
12、支援std::move,右值引用无损移动 function 内部托管字段。
实战例子:
bool(*xxx)(int, int);
ppp::function<bool(int x, int y)> x0 = xxx;
ppp::function<bool(int x, int y)> x2 = NULL;
ppp::function<bool(int x, int y)> x1 = [](int x, int y)
{
return x > y;
};
ppp::function<bool(int x, int y)> x3 = [&argc](int x, int y)
{
return x > y;
};
x0.swap(x2);
x1(100, 200);
x3(300, 400);
模板实现:
stl::is_invocable<...> 实现
template <typename F, typename... Args>
class is_invocable {
template <typename U>
static auto test(int) -> decltype(std::declval<U>()(std::declval<Args>()...), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = std::is_same<decltype(test<F>(0)), std::true_type>::value;
};
ppp::function<...> 实现
template <typename Signature>
class function;
template <typename R, typename... Args>
class function<R(Args...)> {
public:
using Function = R(*)(Args...);
public:
function() noexcept : lk_(false), f_(NULL) {}
function(std::nullptr_t) noexcept : lk_(false), f_(NULL) {}
function(function&& other) noexcept {
move(std::forward<function>(other));
}
function(const function& other) noexcept {
LockScope<typename std::decay<decltype(*this)>::type> scope(const_cast<function&>(other));
this->f_ = other.f_;
this->callable_ = other.callable_;
}
public:
template <typename F>
function(F&& f) noexcept {
constructor(std::forward<F>(f));
}
private:
template <typename F>
typename std::enable_if<std::is_convertible<typename std::decay<F>::type, Function>::value, void>::type
inline constructor_fx(F&& f) noexcept {
const Function fx = static_cast<Function>(f);
reset(fx);
}
template <typename F>
typename std::enable_if<!std::is_convertible<typename std::decay<F>::type, Function>::value, void>::type
inline constructor_fx(F&& f) noexcept {
reset(std::forward<F>(f));
}
template <typename F>
typename std::enable_if<std::is_same<typename std::decay<F>::type, Function>::value, void>::type
inline constructor_rt(F& f) noexcept {
const Function fx = static_cast<Function>(f);
reset(fx);
}
template <typename F>
typename std::enable_if<!std::is_same<typename std::decay<F>::type, Function>::value, void>::type
inline constructor_rt(F&& f) noexcept {
constructor_fx(f);
}
template <typename F>
typename std::enable_if<stl::is_invocable<typename std::decay<F>::type, Args...>::value, void>::type
inline constructor(F&& f) noexcept {
constructor_rt(std::forward<F>(f));
}
template <typename F>
typename std::enable_if<!stl::is_invocable<typename std::decay<F>::type, Args...>::value, void>::type
inline constructor(F&&) noexcept {
reset();
}
public:
virtual ~function() noexcept {
reset();
}
public:
inline function& operator=(function&& other) noexcept {
move(std::forward<function>(other));
return *this;
}
inline function& operator=(const function& other) noexcept {
function* const reft = (function*)&reinterpret_cast<const char&>(other);
function* const left = this;
if (left != reft) {
// Copy the field value on the right to the top of the stack.
Function reft_f = NULL;
std::shared_ptr<ICallable> reft_callable;
{
LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function&>(other));
reft_f = other.f_;
reft_callable = other.callable_;
}
// Writes the field value stored on the stack to the corresponding field of this function object.
{
LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
this->f_ = reft_f;
this->callable_ = reft_callable;
}
}
return *left;
}
inline function& operator=(std::nullptr_t) {
reset();
return *this;
}
inline explicit operator bool() const {
using TFunctionConst = typename std::decay<decltype(*this)>::type;
using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;
LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable&>(*this));
return NULL != f_ || NULL != callable_;
}
public:
virtual R operator()(Args... args) const {
using TFunctionConst = typename std::decay<decltype(*this)>::type;
using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;
// Calls still first synchronize the destination function address,
// held from the function object or wrap a reference to the calling object onto the stack.
do {
Function f = NULL;
std::shared_ptr<ICallable> i;
{
LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable&>(*this));
f = this->f_;
i = this->callable_;
}
if (NULL != i) {
return i->Invoke(std::forward<Args>(args)...);
}
if (NULL != f) {
return f(std::forward<Args>(args)...);
}
} while (false);
// It may be a thread-safe issue to throw an exception for the caller to catch
// if the current function object is not a null pointer.
throw std::runtime_error("Cannot call a function with an null address delegated.");
}
public:
inline void swap(function& other) noexcept {
// Copy the field values of the function on the left.
Function left_f = NULL;
std::shared_ptr<ICallable> left_callable;
{
LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
left_f = this->f_;
left_callable = this->callable_;
}
// Copy the field values of the function on the right.
Function reft_f = NULL;
std::shared_ptr<ICallable> reft_callable;
{
LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function&>(other));
reft_f = other.f_;
reft_callable = other.callable_;
}
// Formally replace the values on both sides, but in the process of exchange,
// high concurrency may occur and the newly written field values will be overwritten,
// there will be new and old data overwriting problems, developers need to use the function carefully,
// or ensure the linearity of the logic outside.
{
LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
this->f_ = reft_f;
this->callable_ = reft_callable;
}
// Swap the value on the left to the function object on the right.
{
LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function&>(other));
other.f_ = left_f;
other.callable_ = left_callable;
}
}
inline void reset() noexcept {
LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
reset_unsafe();
}
inline void reset(const Function& f) noexcept {
LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
reset_unsafe(f);
}
template <typename F>
inline void reset(F&& f) noexcept {
LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
reset_unsafe(std::forward<F>(f));
}
private:
inline void reset_unsafe() noexcept {
this->f_ = NULL;
this->callable_.reset();
}
inline void reset_unsafe(const Function& f) noexcept {
reset_unsafe();
this->f_ = f;
}
template <typename F>
inline void reset_unsafe(F&& f) noexcept {
reset_unsafe_bind<R>(std::forward<F>(f));
}
template <typename E, typename F>
typename std::enable_if<!std::is_same<E, void>::value, void>::type
inline reset_unsafe_bind(F&& f) noexcept {
using TFunction = typename std::decay<F>::type;
using TCallable = Callable<TFunction>;
reset_unsafe_bind_fx<F, TFunction, TCallable>(std::forward<F>(f));
}
template <typename E, typename F>
typename std::enable_if<std::is_same<E, void>::value, void>::type
inline reset_unsafe_bind(F&& f) noexcept {
using TFunction = typename std::decay<F>::type;
using TCallable = CallableVoid<TFunction>;
reset_unsafe_bind_fx<F, TFunction, TCallable>(std::forward<F>(f));
}
template <typename F, typename TFunction, typename TCallable>
inline void reset_unsafe_bind_fx(F&& f) noexcept {
reset_unsafe();
TCallable* fx = new TCallable(std::forward<TFunction>(f));
if (NULL != fx) {
this->callable_ = std::shared_ptr<TCallable>(fx);
}
}
private:
inline void lock() noexcept {
for (;;) {
bool expected = false;
if (lk_.compare_exchange_strong(expected, true, std::memory_order_acquire)) {
break;
}
}
}
inline void unlock() {
bool expected = true;
if (!lk_.compare_exchange_strong(expected, false, std::memory_order_release)) {
throw std::runtime_error("failed to acquire the atomic lock.");
}
}
inline void move(function&& other) noexcept {
Function left_f = NULL;
std::shared_ptr<ICallable> left_callable; // COW.
{
// Move and copy the field value of the right function object to the left function object.
LockScope<typename std::decay<decltype(*this)>::type> scope(other);
left_f = other.f_;
left_callable = std::move(other.callable_);
// Reset and release the field value reference technique held by the function object on the right and so on.
other.f_ = NULL;
other.callable_.reset();
}
// Writes the field value stored on the stack to the corresponding field of this function object.
{
LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
this->f_ = left_f;
this->callable_ = left_callable;
}
}
private:
class ICallable {
public:
ICallable() = default;
virtual ~ICallable() noexcept {}
public:
virtual R Invoke(Args&&... args) const = 0;
};
template <typename F>
class Callable : public ICallable {
public:
Callable(F&& f) noexcept : f_(std::forward<F>(f)) {}
virtual ~Callable() noexcept {}
public:
virtual R Invoke(Args&&... args) const override {
return f_(std::forward<Args>(args)...);
}
private:
mutable F f_;
};
template <typename F>
class CallableVoid : public ICallable {
public:
CallableVoid(F&& f) noexcept : f_(std::forward<F>(f)) {}
virtual ~CallableVoid() noexcept {}
public:
virtual R Invoke(Args&&... args) const override {
f_(std::forward<Args>(args)...);
return R{};
}
private:
mutable F f_;
};
template <typename T>
class LockScope {
public:
LockScope(T& obj) noexcept
: obj_(obj) {
obj_.lock();
}
~LockScope() noexcept {
obj_.unlock();
}
private:
T& obj_;
};
private:
mutable std::atomic<bool> lk_;
mutable Function f_;
mutable std::shared_ptr<ICallable> callable_; // COW.
};
template <class F>
inline bool operator==(const function<F>& other, std::nullptr_t) noexcept {
return !other;
}
template <class F>
inline bool operator==(std::nullptr_t, const function<F>& other) noexcept {
return !other;
}
template <class F>
inline bool operator!=(const function<F>& other, std::nullptr_t) noexcept {
return static_cast<bool>(other);
}
template <class F>
inline bool operator!=(std::nullptr_t, const function<F>& other) noexcept {
return static_cast<bool>(other);
}
C++ 17 实现
template <typename Signature>
class function;
template <typename R, typename... Args>
class function<R(Args...)> {
public:
using Function = R(*)(Args...);
public:
function() noexcept {}
function(std::nullptr_t) noexcept {}
function(function&& other) noexcept {
move(std::forward<function>(other));
}
function(const function& other) noexcept {
LockScope<typename std::decay<decltype(*this)>::type> scope(const_cast<function&>(other));
this->f_ = other.f_;
this->callable_ = other.callable_;
}
public:
template <typename F>
function(F&& f) {
reset(std::forward<F>(f));
}
public:
virtual ~function() noexcept {
reset();
}
public:
inline function& operator=(function&& other) noexcept {
move(std::forward<function>(other));
return *this;
}
inline function& operator=(const function& other) noexcept {
function* const reft = (function*)&reinterpret_cast<const char&>(other);
function* const left = this;
if (left != reft) {
// Copy the field value on the right to the top of the stack.
Function reft_f = NULL;
std::shared_ptr<ICallable> reft_callable;
{
LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function&>(other));
reft_f = other.f_;
reft_callable = other.callable_;
}
// Writes the field value stored on the stack to the corresponding field of this function object.
{
LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
this->f_ = reft_f;
this->callable_ = reft_callable;
}
}
return *left;
}
inline function& operator=(std::nullptr_t) {
reset();
return *this;
}
inline explicit operator bool() const {
using TFunctionConst = typename std::decay<decltype(*this)>::type;
using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;
LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable&>(*this));
return NULL != f_ || NULL != callable_;
}
public:
virtual R operator()(Args... args) const {
using TFunctionConst = typename std::decay<decltype(*this)>::type;
using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;
// Calls still first synchronize the destination function address,
// held from the function object or wrap a reference to the calling object onto the stack.
do {
Function f = NULL;
std::shared_ptr<ICallable> i;
{
LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable&>(*this));
f = this->f_;
i = this->callable_;
}
if (NULL != i) {
return i->Invoke(std::forward<Args>(args)...);
}
if (NULL != f) {
return f(std::forward<Args>(args)...);
}
} while (false);
// It may be a thread-safe issue to throw an exception for the caller to catch
// if the current function object is not a null pointer.
throw std::runtime_error("Cannot call a function with an null address delegated.");
}
public:
inline void swap(function& other) noexcept {
// Copy the field values of the function on the left.
Function left_f = NULL;
std::shared_ptr<ICallable> left_callable;
{
LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
left_f = this->f_;
left_callable = this->callable_;
}
// Copy the field values of the function on the right.
Function reft_f = NULL;
std::shared_ptr<ICallable> reft_callable;
{
LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function&>(other));
reft_f = other.f_;
reft_callable = other.callable_;
}
// Formally replace the values on both sides, but in the process of exchange,
// high concurrency may occur and the newly written field values will be overwritten,
// there will be new and old data overwriting problems, developers need to use the function carefully,
// or ensure the linearity of the logic outside.
{
LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
this->f_ = reft_f;
this->callable_ = reft_callable;
}
// Swap the value on the left to the function object on the right.
{
LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function&>(other));
other.f_ = left_f;
other.callable_ = left_callable;
}
}
inline void reset() noexcept {
LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
this->f_ = NULL;
this->callable_.reset();
}
inline void reset(const Function& f) noexcept {
LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
this->f_ = f;
this->callable_.reset();
}
template <typename F>
inline void reset(F&& f) {
using TFunction = typename std::decay<F>::type;
using TSynchronizedObject = typename std::decay<decltype(*this)>::type;
LockScope<TSynchronizedObject> scope(*this);
reset<F, TFunction>(std::forward<F>(f));
}
private:
template <typename F, typename TFunction>
inline void reset(F&& f) {
this->f_ = NULL;
this->callable_.reset();
if constexpr (std::is_same<Function, TFunction>::value) {
this->f_ = f;
this->callable_ = NULL;
}
elif constexpr (std::is_same<function, TFunction>::value) {
this->f_ = f.f_;
this->callable_ = f.callable_;
}
elif constexpr (std::is_empty<TFunction>::value) {
static_assert(stl::is_invocable<TFunction, Args...>::value, "Unknown expressions, not supported!");
this->f_ = f;
this->callable_ = NULL;
}
elif constexpr (std::is_integral<TFunction>::value) {
if (f != 0) {
throw std::runtime_error("It's not allowed to pass an integer value to the constructor, but it's allowed to pass an integer 0 to the constructor of a function, which represents a NULL function pointer.");
}
}
else {
using TCallable = Callable<TFunction>;
TCallable* fx = new TCallable(std::forward<TFunction>(f));
if (NULL != fx) {
this->callable_ = std::shared_ptr<TCallable>(fx);
}
}
}
private:
inline void lock() noexcept {
for (;;) {
bool expected = false;
if (lk_.compare_exchange_strong(expected, true, std::memory_order_acquire)) {
break;
}
}
}
inline void unlock() {
bool expected = true;
if (!lk_.compare_exchange_strong(expected, false, std::memory_order_release)) {
throw std::runtime_error("failed to acquire the atomic lock.");
}
}
inline void move(function&& other) noexcept {
Function left_f = NULL;
std::shared_ptr<ICallable> left_callable; // COW.
{
// Move and copy the field value of the right function object to the left function object.
LockScope<typename std::decay<decltype(*this)>::type> scope(other);
left_f = other.f_;
left_callable = std::move(other.callable_);
// Reset and release the field value reference technique held by the function object on the right and so on.
other.f_ = NULL;
other.callable_.reset();
}
// Writes the field value stored on the stack to the corresponding field of this function object.
{
LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
this->f_ = left_f;
this->callable_ = left_callable;
}
}
private:
class ICallable {
public:
ICallable() = default;
virtual ~ICallable() noexcept {}
public:
virtual R Invoke(Args&&... args) const = 0;
};
template <typename F>
class Callable : public ICallable {
public:
Callable(const F& f) noexcept : f_(f) {}
Callable(F&& f) noexcept : f_(std::forward<F>(f)) {}
virtual ~Callable() noexcept {}
public:
virtual R Invoke(Args&&... args) const override {
if constexpr (std::is_same<R, void>::value) { /* sizeof...(args) */
f_(std::forward<Args>(args)...);
}
else {
return f_(std::forward<Args>(args)...); /* return R{}; */
}
}
private:
mutable F f_;
};
template <typename T>
class LockScope {
public:
LockScope(T& obj) noexcept
: obj_(obj) {
obj_.lock();
}
~LockScope() noexcept {
obj_.unlock();
}
private:
T& obj_;
};
private:
mutable std::atomic<bool> lk_ = false;
mutable Function f_ = NULL;
mutable std::shared_ptr<ICallable> callable_ = NULL; // COW.
};
template <class F>
inline bool operator==(const function<F>& other, std::nullptr_t) noexcept {
return !other;
}
template <class F>
inline bool operator==(std::nullptr_t, const function<F>& other) noexcept {
return !other;
}
template <class F>
inline bool operator!=(const function<F>& other, std::nullptr_t) noexcept {
return static_cast<bool>(other);
}
template <class F>
inline bool operator!=(std::nullptr_t, const function<F>& other) noexcept {
return static_cast<bool>(other);
}