mirror of
git://git.acid.vegas/anope.git
synced 2024-11-14 11:46:42 +00:00
264 lines
5.8 KiB
C++
264 lines
5.8 KiB
C++
/*
|
|
*
|
|
* (C) 2003-2022 Anope Team
|
|
* Contact us at team@anope.org
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*/
|
|
|
|
#ifndef EXTENSIBLE_H
|
|
#define EXTENSIBLE_H
|
|
|
|
#include "anope.h"
|
|
#include "serialize.h"
|
|
#include "service.h"
|
|
#include "logger.h"
|
|
|
|
class Extensible;
|
|
|
|
class CoreExport ExtensibleBase : public Service
|
|
{
|
|
protected:
|
|
std::map<Extensible *, void *> items;
|
|
|
|
ExtensibleBase(Module *m, const Anope::string &n);
|
|
~ExtensibleBase();
|
|
|
|
public:
|
|
virtual void Unset(Extensible *obj) = 0;
|
|
|
|
/* called when an object we are keep track of is serializing */
|
|
virtual void ExtensibleSerialize(const Extensible *, const Serializable *, Serialize::Data &) const { }
|
|
virtual void ExtensibleUnserialize(Extensible *, Serializable *, Serialize::Data &) { }
|
|
};
|
|
|
|
class CoreExport Extensible
|
|
{
|
|
public:
|
|
std::set<ExtensibleBase *> extension_items;
|
|
|
|
virtual ~Extensible();
|
|
|
|
void UnsetExtensibles();
|
|
|
|
template<typename T> T* GetExt(const Anope::string &name) const;
|
|
bool HasExt(const Anope::string &name) const;
|
|
|
|
template<typename T> T* Extend(const Anope::string &name, const T &what);
|
|
template<typename T> T* Extend(const Anope::string &name);
|
|
template<typename T> T* Require(const Anope::string &name);
|
|
template<typename T> void Shrink(const Anope::string &name);
|
|
|
|
static void ExtensibleSerialize(const Extensible *, const Serializable *, Serialize::Data &data);
|
|
static void ExtensibleUnserialize(Extensible *, Serializable *, Serialize::Data &data);
|
|
};
|
|
|
|
template<typename T>
|
|
class BaseExtensibleItem : public ExtensibleBase
|
|
{
|
|
protected:
|
|
virtual T *Create(Extensible *) = 0;
|
|
|
|
public:
|
|
BaseExtensibleItem(Module *m, const Anope::string &n) : ExtensibleBase(m, n) { }
|
|
|
|
~BaseExtensibleItem()
|
|
{
|
|
while (!items.empty())
|
|
{
|
|
std::map<Extensible *, void *>::iterator it = items.begin();
|
|
Extensible *obj = it->first;
|
|
T *value = static_cast<T *>(it->second);
|
|
|
|
obj->extension_items.erase(this);
|
|
items.erase(it);
|
|
delete value;
|
|
}
|
|
}
|
|
|
|
T* Set(Extensible *obj, const T &value)
|
|
{
|
|
T* t = Set(obj);
|
|
if (t)
|
|
*t = value;
|
|
return t;
|
|
}
|
|
|
|
T* Set(Extensible *obj)
|
|
{
|
|
T* t = Create(obj);
|
|
Unset(obj);
|
|
items[obj] = t;
|
|
obj->extension_items.insert(this);
|
|
return t;
|
|
}
|
|
|
|
void Unset(Extensible *obj) anope_override
|
|
{
|
|
T *value = Get(obj);
|
|
items.erase(obj);
|
|
obj->extension_items.erase(this);
|
|
delete value;
|
|
}
|
|
|
|
T* Get(const Extensible *obj) const
|
|
{
|
|
std::map<Extensible *, void *>::const_iterator it = items.find(const_cast<Extensible *>(obj));
|
|
if (it != items.end())
|
|
return static_cast<T *>(it->second);
|
|
return NULL;
|
|
}
|
|
|
|
bool HasExt(const Extensible *obj) const
|
|
{
|
|
return items.find(const_cast<Extensible *>(obj)) != items.end();
|
|
}
|
|
|
|
T* Require(Extensible *obj)
|
|
{
|
|
T* t = Get(obj);
|
|
if (t)
|
|
return t;
|
|
|
|
return Set(obj);
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
class ExtensibleItem : public BaseExtensibleItem<T>
|
|
{
|
|
protected:
|
|
T* Create(Extensible *obj) anope_override
|
|
{
|
|
return new T(obj);
|
|
}
|
|
public:
|
|
ExtensibleItem(Module *m, const Anope::string &n) : BaseExtensibleItem<T>(m, n) { }
|
|
};
|
|
|
|
template<typename T>
|
|
class PrimitiveExtensibleItem : public BaseExtensibleItem<T>
|
|
{
|
|
protected:
|
|
T* Create(Extensible *obj) anope_override
|
|
{
|
|
return new T();
|
|
}
|
|
public:
|
|
PrimitiveExtensibleItem(Module *m, const Anope::string &n) : BaseExtensibleItem<T>(m, n) { }
|
|
};
|
|
|
|
template<>
|
|
class PrimitiveExtensibleItem<bool> : public BaseExtensibleItem<bool>
|
|
{
|
|
protected:
|
|
bool* Create(Extensible *) anope_override
|
|
{
|
|
return NULL;
|
|
}
|
|
public:
|
|
PrimitiveExtensibleItem(Module *m, const Anope::string &n) : BaseExtensibleItem<bool>(m, n) { }
|
|
};
|
|
|
|
template<typename T>
|
|
class SerializableExtensibleItem : public PrimitiveExtensibleItem<T>
|
|
{
|
|
public:
|
|
SerializableExtensibleItem(Module *m, const Anope::string &n) : PrimitiveExtensibleItem<T>(m, n) { }
|
|
|
|
void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override
|
|
{
|
|
T* t = this->Get(e);
|
|
data[this->name] << *t;
|
|
}
|
|
|
|
void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override
|
|
{
|
|
T t;
|
|
if (data[this->name] >> t)
|
|
this->Set(e, t);
|
|
else
|
|
this->Unset(e);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
class SerializableExtensibleItem<bool> : public PrimitiveExtensibleItem<bool>
|
|
{
|
|
public:
|
|
SerializableExtensibleItem(Module *m, const Anope::string &n) : PrimitiveExtensibleItem<bool>(m, n) { }
|
|
|
|
void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override
|
|
{
|
|
data[this->name] << true;
|
|
}
|
|
|
|
void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override
|
|
{
|
|
bool b = false;
|
|
data[this->name] >> b;
|
|
if (b)
|
|
this->Set(e);
|
|
else
|
|
this->Unset(e);
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct ExtensibleRef : ServiceReference<BaseExtensibleItem<T> >
|
|
{
|
|
ExtensibleRef(const Anope::string &n) : ServiceReference<BaseExtensibleItem<T> >("Extensible", n) { }
|
|
};
|
|
|
|
template<typename T>
|
|
T* Extensible::GetExt(const Anope::string &name) const
|
|
{
|
|
ExtensibleRef<T> ref(name);
|
|
if (ref)
|
|
return ref->Get(this);
|
|
|
|
Log(LOG_DEBUG) << "GetExt for nonexistent type " << name << " on " << static_cast<const void *>(this);
|
|
return NULL;
|
|
}
|
|
|
|
template<typename T>
|
|
T* Extensible::Extend(const Anope::string &name, const T &what)
|
|
{
|
|
T* t = Extend<T>(name);
|
|
if (t)
|
|
*t = what;
|
|
return t;
|
|
}
|
|
|
|
template<typename T>
|
|
T* Extensible::Extend(const Anope::string &name)
|
|
{
|
|
ExtensibleRef<T> ref(name);
|
|
if (ref)
|
|
return ref->Set(this);
|
|
|
|
Log(LOG_DEBUG) << "Extend for nonexistent type " << name << " on " << static_cast<void *>(this);
|
|
return NULL;
|
|
}
|
|
|
|
template<typename T>
|
|
T* Extensible::Require(const Anope::string &name)
|
|
{
|
|
if (HasExt(name))
|
|
return GetExt<T>(name);
|
|
else
|
|
return Extend<T>(name);
|
|
}
|
|
|
|
template<typename T>
|
|
void Extensible::Shrink(const Anope::string &name)
|
|
{
|
|
ExtensibleRef<T> ref(name);
|
|
if (ref)
|
|
ref->Unset(this);
|
|
else
|
|
Log(LOG_DEBUG) << "Shrink for nonexistent type " << name << " on " << static_cast<void *>(this);
|
|
}
|
|
|
|
#endif // EXTENSIBLE_H
|