mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 22:02:58 -06:00
286 lines
9.1 KiB
C++
286 lines
9.1 KiB
C++
#ifndef _Gen_Gen_h
|
|
#define _Gen_Gen_h
|
|
|
|
#include <Core/Core.h>
|
|
|
|
NAMESPACE_UPP
|
|
|
|
//copyable interface, implementing the Copy function, used i.e. by PolyDeepCopyNew
|
|
template<class T, class B = EmptyClass>
|
|
class Copyable : public B
|
|
{
|
|
public:
|
|
virtual ~Copyable() {}
|
|
virtual T* Copy() const { return PartialCopy(); }
|
|
virtual T* PartialCopy() const = 0;
|
|
};
|
|
|
|
//when exporting an iterface at base lavel which is implemented/derived at top
|
|
template<class T, class B = EmptyClass>
|
|
class TypeHook : public B
|
|
{
|
|
public:
|
|
virtual ~TypeHook() {}
|
|
virtual const T& GetT() const = 0;
|
|
virtual T& GetT() = 0;
|
|
|
|
operator const T&() const { return GetT(); }
|
|
operator T&() { return GetT(); }
|
|
};
|
|
|
|
//copyable interface defining the common base class C, without implementing Copy
|
|
//makes possible to clone things and accessing some defined interface
|
|
template<class C, class B = EmptyClass>
|
|
class PolyCopyableHook : public PolyDeepCopyNew<PolyCopyableHook<C,B>, TypeHook<C, Copyable<PolyCopyableHook<C,B>, B> > >
|
|
{
|
|
};
|
|
|
|
// implements the base class accessors.
|
|
//B is the derived type, i.e. EditInt, C is common base class, i.e. Ctrl
|
|
//forward another baseclass CB to extend CopyableC interface
|
|
template<class T, class B, class C, class CB = EmptyClass>
|
|
class PolyElement : public PolyDeepCopyNew<T, B>, public PolyCopyableHook<C, CB>
|
|
{
|
|
public:
|
|
virtual const C& GetT() const { return *this; }
|
|
virtual C& GetT() { return *this; }
|
|
};
|
|
|
|
//by providing additional information about the common base class
|
|
//with template specialization can be defined what is copied
|
|
template<class B, class C, class CB = EmptyClass>
|
|
class PolyElementWrap : public PolyElement<PolyElementWrap<B,C,CB>,B,C,CB>
|
|
{
|
|
public:
|
|
virtual PolyElementWrap* PartialCopy() const { return new PolyElementWrap(); }
|
|
};
|
|
|
|
//declares a class Serializable for Stream
|
|
//maybe redundant because of global template for operator%(Stream& s, T& t)
|
|
//which calls t.Serialize()
|
|
//but to ensure implementation
|
|
template<class B = EmptyClass>
|
|
class Serializeable : public B
|
|
{
|
|
public:
|
|
virtual void Serialize(Stream& s) = 0;
|
|
};
|
|
|
|
//maybe this should go to Stream.h
|
|
template<class T>
|
|
void SerializeStore(Stream& s, const T& x)
|
|
{
|
|
ASSERT(s.IsStoring());
|
|
s % const_cast<T&>(x);
|
|
}
|
|
|
|
//declares a class Xmlizeable
|
|
//maybe redundant because of global template Xmlize(XmlIO& xml, T&t)
|
|
//which calls t.Xmlize()
|
|
//but to ensure implementations
|
|
template<class B = EmptyClass>
|
|
class Xmlizeable : public B
|
|
{
|
|
public:
|
|
virtual void Xmlize(XmlIO& xml) = 0;
|
|
};
|
|
|
|
//most times it is a good idea to implement both
|
|
template<class B = EmptyClass>
|
|
class Persistable : public Xmlizeable<Serializeable<B> > {};
|
|
|
|
//a helper when using a class with XmlParser for DOM/SAX parsing
|
|
template<class B = EmptyClass>
|
|
class XmlParseable : public B
|
|
{
|
|
public:
|
|
virtual String ToXML() = 0;
|
|
virtual void LoadXML(XmlParser& p) = 0;
|
|
};
|
|
|
|
typedef void*(*GlobalInstancerType)();
|
|
typedef VectorMap<Value, GlobalInstancerType> GlobalInstancerMapType;
|
|
GlobalInstancerMapType& GetGlobalInstancerMap();
|
|
|
|
//Instancer help class, for maps of Instancers. the static Map should
|
|
//somewhere be ONCELOCK initialized with the elements
|
|
//B is the common base class, T should be the derived class, to ensure
|
|
//proper pointer arithmetic
|
|
template<class B>
|
|
class Instancer
|
|
{
|
|
public:
|
|
typedef B*(*Type)();
|
|
typedef VectorMap<Value, Type> MapType;
|
|
|
|
template<class T = B>
|
|
class Typed
|
|
{
|
|
public:
|
|
static B* GetInstance() { return new T(); }
|
|
static Type GetInstancer() { return &GetInstance; }
|
|
static GlobalInstancerType GetGlobalInstancer() { return (GlobalInstancerType)&GetInstance; }
|
|
};
|
|
|
|
static B* GetInstance() { return Typed<B>::GetInstance(); }
|
|
static MapType& Map() { static MapType _; return _; }
|
|
};
|
|
|
|
template<class T> inline String TypeOfS(T* = 0) { return String(typeid(T).name()); }
|
|
template<class T> inline String TypeOf(T* t = 0) { return TypeOfS<T>(t); }
|
|
|
|
//in polymorph environment, type info is needed, i.e. when xmlizing/serializing elements
|
|
//to know later which one to instantiate..best used with Instancer
|
|
class Typer
|
|
{
|
|
friend class TyperRegistrar;
|
|
public:
|
|
String TypeOf() const { ASSERT(tf); return (*tf)(); } //no virtual, dont permit override
|
|
Typer() : tf(NULL) {}
|
|
private:
|
|
String (*tf)();
|
|
};
|
|
|
|
class TyperRegistrar
|
|
{
|
|
public:
|
|
static void RegisterType(Typer& t, String (*tf)()) { t.tf = tf; }
|
|
};
|
|
|
|
template<class T, class B = EmptyClass>
|
|
class TyperT : public B, public TyperRegistrar
|
|
{
|
|
public:
|
|
TyperT() { TyperRegistrar::RegisterType((T&)(*this), &Invoke); }
|
|
protected:
|
|
static inline String Invoke() { return TypeOfS<T>((T*)NULL); }
|
|
};
|
|
|
|
//to declare a class beeing partaker in Instanciating.
|
|
//T is the interface / class that should be acessible at base
|
|
template<class T>
|
|
class Instance : public TypeHook<T, Typer> {};
|
|
|
|
template <class T>
|
|
class Shared : Moveable< Shared<T> > {
|
|
mutable T *ptr;
|
|
Atomic *rfc;
|
|
|
|
void Retain() const { ASSERT(rfc); AtomicInc(*rfc); }
|
|
void Release() { ASSERT(rfc); if(AtomicDec(*rfc) == 0) { Free(); delete rfc; rfc = NULL; } }
|
|
|
|
void Free() { if(ptr && ptr != (T*)1) delete ptr; }
|
|
void Chk() const { ASSERT(ptr != (T*)1); }
|
|
void ChkP() const { Chk(); ASSERT(ptr); }
|
|
|
|
public:
|
|
void Attach(T *data) { Free(); ptr = data; }
|
|
T *Detach() pick_ { ChkP(); T *t = ptr; ptr = NULL; return t; }
|
|
T *operator-() pick_ { return Detach(); }
|
|
void Clear() { Free(); ptr = NULL; }
|
|
|
|
void operator=(T *data) { Attach(data); }
|
|
void operator=(const Shared<T>& d){ Release(); ptr = d.ptr; rfc = d.rfc; Retain(); }
|
|
void operator=(pick_ One<T>& d) { Attach(d.Detach()); }
|
|
|
|
const T *operator->() const { ChkP(); return ptr; }
|
|
T *operator->() { ChkP(); return ptr; }
|
|
const T *operator~() const { Chk(); return ptr; }
|
|
T *operator~() { Chk(); return ptr; }
|
|
const T& operator*() const { ChkP(); return *ptr; }
|
|
T& operator*() { ChkP(); return *ptr; }
|
|
|
|
template <class TT>
|
|
TT& Create() { TT *q = new TT; Attach(q); return *q; }
|
|
T& Create() { T *q = new T; Attach(q); return *q; }
|
|
|
|
bool IsEmpty() const { Chk(); return !ptr; }
|
|
|
|
operator bool() const { return ptr; }
|
|
|
|
Shared() { ptr = NULL; rfc = new Atomic(1); }
|
|
Shared(T *newt) { ptr = newt; rfc = new Atomic(1); }
|
|
Shared(const Shared<T>& p) { ptr = p.ptr; rfc = p.rfc; Retain(); }
|
|
~Shared() { Release(); }
|
|
|
|
Shared(pick_ One<T>& p) { ptr = p.Detach(); rfc = new Atomic(1); }
|
|
Shared(const One<T>& p, int) { ptr = DeepCopyNew(*p); rfc = new Atomic(1); }
|
|
|
|
template<class TT> friend class GenerateShared;
|
|
private:
|
|
Shared(T* p, Atomic* r) { ptr = p; rfc = r; Retain(); }
|
|
};
|
|
|
|
template<class T>
|
|
class GenerateShared //can access the internals of any Shared<T>
|
|
{
|
|
public:
|
|
template<class TT>
|
|
static Shared<T> FromShared(const Shared<TT>& p)
|
|
{
|
|
return Shared<T>((T*)p.ptr, p.rfc);
|
|
}
|
|
};
|
|
|
|
template<class T = double>
|
|
class Scaler
|
|
{
|
|
public:
|
|
Scaler() : mn(0), mx(0) {}
|
|
Scaler(const T& mn, const T& mx) : mn(mn), mx(mx) {}
|
|
|
|
inline void Min(const T& t) { mn = t; }
|
|
inline T Min() const { return mn; }
|
|
inline void Max(const T& t) { mx = t; }
|
|
inline T Max() const { return mx; }
|
|
inline void MinMax(const T& _mn, const T& _mx) { mn = _mn; mx = _mx; }
|
|
|
|
//scales local dimension value t to foreign dimensions d
|
|
//returned in foreign dimension
|
|
inline T To(const Scaler& d, const T& t) { return (t-mn)*(d.mx-d.mn)/(mx-mn)+d.mn; }
|
|
//scales foreign dimension value t from foreign s to local dimension
|
|
//return in local dimension
|
|
inline T From(const Scaler& s, const T& t) { return (t-s.mn)*(mx-mn)/(s.mx-s.mn)+mn; }
|
|
|
|
inline T operator() (const Scaler& s, const T& t) { return From(s, t); }
|
|
protected:
|
|
T mn, mx;
|
|
};
|
|
|
|
//some Link helpers
|
|
|
|
//returns count of linked elements
|
|
//not counting the reported l element, which most times is LinkOwner anyway.
|
|
template<class T>
|
|
int GetLinkCount(const T& l, bool f = true)
|
|
{
|
|
int c = 0;
|
|
const T *list = l.GetPtr(), *e = list;
|
|
if(f) while((e = e->GetNext()) != list) ++c;
|
|
else while((e = e->GetPrev()) != list) ++c;
|
|
return c;
|
|
}
|
|
|
|
template<class T>
|
|
inline void ChkLinkCount(const T& l) { ASSERT(GetLinkCount(l, true) == GetLinkCount(l, false)); }
|
|
|
|
template<class T>
|
|
inline void ChkLink(const T& l, bool f = true)
|
|
{
|
|
if(f) ASSERT(l.GetNext()->GetPrev() == l.GetPtr());
|
|
else ASSERT(l.GetPrev()->GetNext() == l.GetPtr());
|
|
}
|
|
|
|
template<class T>
|
|
int ChkLinkDeep(const T& l, bool f = true)
|
|
{
|
|
int c = 0;
|
|
const T *list = l.GetPtr(), *e = list;
|
|
do { ChkLink(*e, f); ++c; }
|
|
while((e = e->GetNext()) != list);
|
|
return --c;
|
|
}
|
|
|
|
END_UPP_NAMESPACE
|
|
|
|
#endif
|