]> git.lizzy.rs Git - minetest.git/blob - src/irr_ptr.h
Add keybind to swap items between hands
[minetest.git] / src / irr_ptr.h
1 /*
2 Minetest
3 Copyright (C) 2018 numzero, Lobachevskiy Vitaliy <numzer0@yandex.ru>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #pragma once
21 #include <type_traits>
22 #include "irrlichttypes.h"
23 #include "IReferenceCounted.h"
24
25 /** Shared pointer for IrrLicht objects.
26  *
27  * It should only be used for user-managed objects, i.e. those created with
28  * the @c new operator or @c create* functions, like:
29  * `irr_ptr<scene::IMeshBuffer> buf{new scene::SMeshBuffer()};`
30  * The reference counting is *not* balanced as new objects have reference
31  * count set to one, and the @c irr_ptr constructor (and @c reset) assumes
32  * ownership of that reference.
33  *
34  * It shouldn’t be used for engine-managed objects, including those created
35  * with @c addTexture and similar methods. Constructing @c irr_ptr directly
36  * from such object is a bug and may lead to a crash. Indirect construction
37  * is possible though; see the @c grab free function for details and use cases.
38  */
39 template <class ReferenceCounted,
40                 class = typename std::enable_if<std::is_base_of<IReferenceCounted,
41                                 ReferenceCounted>::value>::type>
42 class irr_ptr
43 {
44         ReferenceCounted *value = nullptr;
45
46 public:
47         irr_ptr() {}
48
49         irr_ptr(std::nullptr_t) noexcept {}
50
51         irr_ptr(const irr_ptr &b) noexcept { grab(b.get()); }
52
53         irr_ptr(irr_ptr &&b) noexcept { reset(b.release()); }
54
55         template <typename B, class = typename std::enable_if<std::is_convertible<B *,
56                                               ReferenceCounted *>::value>::type>
57         irr_ptr(const irr_ptr<B> &b) noexcept
58         {
59                 grab(b.get());
60         }
61
62         template <typename B, class = typename std::enable_if<std::is_convertible<B *,
63                                               ReferenceCounted *>::value>::type>
64         irr_ptr(irr_ptr<B> &&b) noexcept
65         {
66                 reset(b.release());
67         }
68
69         /** Constructs a shared pointer out of a plain one to control object lifetime.
70          * @param object The object, usually returned by some @c create* function.
71          * @note Move semantics: reference counter is *not* increased.
72          * @warning Never wrap any @c add* function with this!
73          */
74         explicit irr_ptr(ReferenceCounted *object) noexcept { reset(object); }
75
76         ~irr_ptr() { reset(); }
77
78         irr_ptr &operator=(const irr_ptr &b) noexcept
79         {
80                 grab(b.get());
81                 return *this;
82         }
83
84         irr_ptr &operator=(irr_ptr &&b) noexcept
85         {
86                 reset(b.release());
87                 return *this;
88         }
89
90         template <typename B, class = typename std::enable_if<std::is_convertible<B *,
91                                               ReferenceCounted *>::value>::type>
92         irr_ptr &operator=(const irr_ptr<B> &b) noexcept
93         {
94                 grab(b.get());
95                 return *this;
96         }
97
98         template <typename B, class = typename std::enable_if<std::is_convertible<B *,
99                                               ReferenceCounted *>::value>::type>
100         irr_ptr &operator=(irr_ptr<B> &&b) noexcept
101         {
102                 reset(b.release());
103                 return *this;
104         }
105
106         ReferenceCounted &operator*() const noexcept { return *value; }
107         ReferenceCounted *operator->() const noexcept { return value; }
108         explicit operator ReferenceCounted *() const noexcept { return value; }
109         explicit operator bool() const noexcept { return !!value; }
110
111         /** Returns the stored pointer.
112          */
113         ReferenceCounted *get() const noexcept { return value; }
114
115         /** Returns the stored pointer, erasing it from this class.
116          * @note Move semantics: reference counter is not changed.
117          */
118         ReferenceCounted *release() noexcept
119         {
120                 ReferenceCounted *object = value;
121                 value = nullptr;
122                 return object;
123         }
124
125         /** Drops stored pointer replacing it with the given one.
126          * @note Move semantics: reference counter is *not* increased.
127          */
128         void reset(ReferenceCounted *object = nullptr) noexcept
129         {
130                 if (value)
131                         value->drop();
132                 value = object;
133         }
134
135         /** Drops stored pointer replacing it with the given one.
136          * @note Copy semantics: reference counter *is* increased.
137          */
138         void grab(ReferenceCounted *object) noexcept
139         {
140                 if (object)
141                         object->grab();
142                 reset(object);
143         }
144 };
145
146 // clang-format off
147 // ^ dislikes long lines
148
149 /** Constructs a shared pointer as a *secondary* reference to an object
150  *
151  * This function is intended to make a temporary reference to an object which
152  * is owned elsewhere so that it is not destroyed too early. To achieve that
153  * it does balanced reference counting, i.e. reference count is increased
154  * in this function and decreased when the returned pointer is destroyed.
155  */
156 template <class ReferenceCounted>
157 irr_ptr<ReferenceCounted> grab(ReferenceCounted *object) noexcept
158 {
159         irr_ptr<ReferenceCounted> ptr;
160         ptr.grab(object);
161         return ptr;
162 }
163
164 template <typename ReferenceCounted>
165 bool operator==(const irr_ptr<ReferenceCounted> &a, const irr_ptr<ReferenceCounted> &b) noexcept
166 {
167         return a.get() == b.get();
168 }
169
170 template <typename ReferenceCounted>
171 bool operator==(const irr_ptr<ReferenceCounted> &a, const ReferenceCounted *b) noexcept
172 {
173         return a.get() == b;
174 }
175
176 template <typename ReferenceCounted>
177 bool operator==(const ReferenceCounted *a, const irr_ptr<ReferenceCounted> &b) noexcept
178 {
179         return a == b.get();
180 }
181
182 template <typename ReferenceCounted>
183 bool operator!=(const irr_ptr<ReferenceCounted> &a, const irr_ptr<ReferenceCounted> &b) noexcept
184 {
185         return a.get() != b.get();
186 }
187
188 template <typename ReferenceCounted>
189 bool operator!=(const irr_ptr<ReferenceCounted> &a, const ReferenceCounted *b) noexcept
190 {
191         return a.get() != b;
192 }
193
194 template <typename ReferenceCounted>
195 bool operator!=(const ReferenceCounted *a, const irr_ptr<ReferenceCounted> &b) noexcept
196 {
197         return a != b.get();
198 }
199
200 // clang-format on