mirror of
https://github.com/Icinga/icinga2.git
synced 2025-08-15 06:38:13 +02:00
The Array, Dictionary, and Namespace types provide a Freeze() method that makes them read-only. So far, there was the possibility to call some methods with `overrideFrozen=true` which would then bypass the corresponding check and allow modification of the data structures nonetheless. With 24b57f0d3a222835178e88489eabd595755ed883, this possibility was already removed from the Namespace type. However, for interface compatibility, it kept the parameter and just ignores it, throwing an exception on any modification on a frozen instance. The only place using `overrideFrozen` was processing of the `-D`/`--define` command line flag that allows setting additional variables in the DSL. At the time it is evaluated, there are no user-created data structures yet that could be frozen, so the only frozen objects that could be encountered are Namespaces (Icinga doesn't freeze other types by itself) and for these, `overrideFrozen` already has no effect. Hence, there is no harm in removing `overrideFrozen` altogether. This simplifies the code and also means that frozen objects are now indeed read-only without exceptions, allowing further optimizations regarding locking in the future.
227 lines
4.9 KiB
C++
227 lines
4.9 KiB
C++
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
|
|
|
|
#ifndef OBJECT_H
|
|
#define OBJECT_H
|
|
|
|
#include "base/i2-base.hpp"
|
|
#include "base/debug.hpp"
|
|
#include "base/intrusive-ptr.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 const 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, 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"
|