Changeset 9c00022 in mainline


Ignore:
Timestamp:
2018-07-05T21:41:22Z (6 years ago)
Author:
Dzejrou <dzejrou@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
55540fca
Parents:
d2a66ae7
git-author:
Dzejrou <dzejrou@…> (2018-05-03 20:30:54)
git-committer:
Dzejrou <dzejrou@…> (2018-07-05 21:41:22)
Message:

cpp: added function

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/impl/functional.hpp

    rd2a66ae7 r9c00022  
    3131
    3232#include <limits>
     33#include <memory>
     34#include <typeinfo>
    3335#include <type_traits>
    3436#include <utility>
     
    753755     */
    754756
     757    namespace aux
     758    {
     759        // TODO: fix this
     760        /* template<class, class T, class... Args> */
     761        /* struct is_callable_impl: false_type */
     762        /* { /1* DUMMY BODY *1/ }; */
     763
     764        /* template<class, class R, class... Args> */
     765        /* struct is_callable_impl< */
     766        /*     void_t<decltype(aux::invoke(declval<R(Args...)>(), declval<Args>()..., R))>, */
     767        /*     R, Args... */
     768        /* > : true_type */
     769        /* { /1* DUMMY BODY *1/ }; */
     770
     771        /* template<class T> */
     772        /* struct is_callable: is_callable_impl<void_t<>, T> */
     773        /* { /1* DUMMY BODY *1/ }; */
     774
     775        template<class Callable, class R, class... Args>
     776        R invoke_callable(Callable* clbl, Args&&... args)
     777        {
     778            return (*clbl)(forward<Args>(args)...);
     779        }
     780
     781        template<class Callable>
     782        void copy_callable(Callable* to, Callable* from)
     783        {
     784            new(to) Callable{*from};
     785        }
     786
     787        template<class Callable>
     788        void destroy_callable(Callable* clbl)
     789        {
     790            if (clbl)
     791                clbl->~Callable();
     792        }
     793    }
     794
    755795    class bad_function_call;
    756796
     
    758798    class function; // undefined
    759799
     800    /**
     801     * Note: Ideally, this implementation wouldn't
     802     *       copy the target if it was a pointer to
     803     *       a function, but for the simplicity of the
     804     *       implementation, we do copy even in that
     805     *       case for now. It would be a nice optimization
     806     *       if this was changed in the future.
     807     */
    760808    template<class R, class... Args>
    761     class function<R(Args...)>;
     809    class function<R(Args...)>
     810    {
     811        public:
     812            using result_type = R;
     813            // TODO: conditional typedefs
     814
     815            /**
     816             * 20.9.12.2.1, construct/copy/destroy:
     817             */
     818
     819            function() noexcept
     820                : callable_{}, callable_size_{}, call_{},
     821                  copy_{}, dest_{}
     822            { /* DUMMY BODY */ }
     823
     824            function(nullptr_t) noexcept
     825                : function{}
     826            { /* DUMMY BODY */ }
     827
     828            function(const function& other)
     829                : callable_{}, callable_size_{other.callable_size_},
     830                  call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
     831            {
     832                callable_ = new uint8_t[callable_size_];
     833                (*copy_)(callable_, other.callable_);
     834            }
     835
     836            function(function&& other)
     837                : callable_{other.callable_}, callable_size_{other.callable_size_},
     838                  call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
     839            {
     840                other.callable_ = nullptr;
     841                other.callable_size_ = size_t{};
     842                other.call_ = nullptr;
     843                other.copy_ = nullptr;
     844                other.dest_ = nullptr;
     845            }
     846
     847            // TODO: shall not participate in overloading unless aux::is_callable<F>
     848            template<class F>
     849            function(F f)
     850                : callable_{}, callable_size_{sizeof(F)},
     851                  call_{(call_t)aux::invoke_callable<F, R, Args...>},
     852                  copy_{(copy_t)aux::copy_callable<F>},
     853                  dest_{(dest_t)aux::destroy_callable<F>}
     854            {
     855                callable_ = new uint8_t[callable_size_];
     856                (*copy_)(callable_, (uint8_t*)&f);
     857            }
     858
     859            /**
     860             * Note: For the moment we're ignoring the allocator
     861             *       for simplicity of the implementation.
     862             */
     863
     864            template<class A>
     865            function(allocator_arg_t, const A& a) noexcept
     866                : function{}
     867            { /* DUMMY BODY */ }
     868
     869            template<class A>
     870            function(allocator_arg_t, const A& a, nullptr_t) noexcept
     871                : function{}
     872            { /* DUMMY BODY */ }
     873
     874            template<class A>
     875            function(allocator_arg_t, const A& a, const function& other)
     876                : function{other}
     877            { /* DUMMY BODY */ }
     878
     879            template<class A>
     880            function(allocator_arg_t, const A& a, function&& other)
     881                : function{move(other)}
     882            { /* DUMMY BODY */ }
     883
     884            // TODO: shall not participate in overloading unless aux::is_callable<F>
     885            template<class F, class A>
     886            function(allocator_arg_t, const A& a, F f)
     887                : function{f}
     888            { /* DUMMY BODY */ }
     889
     890            function& operator=(const function& rhs)
     891            {
     892                function{rhs}.swap(*this);
     893
     894                return *this;
     895            }
     896
     897            /**
     898             * Note: We have to copy call_, copy_
     899             *       and dest_ because they can be templated
     900             *       by a type F we don't know.
     901             */
     902            function& operator=(function&& rhs)
     903            {
     904                clear_();
     905
     906                callable_ = rhs.callable_;
     907                callable_size_ = rhs.callable_size_;
     908                call_ = rhs.call_;
     909                copy_ = rhs.copy_;
     910                dest_ = rhs.dest_;
     911
     912                rhs.callable_ = nullptr;
     913                rhs.callable_size_ = size_t{};
     914                rhs.call_ = nullptr;
     915                rhs.copy_ = nullptr;
     916                rhs.dest_ = nullptr;
     917
     918                return *this;
     919            }
     920
     921            function& operator=(nullptr_t) noexcept
     922            {
     923                clear_();
     924
     925                return *this;
     926            }
     927
     928            // TODO: shall not participate in overloading unless aux::is_callable<F>
     929            template<class F>
     930            function& operator=(F&& f)
     931            {
     932                callable_size_ = sizeof(F);
     933                callable_ = new uint8_t[callable_size_];
     934                call_ = aux::invoke_callable<F, R, Args...>;
     935                copy_ = aux::copy_callable<F>;
     936                dest_ = aux::destroy_callable<F>;
     937
     938                (*copy_)(callable_, (uint8_t*)&f);
     939            }
     940
     941            template<class F>
     942            function& operator=(reference_wrapper<F> ref) noexcept
     943            {
     944                return (*this) = ref.get();
     945            }
     946
     947            ~function()
     948            {
     949                if (callable_)
     950                {
     951                    (*dest_)(callable_);
     952                    delete[] callable_;
     953                }
     954            }
     955
     956            /**
     957             * 20.9.12.2.2, function modifiers:
     958             */
     959
     960            void swap(function& other) noexcept
     961            {
     962                std::swap(callable_, other.callable_);
     963                std::swap(callable_size_, other.callable_size_);
     964                std::swap(call_, other.call_);
     965                std::swap(copy_, other.copy_);
     966                std::swap(dest_, other.dest_);
     967            }
     968
     969            template<class F, class A>
     970            void assign(F&& f, const A& a)
     971            {
     972                function{allocator_arg, a, forward<F>(f)}.swap(*this);
     973            }
     974
     975            /**
     976             * 20.9.12.2.3, function capacity:
     977             */
     978
     979            explicit operator bool() const noexcept
     980            {
     981                return callable_ != nullptr;
     982            }
     983
     984            /**
     985             * 20.9.12.2.4, function invocation:
     986             */
     987
     988            result_type operator()(Args... args) const
     989            {
     990                // TODO: throw bad_function_call if !callable_ || !call_
     991                if constexpr (is_same_v<R, void>)
     992                    (*call_)(callable_, forward<Args>(args)...);
     993                else
     994                    return (*call_)(callable_, forward<Args>(args)...);
     995            }
     996
     997            /**
     998             * 20.9.12.2.5, function target access:
     999             */
     1000
     1001            const type_info& target_type() const noexcept
     1002            {
     1003                return typeid(*callable_);
     1004            }
     1005
     1006            template<class T>
     1007            T* target() noexcept
     1008            {
     1009                if (target_type() == typeid(T))
     1010                    return (T*)callable_;
     1011                else
     1012                    return nullptr;
     1013            }
     1014
     1015            template<class T>
     1016            const T* target() const noexcept
     1017            {
     1018                if (target_type() == typeid(T))
     1019                    return (T*)callable_;
     1020                else
     1021                    return nullptr;
     1022            }
     1023
     1024        private:
     1025            using call_t = R(*)(uint8_t*, Args&&...);
     1026            using copy_t = void (*)(uint8_t*, uint8_t*);
     1027            using dest_t = void (*)(uint8_t*);
     1028
     1029            uint8_t* callable_;
     1030            size_t callable_size_;
     1031            call_t call_;
     1032            copy_t copy_;
     1033            dest_t dest_;
     1034
     1035            void clear_()
     1036            {
     1037                if (callable_)
     1038                {
     1039                    (*dest_)(callable_);
     1040                    delete[] callable_;
     1041                    callable_ = nullptr;
     1042                }
     1043            }
     1044    };
     1045
     1046    /**
     1047     * 20.9.12.2.7, specialized algorithms:
     1048     */
    7621049
    7631050    template<class R, class... Args>
    764     void swap(function<R(Args...)>& f1, function<R(Args...)>& f2);
     1051    void swap(function<R(Args...)>& f1, function<R(Args...)>& f2)
     1052    {
     1053        f1.swap(f2);
     1054    }
     1055
     1056    /**
     1057     * 20.9.12.2.6, null pointer comparisons:
     1058     */
    7651059
    7661060    template<class R, class... Args>
    767     bool operator==(const function<R(Args...)>&, nullptr_t) noexcept;
     1061    bool operator==(const function<R(Args...)>& f, nullptr_t) noexcept
     1062    {
     1063        return !f;
     1064    }
    7681065
    7691066    template<class R, class... Args>
    770     bool operator==(nullptr_t, const function<R(Args...)>&) noexcept;
     1067    bool operator==(nullptr_t, const function<R(Args...)>& f) noexcept
     1068    {
     1069        return !f;
     1070    }
    7711071
    7721072    template<class R, class... Args>
    773     bool operator!=(const function<R(Args...)>&, nullptr_t) noexcept;
     1073    bool operator!=(const function<R(Args...)>& f, nullptr_t) noexcept
     1074    {
     1075        return (bool)f;
     1076    }
    7741077
    7751078    template<class R, class... Args>
    776     bool operator!=(nullptr_t, const function<R(Args...)>&) noexcept;
     1079    bool operator!=(nullptr_t, const function<R(Args...)>& f) noexcept
     1080    {
     1081        return (bool)f;
     1082    }
    7771083
    7781084    /**
Note: See TracChangeset for help on using the changeset viewer.