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

File:
1 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_;
Note: See TracChangeset for help on using the changeset viewer.