00001 #ifndef StiFactory_H
00002 #define StiFactory_H
00003 #include <string.h>
00004 #include <assert.h>
00005 #include <typeinfo>
00006 #include "Sti/Base/Factory.h"
00018
00019 template<class Object>
00020 class StiHolder {
00021 public:
00022 StiHolder();
00023 union {
00024 StiHolder *fNext;
00025 long fLong;
00026 char fChar[1];
00027 };
00028 Object fObj;
00029 };
00030
00031
00032 template<class Object>
00033 class StiBlock {
00034 public:
00035 enum {kSize=100};
00036 StiBlock(StiBlock **bTop,StiHolder<Object> **hTop,char *buf);
00037 void reset(StiBlock **bTop,StiHolder<Object> **hTop);
00038 int getSize() const {return kSize;}
00039
00040 StiBlock *fNext;
00041 char *fBuff;
00042 StiHolder<Object> fArr[kSize];
00043 };
00044
00045
00046
00047 template <class Concrete, class Abstract>
00048 class StiFactory : public Factory<Abstract>
00049 {
00050 public:
00051 void free(Abstract *obj);
00052 void free(void *obj) { free((Abstract*)obj);}
00054 void clear();
00055
00057 void reset();
00058
00060 Abstract* getInstance();
00061 static StiFactory* myInstance();
00062
00063 private:
00064 StiFactory();
00065 ~StiFactory(){clear();}
00066 StiBlock<Concrete> *fBTop;
00067 StiHolder<Concrete> *fHTop;
00068
00069 };
00070
00071
00072
00073 template <class Object>
00074 StiBlock<Object>::StiBlock(StiBlock **bTop,StiHolder<Object> **hTop,char *buf)
00075 {
00076 fBuff=buf;
00077 reset(bTop,hTop);
00078 }
00079 template <class Object>
00080 void StiBlock<Object>::reset(StiBlock **bTop,StiHolder<Object> **hTop)
00081 {
00082 fNext=*bTop; *bTop=this;
00083 for (int i=0;i<kSize;i++) {
00084 fArr[i].fNext = *hTop;
00085 *hTop = fArr+i;
00086 }
00087 }
00088
00089
00090 template <class Object>
00091 StiHolder<Object>::StiHolder()
00092 {
00093 memset(fChar,0,((char*)&fObj)-fChar);
00094 }
00095
00096
00097 template <class Concrete, class Abstract>
00098 StiFactory<Concrete,Abstract>::StiFactory():Factory<Abstract>("")
00099 {
00100 fHTop=0;fBTop=0;
00101 this->setName(typeid(*this).name());
00102 printf("*** Factory created *** %s\n",this->getName().c_str());
00103 }
00104 template <class Concrete, class Abstract>
00105 StiFactory<Concrete,Abstract>* StiFactory<Concrete,Abstract>::myInstance()
00106 {
00107 static StiFactory* my=0;
00108 if (!my) my = new StiFactory;
00109 return my;
00110 }
00111
00112 template <class Concrete, class Abstract>
00113 Abstract *StiFactory<Concrete,Abstract>::getInstance()
00114 {
00115 enum {FENCE = sizeof(double)+2*sizeof(long)+1};
00116 if (!fHTop) {
00117 if (this->fCurCount >= this->fMaxCount) {
00118 throw runtime_error("StiFactory::getInstance() - Too many instances");
00119 }
00120 assert(this->fCurCount < this->fMaxCount);
00121 if (this->fFastDel) {
00122 int nBuf = sizeof(StiBlock<Concrete>) + FENCE;
00123 char *cBuf = new char[nBuf];
00124 cBuf[nBuf-1]=46;
00125 new((StiBlock<Concrete>*)cBuf) StiBlock<Concrete>(&fBTop,&fHTop,cBuf);
00126 assert(cBuf[nBuf-1]==46);
00127 } else {
00128 new StiBlock<Concrete>(&fBTop,&fHTop, 0);
00129 }
00130 this->fCurCount += fBTop->getSize();
00131 this->fgTotal += sizeof(StiBlock<Concrete>)*1e-6;
00132 }
00133 this->fInstCount++;
00134 StiHolder<Concrete> *h = fHTop;
00135 fHTop = h->fNext;
00136 h->fNext=0;
00137 h->fObj.reset();
00138 this->fUseCount++;
00139 h->fLong= ((long)this)+1;
00140 return &h->fObj;
00141 }
00142
00143 template <class Concrete, class Abstract>
00144 void StiFactory<Concrete,Abstract>::free(Abstract *obj)
00145 {
00146 static const int shift = (char*)(&(((StiHolder<Concrete>*)1)->fObj))-(char*)1;
00147 obj->unset();
00148 StiHolder<Concrete>* h = (StiHolder<Concrete>*)((char*)obj-shift);
00149 assert((h->fLong-1)== (long)this);
00150 h->fNext = fHTop; fHTop=h; this->fUseCount--; this->fFreeCount++;
00151 }
00152
00153
00154 template <class Concrete, class Abstract>
00155 void StiFactory<Concrete,Abstract>::clear()
00156 {
00157 double sz=0;
00158 StiBlock<Concrete>* b = fBTop;
00159 while (b) {
00160 StiBlock<Concrete>* d = b;
00161 b=b->fNext;
00162 if (this->fFastDel) {delete [] d->fBuff;} else { delete d;}
00163 sz += sizeof(StiBlock<Concrete>);
00164 this->fgTotal -= sizeof(StiBlock<Concrete>)*1e-6;
00165 }
00166 fBTop=0; fHTop=0; this->fCurCount=0; this->fUseCount=0;
00167 printf("*** %s::clear() %g MegaBytes Total %g Inst/Free=%d %d\n"
00168 ,this->getName().c_str(),sz*1e-6
00169 ,this->fgTotal,this->fInstCount,this->fFreeCount);
00170 this->fInstCount=0; this->fFreeCount=0;
00171 }
00172
00173 template <class Concrete, class Abstract>
00174 void StiFactory<Concrete,Abstract>::reset()
00175 {
00176 if (!this->fUseCount) return;
00177
00178 typedef StiBlock<Concrete> B_t;
00179 B_t* b = fBTop;
00180 fBTop=0;fHTop=0;
00181 while (b) {
00182 B_t* n = b->fNext;
00183 b->reset(&fBTop,&fHTop);
00184 b=n;
00185 }
00186 this->fUseCount=0;
00187 }
00188 #endif