/////////////////////////////////
// smart.hpp
// generic assign/copy wrapper
//
#pragma once
#include "dependency.h"
#pragma message ("Compiling " __FILE__)
namespace GE_{ namespace stdx{
//class smart: inherit from a policy.
// requires:
// assign, alias_type, value_type, acquire_type
// provides
// copy, assignment, conversion operators
template<class smart_policy>
class smart:
public smart_policy,
public operators<smart>
{
public:
smart() {}
~smart() {}
smart(const smart& s) { assign(static_cast<const smart_policy&>(s)); }
template<class other>
smart(const smart<other>& s) { assign(static_cast<const other&>(s)); }
template<class A, class B>
smart(const A& a, const B& b) { assign(a,b); }
//dumb-to-smart is potentially unsafe for policy requiring extra data to be recorded
// see pointers::mappedpolicy or pointers::intrpolicy for safe assignments.
smart(typename smart_policy::acquire_type a) { assign(a); }
smart& operator=(const smart& s) { assign(static_cast<const smart_policy&>(s)); return *this; }
typedef typename smart_policy::alias_type alias_type;
typedef typename smart_policy::acquire_type acquire_type;
typedef typename smart_policy::value_type value_type;
};
namespace refcounts
{
/////////////////////////
// reference counting
struct counters
{
private:
unsigned ref, hold;
bool locked;
public:
counters() { ref=hold=0; locked=false; }
template<class P>
void decrement(P& p, bool bStrong)
{
if(bStrong && !locked)
{
p.on_release();
if(hold == 1)
{
locked = true;
p.on_lastrelease();
p.on_delete();
}
hold--;
}
ref--;
if(!ref)
{
counters* p(this);
stdx::Delete(p);
}
}
template<class P>
void increment(P& p, bool bStrong)
{
ref++;
if(bStrong && !locked)
{
hold++;
if(hold==1)
p.on_firstref();
p.on_addref();
}
}
unsigned get_hold() const {return hold;}
unsigned get_ref() const { return ref; }
};
//
// requires:
// assign, equal, less,
// on_addref, on_firstref, on_release, on_lastrelease, on_delete
// operator!, alias_type, get_counters, New
// provides:
// assign, equal, less, operator!, alias_type, New
//
template<class refcnt_policy, bool bStrong>
class policy:
public refcnt_policy
{
private:
friend class policy;
friend struct counters;
counters* pCnt;
void clear_()
{
if(!!pCnt)
pCnt->decrement(*this, bStrong);
pCnt = 0;
}
void set_(counters* p)
{
ASSERT(!pCnt);
pCnt = p;
if(pCnt)
pCnt->increment(*this, bStrong);
}
protected:
policy() { pCnt=0; }
~policy() { clear_(); }
typedef typename refcnt_policy::acquire_type acquire_type;
typedef typename refcnt_policy::alias_type alias_type;
template<class other, bool b>
void assign(const policy<other,b>& a)
{
if(a.pCnt == pCnt) return;
clear_();
refcnt_policy::assign(static_cast<const other&>(a));
if(!refcnt_policy::operator!()) set_(a.pCnt);
}
void assign(acquire_type a)
{
counters* p = get_counters(a);
if(pCnt == p) return;
clear_();
refcnt_policy::assign(a);
set_(p);
}
public:
bool operator!() const { return !pCnt || !pCnt->get_hold() || refcnt_policy::operator!(); }
bool operator==(const policy& r) const
{ return (pCnt == r.pCnt) || refcnt_policy::operator==(static_cast<const refcnt_policy&>(r)); }
bool operator<(const policy& r) const
{ return (pCnt != r.pCnt) && refcnt_policy::operator<(static_cast<const refcnt_policy&>(r)); }
void clear() { clear_(); }
alias_type New() { clear(); assign(refcnt_policy::New()); return operator()(); }
template <class A>
alias_type New(const A& a) { clear(); assign(refcnt_policy::New(a)); return operator()(); }
template <class A, class B>
alias_type New(const A& a, const B& b) { clear(); assign(refcnt_policy::New(a,b)); return operator()(); }
unsigned get_holdcount() { return (!pCnt)? 0: pCnt->get_hold(); }
unsigned get_refcount() { return (!pCnt)? 0: pCnt->get_ref(); }
typedef policy refcnt_plc;
};
}
namespace pointers
{
struct excp_base {};
template<class Type>
struct excp: public excp_base {}; //thrown as excp* in case of null dereferencing
//
// pointer: use static cast in conversions
//
// requires:
// Type
// provides:
// assign, equal, less,
// on_addref, on_firstref, on_release, on_lastrelease,
// operator!, alias_type, get_counters, clear, New
//
template<class Type>
class policy
{
friend class policy;
protected:
Type* ptr;
protected:
typedef Type* alias_type;
typedef Type* acquire_type;
typedef Type value_type;
policy() { ptr=0; }
void on_addref() {}
void on_firstref() { STRACE(t,1,("first reference to %p, %s\n", ptr, typeid(*ptr).name())); }
void on_release() {}
void on_lastrelease() { STRACE(t,1,("last releasing to %p, %s\n", ptr, typeid(*ptr).name())); }
void on_delete() { if(ptr) stdx::Delete(ptr); ptr=0; }
refcounts::counters* get_counters(Type* p) { refcounts::counters* pcnt(0); if(p) stdx::New(pcnt); return pcnt; }
void clear() { ptr = 0; }
template<class other>
void assign(const policy<other>& p) { ptr = static_cast<Type*>(p.ptr); }
void assign(const policy& p) { ptr = p.ptr; }
void assign(Type* p) { ptr = p; }
public:
bool operator==(const policy& p) const { return ptr == p.ptr; }
bool operator<(const policy& p) const { return ptr < p.ptr; }
bool operator!() const { return !ptr; }
Type* operator()() const { return ptr; }
template<class I>
Type& operator[](const I& i) const { ASSERT(i==0); return operator*(); }
Type* operator->() const { if(!ptr) throw_excpptr<excp<Type> >(); return ptr; }
Type& operator*() const { if(!ptr) throw_excpptr<excp<Type> >(); return *ptr; }
operator Type*() const { return ptr; }
Type* New() { stdx::New(ptr); return ptr; }
template<class A>
Type* New(const A& a) { stdx::New(ptr,a); return ptr; }
template<class A, class B>
Type* New(const A& a, const B& b) { stdx::New(ptr,a,b); return ptr; }
typedef policy pointer_plc;
};
//array
template<class Type>
class vectpolicy:
public pointers::policy<Type>
{
protected:
void on_delete()
{ delete[] operator()(); }
public:
template<class I>
Type& operator[](const I& i)
{ return operator()()[i]; }
};
// dynptr: specialize ptr, using dynamic cast
template<class Type>
class dynpolicy:
public policy<Type>
{
protected:
template<class other>
void assign(const policy<other>& p) { assign(dynamic_cast<Type*>(p())); }
void assign(const dynpolicy& p) { assign(p()); }
void assign(Type* p) { policy<Type>::assign(p); }
};
//mapped pointers: use aglobally referred map to associate counters to objects.
// the existence of the map is ... refcounted(!) - without a map, of course. -
template<class Type>
class mappedpolicy:
public dynpolicy<Type>
{
private:
typedef typename std::map<void*, refcounts::counters*> map_t;
typedef typename dynpolicy<Type> base_t;
typedef typename smart<refcounts::policy<pointers::policy<map_t>, true> > map_p;
static map_p map() { static map_p p; if(!p) p.New(); return p; }
map_p pMap;
protected:
// a map will exist until the program terminates or someone will refer it
mappedpolicy() { pMap = map(); }
refcounts::counters* get_counters(Type* p)
{
refcounts::counters*& pcnt = (*pMap)[dynamic_cast<void*>(p)];
if(!pcnt) stdx::New(pcnt);
return pcnt;
}
void on_delete()
{
pMap->erase(dynamic_cast<void*>(operator()()));
base_t::on_delete();
}
};
//////////////////////////
// intrusive refocunters:
// Type supposed to be an stdx::i_referrable implementation
// stdx::refcountable can be used that way
//
template<class Type>
class intrpolicy:
public dynpolicy<Type>
{
private:
typedef dynpolicy<Type> base_t;
protected:
void on_addref() { if((*this)()) dynamic_cast<refcountable*>((*this)())->on_addref(); }
void on_firstref()
{
STRACE(t,1,("first intrusive reference to %p, %s\n", (*this)(), typeid(*(*this)()).name()));
if((*this)()) dynamic_cast<refcountable*>((*this)())->on_firstref();
}
void on_release() { if((*this)()) dynamic_cast<refcountable*>((*this)())->on_release(); }
void on_lastrelease()
{
STRACE(t,1,("last intrusive releasing to %p, %s\n", (*this)(), typeid(*(*this)()).name()));
if((*this)()) dynamic_cast<refcountable*>((*this)())->on_lastrelease();
}
void on_delete()
{ if((*this)()) dynamic_cast<refcountable*>((*this)())->on_delete(); ptr = 0; }
refcounts::counters* get_counters(Type* p) { return (!p)? 0: dynamic_cast<refcountable*>(p)->get_counters(); }
};
}
class refcountable
{
friend struct refcounts::counters;
friend class pointers::intrpolicy;
public:
refcountable()
{
stdx::New(pCnt);
pCnt->increment(*this, false);
}
virtual ~refcountable()
{
if(pCnt)
pCnt->decrement(*this, false);
pCnt=0;
}
private:
refcounts::counters* pCnt;
protected:
virtual void on_addref() {}
virtual void on_firstref() {}
virtual void on_release() {}
virtual void on_lastrelease() { }
virtual void on_delete() { refcountable* p(this); stdx::Delete(p); }
virtual refcounts::counters* get_counters() { return pCnt; }
};
////////////////////
// shortcuts for frequent types
//
template<class Type>
struct ptr //intrusive ptrs, dumb-to smart safe assignment
{
typedef smart<refcounts::policy<pointers::intrpolicy<Type>, true> > strong;
typedef smart<refcounts::policy<pointers::intrpolicy<Type>, false> > weak;
};
template<class Type>
struct statptr //static_cast non-intrusive ptrs, usafe dumb-to smart assignments
{
typedef smart<refcounts::policy<pointers::policy<Type>, true> > strong;
typedef smart<refcounts::policy<pointers::policy<Type>, false> > weak;
};
template<class Type>
struct refcntvect //non casting, non intrusive ptr to an array. unsafe dumb-to smart assign
{
typedef smart<refcounts::policy<pointers::vectpolicy<Type>, true> > strong;
typedef smart<refcounts::policy<pointers::vectpolicy<Type>, false> > weak;
};
template<class Type>
struct dynptr //dynamic_cast non-intrusive ptrs, usafe dumb-to smart assignments
{
typedef smart<refcounts::policy<pointers::dynpolicy<Type>, true> > strong;
typedef smart<refcounts::policy<pointers::dynpolicy<Type>, false> > weak;
};
template<class Type>
struct mappedptr //dynamic_cast non-intrusive, safe dumb to smart assignment
{
typedef smart<refcounts::policy<pointers::mappedpolicy<Type>, true> > strong;
typedef smart<refcounts::policy<pointers::mappedpolicy<Type>, false> > weak;
};
/////////////////////////////////////////
//// other policies
//
namespace values {
// like "pointers", but giving value semantics
template<
class Type,
Type nullval, //a singular value for Type
class CleanupFn //a "void operator()(Type&)" functor, doing cleanup action
>
class policy
{
friend class policy;
protected:
Type val;
CleanupFn fnCleanup;
protected:
typedef const Type& alias_type;
typedef const Type& acquire_type;
typedef Type value_type;
policy() { val=nullval; }
void on_addref() {}
void on_firstref() { STRACE(t,1,("first value reference to %p, %s\n", (*this)(), typeid((*this)()).name())); }
void on_release() {}
void on_lastrelease()
{
STRACE(t,1,("last value release to %p, %s\n", (*this)(), typeid((*this)()).name()));
}
void on_delete() { fnCleanup(val); val=nullval; }
refcounts::counters* get_counters(Type* p) { refcounts::counters* p(0); stdx::New(p); return p; }
void clear() { val = nullval; }
void assign(const policy& p) { val = p.val; }
void assign(const Type& p) { val = p; }
public:
bool operator==(const policy& p) const { return val == p.val; }
bool operator<(const policy& p) const { return val < p.val; }
bool operator!() const { return val == nullval; }
const Type& operator()() const { return val; }
operator const Type&() const { return val; }
};
//mapped values: use a globally referred map to associate counters to values.
// the existence of the map is ... refcounted(!) - without a map, of course. -
template<class Type, Type nullval, class CleanupFn>
class mappedpolicy:
public policy<Type, nullval, CleanupFn>
{
private:
typedef typename std::map<Type, refcounts::counters*> map_t;
typedef typename policy<Type, nullval, CleanupFn> base_t;
typedef typename smart<refcounts::policy<pointers::policy<map_t>, true> > map_p;
static map_p map() { static map_p p; if(!p) p.New(); return p; }
map_p pMap;
protected:
// a map will exist until the program terminates or someone will refer it
mappedpolicy() { pMap = map(); }
~mappedpolicy() {}
refcounts::counters* get_counters(const Type& p)
{
refcounts::counters*& pcnt = (*pMap)[p];
if(!pcnt) stdx::New(pcnt);
return pcnt;
}
void on_delete()
{
pMap->erase(operator()());
base_t::on_delete();
}
};
}
template<class Type, Type nullval, class CleanupFn>
struct hnd
{
typedef smart<refcounts::policy<values::policy<Type,nullval,CleanupFn>, true> > strong;
typedef smart<refcounts::policy<values::policy<Type,nullval,CleanupFn>, false> > weak;
};
template<class Type, Type nullval, class CleanupFn>
struct mappedhnd
{
typedef smart<refcounts::policy<values::mappedpolicy<Type,nullval,CleanupFn>, true> > strong;
typedef smart<refcounts::policy<values::mappedpolicy<Type,nullval,CleanupFn>, false> > weak;
};
}}