1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #ifndef OBJECT_H
4 #define OBJECT_H
5
6 #include "base/i2-base.hpp"
7 #include "base/debug.hpp"
8 #include <boost/smart_ptr/intrusive_ptr.hpp>
9 #include <atomic>
10 #include <cstddef>
11 #include <cstdint>
12 #include <mutex>
13 #include <thread>
14 #include <vector>
15
16 using boost::intrusive_ptr;
17 using boost::dynamic_pointer_cast;
18 using boost::static_pointer_cast;
19
20 namespace icinga
21 {
22
23 class Value;
24 class Object;
25 class Type;
26 class String;
27 struct DebugInfo;
28 class ValidationUtils;
29
30 extern Value Empty;
31
32 #define DECLARE_PTR_TYPEDEFS(klass) \
33 typedef intrusive_ptr<klass> Ptr
34
35 #define IMPL_TYPE_LOOKUP_SUPER() \
36
37 #define IMPL_TYPE_LOOKUP() \
38 static intrusive_ptr<Type> TypeInstance; \
39 virtual intrusive_ptr<Type> GetReflectionType() const override \
40 { \
41 return TypeInstance; \
42 }
43
44 #define DECLARE_OBJECT(klass) \
45 DECLARE_PTR_TYPEDEFS(klass); \
46 IMPL_TYPE_LOOKUP();
47
48 #define REQUIRE_NOT_NULL(ptr) RequireNotNullInternal(ptr, #ptr)
49
50 void RequireNotNullInternal(const intrusive_ptr<Object>& object, const char *description);
51
52 void DefaultObjectFactoryCheckArgs(const std::vector<Value>& args);
53
54 template<typename T>
DefaultObjectFactory(const std::vector<Value> & args)55 intrusive_ptr<Object> DefaultObjectFactory(const std::vector<Value>& args)
56 {
57 DefaultObjectFactoryCheckArgs(args);
58
59 return new T();
60 }
61
62 template<typename T>
DefaultObjectFactoryVA(const std::vector<Value> & args)63 intrusive_ptr<Object> DefaultObjectFactoryVA(const std::vector<Value>& args)
64 {
65 return new T(args);
66 }
67
68 typedef intrusive_ptr<Object> (*ObjectFactory)(const std::vector<Value>&);
69
70 template<typename T, bool VA>
71 struct TypeHelper
72 {
73 };
74
75 template<typename T>
76 struct TypeHelper<T, false>
77 {
GetFactoryicinga::TypeHelper78 static ObjectFactory GetFactory()
79 {
80 return DefaultObjectFactory<T>;
81 }
82 };
83
84 template<typename T>
85 struct TypeHelper<T, true>
86 {
GetFactoryicinga::TypeHelper87 static ObjectFactory GetFactory()
88 {
89 return DefaultObjectFactoryVA<T>;
90 }
91 };
92
93 template<typename T>
94 struct Lazy
95 {
96 using Accessor = std::function<T ()>;
97
Lazyicinga::Lazy98 explicit Lazy(T value)
99 : m_Cached(true), m_Value(value)
100 { }
101
Lazyicinga::Lazy102 explicit Lazy(Accessor accessor)
103 : m_Accessor(accessor)
104 { }
105
106 template<typename U>
Lazyicinga::Lazy107 explicit Lazy(const Lazy<U>& other)
108 {
109 if (other.m_Cached) {
110 m_Accessor = Accessor();
111 m_Value = static_cast<T>(other.m_Value);
112 m_Cached = true;
113 } else {
114 auto accessor = other.m_Accessor;
115 m_Accessor = [accessor]() { return static_cast<T>(accessor()); };
116 m_Cached = false;
117 }
118 }
119
120 template<typename U>
operator Lazy<U>icinga::Lazy121 operator Lazy<U>() const
122 {
123 if (m_Cached)
124 return Lazy<U>(static_cast<U>(m_Value));
125 else {
126 Accessor accessor = m_Accessor;
127 return Lazy<U>(static_cast<typename Lazy<U>::Accessor>([accessor]() { return static_cast<U>(accessor()); }));
128 }
129 }
130
operator ()icinga::Lazy131 const T& operator()() const
132 {
133 if (!m_Cached) {
134 m_Value = m_Accessor();
135 m_Cached = true;
136 }
137
138 return m_Value;
139 }
140
141 private:
142 Accessor m_Accessor;
143 mutable bool m_Cached{false};
144 mutable T m_Value;
145
146 template<typename U>
147 friend struct Lazy;
148 };
149
150 /**
151 * Base class for all heap-allocated objects. At least one of its methods
152 * has to be virtual for RTTI to work.
153 *
154 * @ingroup base
155 */
156 class Object
157 {
158 public:
159 DECLARE_PTR_TYPEDEFS(Object);
160
161 Object();
162 virtual ~Object();
163
164 virtual String ToString() const;
165
166 virtual intrusive_ptr<Type> GetReflectionType() const;
167
168 virtual void Validate(int types, const ValidationUtils& utils);
169
170 virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty);
171 virtual Value GetField(int id) const;
172 virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const;
173 virtual void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo);
174 virtual bool HasOwnField(const String& field) const;
175 virtual bool GetOwnField(const String& field, Value *result) const;
176 virtual void ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils);
177 virtual void NotifyField(int id, const Value& cookie = Empty);
178 virtual Object::Ptr NavigateField(int id) const;
179
180 #ifdef I2_DEBUG
181 bool OwnsLock() const;
182 #endif /* I2_DEBUG */
183
184 static Object::Ptr GetPrototype();
185
186 virtual Object::Ptr Clone() const;
187
188 static intrusive_ptr<Type> TypeInstance;
189
190 private:
191 Object(const Object& other) = delete;
192 Object& operator=(const Object& rhs) = delete;
193
194 std::atomic<uint_fast64_t> m_References;
195 mutable std::recursive_mutex m_Mutex;
196
197 #ifdef I2_DEBUG
198 mutable std::atomic<std::thread::id> m_LockOwner;
199 mutable size_t m_LockCount = 0;
200 #endif /* I2_DEBUG */
201
202 friend struct ObjectLock;
203
204 friend void intrusive_ptr_add_ref(Object *object);
205 friend void intrusive_ptr_release(Object *object);
206 };
207
208 Value GetPrototypeField(const Value& context, const String& field, bool not_found_error, const DebugInfo& debugInfo);
209
210 void TypeAddObject(Object *object);
211 void TypeRemoveObject(Object *object);
212
213 void intrusive_ptr_add_ref(Object *object);
214 void intrusive_ptr_release(Object *object);
215
216 template<typename T>
217 class ObjectImpl
218 {
219 };
220
221 }
222
223 #endif /* OBJECT_H */
224
225 #include "base/type.hpp"
226