C/C++ 11/14重写一个支援安全、不多次复制 std::function<...> 函数模板,支援 Lambda λ 及重载 operator()(...) 运元结构及C/C++语言普通函数。

159 篇文章 1 订阅

如本文标题所示,是为了进行优化,才进行重写的,并且砍掉了标准库 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);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值