libStatGen Software  1
LongHash.h
00001 /*
00002  *  Copyright (C) 2010  Regents of the University of Michigan
00003  *
00004  *   This program is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (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, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #ifndef __LONGHASH_H__
00019 #define __LONGHASH_H__
00020 
00021 #include "Error.h"
00022 
00023 #include <limits.h>
00024 
00025 #ifdef   UINT_MAX
00026 #define  LH_NOTFOUND     (UINT_MAX)
00027 #else
00028 #define  LH_NOTFOUND     0xFFFFFFFF
00029 #endif
00030 
00031 template <class ObjectT> class LongHash
00032 {
00033 protected:
00034     ObjectT        * objects;
00035     long long      * keys;
00036     bool           * occupancy;
00037     unsigned int     count, size;
00038     unsigned int     mask;
00039     bool             allowDuplicates;
00040 
00041 public:
00042     LongHash(int startsize = 32)
00043     {
00044         count = 0;
00045         size  = startsize;
00046         mask  = startsize - 1;
00047 
00048         // In this implementation, the size of hash tables must be a power of two
00049         if (startsize & mask)
00050             error("LongHash: Hash table size must be a power of two.\n");
00051 
00052         occupancy = new bool [size];
00053         objects = new ObjectT [size];
00054         keys    = new long long [size];
00055 
00056         allowDuplicates = false;
00057 
00058         for (unsigned int i = 0; i < size; i++)
00059         {
00060             occupancy[i] = false;
00061         }
00062     };
00063 
00064     ~LongHash()
00065     {
00066         delete [] occupancy;
00067         delete [] objects;
00068         delete [] keys;
00069     }
00070 
00071     void Grow()
00072     {
00073         SetSize(size * 2);
00074     }
00075     void Shrink()
00076     {
00077         SetSize(size / 2);
00078     }
00079 
00080     void SetSize(int newsize)
00081     {
00082         int newmask = newsize - 1;
00083 
00084         bool      * newoccupancy = new bool [newsize];
00085         ObjectT   * newobjects = new ObjectT [newsize];
00086         long long * newkeys = new long long [newsize];
00087 
00088         for (int i = 0; i < newsize; i++)
00089             newoccupancy[i] = false;
00090 
00091         if (count)
00092             for (unsigned int i = 0; i < size; i++)
00093                 if (occupancy[i] != false)
00094                 {
00095                     long long  key = keys[i];
00096                     unsigned int h = newmask & (unsigned int) key;
00097 
00098                     while (newoccupancy[h] == true && (newkeys[h] != key || allowDuplicates))
00099                         h = (h + 1) & newmask;
00100 
00101                     if (newoccupancy[h])
00102                         count--;
00103 
00104                     newkeys[h] = key;
00105                     newobjects[h] = objects[i];
00106                     newoccupancy[h] = true;
00107                 }
00108 
00109         delete [] occupancy;
00110         delete [] objects;
00111         delete [] keys;
00112 
00113         occupancy = newoccupancy;
00114         objects = newobjects;
00115         keys = newkeys;
00116         size = newsize;
00117         mask = newmask;
00118     }
00119 
00120     void Clear()
00121     {
00122         count = 0;
00123 
00124         if (size > 32)
00125             SetSize(32);
00126 
00127         for (unsigned int i = 0; i < size; i++)
00128             occupancy[i] = false;
00129     }
00130 
00131     int  Capacity() const
00132     {
00133         return size;
00134     }
00135     int  Entries() const
00136     {
00137         return count;
00138     }
00139 
00140     ObjectT Object(int i) const
00141     {
00142         return objects[i];
00143     }
00144     ObjectT & Object(int i)
00145     {
00146         return objects[i];
00147     }
00148 
00149     void SetObject(int i, ObjectT object)
00150     {
00151         objects[i] = object;
00152     }
00153 
00154     unsigned int Add(long long key, ObjectT object)
00155     {
00156         if (count * 2 > size)
00157             Grow();
00158 
00159         unsigned int h = Iterate(key);
00160 
00161         while (allowDuplicates && occupancy[h] && objects[h] != object)
00162             h = ReIterate(key, h);
00163 
00164         if (!occupancy[h])
00165         {
00166             occupancy[h] = true;
00167             keys[h] = key;
00168             count++;
00169         }
00170 
00171         objects[h] = object;
00172 
00173         return h;
00174     }
00175 
00176     unsigned int Find(long long key)
00177     {
00178         unsigned int h = Iterate(key);
00179 
00180         return occupancy[h] ? h : LH_NOTFOUND;
00181     }
00182 
00183     unsigned int Rehash(long long key, unsigned int h)
00184     {
00185         h = ReIterate(key, h);
00186 
00187         return occupancy[h] ? h : LH_NOTFOUND;
00188     }
00189 
00190     LongHash & operator = (const LongHash & rhs);
00191 
00192     ObjectT operator [](int i) const
00193     {
00194         return objects[i];
00195     }
00196     ObjectT operator [](unsigned int i) const
00197     {
00198         return objects[i];
00199     }
00200 
00201     void Delete(unsigned int index)
00202     {
00203         if (index >= size || !occupancy[index])
00204             return;
00205 
00206         occupancy[index] = false;
00207         count--;
00208 
00209         if (count * 8 < size && size > 32)
00210             Shrink();
00211         else
00212         {
00213             // rehash the next entries until we find empty slot
00214             index = (index + 1) & mask;
00215 
00216             while (occupancy[index])
00217             {
00218                 if ((keys[index] & mask) != index)
00219                 {
00220                     unsigned int h = Iterate(keys[index]);
00221 
00222                     while (occupancy[h] && objects[h] != objects[index])
00223                         h = ReIterate(keys[index], h);
00224 
00225                     if (h != (unsigned int) index)
00226                     {
00227                         keys[h] = keys[index];
00228                         occupancy[h] = true;
00229                         objects[h] = objects[index];
00230 
00231                         occupancy[index] = false;
00232                     }
00233                 }
00234 
00235                 index = (index + 1) & mask;
00236             }
00237         }
00238     }
00239 
00240 
00241     bool SlotInUse(int index) const
00242     {
00243         return occupancy[index] == true;
00244     }
00245     bool SlotInUse(unsigned int index) const
00246     {
00247         return occupancy[index] == true;
00248     }
00249 
00250     // Accessor to get a key.
00251     long long GetKey(int index) const
00252     {
00253         return keys[index];
00254     }
00255 
00256     long long GetKey(const unsigned int index) const
00257     {
00258         return keys[index];
00259     }
00260 
00261     void SetAllowDuplicateKeys(bool toggle)
00262     {
00263         allowDuplicates = toggle;
00264 
00265         if (count && !allowDuplicates)
00266             SetSize(size);
00267     }
00268 
00269 private:
00270     unsigned int Iterate(long long key) const
00271     {
00272         unsigned int h = mask & (unsigned int) key;
00273 
00274         while (occupancy[h] == true && keys[h] != key)
00275             h = (h + 1) & mask;
00276 
00277         return h;
00278     }
00279 
00280     unsigned int ReIterate(long long key, unsigned int h) const
00281     {
00282         h = (h + 1) & mask;
00283 
00284         while (occupancy[h] == true && keys[h] != key)
00285             h = (h + 1) & mask;
00286 
00287         return h;
00288     }
00289 };
00290 
00291 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends