ultimatepp/uppsrc/Core/Hash.cpp
cxl 03a012161c .Cosmetics
git-svn-id: svn://ultimatepp.org/upp/trunk@5258 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2012-08-05 10:27:14 +00:00

369 lines
6 KiB
C++

#include <Core/Core.h>
NAMESPACE_UPP
#ifdef _MSC_VER
#pragma inline_depth(255)
#pragma optimize("t", on)
#endif
unsigned Pow2Bound(unsigned i)
{
unsigned n = 1;
while(n < i) {
n <<= 1;
if(n == 0)
return 1 << 31;
}
return n;
}
unsigned PrimeBound(unsigned n)
{
static unsigned prime_tab[] = {
17, 29, 61, 127, 257, 509, 1021, 2053, 4093, 8191, 16381,
32771, 65537, 131071, 262147, 524287, 1048573, 2097143,
4194301, 8388617, 16777213, 33554467, 67108859, 134217757,
268435459, 536870909, 1073741827, 2147483647u, 4294967291u
};
return *FindUpperBoundIter(prime_tab, prime_tab + __countof(prime_tab), n);
}
#ifdef FOLDHASH
inline unsigned HashBound(unsigned i) { return Pow2Bound(i); }
#else
inline unsigned HashBound(unsigned i) { return PrimeBound(i); }
#endif
void HashBase::Free()
{
if(map)
delete [](byte *)map;
map = NULL;
mcount = 0;
}
void HashBase::ClearIndex()
{
link.Clear();
unlinked = -1;
Free();
}
HashBase::HashBase()
{
unlinked = -1;
map = NULL;
mcount = 0;
}
HashBase::HashBase(pick_ HashBase& b)
: hash(b.hash),
link(b.link)
{
map = b.map;
mcount = b.mcount;
unlinked = b.unlinked;
const_cast<HashBase &>(b).map = NULL;
}
void HashBase::operator=(pick_ HashBase& b)
{
hash = b.hash;
link = b.link;
Free();
map = b.map;
mcount = b.mcount;
unlinked = b.unlinked;
const_cast<HashBase &>(b).map = NULL;
}
HashBase::HashBase(const HashBase& b, int)
: hash(b.hash, 0)
{
unlinked = -1;
mcount = 0;
map = NULL;
Reindex();
}
void HashBase::operator<<=(const HashBase& b)
{
ClearIndex();
hash <<= b.hash;
Reindex();
}
HashBase::~HashBase()
{
Free();
}
force_inline void HashBase::LinkBefore(int i, Link& l, int bi)
{
Link& bl = link[bi];
l.next = bi;
l.prev = bl.prev;
bl.prev = i;
link[l.prev].next = i;
}
void HashBase::Trim(int count)
{
ASSERT(count <= hash.GetCount() && count >= 0);
for(int i = count; i < link.GetCount(); i++)
Unlink(i, link[i]);
link.Trim(count);
hash.SetCount(count);
}
void HashBase::Drop(int n)
{
Trim(hash.GetCount() - n);
}
void HashBase::FinishIndex()
{
int q = link.GetCount();
link.Reserve(hash.GetAlloc());
link.AddN(hash.GetCount() - q);
for(int i = q; i < hash.GetCount(); i++)
LinkTo(i, link[i], hash[i] & UNSIGNED_HIBIT ? unlinked : Mapi(i));
}
void HashBase::Reindex(int n)
{
ClearIndex();
Free();
mcount = n = HashBound(n);
map = (int *)new byte[n * sizeof(int)];
Fill(map, map + n, -1);
FinishIndex();
}
void HashBase::Reindex()
{
Reindex(hash.GetCount());
}
void HashBase::Add(unsigned _hash)
{
hash.Add(_hash & ~UNSIGNED_HIBIT);
DoIndex();
}
void HashBase::SetUn(int i, unsigned _hash)
{
if(map) {
Link& lnk = link[i];
Unlink(i, lnk);
LinkTo(i, lnk, Maph(_hash & ~UNSIGNED_HIBIT));
}
hash[i] = _hash & ~UNSIGNED_HIBIT;
}
Vector<int> HashBase::GetUnlinked() const
{
Vector<int> r;
int q = unlinked;
if(q >= 0) {
do {
r.Add(q);
q = link[q].next;
}
while(q != unlinked);
}
return r;
}
int HashBase::Put(unsigned _hash)
{
if(unlinked < 0) return -1;
Link& l = link[unlinked];
int i = unlinked;
unlinked = link[unlinked].next;
if(i == unlinked)
unlinked = -1;
else {
link[l.next].prev = l.prev;
link[l.prev].next = l.next;
}
LinkTo(i, l, Maph(_hash & ~UNSIGNED_HIBIT));
hash[i] = _hash & ~UNSIGNED_HIBIT;
return i;
}
void HashBase::Set(int i, unsigned _hash) {
if(map) {
Link& lnk = link[i];
Unlink(i, lnk);
int& mi = Maph(_hash & ~UNSIGNED_HIBIT);
int ii = mi;
if(ii < 0)
mi = lnk.prev = lnk.next = i;
else
if(i < ii) {
LinkBefore(i, lnk, ii);
mi = i;
}
else {
int l = ii;
int h = link[ii].prev;
if(h - i < i - l) {
while(i < h) {
h = link[h].prev;
}
LinkBefore(i, lnk, link[h].next);
}
else {
l = link[l].next;
while(i > l && l != ii) {
l = link[l].next;
}
LinkBefore(i, lnk, l);
}
}
}
hash[i] = _hash & ~UNSIGNED_HIBIT;
}
void HashBase::Shrink() {
hash.Shrink();
if((int)HashBound(hash.GetCount()) < mcount) {
ClearIndex();
DoIndex();
}
else
link.Shrink();
}
void HashBase::Reserve(int n)
{
hash.Reserve(n);
link.Reserve(n);
if((int)HashBound(n) > mcount)
Reindex(n);
}
void HashBase::Remove(int i)
{
hash.Remove(i);
ClearIndex();
Reindex();
}
void HashBase::Remove(int i, int count)
{
hash.Remove(i, count);
ClearIndex();
Reindex();
}
void HashBase::Remove(const int *sorted_list, int count)
{
hash.Remove(sorted_list, count);
ClearIndex();
Reindex();
}
void HashBase::Insert(int i, unsigned _hash) {
hash.Insert(i, _hash & ~UNSIGNED_HIBIT);
ClearIndex();
Reindex();
}
#ifdef UPP
void HashBase::Serialize(Stream& s) {
int version = 0;
s / version;
if(s.IsLoading())
ClearIndex();
hash.Serialize(s);
Reindex();
}
#endif
void HashBase::Swap(HashBase& b) {
UPP::Swap(hash, b.hash);
UPP::Swap(link, b.link);
UPP::Swap(map, b.map);
UPP::Swap(mcount, b.mcount);
UPP::Swap(unlinked, b.unlinked);
}
#ifdef CPU_X86
unsigned memhash(const void *ptr, size_t count)
{
unsigned hash = 1234567890U;
const unsigned *ds = (unsigned *)ptr;
const unsigned *de = ds + (count >> 2);
while(ds < de)
hash = ((hash << 5) - hash) ^ *ds++;
const byte *s = (byte *)ds;
const byte *e = s + (count & 3);
while(s < e)
hash = ((hash << 5) - hash) ^ *s++;
return hash;
}
#else
unsigned memhash(const void *ptr, size_t count)
{
unsigned hash = 1234567890U;
const byte *s = (byte *)ptr;
const byte *e = s + count;
while(s < e)
hash = ((hash << 5) - hash) ^ *s++;
return hash;
}
#endif
unsigned GetHashValue0(const double& d)
{
return memhash(&d, sizeof(double));
}
void Bits::Clear()
{
if(bp && alloc >= 0)
delete[] bp;
alloc = 0;
bp = NULL;
}
void Bits::Set(int i, bool b)
{
ASSERT(i >= 0 && alloc >= 0);
int q = i >> 5;
if(q >= alloc) {
int nalloc = 2 * q + 1;
dword *nbp = new dword[nalloc];
if(bp) {
Copy(nbp, bp, bp + alloc);
delete[] bp;
}
Fill(nbp + alloc, nbp + nalloc, (dword)0);
bp = nbp;
alloc = nalloc;
}
i &= 31;
ASSERT(q < alloc);
bp[q] = (bp[q] & ~(1 << i)) | (b << i);
}
void Bits::Set(int i, bool b, int count)
{ //! Optimize !!!
while(count--)
Set(i++, b);
}
END_UPP_NAMESPACE