Changeset 5735b111 in mainline


Ignore:
Timestamp:
2018-07-05T21:41:23Z (6 years ago)
Author:
Dzejrou <dzejrou@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5df0491
Parents:
e13c378
git-author:
Dzejrou <dzejrou@…> (2018-05-09 20:16:49)
git-committer:
Dzejrou <dzejrou@…> (2018-07-05 21:41:23)
Message:

cpp: added a basic shared_ptr implementation

Location:
uspace/lib/cpp/include/internal/memory
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/internal/memory/shared_payload.hpp

    re13c378 r5735b111  
    3030#define LIBCPP_INTERNAL_MEMORY_SHARED_PAYLOAD
    3131
    32 #include <internal/list.hpp>
     32#include <cinttypes>
     33#include <utility>
     34
     35namespace std
     36{
     37    template<class>
     38    struct default_delete;
     39
     40    struct allocator_arg_t;
     41}
    3342
    3443namespace std::aux
     
    4049    using refcount_t = long;
    4150
     51    template<class D, class T>
     52    void use_payload_deleter(D* deleter, T* data)
     53    {
     54        if (deleter)
     55            (*deleter)(data);
     56    }
     57
    4258    template<class T>
    43     class shared_payload
     59    class shared_payload_base
    4460    {
    4561        public:
     62            virtual void destroy() = 0;
     63            virtual T* get() const noexcept = 0;
     64
     65            virtual uint8_t* deleter() const noexcept = 0;
     66
     67            virtual void increment() noexcept = 0;
     68            virtual void increment_weak() noexcept = 0;
     69            virtual bool decrement() noexcept = 0;
     70            virtual bool decrement_weak() noexcept = 0;
     71            virtual refcount_t refs() const noexcept = 0;
     72            virtual refcount_t weak_refs() const noexcept = 0;
     73            virtual bool expired() const noexcept = 0;
     74
     75            virtual ~shared_payload_base() = default;
     76    };
     77
     78    template<class T, class D = default_delete<T>>
     79    class shared_payload: public shared_payload_base<T>
     80    {
     81        public:
     82            shared_payload(T* ptr, D deleter = D{})
     83                : data_{ptr}, deleter_{deleter},
     84                  refcount_{1}, weak_refcount_{1}
     85            { /* DUMMY BODY */ }
    4686
    4787            template<class... Args>
    4888            shared_payload(Args&&... args)
     89                : data_{new T{forward<Args>(args)...}},
     90                  deleter_{}, refcount_{1}, weak_refcount_{1}
    4991            { /* DUMMY BODY */ }
    5092
    5193            template<class Alloc, class... Args>
    52             shared_payloda(Alloc alloc, Args&&... args)
    53             { /* DUMMY BODY */ }
     94            shared_payload(allocator_arg_t, Alloc alloc, Args&&... args)
     95                : data_{alloc.allocate(1)},
     96                  deleter_{}, refcount_{1}, weak_refcount_{1}
     97            {
     98                alloc.construct(data_, forward<Args>(args)...);
     99            }
    54100
    55             T* get() const
     101            template<class Alloc, class... Args>
     102            shared_payload(D deleter, Alloc alloc, Args&&... args)
     103                : data_{alloc.allocate(1)},
     104                  deleter_{deleter}, refcount_{1}, weak_refcount_{1}
     105            {
     106                alloc.construct(data_, forward<Args>(args)...);
     107            }
     108
     109            void destroy() override
     110            {
     111                if (refs() == 0)
     112                {
     113                    if (data_)
     114                    {
     115                        deleter_(data_);
     116                        data_ = nullptr;
     117                    }
     118
     119                    if (weak_refs() == 0)
     120                        delete this;
     121                }
     122            }
     123
     124            T* get() const noexcept override
    56125            {
    57126                return data_;
    58127            }
    59128
    60             void increment_refcount()
     129            uint8_t* deleter() const noexcept override
    61130            {
    62                 ++refcount_;
     131                return (uint8_t*)&deleter_;
    63132            }
    64133
    65             void increment_weak_refcount()
     134            void increment() noexcept override
    66135            {
    67                 ++weak_refcount_;
     136                __atomic_add_fetch(&refcount_, 1, __ATOMIC_ACQ_REL);
    68137            }
    69138
    70             bool decrement_refcount()
     139            void increment_weak() noexcept override
    71140            {
    72                 return --refcount_ == 0;
     141                __atomic_add_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL);
    73142            }
    74143
    75             bool decrement_weak_refcount()
     144            bool decrement() noexcept override
    76145            {
    77                 return --weak_refcount_ == 0;
     146                if (__atomic_sub_fetch(&refcount_, 1, __ATOMIC_ACQ_REL) == 0)
     147                    return decrement_weak();
     148                else
     149                    return false;
    78150            }
    79151
    80             refcount_t refs() const
     152            bool decrement_weak() noexcept override
    81153            {
    82                 return refcount_;
     154                return __atomic_sub_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL) == 0 && refs() == 0;
    83155            }
    84156
    85             refcount_t weak_refs() const
     157            refcount_t refs() const noexcept override
    86158            {
    87                 return weak_refcount_;
     159                return __atomic_load_n(&refcount_, __ATOMIC_RELAXED);
     160            }
     161
     162            refcount_t weak_refs() const noexcept override
     163            {
     164                return __atomic_load_n(&weak_refcount_, __ATOMIC_RELAXED);
     165            }
     166
     167            bool expired() const noexcept override
     168            {
     169                return refs() == 0;
    88170            }
    89171
    90172        private:
    91173            T* data_;
     174            D deleter_;
     175
     176            /**
     177             * We're using a trick where refcount_ > 0
     178             * means weak_refcount_ has 1 added to it,
     179             * this makes it easier for weak_ptrs that
     180             * can't decrement the weak_refcount_ to
     181             * zero with shared_ptrs using this object.
     182             */
    92183            refcount_t refcount_;
    93184            refcount_t weak_refcount_;
  • uspace/lib/cpp/include/internal/memory/shared_ptr.hpp

    re13c378 r5735b111  
    3232#include <exception>
    3333#include <functional>
     34#include <internal/memory/allocator_arg.hpp>
     35#include <internal/memory/shared_payload.hpp>
    3436#include <type_traits>
    3537
    3638namespace std
    3739{
     40    template<class T>
     41    class weak_ptr;
     42
    3843    /**
    3944     * 20.8.2.1, class bad_weak_ptr:
     
    6570             */
    6671
    67             constexpr shared_ptr() noexcept;
    68 
    69             template<class U>
    70             explicit shared_ptr(U* ptr);
     72            constexpr shared_ptr() noexcept
     73                : payload_{}, data_{}
     74            { /* DUMMY BODY */ }
     75
     76            template<class U>
     77            explicit shared_ptr(
     78                enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr
     79            )
     80                : payload_{}, data_{ptr}
     81            {
     82                try
     83                {
     84                    payload_ = new aux::shared_payload<T>{ptr};
     85                }
     86                catch (const bad_alloc&)
     87                {
     88                    delete ptr;
     89
     90                    throw;
     91                }
     92            }
    7193
    7294            template<class U, class D>
    73             shared_ptr(U* ptr, D deleter);
     95            shared_ptr(
     96                enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr, D deleter
     97            )
     98                : shared_ptr{}
     99            {
     100                try
     101                {
     102                    payload_ = new aux::shared_payload<T, D>{ptr, deleter};
     103                }
     104                catch (const bad_alloc&)
     105                {
     106                    deleter(ptr);
     107
     108                    throw;
     109                }
     110            }
    74111
    75112            template<class U, class D, class A>
    76             shared_ptr(U* ptr, D deleter, A alloc);
     113            shared_ptr(
     114                enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr,
     115                D deleter, A
     116            )
     117                : shared_ptr{}
     118            {
     119                try
     120                {
     121                    payload_ = new aux::shared_payload<T, D>{ptr, deleter};
     122                }
     123                catch (const bad_alloc&)
     124                {
     125                    deleter(ptr);
     126
     127                    throw;
     128                }
     129            }
    77130
    78131            template<class D>
    79             shared_ptr(nullptr_t, D deleter);
     132            shared_ptr(nullptr_t ptr, D deleter)
     133                : shared_ptr{}
     134            { /* DUMMY BODY */ }
    80135
    81136            template<class D, class A>
    82             shared_ptr(nullptr_t, D deleter, A alloc);
    83 
    84             template<class U>
    85             shared_ptr(const shared_ptr<U>& other, value_type* ptr);
    86 
    87             shared_ptr(const shared_ptr& other);
    88 
    89             template<class U>
    90             shared_ptr(const shared_ptr<U>& other);
    91 
    92             shared_ptr(shared_ptr&& other);
    93 
    94             template<class U>
    95             shared_ptr(shared_ptr<U>&& other);
    96 
    97             template<class U>
    98             explicit shared_ptr(const weak_ptr<U>& other);
     137            shared_ptr(nullptr_t, D deleter, A)
     138                : shared_ptr{}
     139            { /* DUMMY BODY */ }
     140
     141            template<class U>
     142            shared_ptr(
     143                enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> other,
     144                element_type* ptr
     145            )
     146                : payload_{other.payload_}, data_{ptr}
     147            {
     148                if (payload_)
     149                    payload_->increment();
     150            }
     151
     152            shared_ptr(const shared_ptr& other)
     153                : payload_{other.payload_}, data_{other.data_}
     154            {
     155                if (payload_)
     156                    payload_->increment();
     157            }
     158
     159            template<class U>
     160            shared_ptr(
     161                enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> other
     162            )
     163                : payload_{other.payload_}, data_{other.data_}
     164            {
     165                if (payload_)
     166                    payload_->increment();
     167            }
     168
     169            shared_ptr(shared_ptr&& other)
     170                : payload_{move(other.payload_)}, data_{move(other.data_)}
     171            {
     172                other.payload_ = nullptr;
     173                other.data_ = nullptr;
     174            }
     175
     176            template<class U>
     177            shared_ptr(
     178                enable_if_t<is_convertible_v<U*, element_type*>, shared_ptr<U>&&> other
     179            )
     180                : payload_{move(other.payload_)}, data_{move(other.data_)}
     181            {
     182                other.payload_ = nullptr;
     183                other.data_ = nullptr;
     184            }
     185
     186            template<class U>
     187            explicit shared_ptr(
     188                enable_if_t<is_convertible_v<U*, element_type*>, const weak_ptr<U>&> other
     189            )
     190            {
     191                if (other.expired())
     192                    throw bad_weak_ptr{};
     193                // TODO:
     194            }
    99195
    100196            template<class U, class D>
    101             shared_ptr(unique_ptr<U, D>&& other);
     197            shared_ptr(
     198                enable_if_t<
     199                    is_convertible_v<
     200                        typename unique_ptr<U, D>::pointer,
     201                        element_type*
     202                    >,
     203                    unique_ptr<U, D>&&
     204                > other
     205            ) // TODO: if D is a reference type, it should be ref(other.get_deleter())
     206                : shared_ptr{other.release(), other.get_deleter()}
     207            { /* DUMMY BODY */ }
    102208
    103209            constexpr shared_ptr(nullptr_t) noexcept
     
    109215             */
    110216
    111             ~shared_ptr();
     217            ~shared_ptr()
     218            {
     219                remove_payload_();
     220            }
    112221
    113222            /**
     
    115224             */
    116225
    117             shared_ptr& operator=(const shared_ptr& rhs) noexcept;
    118 
    119             template<class U>
    120             shared_ptr& operator=(const shared_ptr<U>& rhs) noexcept;
    121 
    122             shared_ptr& operator=(shared_ptr&& rhs) noexcept;
    123 
    124             template<class U>
    125             shared_ptr& operator=(shared_ptr<U>&& rhs) noexcept;
     226            shared_ptr& operator=(const shared_ptr& rhs) noexcept
     227            {
     228                if (rhs.payload_)
     229                    rhs.payload_->increment();
     230
     231                remove_payload_();
     232
     233                payload_ = rhs.payload_;
     234                data_ = rhs.data_;
     235
     236                return *this;
     237            }
     238
     239            template<class U>
     240            shared_ptr& operator=(
     241                enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> rhs
     242            ) noexcept
     243            {
     244                if (rhs.payload_)
     245                    rhs.payload_->increment();
     246
     247                remove_payload_();
     248
     249                payload_ = rhs.payload_;
     250                data_ = rhs.data_;
     251
     252                return *this;
     253            }
     254
     255            shared_ptr& operator=(shared_ptr&& rhs) noexcept
     256            {
     257                shared_ptr{move(rhs)}.swap(*this);
     258
     259                return *this;
     260            }
     261
     262            template<class U>
     263            shared_ptr& operator=(
     264                enable_if_t<is_convertible_v<U*, element_type*>, shared_ptr<U>&&> rhs
     265            ) noexcept
     266            {
     267                shared_ptr{move(rhs)}.swap(*this);
     268
     269                return *this;
     270            }
    126271
    127272            template<class U, class D>
    128             shared_ptr& operator=(unique_ptr<U, D>&& rhs);
     273            shared_ptr& operator=(unique_ptr<U, D>&& rhs)
     274            {
     275                shared_ptr{move(rhs)}.swap(*this);
     276
     277                return *this;
     278            }
    129279
    130280            /**
     
    132282             */
    133283
    134             void swap(shared_ptr& other) noexcept;
    135 
    136             void reset() noexcept;
    137 
    138             template<class U>
    139             void reset(U* ptr);
     284            void swap(shared_ptr& other) noexcept
     285            {
     286                std::swap(payload_, other.payload_);
     287                std::swap(data_, other.data_);
     288            }
     289
     290            void reset() noexcept
     291            {
     292                shared_ptr{}.swap(*this);
     293            }
     294
     295            template<class U>
     296            void reset(U* ptr)
     297            {
     298                shared_ptr{ptr}.swap(*this);
     299            }
    140300
    141301            template<class U, class D>
    142             void reset(U* ptr, D deleter);
     302            void reset(U* ptr, D deleter)
     303            {
     304                shared_ptr{ptr, deleter}.swap(*this);
     305            }
    143306
    144307            template<class U, class D, class A>
    145             void reset(U* ptr, D deleter, A alloc);
     308            void reset(U* ptr, D deleter, A alloc)
     309            {
     310                shared_ptr{ptr, deleter, alloc}.swap(*this);
     311            }
    146312
    147313            /**
     
    151317            element_type* get() const noexcept
    152318            {
    153                 if (payload_)
    154                     return payload_->get();
    155                 else
    156                     return nullptr;
    157             }
    158 
    159             T& operator*() const noexcept;
     319                return data_;
     320            }
     321
     322            enable_if_t<!is_void_v<T>, T&> operator*() const noexcept
     323            {
     324                return *data_;
     325            }
    160326
    161327            T* operator->() const noexcept
     
    189355
    190356            template<class U>
    191             bool owner_before(const weak_ptr<U>& ptr) const;
     357            bool owner_before(const weak_ptr<U>& ptr) const
     358            {
     359                return payload_ < ptr.payload_;
     360            }
    192361
    193362        private:
    194             aux::shared_payload<element_type>* payload_;
    195 
    196             shared_ptr(aux::shared_payload<element_type>* payload)
    197                 : payload_{payload}
     363            aux::shared_payload_base<element_type>* payload_;
     364            element_type* data_;
     365
     366            shared_ptr(aux::shared_payload_base<element_type>* payload)
     367                : payload_{payload}, data_{payload->get()}
    198368            { /* DUMMY BODY */ }
     369
     370            void remove_payload_()
     371            {
     372                if (payload_)
     373                {
     374                    auto res = payload_->decrement();
     375                    if (res)
     376                        payload_->destroy();
     377
     378                    payload_ = nullptr;
     379                }
     380
     381                if (data_)
     382                    data_ = nullptr;
     383            }
    199384
    200385            template<class U, class... Args>
     
    203388            template<class U, class A, class... Args>
    204389            friend shared_ptr<U> allocate_shared(const A&, Args&&...);
     390
     391            template<class D, class U>
     392            D* get_deleter(const shared_ptr<U>&) noexcept;
     393
     394            template<class U>
     395            friend class weak_ptr;
    205396    };
    206397
     
    226417    {
    227418        return shared_ptr<T>{
    228             new aux::shared_payload<T>{A{alloc}, forward<Args>(args)...}
     419            new aux::shared_payload<T>{allocator_arg, A{alloc}, forward<Args>(args)...}
    229420        };
    230421    }
     
    394585    D* get_deleter(const shared_ptr<T>& ptr) noexcept
    395586    {
    396         // TODO: implement this through payload
     587        if (ptr.payload_)
     588            return static_cast<D*>(ptr.payload_->deleter());
     589        else
     590            return nullptr;
    397591    }
    398592
Note: See TracChangeset for help on using the changeset viewer.