//Misc.h - miscellaneous
#pragma once
namespace GE_{ namespace NUtil{
// // STmpAssign
// // temporarily assign a value to a specifyed variable.
// // value is restored on destroy
// // example:
//
// {
// STmpAssign<bool> lock(_lockval, true);
// ...
// }
//
// // assuming _lockval is initially false,
// // its value will be true until the '}' is reached
template<class T>
struct STmpAssign
{
private:
T* _pVar;
T _oldVal;
public:
STmpAssign(T& t, const T& val)
{ _pVar = &t; _oldVal = t; t = val; }
~STmpAssign()
{ *_pVar = _oldVal; }
};
//STrace
// // tracing class for trace into debug
// // usage:
// {
// STrace(3) trc; trc("fomatstring %p\n", this);
// }
// // will trace ".....formatstring 0xXXXXXXXX" on debug output
// // with the number of '.' setted to the recursion level
// // (how many STrace object are actually on the stack)
struct STrace //do trace into debug
{
private:
static int& _Deep() { static int deep=0; return deep; }
UINT _filter; // the filter value for this trace object
public:
//_Filter is the warning level: the lower the level, the greater are thre received messages
static UINT& _Filter() { static UINT filter = 0; return filter; }
STrace(UINT filter) { _filter = filter; _Deep()++; }
~STrace() { _Deep()--; }
void operator() (LPCTSTR format, ...); //printf like syntax
void createmsg(const type_info& ti, LPVOID address);
void deletemsg(const type_info& ti, LPVOID address);
};
#ifdef _DEBUG
#define STRACE(variable,lev,command) GE_::NUtil::STrace variable(lev);variable command;
#else
#define STRACE(variable,lev,command) //defined as "empty"
#endif
//SEmpty
// Empty structure
struct SEmpty {};
//SResID
// converts automatically UINT into LPCTSTR. useful when loading resources
struct SResID
{
protected:
LPCTSTR _pStr;
public:
SResID() { _pStr = NULL;}
SResID(LPCTSTR pstr) { _pStr = pstr; }
SResID(UINT nID) { _pStr = MAKEINTRESOURCE(nID); }
SResID(const SResID& s) { _pStr = s._pStr; }
LPCTSTR GetString() { return _pStr; }
operator LPCTSTR() { return _pStr; }
};
//SPerthread
// //instantiate a data into a threadID ordered map
// //data are accessible only by the "current thread"
//
template<class D>
struct SPerThread
{
protected:
std::map<DWORD, D> _map;
public:
D& Data() {return _map[GetCurrentThreadId()]; }
operator D&() { return Data(); }
operator const D&() const { return Data(); }
void ClearThread() { _map.erase(GetCurrentThreadId()); }
void Clear() { _map.clear(); }
};
//EGlobal
// //define an instance of an object that can exixt only in one copy
// // GetGlobal returnd the singleton
//
template<class D> //the derived class
class EGlobal
{
private:
static EGlobal*& _ptr() { static EGlobal* ptr = NULL; return ptr;}
public:
EGlobal() { if(!_ptr()) _ptr() = this; }
~EGlobal() { if(_ptr() == this) _ptr() = NULL; }
static D& GetGlobal()
{
static std::runtime_error e("Unititialized singleton dereference");
if(!_ptr()) throw &e;
return *static_cast<D*>(_ptr());
}
static SetGlobal(D& d)
{ _ptr() = &d; }
};
//parametric foreach
template<class InputIterator, class Function, class Parameter>
Function for_each(
InputIterator _First,
InputIterator _Last,
Function _Func,
Parameter& _Parameter)
{
for(;_First != _Last; ++_First)
_Func(*_First, _Parameter);
return _Func;
}
//EAutocollection
// //collect object of a given type together
template<class D>
struct EAutocollect
{
private:
typedef std::list<D*> t_list;
static t_list& List() { static t_list list; return list; }
public:
typedef typename t_list::iterator iterator;
EAutocollect()
{ List().push_back( static_cast<D*>(this)); }
~EAutocollect() { List().remove( static_cast<D*>(this)); }
static iterator begin_collection() { return List().begin(); }
static iterator end_collection() { return List().end(); }
static void Broadcast(void (D::*pfn)())
{ std::for_each(begin_collection(), end_collection(), mem_fun(pfn)); }
static void Broadcast(void (*pfn)(D*))
{ std::for_each(begin_collection(), end_collection(), pfn); }
template<class A>
static void Broadcast(void (D::*pfn)(A&), A& a)
{ for_each(begin_collection(), end_collection(), mem_fun1(pfn), a); }
template<class A>
static void Broadcast(void (*pfn)(A&), A& a)
{ for_each(begin_collection(), end_collection(), pfn, a); }
};
//EAutodelete
// derive form here if you need "autodelete" facility
//
class EAutodeleteFlag
{
protected:
bool _bHasAutodelete;
struct XChain: public std::list<EAutodeleteFlag*>
{
~XChain()
{
STRACE(trc, 3, ("Clearing up %d Autodelete orphans\n", (int)size()));
while(size())
{
delete *begin();
pop_front();
}
}
};
static XChain& AutoDeleteChain() { static XChain c; return c; }
public:
EAutodeleteFlag() { _bHasAutodelete = false; }
virtual ~EAutodeleteFlag() { AutoDeleteChain().remove(this); }
bool HasAutodelete() const { return _bHasAutodelete; }
void Autodelete(bool bOn)
{
if(bOn && !_bHasAutodelete) AutoDeleteChain().push_back(this);
if(!bOn && _bHasAutodelete) AutoDeleteChain().remove(this);
_bHasAutodelete = bOn;
}
};
//generictemplate base
template<class D> //drived class
class EThis
{
public:
D* pThis() { return static_cast<D*>(this); }
const D* pThis() const { return static_cast<const D*>(this); }
};
struct SLimit
{
template<class A> static A Min(const A& left, const A& right) {return (left<right)? left:right; }
template<class A> static A Max(const A& left, const A& right) {return (right<left)? left:right; }
template<class A> static A& OrMin(A& ref, const A& val) { if(val<ref) ref=val; return ref; }
template<class A> static A& OrMax(A& ref, const A& val) { if(ref<val) ref=val; return ref; }
template<class A> static A OrRange(A& rmin, A& rmax, const A& val) { OrMin(rmin, val); OrMax(rmax, val); return val; }
template<class A> static A& AndRange(A& ref, const A& min, const A& max) { OrMax(ref, min); OrMin(ref, max); return ref; }
};
//numeric range manager
template<class I>
struct SRange
{
protected:
I _min,_max;
public:
SRange(const I& a, const I& b)
{ if(a<b) _min = a, _max = b; else _min=b, _max = a; }
SRange(const SRange& s)
{ _min = s._min; _max = s._max; }
int compare(const I& i) const
{ return (i<_min)? -1: (i<_max)? 0: 1; }
const I& Min() const { return _min; }
const I& Max() const { return _max; }
I Size() const { return _max - _min; }
I Center() const { return (_max+_min)/2; }
bool IsEmpty() const { return _max - _min <= 0; }
bool IsUnit() const { return _max - _min == 1; }
bool Clip(I& i) const
{ bool b= false; if(i<_min) i=_min, b=true; if(_max<i) i=_max, b=true; return b; }
bool ClipMin(I& i) const
{ bool b= false; if(i<_min) i=_min, b=true; return b; }
bool ClipMax(I& i) const
{ bool b= false; if(_max<i) i=_max, b=true; return b; }
SRange& operator|=(const I& i)
{ if(i<_min)_min = i; if(_max < i) _max = i; return *this; }
SRange& operator|=(const SRange& R)
{ if(R._min<_min) _min = R._min; if(_max < R._max) _max = R._max; return *this;}
SRange& operator&=(const SRange& R)
{ if(_min < R._min) _min = R._min; if(R._max < _max) _max = R._max; if(_max<_min) _max=_min; return *this; }
SRange operator|(const I& i) const
{ return SRange(*this)|=i; }
SRange operator|(const SRange& R) const
{ return SRange(*this)|= R; }
SRange operator&(const SRange& R) const
{ return SRange(*this)&=R; }
bool operator&(const I& i) const
{ return compare(i); }
};
//globally stored Maps
struct XMap_base
{
struct XList: public std::list<XMap_base*>
{
XList()
{
STRACE(trc, 4, ("Initializing global maps list @%p\n", this));
}
~XList()
{
STRACE(trc, 4, ("Deleting global maps list @%p\n", this));
while(size()) //delete object pointed inside
{
delete *begin();
pop_front();
}
}
};
static XList& Maps() { static XList s_maps; return s_maps; }
virtual ~XMap_base() {}
};
namespace {
struct XInit
{
XInit()
{
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
XMap_base::Maps().clear();
}
};
_declspec(selectany) XInit g_init;
}
template<class Key, class Val, class Store = Val>
struct EMap
{
typedef Key TKey;
typedef Val TVal;
typedef Store TStore;
struct TMap:
public std::map<Key, Store>,
public XMap_base
{
TMap()
{
Maps().push_front(this); //collect itself into XMap_base chain
STRACE(trc,4,("Creating %s at %p\n", typeid(*this).name(), this));
}
virtual ~TMap()
{
STRACE(trc,4,("Destroying %s at %p \n\t\tafter %u access and %u max stored elements\n", typeid(*this).name(), this, Accesscounter(), Stats().Max()));
}
};
#ifdef _DEBUG
static NUtil::SRange<ULONG>& Stats() { static NUtil::SRange<ULONG> r(0,0); return r;}
static ULONG& Accesscounter() { static ULONG n=0; return n; }
#endif
static TMap& map()
{
static TMap* s_pmap=NULL;
if(!s_pmap) s_pmap = new TMap; //craete, it it is the very first time
#ifdef _DEBUG
Accesscounter()++;
#endif
return *s_pmap;
}
static void Map(const Key& key, const Val& val)
{
if(!key) return; //don't map() NULL values !
map()[key] = val; //map() the passed range
#ifdef _DEBUG
Stats()|=(ULONG)map().size();
#endif
STRACE(trc,1,("EMap %p::Map: %d elements in map()\n",&map(), map().size()));
}
static void Unmap(const Key& key)
{
map().erase(key); //erase tha range based on key
STRACE(trc,1,("EMap %p::Unmap: %d elements in map()\n",&map(), map().size()));
}
static Val Find(const Key& key)
{
if(!key) return NULL;
TMap::iterator i = map().find(key);
if(i == map().end())
return Val(NULL); //return NULL if not found
return Val(i->second); //return the found value
}
Store& operator[](const Key& key)
{ return map()[key]; }
};
//WinMain Parameters store
struct SWinMain:
public EGlobal<SWinMain>
{
struct XParams
{
HINSTANCE hInst;
HINSTANCE hPevInst;
LPTSTR lpstrCmdLine;
UINT nCmdShow;
};
protected:
XParams* _pParams;
public:
SWinMain(HINSTANCE& hinst)
{
_pParams = (XParams*)&hinst;
}
static const XParams& Params()
{ return *GetGlobal()._pParams; }
};
//generic color COLORREF linear mixer
inline COLORREF MixColor(COLORREF a, COLORREF b, int w=50) //w = ..0..100.. for ..a..b..
{
int ra,ga,ba;
int rb,gb,bb;
ra = GetRValue(a); ga = GetGValue(a); ba = GetBValue(a);
rb = GetRValue(b); gb = GetGValue(b); bb = GetBValue(b);
int rc, gc, bc;
rc = (ra*(100-w) + rb*w)/100;
gc = (ga*(100-w) + gb*w)/100;
bc = (ba*(100-w) + bb*w)/100;
SRange<int> z(0,255);
z.Clip(rc); z.Clip(gc); z.Clip(bc);
return RGB(rc,gc,bc);
}
//SMappablePair
// use to create vry simple static map by putting it into vectors
template<class K, class V, V invalid = 0>
struct SMappablePair
{
K _k;
V _v;
static V& Unfound() { static V v = invalid; return v; }
V& find(const K& k, UINT n)
{
for(UINT i=0; i<n; i++)
{
SMappablePair& pair = this[i];
if(k == pair._k)
return pair._v;
}
return Unfound();
}
};
//SAutoVector: an std::vector that autoresize to accomodate the queryed index
// note: coded usinf STL styles:
// Template_parameters, types, _members, _Parameters, Variables, functions()
template <class Type, class Allocator = std::allocator<Type> >
struct SAutoVector: public std::vector<Type, Allocator>
{
typedef std::vector<Type, Allocator> _vector;
typedef typename _vector::size_type size_type;
typedef typename _vector::reference reference;
typedef typename _vector::const_reference const_reference;
SAutoVector( ) {} ;
explicit SAutoVector(const Allocator& _Al) : _vector(_Al) {}
explicit SAutoVector(size_type _Count) : _vector(_Count) {}
SAutoVector(size_type _Count, const Type& _Val) : _vector(_Count, _Val) {}
SAutoVector(size_type _Count, const Type& _Val, const Allocator& _Al) : _vector(_Count, _val, _Al) {}
SAutoVector(const _vector& _Right) : _vector(_Right) {}
template<class InputIterator>
SAutoVector(InputIterator _First, InputIterator _Last) : _vector(_First, _Last) {}
template<class InputIterator>
SAutoVector(InputIterator _First, InputIterator _Last, const Allocator& _Al): _vector(_First, _Last, _Al) {}
reference operator[]( size_type _Pos)
{
if(!(_Pos < size())) // !(<) is >= , but all STL requires only < and ==
resize(_Pos+1);
return _vector::operator[](_Pos);
}
const_reference operator[]( size_type _Pos) const
{
ASSERT(_Pos < size());
return _vector::operator[](_Pos);
}
};
}}
//SRange commutative operators (must be global)
template<class I>
GE_::NUtil::SRange<I> operator|(const I& i, const GE_::NUtil::SRange<I>& R)
{ return R|i; }
template<class I>
bool operator& (const I& i, const GE_::NUtil::SRange<I>& R)
{ return R&i; }
#ifdef GE_FORCEINLINE
#include "misc.cpp"
#endif