1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#ifndef LOVE_OBJECT_H
22#define LOVE_OBJECT_H
23
24#include <atomic>
25#include "types.h"
26
27namespace love
28{
29
30/**
31 * Superclass for all object that should be able to cross the Lua/C border
32 * (this pertains to most objects).
33 *
34 * This class is an alternative to using smart pointers; it contains retain/release
35 * methods, and will delete itself with the reference count hits zero. The wrapper
36 * code assumes that all userdata inherits from this class.
37 **/
38class Object
39{
40public:
41
42 static love::Type type;
43
44 /**
45 * Constructor. Sets reference count to one.
46 **/
47 Object();
48 Object(const Object &other);
49
50 /**
51 * Destructor.
52 **/
53 virtual ~Object() = 0;
54
55 /**
56 * Gets the reference count of this Object.
57 * @returns The reference count.
58 **/
59 int getReferenceCount() const;
60
61 /**
62 * Retains the Object, i.e. increases the
63 * reference count by one.
64 **/
65 void retain();
66
67 /**
68 * Releases one reference to the Object, i.e. decrements the
69 * reference count by one, and potentially deletes the Object
70 * if there are no more references.
71 **/
72 void release();
73
74private:
75
76 // The reference count.
77 std::atomic<int> count;
78
79}; // Object
80
81
82enum class Acquire
83{
84 RETAIN,
85 NORETAIN,
86};
87
88template <typename T>
89class StrongRef
90{
91public:
92
93 StrongRef()
94 : object(nullptr)
95 {
96 }
97
98 StrongRef(T *obj, Acquire acquire = Acquire::RETAIN)
99 : object(obj)
100 {
101 if (object && acquire == Acquire::RETAIN) object->retain();
102 }
103
104 StrongRef(const StrongRef &other)
105 : object(other.get())
106 {
107 if (object) object->retain();
108 }
109
110 StrongRef(StrongRef &&other)
111 : object(other.object)
112 {
113 other.object = nullptr;
114 }
115
116 ~StrongRef()
117 {
118 if (object) object->release();
119 }
120
121 StrongRef &operator = (const StrongRef &other)
122 {
123 set(other.get());
124 return *this;
125 }
126
127 T *operator->() const
128 {
129 return object;
130 }
131
132 explicit operator bool() const
133 {
134 return object != nullptr;
135 }
136
137 operator T*() const
138 {
139 return object;
140 }
141
142 void set(T *obj, Acquire acquire = Acquire::RETAIN)
143 {
144 if (obj && acquire == Acquire::RETAIN) obj->retain();
145 if (object) object->release();
146 object = obj;
147 }
148
149 T *get() const
150 {
151 return object;
152 }
153
154private:
155
156 T *object;
157
158}; // StrongRef
159
160} // love
161
162#endif // LOVE_OBJECT_H
163