Ignore:
Timestamp:
2018-07-05T21:41:23Z (7 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_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.