idMan.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 #include "idMan.h"
00021 
00022 #include "IDataSource.h"
00023 #include "ODataSource.h"
00024 
00025 idMan::idMan(uint16 Begin, uint16 MaxEnd, uint16 StartCount)
00026         : begin(Begin), max_end(MaxEnd), startcount(StartCount)
00027 {
00028         // 0 is always reserved, as is 65535
00029         if (begin == 0) begin = 1;
00030         if (max_end == 65535) max_end = 65534;
00031         if (startcount == 0) startcount = max_end - begin + 1;
00032 
00033         end = begin + startcount - 1;
00034         if (end > max_end) end = max_end;
00035 
00036         ids.resize(end+1);
00037         clearAll();
00038 }
00039 
00040 idMan::~idMan()
00041 {
00042 
00043 }
00044 
00045 void idMan::clearAll()
00046 {
00047         end = begin + startcount - 1;
00048         if (end > max_end) end = max_end;
00049         ids.resize(end+1);
00050 
00051         first = begin;
00052         last  = end;
00053         usedcount = 0;
00054 
00055         uint16 i;
00056         for (i = 0; i < first; i++) ids[i] = 0;         // NPCs always used
00057         for (     ; i < last;  i++) ids[i] = i+1;       // Free IDs
00058         ids[last] = 0;                                                          // Terminates the list
00059 
00060 }
00061 
00062 uint16 idMan::getNewID()
00063 {
00064         // more than 75% used and room to expand?
00065         if (usedcount * 4 > (end - begin + 1) * 3 && end < max_end)
00066         {
00067                 expand();
00068         }
00069 
00070         // Uh oh, what to do when there is none
00071         if (!first) 
00072         {
00073                 perr << "Unable to allocate id" << std::endl;
00074                 return 0;
00075         }
00076 
00077         // Get the next id
00078         uint16 id = first;
00079 
00080         // Set the first in the list to next
00081         first = ids[id];
00082 
00083         // Set us to used
00084         ids[id] = 0;
00085 
00086         // If there is no first, there is no list, cause there's none left
00087         // So clear the last pointer
00088         if (!first) last = 0;
00089 
00090         usedcount++;
00091 
00092         return id;
00093 
00094 }
00095 
00096 void idMan::expand()
00097 {
00098         if (end == max_end) return;
00099 
00100         uint16 old_end = end;
00101         unsigned int new_end = end * 2;
00102         if (new_end > max_end) new_end = max_end;
00103         end = new_end;
00104         ids.resize(end+1);
00105 
00106 #if 0
00107         perr << "Expanding idMan from (" << begin << "-" << old_end << ") to ("
00108                  << begin << "-" << end << ")" << std::endl;
00109 #endif
00110         
00111         // insert the new free IDs at the start
00112         for (uint16 i = old_end + 1; i < end; ++i) {
00113                 ids[i] = i+1;
00114         }
00115         ids[end] = first;
00116         first = old_end + 1;
00117 }
00118 
00119 bool idMan::reserveID(uint16 id)
00120 {
00121         if (id < begin || id > max_end) {
00122                 return false;
00123         }
00124 
00125         // expand until we're big enough to reserve this ID
00126         while (id > end) {
00127                 expand();
00128         }
00129 
00130         if (isIDUsed(id))
00131                 return false; // already used
00132 
00133         usedcount++;
00134         // more than 75% used and room to expand?
00135         if (usedcount * 4 > (end - begin + 1) * 3 && end < max_end)
00136         {
00137                 expand();
00138         }
00139 
00140         if (id == first) {
00141                 first = ids[id];
00142                 ids[id] = 0;
00143                 if (!first) last = 0;
00144                 return true;
00145         }
00146 
00147         uint16 node = ids[first];
00148         uint16 prev = first;
00149 
00150         while (node != id && node != 0) {
00151                 prev = node;
00152                 node = ids[node];
00153         }
00154         assert(node != 0); // list corrupt...
00155 
00156         ids[prev] = ids[node];
00157         ids[node] = 0;
00158         if (last == node)
00159                 last = prev;
00160         return true;
00161 }
00162 
00163 void idMan::clearID(uint16 id)
00164 {
00165         // Only clear IF it is used. We don't want to screw up the linked list
00166         // if an id gets cleared twice
00167         if (isIDUsed(id))
00168         {
00169                 // If there is a last, then set the last's next to us
00170                 // or if there isn't a last, obviously no list exists,
00171                 // so set the first to us
00172                 if (last) ids[last] = id;
00173                 else first = id;
00174 
00175                 // Set the end to us
00176                 last = id;
00177 
00178                 // Set our next to terminate
00179                 ids[id] = 0;
00180 
00181                 usedcount--;
00182         }
00183 
00184         // double-check we didn't break the list
00185         assert(!first || last);
00186 }
00187 
00188 void idMan::save(ODataSource* ods)
00189 {
00190         ods->write2(begin);
00191         ods->write2(end);
00192         ods->write2(max_end);
00193         ods->write2(startcount);
00194         ods->write2(usedcount);
00195         uint16 cur = first;
00196         while (cur) {
00197                 ods->write2(cur);
00198                 cur = ids[cur];
00199         }
00200         ods->write2(0); // terminator
00201 }
00202 
00203 bool idMan::load(IDataSource* ds, uint32 version)
00204 {
00205         begin = ds->read2();
00206         end = ds->read2();
00207         max_end = ds->read2();
00208         startcount = ds->read2();
00209         uint16 realusedcount = ds->read2();
00210 
00211         ids.resize(end+1);
00212 
00213         for (unsigned int i = 0; i <= end; ++i) {
00214                 ids[i] = 0;
00215         }
00216         first = last = 0;
00217 
00218         uint16 cur = ds->read2();
00219         while (cur) {
00220                 clearID(cur);
00221                 cur = ds->read2();
00222         }
00223 
00224         usedcount = realusedcount;
00225 
00226         return true;
00227 }

Generated on Fri Jul 27 22:27:19 2007 for pentagram by  doxygen 1.4.7