#include "TExMap.h"
#include "TError.h"
#include "TMathBase.h"
#include <string.h>
ClassImp(TExMap)
TExMap::TExMap(Int_t mapSize)
{
if (mapSize < 4) mapSize = 5;
switch (mapSize) {
case 5: fSize = 5; break;
case 503: fSize = 503; break;
default:
fSize = (Int_t)TMath::NextPrime(mapSize);
}
fTable = new Assoc_t [fSize];
memset(fTable,0,sizeof(Assoc_t)*fSize);
fTally = 0;
}
TExMap::TExMap(const TExMap &map) : TObject(map)
{
fSize = map.fSize;
fTally = map.fTally;
fTable = new Assoc_t [fSize];
memcpy(fTable, map.fTable, fSize*sizeof(Assoc_t));
}
TExMap& TExMap::operator=(const TExMap &map)
{
if (this != &map) {
TObject::operator=(map);
fSize = map.fSize;
fTally = map.fTally;
fTable = new Assoc_t [fSize];
memcpy(fTable, map.fTable, fSize*sizeof(Assoc_t));
}
return *this;
}
TExMap::~TExMap()
{
delete [] fTable; fTable = 0;
}
void TExMap::Add(ULong_t hash, Long_t key, Long_t value)
{
if (!fTable) return;
Int_t slot = FindElement(hash, key);
if (!fTable[slot].InUse()) {
fTable[slot].SetHash(hash);
fTable[slot].fKey = key;
fTable[slot].fValue = value;
fTally++;
if (HighWaterMark())
Expand(2 * fSize);
} else
Error("Add", "key %ld is not unique", key);
}
void TExMap::AddAt(UInt_t slot, ULong_t hash, Long_t key, Long_t value)
{
if (!fTable) return;
if (!fTable[slot].InUse()) {
fTable[slot].SetHash(hash);
fTable[slot].fKey = key;
fTable[slot].fValue = value;
fTally++;
if (HighWaterMark())
Expand(2 * fSize);
} else {
Add(hash,key,value);
}
}
Long_t &TExMap::operator()(ULong_t hash, Long_t key)
{
static Long_t err;
if (!fTable) {
Error("operator()", "fTable==0, should never happen");
return err;
}
Int_t slot = FindElement(hash, key);
if (!fTable[slot].InUse()) {
fTable[slot].SetHash(hash);
fTable[slot].fKey = key;
fTable[slot].fValue = 0;
fTally++;
if (HighWaterMark()) {
Expand(2 * fSize);
slot = FindElement(hash, key);
}
}
return fTable[slot].fValue;
}
void TExMap::Delete(Option_t *)
{
memset(fTable,0,sizeof(Assoc_t)*fSize);
fTally = 0;
}
Long_t TExMap::GetValue(ULong_t hash, Long_t key)
{
if (!fTable) return 0;
hash |= 0x1;
Int_t slot = Int_t(hash % fSize);
Int_t firstSlot = slot;
do {
if (!fTable[slot].InUse()) return 0;
if (key == fTable[slot].fKey) return fTable[slot].fValue;
if (++slot == fSize) slot = 0;
} while (firstSlot != slot);
Error("GetValue", "table full");
return 0;
}
Long_t TExMap::GetValue(ULong_t hash, Long_t key, UInt_t &slot)
{
if (!fTable) { slot = 0; return 0; }
hash |= 0x1;
slot = Int_t(hash % fSize);
UInt_t firstSlot = slot;
do {
if (!fTable[slot].InUse()) return 0;
if (key == fTable[slot].fKey) return fTable[slot].fValue;
if (++slot == (UInt_t)fSize) slot = 0;
} while (firstSlot != slot);
Error("GetValue", "table full");
return 0;
}
void TExMap::Remove(ULong_t hash, Long_t key)
{
if (!fTable)
return;
Int_t i = FindElement(hash, key);
if (!fTable[i].InUse()) {
Error("Remove", "key %ld not found at %d", key, i);
return;
}
fTable[i].Clear();
FixCollisions(i);
fTally--;
}
Int_t TExMap::FindElement(ULong_t hash, Long_t key)
{
if (!fTable) return 0;
hash |= 0x1;
Int_t slot = Int_t(hash % fSize);
Int_t firstSlot = slot;
do {
if (!fTable[slot].InUse()) return slot;
if (key == fTable[slot].fKey) return slot;
if (++slot == fSize) slot = 0;
} while (firstSlot != slot);
Error("FindElement", "table full");
return 0;
}
void TExMap::FixCollisions(Int_t index)
{
Int_t oldIndex, nextIndex;
Assoc_t nextObject;
for (oldIndex = index+1; ;oldIndex++) {
if (oldIndex >= fSize)
oldIndex = 0;
nextObject = fTable[oldIndex];
if (!nextObject.InUse())
break;
nextIndex = FindElement(nextObject.GetHash(), nextObject.fKey);
if (nextIndex != oldIndex) {
fTable[nextIndex] = nextObject;
fTable[oldIndex].Clear();
}
}
}
void TExMap::Expand(Int_t newSize)
{
Int_t i;
Assoc_t *oldTable = fTable;
Int_t oldsize = fSize;
newSize = (Int_t)TMath::NextPrime(newSize);
fTable = new Assoc_t [newSize];
for (i = newSize; --i >= 0;) {
fTable[i].Clear();
}
fSize = newSize;
for (i = 0; i < oldsize; i++)
if (oldTable[i].InUse()) {
Int_t slot = FindElement(oldTable[i].GetHash(), oldTable[i].fKey);
if (!fTable[slot].InUse())
fTable[slot] = oldTable[i];
else
Error("Expand", "slot %d not empty (should never happen)", slot);
}
delete [] oldTable;
}
void TExMap::Streamer(TBuffer &b)
{
Int_t i;
UInt_t R__s, R__c;
if (b.IsReading()) {
Version_t R__v = b.ReadVersion(&R__s, &R__c);
TObject::Streamer(b);
if (R__v >= 2) {
Int_t size, tally;
b >> size;
Expand(size);
b >> tally;
Int_t slot;
ULong_t hash;
Long_t key,value;
for (i = 0; i < tally; ++i) {
b >> slot;
b >> hash;
b >> key;
b >> value;
Assoc_t* assoc = fTable + slot;
assoc->SetHash(hash);
assoc->fKey = key;
assoc->fValue = value;
}
fTally = tally;
} else {
Int_t n;
b >> n;
ULong_t hash;
Long_t key,value;
for (i = 0; i < n; i++) {
b >> hash;
b >> key;
b >> value;
Add(hash,key,value);
}
}
b.CheckByteCount(R__s, R__c,TExMap::IsA());
} else {
R__c = b.WriteVersion(TExMap::IsA(), kTRUE);
TObject::Streamer(b);
b << fSize;
b << fTally;
for (i=0;i<fSize;i++) {
if (!fTable[i].InUse()) continue;
b << i;
b << fTable[i].GetHash();
b << fTable[i].fKey;
b << fTable[i].fValue;
}
b.SetByteCount(R__c, kTRUE);
}
}
ClassImp(TExMapIter)
TExMapIter::TExMapIter(const TExMap *map) : fMap(map), fCursor(0)
{
}
TExMapIter &TExMapIter::operator=(const TExMapIter &rhs)
{
if (this != &rhs) {
fMap = rhs.fMap;
fCursor = rhs.fCursor;
}
return *this;
}
Bool_t TExMapIter::Next(ULong_t &hash, Long_t &key, Long_t &value)
{
while (fCursor < fMap->fSize && !fMap->fTable[fCursor].InUse())
fCursor++;
if (fCursor == fMap->fSize)
return kFALSE;
hash = fMap->fTable[fCursor].GetHash();
key = fMap->fTable[fCursor].fKey;
value = fMap->fTable[fCursor].fValue;
fCursor++;
return kTRUE;
}
Bool_t TExMapIter::Next(Long_t &key, Long_t &value)
{
ULong_t hash;
return Next(hash, key, value);
}