00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <archon/util/text.H>
00021 #include <archon/util/ref.H>
00022
00023 namespace Archon
00024 {
00025 namespace Utilities
00026 {
00027 RefMapBase::RefMapBase()
00028 {
00029 for(unsigned i=0; i<hashSize; ++i) chunks[i] = 0;
00030
00031
00032
00033 refs.push_back(pair<RefObjectBase *, unsigned long>(0, 0));
00034 }
00035
00036 RefMapBase::~RefMapBase()
00037 {
00038 for(unsigned i=0; i<hashSize; ++i) if(chunks[i]) delete chunks[i];
00039 for(unsigned i=1; i<refs.size(); ++i)
00040 {
00041 RefObjectBase *r = refs[i].first;
00042 if(r) r->refDec();
00043 }
00044 }
00045
00046 string RefMapBase::disp()
00047 {
00048 Mutex::Lock l(refMapMutex);
00049 string s;
00050 unsigned long m = 1;
00051 for(unsigned i=0; i<hashSize; ++i)
00052 if(chunks[i] && chunks[i]->size() > m) m = chunks[i]->size();
00053 char buffer[1024];
00054 for(unsigned i=0; i<hashSize; ++i)
00055 {
00056 unsigned long n = chunks[i] ? chunks[i]->size() : 0;
00057 string bar = string(unsigned(70UL*n/m), '+');
00058 sprintf(buffer, "%7lu |%-70s|\n", n, bar.c_str());
00059 s += string(buffer);
00060 }
00061 return s;
00062 }
00063
00064 unsigned long RefMapBase::get(RefObjectBase *r, bool create)
00065 {
00066 if(!r) return 0;
00067 unsigned long h = reinterpret_cast<unsigned long>(r) % hashSize;
00068 vector<unsigned long>::iterator j;
00069 bool f = false;
00070 unsigned long index;
00071 Mutex::Lock l(refMapMutex);
00072 vector<unsigned long> *c = chunks[h];
00073 if(c)
00074 {
00075 vector<unsigned long>::iterator i = c->begin();
00076 while(i != c->end())
00077 {
00078 index = *i;
00079 if(index)
00080 {
00081 pair<RefObjectBase *, unsigned long> &p = refs[index];
00082 if(p.first == r)
00083 {
00084 ++p.second;
00085 return index;
00086 }
00087 }
00088 else if(!f)
00089 {
00090 f = true;
00091 j = i;
00092 }
00093 ++i;
00094 }
00095 }
00096 if(!create) return 0;
00097
00098 if(unused.size())
00099 {
00100 index = unused.back();
00101 unused.pop_back();
00102 pair<RefObjectBase *, unsigned long> &p = refs[index];
00103 p.first = r;
00104 p.second = 1;
00105 }
00106 else
00107 {
00108 index = refs.size();
00109 refs.push_back(pair<RefObjectBase *, unsigned long>(r, 1));
00110 }
00111
00112 r->refInc();
00113
00114 if(f) *j = index;
00115 else
00116 {
00117 if(!c) c = chunks[h] = new vector<unsigned long>;
00118 c->push_back(index);
00119 }
00120
00121 return index;
00122 }
00123
00124 void RefMapBase::removeNoLock(RefObjectBase *r, unsigned long transCount)
00125 {
00126 if(!r) return;
00127 unsigned long h = reinterpret_cast<unsigned long>(r) % hashSize;
00128 vector<unsigned long> *c = chunks[h];
00129 if(!c) return;
00130 vector<unsigned long>::iterator i = c->begin();
00131 while(i != c->end())
00132 {
00133 unsigned long index = *i;
00134 pair<RefObjectBase *, unsigned long> &p = refs[index];
00135 if(p.first == r)
00136 {
00137 if(transCount)
00138 {
00139 if(transCount > p.second) transCount = p.second;
00140 p.second -= transCount;
00141 if(p.second) return;
00142 }
00143 *i = 0;
00144 r->refDec();
00145 p.first = 0;
00146 p.second = 0;
00147 unused.push_back(index);
00148 return;
00149 }
00150 ++i;
00151 }
00152 }
00153
00154 void RefMapBase::clearNoLock(bool destroyRefs)
00155 {
00156 if(destroyRefs)
00157 for(unsigned i=1; i<refs.size(); ++i)
00158 {
00159 RefObjectBase *r = refs[i].first;
00160 if(r) r->refDec();
00161 }
00162 for(unsigned i=0; i<hashSize; ++i)
00163 {
00164 if(!chunks[i]) continue;
00165 delete chunks[i];
00166 chunks[i] = 0;
00167 }
00168 refs.clear();
00169 unused.clear();
00170 refs.push_back(pair<RefObjectBase *, unsigned long>(0, 0));
00171 }
00172 }
00173 }