浏览代码

fix(shared_ptr): operator= on derived class, swap

greatbridf 9 月之前
父节点
当前提交
80d0ee4dd2
共有 3 个文件被更改,包括 140 次插入109 次删除
  1. 4 4
      gblibstdc++/include/bits/rbtree
  2. 132 101
      gblibstdc++/include/memory
  3. 4 4
      gblibstdc++/include/set

+ 4 - 4
gblibstdc++/include/bits/rbtree

@@ -24,7 +24,7 @@ struct rbtree {
         constexpr node(T&& val)
             : parent {}, left {}, right {}
             , value { std::move(val) } , color {node_color::RED} {}
-        
+
         template <typename... Args, std::enable_if_t<
             (sizeof...(Args) > 1)
             || !(... && std::is_same_v<T, std::remove_cvref_t<Args>>)
@@ -343,7 +343,7 @@ public:
         if (root)
             root->parent = nullptr;
     }
-    
+
     constexpr rbtree(rbtree&& other) noexcept
         : root(std::exchange(other.root, nullptr))
         , alloc(std::move(other.alloc))
@@ -354,7 +354,7 @@ public:
         : root(std::exchange(other.root, nullptr))
         , alloc(alloc) , _size(std::exchange(other._size, 0))
         , comp(std::move(other.comp)) {}
-    
+
     constexpr ~rbtree() { destroy(); }
 
     constexpr rbtree& operator=(const rbtree& other)
@@ -372,7 +372,7 @@ public:
 
         return *this;
     }
-    
+
     constexpr rbtree& operator=(rbtree&& other) noexcept
     {
         destroy(root);

+ 132 - 101
gblibstdc++/include/memory

@@ -379,10 +379,20 @@ private:
 
         constexpr control_block_base(std::size_t ref_count,
             std::size_t weak_count, pointer ptr)
-            : ref_count(ref_count), weak_count(weak_count), ptr(ptr) { }
+            : ref_count(ref_count)
+            , weak_count(weak_count)
+            , ptr(ptr)
+        {
+        }
 
         virtual constexpr ~control_block_base() = default;
         virtual constexpr void do_delete() = 0;
+
+        // template <typename U, std::enable_if_t<std::is_convertible_v<T*, U*>, bool> = true>
+        // constexpr operator typename shared_ptr<U>::control_block_base*() const
+        // {
+        //     return this;
+        // }
     };
 
     template <typename Deleter>
@@ -394,7 +404,9 @@ private:
         constexpr control_block(std::size_t ref_count,
             std::size_t weak_count, pointer ptr, UDeleter&& deleter)
             : control_block_base { ref_count, weak_count, ptr }
-            , deleter(std::forward<UDeleter>(deleter)) { }
+            , deleter(std::forward<UDeleter>(deleter))
+        {
+        }
 
         virtual constexpr void do_delete() override
         {
@@ -409,7 +421,9 @@ private:
 
         constexpr default_control_block(std::size_t ref_count,
             std::size_t weak_count, pointer ptr)
-            : control_block_base { ref_count, weak_count, ptr } { }
+            : control_block_base { ref_count, weak_count, ptr }
+        {
+        }
 
         virtual constexpr void do_delete() override
         {
@@ -419,7 +433,8 @@ private:
         }
     };
 
-    control_block_base* cb { };
+    control_block_base* cb {};
+    pointer ptr {};
 
     void inc_ref()
     {
@@ -438,128 +453,139 @@ private:
 
 private:
     template <typename Deleter>
-    using rebind_allocator = typename std::allocator_traits<Deleter>::template
-        rebind_alloc<control_block<Deleter>>;
+    using rebind_allocator = typename std::allocator_traits<Deleter>::template rebind_alloc<control_block<Deleter>>;
 
     template <typename U>
     friend class shared_ptr;
 
 public:
     constexpr shared_ptr() noexcept = default;
-    constexpr shared_ptr(std::nullptr_t) noexcept : cb { } { }
+    constexpr shared_ptr(std::nullptr_t) noexcept { }
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    explicit shared_ptr(U* ptr) // TODO: array type
-        : cb(new default_control_block { 1, 0, ptr }) { }
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p) // TODO: array type
+        : cb(new default_control_block { 1, 0, p })
+        , ptr(p)
+    {
+    }
 
-    template <typename U, typename Deleter>
-    __GBLIBCPP_CONSTEXPR
-    explicit shared_ptr(U* ptr, Deleter d)
-        : cb(new control_block<Deleter> { 1, 0, ptr, d }) { }
+    template <typename U, typename Deleter, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d)
+        : cb(new control_block<Deleter> { 1, 0, p, d })
+        , ptr(p)
+    {
+    }
 
     template <typename Deleter>
-    __GBLIBCPP_CONSTEXPR
-    explicit shared_ptr(std::nullptr_t, Deleter d)
-        : cb(new control_block<Deleter> { 1, 0, nullptr, d }) { }
-
-    // TODO: what the fuck
-    // template <typename U, typename Deleter, typename Allocator>
-    // __GBLIBCPP_CONSTEXPR
-    // explicit shared_ptr(U* ptr, Deleter d, Allocator alloc)
-    // {
-    //     cb = std::allocator_traits<
-    //         rebind_allocator<Deleter>>::allocate(alloc, 1);
-
-    //     std::allocator_traits<
-    //         rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, ptr, d);
-    // }
-
-    // template <typename Deleter, typename Allocator>
-    // __GBLIBCPP_CONSTEXPR
-    // explicit shared_ptr(std::nullptr_t, Deleter d, Allocator alloc)
-    // {
-    //     cb = std::allocator_traits<
-    //         rebind_allocator<Deleter>>::allocate(alloc, 1);
-
-    //     std::allocator_traits<
-    //         rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, nullptr, d);
-    // }
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d)
+        : cb(new control_block<Deleter> { 1, 0, nullptr, d })
+    {
+    }
+
+    template <typename U, typename Deleter, typename Allocator,
+        enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d, Allocator alloc)
+    {
+        cb = std::allocator_traits<
+            rebind_allocator<Deleter>>::allocate(alloc, 1);
+
+        std::allocator_traits<
+            rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, p, d);
+
+        ptr = p;
+    }
+
+    template <typename Deleter, typename Allocator>
+    __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d, Allocator alloc)
+    {
+        cb = std::allocator_traits<
+            rebind_allocator<Deleter>>::allocate(alloc, 1);
+
+        std::allocator_traits<
+            rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, nullptr, d);
+    }
 
     __GBLIBCPP_CONSTEXPR
     shared_ptr(const shared_ptr& other) noexcept
-        : cb(other.cb) { inc_ref(); }
+        : cb(other.cb)
+        , ptr(other.ptr)
+    {
+        inc_ref();
+    }
 
-    template <typename U>
     __GBLIBCPP_CONSTEXPR
-    shared_ptr(const shared_ptr<U>& other) noexcept
-        : cb(other.cb) { inc_ref(); }
+    shared_ptr(shared_ptr&& other) noexcept
+        : cb(std::exchange(other.cb, nullptr))
+        , ptr(std::exchange(other.ptr, nullptr))
+    {
+    }
 
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
     __GBLIBCPP_CONSTEXPR
-    shared_ptr(shared_ptr&& other) noexcept
-        : cb(std::exchange(other.cb, nullptr)) { }
+    shared_ptr(const shared_ptr<U>& other) noexcept
+        : cb((control_block_base*)other.cb)
+        , ptr((T*)other.ptr)
+    {
+        inc_ref();
+    }
 
-    template <typename U>
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
     __GBLIBCPP_CONSTEXPR
     shared_ptr(shared_ptr<U>&& other) noexcept
-        : cb(std::exchange(other.cb, nullptr)) { }
-    
+        : cb((control_block_base*)std::exchange(other.cb, nullptr))
+        , ptr((T*)std::exchange(other.ptr, nullptr))
+    {
+    }
+
     // TODO: weak_ptr and unique_ptr
 
     __GBLIBCPP_CONSTEXPR
-    ~shared_ptr() { dec_ref(); }
+    ~shared_ptr()
+    {
+        dec_ref();
+        cb = nullptr;
+        ptr = nullptr;
+    }
 
     __GBLIBCPP_CONSTEXPR
     shared_ptr& operator=(const shared_ptr& other) noexcept
     {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = other.cb;
-            inc_ref();
-        }
+        shared_ptr { other }.swap(*this);
         return *this;
     }
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    shared_ptr& operator=(const shared_ptr<U>& other) noexcept
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR shared_ptr& operator=(const shared_ptr<U>& other) noexcept
     {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = other.cb;
-            inc_ref();
-        }
+        shared_ptr { other }.swap(*this);
         return *this;
     }
 
     __GBLIBCPP_CONSTEXPR
     shared_ptr& operator=(shared_ptr&& other) noexcept
     {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = std::exchange(other.cb, nullptr);
-        }
+        shared_ptr { move(other) }.swap(*this);
         return *this;
     }
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    shared_ptr& operator=(shared_ptr<U>&& other) noexcept
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR shared_ptr& operator=(shared_ptr<U>&& other) noexcept
     {
-        if (cb != other.cb) {
-            dec_ref();
-            cb = std::exchange(other.cb, nullptr);
-        }
+        shared_ptr { move(other) }.swap(*this);
         return *this;
     }
 
     __GBLIBCPP_CONSTEXPR
     element_type* get() const noexcept
-    { return cb ? cb->ptr : nullptr; }
+    {
+        return cb ? ptr : nullptr;
+    }
 
     __GBLIBCPP_CONSTEXPR
     explicit operator bool() const noexcept
-    { return get(); }
+    {
+        return get();
+    }
 
     __GBLIBCPP_CONSTEXPR
     T& operator*() const noexcept { return *get(); }
@@ -573,36 +599,41 @@ public:
 
     __GBLIBCPP_CONSTEXPR
     bool owner_before(const shared_ptr& other) const noexcept
-    { return cb < other.cb; }
+    {
+        return cb < other.cb;
+    }
 
     __GBLIBCPP_CONSTEXPR
-    void swap(shared_ptr& other) noexcept { std::swap(cb->ptr, other.cb->ptr); }
+    void swap(shared_ptr& other) noexcept
+    {
+        std::swap(cb, other.cb);
+        std::swap(ptr, other.ptr);
+    }
 
     __GBLIBCPP_CONSTEXPR
-    void reset() noexcept { dec_ref(); cb = nullptr; }
+    void reset() noexcept
+    {
+        shared_ptr {}.swap(*this);
+    }
 
-    template <typename U>
-    __GBLIBCPP_CONSTEXPR
-    void reset(U* ptr) noexcept
-    { dec_ref(); cb = new default_control_block { 1, 0, ptr }; }
+    template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR void reset(U* p) noexcept
+    {
+        shared_ptr { p }.swap(*this);
+    }
 
-    template <typename U, typename Deleter>
-    __GBLIBCPP_CONSTEXPR
-    void reset(U* ptr, Deleter d) noexcept
-    { dec_ref(); cb = new control_block<Deleter> { 1, 0, ptr, d }; }
-
-    // TODO: what the fuck
-    // template <typename U, typename Deleter, typename Allocator>
-    // __GBLIBCPP_CONSTEXPR
-    // void reset(U* ptr, Deleter d, Allocator alloc)
-    // {
-    //     dec_ref();
-    //     cb = std::allocator_traits<
-    //         rebind_allocator<Deleter>>::allocate(alloc, 1);
-
-    //     std::allocator_traits<
-    //         rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, ptr, d);
-    // }
+    template <typename U, typename Deleter, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d) noexcept
+    {
+        shared_ptr { p, d }.swap(*this);
+    }
+
+    template <typename U, typename Deleter, typename Allocator,
+        enable_if_t<is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d, Allocator alloc)
+    {
+        shared_ptr { p, d, alloc }.swap(*this);
+    }
 };
 
 // TODO: use only one allocation

+ 4 - 4
gblibstdc++/include/set

@@ -49,7 +49,7 @@ public:
     set(const Compare& comp,
         const Allocator& alloc = Allocator())
         : tree(comp, alloc) {}
-    
+
     explicit __GBLIBCPP_CONSTEXPR
     set(const Allocator& alloc)
         : set(Compare(), alloc) {}
@@ -91,15 +91,15 @@ public:
         const Allocator& alloc = Allocator())
         : set(comp, alloc)
     { insert(ilist.begin(), ilist.end()); }
-    
+
     __GBLIBCPP_CONSTEXPR
     set(std::initializer_list<Key> ilist,
         const Allocator& alloc)
         : set(ilist, Compare(), alloc) {}
-    
+
     __GBLIBCPP_CONSTEXPR
     ~set() { clear(); }
-    
+
     __GBLIBCPP_CONSTEXPR
     set& operator=(const set& other) = default;
     __GBLIBCPP_CONSTEXPR