summaryrefslogtreecommitdiffhomepage
path: root/compat/borrowed-ptr.inl
blob: 1d0ac7b61e8e94f8d2d679ce55c52471a082a833 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#pragma once
#include "compat/assert.hpp"
#include "borrowed-ptr.hpp"

namespace floormat::detail_borrowed_ptr {

#ifdef __GNUG__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif

struct control_block_
{
    explicit control_block_(void* ptr) noexcept;
    ~control_block_() noexcept;
    void incr() noexcept;
    void decr() noexcept;
    uint32_t count() const noexcept;

    void* _ptr; // todo maybe add directly embeddable objects?
    uint32_t _count;

private:
    virtual void free() noexcept = 0;
};

#ifdef __GNUG__
#pragma GCC diagnostic pop
#endif

template<typename T>
struct control_block final: control_block_
{
    void free() noexcept override;
    [[nodiscard]] static control_block_* create(T* ptr) noexcept;

protected:
    explicit control_block(T* ptr) noexcept;
};

template <typename T>
control_block<T>::control_block(T* ptr) noexcept:
    control_block_{ptr}
{
    fm_debug_assert(ptr);
}

template <typename T>
void control_block<T>::free() noexcept
{
    delete static_cast<T*>(_ptr);
}

template <typename T>
control_block_* control_block<T>::create(T* ptr) noexcept
{
    return ptr ? new control_block<T>{ptr} : nullptr;
}

} // namespace floormat::detail_borrowed_ptr

namespace floormat {

template<typename T>
template<typename... Ts>
requires std::is_constructible_v<T, Ts&&...>
bptr<T>::bptr(InPlaceInitT, Ts&&... args) noexcept:
bptr{ new T{ forward<Ts...>(args...) } }
{
}

template<typename T>
bptr<T>::bptr(T* ptr) noexcept:
    ptr{ptr},
    blk{detail_borrowed_ptr::control_block<T>::create(ptr)}
{
}

template<typename T>
bptr<T>::~bptr() noexcept
{
    if (blk)
        blk->decr();
    //blk = reinterpret_cast<T*>(-1);
}

template<typename T>
template<typename Y>
requires std::is_convertible_v<Y*, T*>
bptr<T>::bptr(const bptr<Y>& other) noexcept:
    ptr{other.ptr}, blk{other.blk}
{
    static_assert(std::is_convertible_v<Y*, T*>);
    if (blk)
        blk->incr();
    else
        fm_debug_assert(!ptr);
}

template<typename T>
template<typename Y>
requires std::is_convertible_v<Y*, T*>
bptr<T>::bptr(bptr<Y>&& other) noexcept: ptr{other.ptr}, blk{other.blk}
{
    other.ptr = nullptr;
    other.blk = nullptr;
}

template<typename T>
template<typename Y>
requires std::is_convertible_v<Y*, T*>
bptr<T>& bptr<T>::operator=(const bptr<Y>& other) noexcept
{
    static_assert(std::is_convertible_v<Y*, T*>);
    auto* const newblk = other.blk;
    if (blk != newblk)
    {
        CORRADE_ASSUME(this != &other);
        ptr = other.ptr;
        if (blk)
            blk->decr();
        blk = newblk;
        if (newblk)
            newblk->incr();
    }
    return *this;
}

template<typename T>
template<typename Y>
requires std::is_convertible_v<Y*, T*>
bptr<T>& bptr<T>::operator=(bptr<Y>&& other) noexcept
{
    ptr = other.ptr;
    blk = other.blk;
    other.ptr = nullptr;
    other.blk = nullptr;
    return *this;
}

template<typename T, typename U>
bptr<T> static_pointer_cast(const bptr<U>& p)
{
    auto ret = bptr<T>{};
    ret.blk = p.blk;
    if (ret.blk) [[likely]]
        ret.blk->incr();
    ret.ptr = static_cast<T*>(p.ptr);
    return ret;
}

} // namespace floormat