ref.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
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       // Add null as the first entry to correspond with the null
00032       // index.
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 }

Generated on Sun Jul 30 22:55:45 2006 for Archon by  doxygen 1.4.4