summaryrefslogtreecommitdiffstats
path: root/deps/include/entt/resource/resource.hpp
blob: 8d73ace2aa9dd9e5d7df6e85e12905c711b556bb (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#ifndef ENTT_RESOURCE_RESOURCE_HPP
#define ENTT_RESOURCE_RESOURCE_HPP

#include <memory>
#include <type_traits>
#include <utility>
#include "fwd.hpp"

namespace entt {

/**
 * @brief Basic resource handle.
 *
 * A handle wraps a resource and extends its lifetime. It also shares the same
 * resource with all other handles constructed from the same element.<br/>
 * As a rule of thumb, resources should never be copied nor moved. Handles are
 * the way to go to push references around.
 *
 * @tparam Type Type of resource managed by a handle.
 */
template<typename Type>
class resource {
    template<typename>
    friend class resource;

    template<typename Other>
    static constexpr bool is_acceptable_v = !std::is_same_v<Type, Other> && std::is_constructible_v<Type &, Other &>;

public:
    /*! @brief Resource type. */
    using element_type = Type;
    /*! @brief Handle type. */
    using handle_type = std::shared_ptr<element_type>;

    /*! @brief Default constructor. */
    resource() noexcept
        : value{} {}

    /**
     * @brief Creates a new resource handle.
     * @param res A handle to a resource.
     */
    explicit resource(handle_type res) noexcept
        : value{std::move(res)} {}

    /*! @brief Default copy constructor. */
    resource(const resource &) noexcept = default;

    /*! @brief Default move constructor. */
    resource(resource &&) noexcept = default;

    /**
     * @brief Aliasing constructor.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle with which to share ownership information.
     * @param res Unrelated and unmanaged resources.
     */
    template<typename Other>
    resource(const resource<Other> &other, element_type &res) noexcept
        : value{other.value, std::addressof(res)} {}

    /**
     * @brief Copy constructs a handle which shares ownership of the resource.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to copy from.
     */
    template<typename Other, typename = std::enable_if_t<is_acceptable_v<Other>>>
    resource(const resource<Other> &other) noexcept
        : value{other.value} {}

    /**
     * @brief Move constructs a handle which takes ownership of the resource.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to move from.
     */
    template<typename Other, typename = std::enable_if_t<is_acceptable_v<Other>>>
    resource(resource<Other> &&other) noexcept
        : value{std::move(other.value)} {}

    /*! @brief Default destructor. */
    ~resource() noexcept = default;

    /**
     * @brief Default copy assignment operator.
     * @return This resource handle.
     */
    resource &operator=(const resource &) noexcept = default;

    /**
     * @brief Default move assignment operator.
     * @return This resource handle.
     */
    resource &operator=(resource &&) noexcept = default;

    /**
     * @brief Copy assignment operator from foreign handle.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to copy from.
     * @return This resource handle.
     */
    template<typename Other, typename = std::enable_if_t<is_acceptable_v<Other>>>
    resource &operator=(const resource<Other> &other) noexcept {
        value = other.value;
        return *this;
    }

    /**
     * @brief Move assignment operator from foreign handle.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to move from.
     * @return This resource handle.
     */
    template<typename Other, typename = std::enable_if_t<is_acceptable_v<Other>>>
    resource &operator=(resource<Other> &&other) noexcept {
        value = std::move(other.value);
        return *this;
    }

    /**
     * @brief Returns a reference to the managed resource.
     *
     * @warning
     * The behavior is undefined if the handle doesn't contain a resource.
     *
     * @return A reference to the managed resource.
     */
    [[nodiscard]] element_type &operator*() const noexcept {
        return *value;
    }

    /*! @copydoc operator* */
    [[nodiscard]] operator element_type &() const noexcept {
        return *value;
    }

    /**
     * @brief Returns a pointer to the managed resource.
     * @return A pointer to the managed resource.
     */
    [[nodiscard]] element_type *operator->() const noexcept {
        return value.get();
    }

    /**
     * @brief Returns true if a handle contains a resource, false otherwise.
     * @return True if the handle contains a resource, false otherwise.
     */
    [[nodiscard]] explicit operator bool() const noexcept {
        return static_cast<bool>(value);
    }

    /*! @brief Releases the ownership of the managed resource. */
    void reset() {
        value.reset();
    }

    /**
     * @brief Replaces the managed resource.
     * @param other A handle to a resource.
     */
    void reset(handle_type other) {
        value = std::move(other);
    }

    /**
     * @brief Returns the underlying resource handle.
     * @return The underlying resource handle.
     */
    [[nodiscard]] const handle_type &handle() const noexcept {
        return value;
    }

private:
    handle_type value;
};

/**
 * @brief Compares two handles.
 * @tparam Lhs Type of resource managed by the first handle.
 * @tparam Rhs Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return True if both handles refer to the same resource, false otherwise.
 */
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator==(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
    return (std::addressof(*lhs) == std::addressof(*rhs));
}

/**
 * @brief Compares two handles.
 * @tparam Lhs Type of resource managed by the first handle.
 * @tparam Rhs Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return False if both handles refer to the same resource, true otherwise.
 */
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator!=(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
    return !(lhs == rhs);
}

/**
 * @brief Compares two handles.
 * @tparam Lhs Type of resource managed by the first handle.
 * @tparam Rhs Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return True if the first handle is less than the second, false otherwise.
 */
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator<(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
    return (std::addressof(*lhs) < std::addressof(*rhs));
}

/**
 * @brief Compares two handles.
 * @tparam Lhs Type of resource managed by the first handle.
 * @tparam Rhs Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return True if the first handle is greater than the second, false otherwise.
 */
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator>(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
    return rhs < lhs;
}

/**
 * @brief Compares two handles.
 * @tparam Lhs Type of resource managed by the first handle.
 * @tparam Rhs Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return True if the first handle is less than or equal to the second, false
 * otherwise.
 */
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator<=(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
    return !(lhs > rhs);
}

/**
 * @brief Compares two handles.
 * @tparam Lhs Type of resource managed by the first handle.
 * @tparam Rhs Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return True if the first handle is greater than or equal to the second,
 * false otherwise.
 */
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator>=(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
    return !(lhs < rhs);
}

} // namespace entt

#endif