diff options
Diffstat (limited to 'lib/base/object.hpp')
-rw-r--r-- | lib/base/object.hpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/lib/base/object.hpp b/lib/base/object.hpp new file mode 100644 index 0000000..5a90cfa --- /dev/null +++ b/lib/base/object.hpp @@ -0,0 +1,225 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef OBJECT_H +#define OBJECT_H + +#include "base/i2-base.hpp" +#include "base/debug.hpp" +#include <boost/smart_ptr/intrusive_ptr.hpp> +#include <atomic> +#include <cstddef> +#include <cstdint> +#include <mutex> +#include <thread> +#include <vector> + +using boost::intrusive_ptr; +using boost::dynamic_pointer_cast; +using boost::static_pointer_cast; + +namespace icinga +{ + +class Value; +class Object; +class Type; +class String; +struct DebugInfo; +class ValidationUtils; + +extern Value Empty; + +#define DECLARE_PTR_TYPEDEFS(klass) \ + typedef intrusive_ptr<klass> Ptr + +#define IMPL_TYPE_LOOKUP_SUPER() \ + +#define IMPL_TYPE_LOOKUP() \ + static intrusive_ptr<Type> TypeInstance; \ + virtual intrusive_ptr<Type> GetReflectionType() const override \ + { \ + return TypeInstance; \ + } + +#define DECLARE_OBJECT(klass) \ + DECLARE_PTR_TYPEDEFS(klass); \ + IMPL_TYPE_LOOKUP(); + +#define REQUIRE_NOT_NULL(ptr) RequireNotNullInternal(ptr, #ptr) + +void RequireNotNullInternal(const intrusive_ptr<Object>& object, const char *description); + +void DefaultObjectFactoryCheckArgs(const std::vector<Value>& args); + +template<typename T> +intrusive_ptr<Object> DefaultObjectFactory(const std::vector<Value>& args) +{ + DefaultObjectFactoryCheckArgs(args); + + return new T(); +} + +template<typename T> +intrusive_ptr<Object> DefaultObjectFactoryVA(const std::vector<Value>& args) +{ + return new T(args); +} + +typedef intrusive_ptr<Object> (*ObjectFactory)(const std::vector<Value>&); + +template<typename T, bool VA> +struct TypeHelper +{ +}; + +template<typename T> +struct TypeHelper<T, false> +{ + static ObjectFactory GetFactory() + { + return DefaultObjectFactory<T>; + } +}; + +template<typename T> +struct TypeHelper<T, true> +{ + static ObjectFactory GetFactory() + { + return DefaultObjectFactoryVA<T>; + } +}; + +template<typename T> +struct Lazy +{ + using Accessor = std::function<T ()>; + + explicit Lazy(T value) + : m_Cached(true), m_Value(value) + { } + + explicit Lazy(Accessor accessor) + : m_Accessor(accessor) + { } + + template<typename U> + explicit Lazy(const Lazy<U>& other) + { + if (other.m_Cached) { + m_Accessor = Accessor(); + m_Value = static_cast<T>(other.m_Value); + m_Cached = true; + } else { + auto accessor = other.m_Accessor; + m_Accessor = [accessor]() { return static_cast<T>(accessor()); }; + m_Cached = false; + } + } + + template<typename U> + operator Lazy<U>() const + { + if (m_Cached) + return Lazy<U>(static_cast<U>(m_Value)); + else { + Accessor accessor = m_Accessor; + return Lazy<U>(static_cast<typename Lazy<U>::Accessor>([accessor]() { return static_cast<U>(accessor()); })); + } + } + + const T& operator()() const + { + if (!m_Cached) { + m_Value = m_Accessor(); + m_Cached = true; + } + + return m_Value; + } + +private: + Accessor m_Accessor; + mutable bool m_Cached{false}; + mutable T m_Value; + + template<typename U> + friend struct Lazy; +}; + +/** + * Base class for all heap-allocated objects. At least one of its methods + * has to be virtual for RTTI to work. + * + * @ingroup base + */ +class Object +{ +public: + DECLARE_PTR_TYPEDEFS(Object); + + Object(); + virtual ~Object(); + + virtual String ToString() const; + + virtual intrusive_ptr<Type> GetReflectionType() const; + + virtual void Validate(int types, const ValidationUtils& utils); + + virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty); + virtual Value GetField(int id) const; + virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const; + virtual void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo); + virtual bool HasOwnField(const String& field) const; + virtual bool GetOwnField(const String& field, Value *result) const; + virtual void ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils); + virtual void NotifyField(int id, const Value& cookie = Empty); + virtual Object::Ptr NavigateField(int id) const; + +#ifdef I2_DEBUG + bool OwnsLock() const; +#endif /* I2_DEBUG */ + + static Object::Ptr GetPrototype(); + + virtual Object::Ptr Clone() const; + + static intrusive_ptr<Type> TypeInstance; + +private: + Object(const Object& other) = delete; + Object& operator=(const Object& rhs) = delete; + + std::atomic<uint_fast64_t> m_References; + mutable std::recursive_mutex m_Mutex; + +#ifdef I2_DEBUG + mutable std::atomic<std::thread::id> m_LockOwner; + mutable size_t m_LockCount = 0; +#endif /* I2_DEBUG */ + + friend struct ObjectLock; + + friend void intrusive_ptr_add_ref(Object *object); + friend void intrusive_ptr_release(Object *object); +}; + +Value GetPrototypeField(const Value& context, const String& field, bool not_found_error, const DebugInfo& debugInfo); + +void TypeAddObject(Object *object); +void TypeRemoveObject(Object *object); + +void intrusive_ptr_add_ref(Object *object); +void intrusive_ptr_release(Object *object); + +template<typename T> +class ObjectImpl +{ +}; + +} + +#endif /* OBJECT_H */ + +#include "base/type.hpp" |