/* * * (C) 2008-2011 Adam * (C) 2008-2022 Anope Team * * Please read COPYING and README for further details. */ #ifndef BASE_H #define BASE_H #include "services.h" /** The base class that most classes in Anope inherit from */ class CoreExport Base { /* References to this base class */ std::set *references; public: Base(); virtual ~Base(); /** Adds a reference to this object. Eg, when a Reference * is created referring to this object this is called. It is used to * cleanup references when this object is destructed. */ void AddReference(ReferenceBase *r); void DelReference(ReferenceBase *r); }; class ReferenceBase { protected: bool invalid; public: ReferenceBase() : invalid(false) { } ReferenceBase(const ReferenceBase &other) : invalid(other.invalid) { } virtual ~ReferenceBase() { } inline void Invalidate() { this->invalid = true; } }; /** Used to hold pointers to objects that may be deleted. A Reference will * no longer be valid once the object it refers is destructed. */ template class Reference : public ReferenceBase { protected: T *ref; public: Reference() : ref(NULL) { } Reference(T *obj) : ref(obj) { if (ref) ref->AddReference(this); } Reference(const Reference &other) : ReferenceBase(other), ref(other.ref) { if (operator bool()) ref->AddReference(this); } virtual ~Reference() { if (operator bool()) ref->DelReference(this); } inline Reference& operator=(const Reference &other) { if (this != &other) { if (*this) this->ref->DelReference(this); this->ref = other.ref; this->invalid = other.invalid; if (*this) this->ref->AddReference(this); } return *this; } /* We explicitly call operator bool here in several places to prevent other * operators, such operator T*, from being called instead, which will mess * with any class inheriting from this that overloads this operator. */ virtual operator bool() { if (!this->invalid) return this->ref != NULL; return false; } inline operator T*() { if (operator bool()) return this->ref; return NULL; } inline T* operator->() { if (operator bool()) return this->ref; return NULL; } inline T* operator*() { if (operator bool()) return this->ref; return NULL; } /** Note that we can't have an operator< that returns this->ref < other.ref * because this function is used to sort objects in containers (such as set * or map), and if the references themselves can change if the object they * refer to is invalidated or changed, then this screws with the order that * the objects would be in the container without properly adjusting the * container, resulting in weird stuff. * * As such, we don't allow storing references in containers that require * operator<, because they would not be able to compare what the references * actually referred to. */ inline bool operator==(const Reference &other) { if (!this->invalid) return this->ref == other; return false; } }; #endif // BASE_H