]> granicus.if.org Git - icinga2/blob - lib/base/object.hpp
Merge pull request #7185 from Icinga/bugfix/gelfwriter-wrong-log-facility
[icinga2] / lib / base / object.hpp
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>
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>
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 {
78         static ObjectFactory GetFactory()
79         {
80                 return DefaultObjectFactory<T>;
81         }
82 };
83
84 template<typename T>
85 struct TypeHelper<T, true>
86 {
87         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
98         explicit Lazy(T value)
99                 : m_Cached(true), m_Value(value)
100         { }
101
102         explicit Lazy(Accessor accessor)
103                 : m_Accessor(accessor)
104         { }
105
106         template<typename U>
107         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>
121         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
131         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"