Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

IntIntTblLR.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Thu Apr 28 23:39:45 EDT 2005 by ken@xorian.net        
00020 //      modified on Sun Jul 28 12:03:20 EDT 2002 by lken@remote.xorian.net
00021 //      modified on Fri Feb 27 18:44:51 PST 1998 by heydon
00022 
00023 #include <Basics.H>
00024 #include <FS.H>
00025 #include <VestaLog.H>
00026 #include <Recovery.H>
00027 
00028 #include "IntIntTblLR.H"
00029 
00030 using std::istream;
00031 using std::ostream;
00032 using std::endl;
00033 
00034 // the value of unused entries in the table
00035 static const short Unused = -1;
00036 
00037 IntIntTblLR::IntIntTblLR(int sizeHint) throw ()
00038 : numEntries(0), eltLen(sizeHint)
00039 {
00040     if (sizeHint > 0) {
00041       this->elt = NEW_PTRFREE_ARRAY(short, sizeHint);
00042       for (int i = 0; i < this->eltLen; i++) {
00043         this->elt[i] = Unused;
00044       }
00045     } else {
00046         assert(sizeHint == 0);
00047         this->elt = (short *)NULL;
00048     }
00049 }
00050 
00051 IntIntTblLR::IntIntTblLR(const IntIntTblLR *tbl) throw ()
00052 : numEntries(tbl->numEntries), eltLen(tbl->eltLen)
00053 {
00054     if (this->eltLen > 0) {
00055       this->elt = NEW_PTRFREE_ARRAY(short, this->eltLen);
00056       int numUsed = 0;
00057       for (int i = 0; i < this->eltLen; i++) {
00058         this->elt[i] = tbl->elt[i];
00059         if (tbl->elt[i] != Unused) numUsed++;
00060       }
00061       assert(numUsed == this->numEntries);
00062     } else {
00063         assert(this->eltLen == 0 && this->numEntries == 0);
00064         this->elt = (short *)NULL;
00065     }
00066 }
00067 
00068 bool IntIntTblLR::Get(short k, /*OUT*/ short& v) const throw ()
00069 {
00070     bool res;
00071     if (k < this->eltLen && this->elt != (short *)NULL) {
00072         short val = this->elt[k];
00073         res = (val != Unused);
00074         if (res) v = val;
00075     } else {
00076         res = false;
00077     }
00078     return res;
00079 }
00080 
00081 bool IntIntTblLR::Put(short k, short v) throw ()
00082 {
00083     bool res;
00084 
00085     if (k < this->eltLen && this->elt != (short *)NULL) {
00086         // fast path: simply test if the slot is in use
00087         res = (this->elt[k] != Unused);
00088         if (!res) this->numEntries++;
00089     } else {
00090         // slow path: the array of elements must be extended or allocated
00091         int oldEltLen = this->eltLen;
00092         this->eltLen = max(k+1, oldEltLen+10);
00093         short *newElt = NEW_PTRFREE_ARRAY(short, this->eltLen);
00094         if (this->elt != (short *)NULL) {
00095             // copy old elts to new array; make remaining elts unused
00096             int i;
00097             for (i = 0; i < oldEltLen; i++) {
00098                 newElt[i] = this->elt[i];
00099             }
00100             for (/*SKIP*/; i < this->eltLen; i++) {
00101                 newElt[i] = Unused;
00102             }
00103         } else {
00104             // initialize the array to entirely unused elts
00105             for (int i = 0; i < this->eltLen; i++) {
00106                 newElt[i] = Unused;
00107             }
00108         }
00109         this->elt = newElt;
00110         this->numEntries++;
00111         res = false;
00112     }
00113     this->elt[k] = v;
00114     return res;
00115 }
00116 
00117 bool IntIntTblLR::Delete(short k, /*OUT*/ short& v) throw ()
00118 {
00119     bool res;
00120     if (k < this->eltLen && this->elt != (short *)NULL
00121         && this->elt[k] != Unused) {
00122         v = this->elt[k];
00123         this->elt[k] = Unused;
00124         this->numEntries--;
00125         res = true;
00126     } else {
00127         res = false;
00128     }
00129     return res;
00130 }
00131 
00132 void IntIntTblLR::Log(VestaLog& log) const
00133   throw (VestaLog::Error)
00134 {
00135     log.write((char *)(&(this->numEntries)), sizeof(this->numEntries));
00136     log.write((char *)(&(this->eltLen)), sizeof(this->eltLen));
00137     if (this->numEntries > 0) {
00138         int numWritten = 0;
00139         for (short k = 0; k < this->eltLen; k++) {
00140             if (this->elt[k] != Unused) {
00141                 log.write((char *)(&k), sizeof(k));
00142                 log.write((char *)(&(this->elt[k])), sizeof(this->elt[k]));
00143                 numWritten++;
00144             }
00145         }
00146         assert(numWritten == this->numEntries);
00147     }
00148 }
00149 
00150 void IntIntTblLR::Recover(RecoveryReader &rd)
00151   throw (VestaLog::Error, VestaLog::Eof)
00152 /* We must set any unused entries to "Unused". We could do this by setting all
00153    entries to "Unused" immediately after the array is allocated. But if the
00154    array is mostly full, that would mean writing most entries twice. Instead,
00155    we set entries to "Unused" between the used entries, and at the end of the
00156    loop. The correctness of this algorithm relies on the fact that the entries
00157    are written by the corresponding "Log" method in order of increasing key.
00158 */
00159 {
00160     rd.readAll((char *)(&(this->numEntries)), sizeof(this->numEntries));
00161     rd.readAll((char *)(&(this->eltLen)), sizeof(this->eltLen));
00162     if (this->numEntries > 0) {
00163         short nextToWrite = 0;
00164         this->elt = NEW_PTRFREE_ARRAY(short, this->eltLen);
00165         // Invariant: All elements of "this->elt" in the half-open
00166         // interval "[0, nextToWrite)" have been written.
00167         for (int i = 0; i < this->numEntries; i++) {
00168             short k;
00169             rd.readAll((char *)(&k), sizeof(k));
00170             // make intervening entries unused
00171             assert(k >= nextToWrite);
00172             while (nextToWrite < k) {
00173                 this->elt[nextToWrite++] = Unused;
00174             }
00175             assert(k < this->eltLen);
00176             rd.readAll((char *)(&(this->elt[k])), sizeof(this->elt[k]));
00177             nextToWrite++; // == k+1
00178         }
00179         // make any remaining entries unused
00180         while (nextToWrite < this->eltLen) {
00181             this->elt[nextToWrite++] = Unused;
00182         }
00183     } else {
00184         this->elt = (short *)NULL;
00185     }
00186 }
00187 
00188 void IntIntTblLR::Write(ostream &ofs) const
00189   throw (FS::Failure)
00190 {
00191     FS::Write(ofs, (char *)(&(this->numEntries)), sizeof(this->numEntries));
00192     FS::Write(ofs, (char *)(&(this->eltLen)), sizeof(this->eltLen));
00193     if (this->numEntries > 0) {
00194         int numWritten = 0;
00195         for (short k = 0; k < this->eltLen; k++) {
00196             if (this->elt[k] != Unused) {
00197                 FS::Write(ofs, (char *)(&k), sizeof(k));
00198                 FS::Write(ofs, (char *)(&(this->elt[k])), sizeof(this->elt[k]));
00199                 numWritten++;
00200             }
00201         }
00202         assert(numWritten == this->numEntries);
00203     }
00204 }
00205 
00206 void IntIntTblLR::Read(istream &ifs)
00207   throw (FS::EndOfFile, FS::Failure)
00208 /* We must set any unused entries to "Unused". We could do this by setting all
00209    entries to "Unused" immediately after the array is allocated. But if the
00210    array is mostly full, that would mean writing most entries twice. Instead,
00211    we set entries to "Unused" between the used entries, and at the end of the
00212    loop. The correctness of this algorithm relies on the fact that the entries
00213    are written by the corresponding "Write" method in order of increasing key.
00214 */
00215 {
00216     FS::Read(ifs, (char *)(&(this->numEntries)), sizeof(this->numEntries));
00217     FS::Read(ifs, (char *)(&(this->eltLen)), sizeof(this->eltLen));
00218     if (this->numEntries > 0) {
00219         short nextToWrite = 0;
00220         this->elt = NEW_PTRFREE_ARRAY(short, this->eltLen);
00221         // Invariant: All elements of "this->elt" in the half-open
00222         // interval "[0, nextToWrite)" have been written.
00223         for (int i = 0; i < this->numEntries; i++) {
00224             short k;
00225             FS::Read(ifs, (char *)(&k), sizeof(k));
00226             // make intervening entries unused
00227             assert(k >= nextToWrite);
00228             while (nextToWrite < k) {
00229                 this->elt[nextToWrite++] = Unused;
00230             }
00231             assert(k < this->eltLen);
00232             FS::Read(ifs, (char *)(&(this->elt[k])), sizeof(this->elt[k]));
00233             nextToWrite++; // == k+1
00234         }
00235         // make any remaining entries unused
00236         while (nextToWrite < this->eltLen) {
00237             this->elt[nextToWrite++] = Unused;
00238         }
00239     } else {
00240         this->elt = (short *)NULL;
00241     }
00242 }
00243 
00244 inline void Indent(ostream &os, int indent) throw ()
00245 {
00246     for (int i = 0; i < indent; i++) os << " ";
00247 }
00248 
00249 void IntIntTblLR::Print(ostream &os, int indent) const throw ()
00250 {
00251     const int NumPerLine = 7;
00252     int cnt = 0;
00253     os << "{ ";
00254     for (short k = 0; cnt < this->numEntries; k++) {
00255         short v;
00256         if (this->Get(k, /*OUT*/ v)) {
00257             if (cnt > 0) os << ", ";
00258             if (cnt % NumPerLine == 0) {
00259                 os << endl; Indent(os, indent);
00260             }
00261             os << k << "->" << v;
00262             cnt++;
00263         }
00264     }
00265     os << " }" << endl;
00266 }
00267 
00268 bool IntIntTblIter::Next(/*OUT*/ short& k, /*OUT*/ short& v) throw ()
00269 {
00270     bool res;
00271     assert(!(this->done));
00272     while (this->k < this->tbl->eltLen && this->tbl->elt[this->k] == Unused) {
00273         (this->k)++;
00274     }
00275     if (this->k < this->tbl->eltLen) {
00276         k = this->k;
00277         v = this->tbl->elt[k];
00278         (this->k)++;
00279         res = true;
00280     } else {
00281         this->done = true;
00282         res = false;
00283     }
00284     return res;
00285 }

Generated on Mon May 8 00:48:34 2006 for Vesta by  doxygen 1.4.2