2006-04-12 01:59:08 +02:00
|
|
|
/**
|
|
|
|
* =========================================================================
|
|
|
|
* File : adts.h
|
|
|
|
* Project : 0 A.D.
|
|
|
|
* Description : useful Abstract Data Types not provided by STL.
|
|
|
|
*
|
|
|
|
* @author Jan.Wassenberg@stud.uni-karlsruhe.de
|
|
|
|
* =========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2005 Jan Wassenberg
|
|
|
|
*
|
|
|
|
* Redistribution and/or modification are also permitted under the
|
|
|
|
* terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation (version 2 or later, at your option).
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*/
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
#ifndef ADTS_H__
|
|
|
|
#define ADTS_H__
|
|
|
|
|
2006-06-23 19:41:55 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// dynamic (grow-able) hash table
|
|
|
|
//-----------------------------------------------------------------------------
|
2006-01-23 08:59:20 +01:00
|
|
|
|
|
|
|
template<typename Key, typename T> class DHT_Traits
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static const size_t initial_entries = 16;
|
|
|
|
size_t hash(Key key) const;
|
|
|
|
bool equal(Key k1, Key k2) const;
|
|
|
|
Key get_key(T t) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<> class DHT_Traits<const char*, const char*>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static const size_t initial_entries = 512;
|
|
|
|
size_t hash(const char* key) const
|
|
|
|
{
|
|
|
|
return (size_t)fnv_lc_hash(key);
|
|
|
|
}
|
|
|
|
bool equal(const char* k1, const char* k2) const
|
|
|
|
{
|
|
|
|
return !strcmp(k1, k2);
|
|
|
|
}
|
|
|
|
const char* get_key(const char* t) const
|
|
|
|
{
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// intended for pointer types
|
2006-03-06 04:46:12 +01:00
|
|
|
template<typename Key, typename T, typename Traits=DHT_Traits<Key,T> >
|
|
|
|
class DynHashTbl
|
2006-01-23 08:59:20 +01:00
|
|
|
{
|
|
|
|
T* tbl;
|
|
|
|
u16 num_entries;
|
|
|
|
u16 max_entries; // when initialized, = 2**n for faster modulo
|
|
|
|
Traits tr;
|
|
|
|
|
|
|
|
T& get_slot(Key key) const
|
|
|
|
{
|
|
|
|
size_t hash = tr.hash(key);
|
|
|
|
debug_assert(max_entries != 0); // otherwise, mask will be incorrect
|
|
|
|
const uint mask = max_entries-1;
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
T& t = tbl[hash & mask];
|
|
|
|
// empty slot encountered => not found
|
|
|
|
if(!t)
|
|
|
|
return t;
|
|
|
|
// keys are actually equal => found it
|
|
|
|
if(tr.equal(key, tr.get_key(t)))
|
|
|
|
return t;
|
|
|
|
// keep going (linear probing)
|
|
|
|
hash++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void expand_tbl()
|
|
|
|
{
|
|
|
|
// alloc a new table (but don't assign it to <tbl> unless successful)
|
|
|
|
T* old_tbl = tbl;
|
|
|
|
tbl = (T*)calloc(max_entries*2, sizeof(T));
|
|
|
|
if(!tbl)
|
|
|
|
{
|
|
|
|
tbl = old_tbl;
|
|
|
|
throw std::bad_alloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
max_entries += max_entries;
|
|
|
|
// must be set before get_slot
|
|
|
|
|
|
|
|
// newly initialized, nothing to copy - done
|
|
|
|
if(!old_tbl)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// re-hash from old table into the new one
|
|
|
|
for(size_t i = 0; i < max_entries/2u; i++)
|
|
|
|
{
|
|
|
|
T t = old_tbl[i];
|
|
|
|
if(t)
|
|
|
|
get_slot(tr.get_key(t)) = t;
|
|
|
|
}
|
|
|
|
free(old_tbl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
DynHashTbl()
|
|
|
|
{
|
|
|
|
tbl = 0;
|
|
|
|
num_entries = 0;
|
2006-01-23 11:35:24 +01:00
|
|
|
max_entries = tr.initial_entries/2; // will be doubled in expand_tbl
|
2006-01-23 08:59:20 +01:00
|
|
|
debug_assert(is_pow2(max_entries));
|
|
|
|
expand_tbl();
|
|
|
|
}
|
|
|
|
|
|
|
|
~DynHashTbl()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
{
|
2006-03-16 08:16:24 +01:00
|
|
|
// note: users might call clear() right before the dtor runs,
|
|
|
|
// so safely handling calling this twice.
|
2006-04-10 08:44:54 +02:00
|
|
|
SAFE_FREE(tbl);
|
2006-01-23 08:59:20 +01:00
|
|
|
num_entries = 0;
|
|
|
|
// rationale: must not set to 0 because expand_tbl only doubles the size.
|
|
|
|
// don't keep the previous size because it may have become huge and
|
|
|
|
// there is no provision for shrinking.
|
2006-01-23 11:35:24 +01:00
|
|
|
max_entries = tr.initial_entries/2; // will be doubled in expand_tbl
|
2006-01-23 08:59:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void insert(const Key key, const T t)
|
|
|
|
{
|
|
|
|
// more than 75% full - increase table size.
|
|
|
|
// do so before determining slot; this will invalidate previous pnodes.
|
|
|
|
if(num_entries*4 >= max_entries*3)
|
|
|
|
expand_tbl();
|
|
|
|
|
|
|
|
T& slot = get_slot(key);
|
|
|
|
debug_assert(slot == 0); // not already present
|
|
|
|
slot = t;
|
|
|
|
num_entries++;
|
|
|
|
}
|
|
|
|
|
|
|
|
T find(Key key) const
|
|
|
|
{
|
|
|
|
return get_slot(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const
|
|
|
|
{
|
|
|
|
return num_entries;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
|
|
typedef T value_type;
|
|
|
|
typedef ptrdiff_t difference_type;
|
|
|
|
typedef const T* pointer;
|
|
|
|
typedef const T& reference;
|
|
|
|
|
|
|
|
iterator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
iterator(T* pos_, T* end_) : pos(pos_), end(end_)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
T& operator*() const
|
|
|
|
{
|
|
|
|
return *pos;
|
|
|
|
}
|
|
|
|
iterator& operator++() // pre
|
|
|
|
{
|
|
|
|
do
|
|
|
|
pos++;
|
|
|
|
while(pos != end && *pos == 0);
|
|
|
|
return (*this);
|
|
|
|
}
|
|
|
|
bool operator==(const iterator& rhs) const
|
|
|
|
{
|
|
|
|
return pos == rhs.pos;
|
|
|
|
}
|
|
|
|
bool operator<(const iterator& rhs) const
|
|
|
|
{
|
|
|
|
return (pos < rhs.pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
// derived
|
|
|
|
const T* operator->() const
|
|
|
|
{
|
|
|
|
return &**this;
|
|
|
|
}
|
|
|
|
bool operator!=(const iterator& rhs) const
|
|
|
|
{
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
iterator operator++(int) // post
|
|
|
|
{
|
|
|
|
iterator tmp = *this; ++*this; return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
T* pos;
|
|
|
|
T* end;
|
|
|
|
// only used when incrementing (avoid going beyond end of table)
|
|
|
|
};
|
|
|
|
|
|
|
|
iterator begin() const
|
|
|
|
{
|
|
|
|
T* pos = tbl;
|
|
|
|
while(pos != tbl+max_entries && *pos == 0)
|
|
|
|
pos++;
|
|
|
|
return iterator(pos, tbl+max_entries);
|
|
|
|
}
|
|
|
|
iterator end() const
|
|
|
|
{
|
|
|
|
return iterator(tbl+max_entries, 0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-02-19 19:51:00 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2005-04-10 00:24:08 +02:00
|
|
|
// FIFO bit queue
|
2006-06-23 19:41:55 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2005-04-10 00:24:08 +02:00
|
|
|
|
|
|
|
struct BitBuf
|
2004-05-06 19:14:30 +02:00
|
|
|
{
|
|
|
|
ulong buf;
|
2005-01-23 18:54:20 +01:00
|
|
|
ulong cur; // bit to be appended (toggled by add())
|
|
|
|
ulong len; // |buf| [bits]
|
2004-05-06 19:14:30 +02:00
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
buf = 0;
|
|
|
|
cur = 0;
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
|
2005-01-23 18:54:20 +01:00
|
|
|
// toggle current bit if desired, and add to buffer (new bit is LSB)
|
2004-05-06 19:14:30 +02:00
|
|
|
void add(ulong toggle)
|
|
|
|
{
|
|
|
|
cur ^= toggle;
|
|
|
|
buf <<= 1;
|
|
|
|
buf |= cur;
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
2005-01-23 18:54:20 +01:00
|
|
|
// extract LS n bits
|
2004-05-06 19:14:30 +02:00
|
|
|
uint extract(ulong n)
|
|
|
|
{
|
|
|
|
ulong i = buf & ((1ul << n) - 1);
|
|
|
|
buf >>= n;
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
2004-06-11 04:14:18 +02:00
|
|
|
};
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
|
2006-06-23 19:41:55 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2005-04-10 00:24:08 +02:00
|
|
|
// ring buffer - static array, accessible modulo n
|
2006-06-23 19:41:55 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2005-04-10 00:24:08 +02:00
|
|
|
|
2006-01-23 08:59:20 +01:00
|
|
|
template<class T, size_t n> class RingBuf
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
size_t size_; // # of entries in buffer
|
2006-02-03 05:02:53 +01:00
|
|
|
size_t head; // index of oldest item
|
|
|
|
size_t tail; // index of newest item
|
2004-03-03 00:56:51 +01:00
|
|
|
T data[n];
|
|
|
|
|
2006-01-23 08:59:20 +01:00
|
|
|
public:
|
2006-02-03 05:02:53 +01:00
|
|
|
RingBuf() : data() { clear(); }
|
|
|
|
void clear() { size_ = 0; head = 0; tail = n-1; }
|
2006-01-23 08:59:20 +01:00
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
size_t size() { return size_; }
|
2006-01-23 08:59:20 +01:00
|
|
|
bool empty() { return size_ == 0; }
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-06-14 15:27:33 +02:00
|
|
|
const T& operator[](int ofs) const
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2006-01-23 08:59:20 +01:00
|
|
|
debug_assert(!empty());
|
|
|
|
size_t idx = (size_t)(head + ofs);
|
2004-06-14 15:27:33 +02:00
|
|
|
return data[idx % n];
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
2006-02-03 05:02:53 +01:00
|
|
|
T& operator[](int ofs)
|
|
|
|
{
|
|
|
|
debug_assert(!empty());
|
|
|
|
size_t idx = (size_t)(head + ofs);
|
|
|
|
return data[idx % n];
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2006-01-23 08:59:20 +01:00
|
|
|
T& front()
|
|
|
|
{
|
|
|
|
debug_assert(!empty());
|
|
|
|
return data[head];
|
|
|
|
}
|
|
|
|
const T& front() const
|
|
|
|
{
|
|
|
|
debug_assert(!empty());
|
|
|
|
return data[head];
|
|
|
|
}
|
|
|
|
T& back()
|
|
|
|
{
|
|
|
|
debug_assert(!empty());
|
|
|
|
return data[tail];
|
|
|
|
}
|
|
|
|
const T& back() const
|
|
|
|
{
|
|
|
|
debug_assert(!empty());
|
|
|
|
return data[tail];
|
|
|
|
}
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
void push_back(const T& item)
|
|
|
|
{
|
|
|
|
if(size_ < n)
|
|
|
|
size_++;
|
2006-01-23 08:59:20 +01:00
|
|
|
// do not complain - overwriting old values is legit
|
|
|
|
// (e.g. sliding window).
|
|
|
|
else
|
|
|
|
head = (head + 1) % n;
|
|
|
|
|
|
|
|
tail = (tail + 1) % n;
|
|
|
|
data[tail] = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pop_front()
|
|
|
|
{
|
2006-02-03 05:02:53 +01:00
|
|
|
if(size_ != 0)
|
|
|
|
{
|
2006-01-23 08:59:20 +01:00
|
|
|
size_--;
|
2006-02-03 05:02:53 +01:00
|
|
|
head = (head + 1) % n;
|
|
|
|
}
|
2006-01-23 08:59:20 +01:00
|
|
|
else
|
|
|
|
debug_warn("underflow");
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
2006-01-24 09:16:29 +01:00
|
|
|
class iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef std::random_access_iterator_tag iterator_category;
|
|
|
|
typedef T value_type;
|
|
|
|
typedef ptrdiff_t difference_type;
|
|
|
|
typedef T* pointer;
|
|
|
|
typedef T& reference;
|
|
|
|
|
|
|
|
iterator() : data(0), pos(0)
|
2006-02-03 21:36:15 +01:00
|
|
|
{}
|
2006-01-24 09:16:29 +01:00
|
|
|
iterator(T* data_, size_t pos_) : data(data_), pos(pos_)
|
2006-02-03 21:36:15 +01:00
|
|
|
{}
|
2006-01-24 09:16:29 +01:00
|
|
|
T& operator[](int idx) const
|
2006-02-03 21:36:15 +01:00
|
|
|
{ return data[(pos+idx) % n]; }
|
2006-01-24 09:16:29 +01:00
|
|
|
T& operator*() const
|
2006-02-03 21:36:15 +01:00
|
|
|
{ return data[pos % n]; }
|
2006-01-24 09:16:29 +01:00
|
|
|
T* operator->() const
|
2006-02-03 21:36:15 +01:00
|
|
|
{ return &**this; }
|
2006-01-24 09:16:29 +01:00
|
|
|
iterator& operator++() // pre
|
2006-02-03 21:36:15 +01:00
|
|
|
{ ++pos; return (*this); }
|
2006-01-24 09:16:29 +01:00
|
|
|
iterator operator++(int) // post
|
2006-02-03 21:36:15 +01:00
|
|
|
{ iterator tmp = *this; ++*this; return tmp; }
|
2006-01-24 09:16:29 +01:00
|
|
|
bool operator==(const iterator& rhs) const
|
2006-02-03 21:36:15 +01:00
|
|
|
{ return data == rhs.data && pos == rhs.pos; }
|
2006-01-24 09:16:29 +01:00
|
|
|
bool operator!=(const iterator& rhs) const
|
2006-02-03 21:36:15 +01:00
|
|
|
{ return !(*this == rhs); }
|
2006-01-24 09:16:29 +01:00
|
|
|
bool operator<(const iterator& rhs) const
|
2006-02-03 21:36:15 +01:00
|
|
|
{ return (pos < rhs.pos); }
|
|
|
|
iterator& operator+=(difference_type ofs)
|
|
|
|
{ pos += ofs; return *this; }
|
|
|
|
iterator& operator-=(difference_type ofs)
|
|
|
|
{ return (*this += -ofs); }
|
|
|
|
iterator operator+(difference_type ofs) const
|
|
|
|
{ iterator tmp = *this; return (tmp += ofs); }
|
|
|
|
iterator operator-(difference_type ofs) const
|
|
|
|
{ iterator tmp = *this; return (tmp -= ofs); }
|
|
|
|
difference_type operator-(const iterator right) const
|
|
|
|
{ return (difference_type)(pos - right.pos); }
|
2006-01-24 09:16:29 +01:00
|
|
|
|
|
|
|
protected:
|
|
|
|
T* data;
|
|
|
|
size_t pos;
|
|
|
|
// not mod-N so that begin != end when buffer is full.
|
|
|
|
};
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
class const_iterator
|
|
|
|
{
|
|
|
|
public:
|
2005-02-27 23:11:26 +01:00
|
|
|
typedef std::random_access_iterator_tag iterator_category;
|
|
|
|
typedef T value_type;
|
|
|
|
typedef ptrdiff_t difference_type;
|
|
|
|
typedef const T* pointer;
|
|
|
|
typedef const T& reference;
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
const_iterator() : data(0), pos(0)
|
|
|
|
{}
|
2006-01-24 09:16:29 +01:00
|
|
|
const_iterator(const T* data_, size_t pos_) : data(data_), pos(pos_)
|
2004-05-06 19:14:30 +02:00
|
|
|
{}
|
2004-03-03 00:56:51 +01:00
|
|
|
const T& operator[](int idx) const
|
2004-05-06 19:14:30 +02:00
|
|
|
{ return data[(pos+idx) % n]; }
|
2004-03-03 00:56:51 +01:00
|
|
|
const T& operator*() const
|
2004-06-27 03:42:17 +02:00
|
|
|
{ return data[pos % n]; }
|
2004-03-03 00:56:51 +01:00
|
|
|
const T* operator->() const
|
2004-05-06 19:14:30 +02:00
|
|
|
{ return &**this; }
|
2004-03-03 00:56:51 +01:00
|
|
|
const_iterator& operator++() // pre
|
2004-06-27 03:42:17 +02:00
|
|
|
{ ++pos; return (*this); }
|
2004-03-03 00:56:51 +01:00
|
|
|
const_iterator operator++(int) // post
|
2004-05-06 19:14:30 +02:00
|
|
|
{ const_iterator tmp = *this; ++*this; return tmp; }
|
2004-03-03 00:56:51 +01:00
|
|
|
bool operator==(const const_iterator& rhs) const
|
2004-06-27 03:42:17 +02:00
|
|
|
{ return data == rhs.data && pos == rhs.pos; }
|
2004-03-03 00:56:51 +01:00
|
|
|
bool operator!=(const const_iterator& rhs) const
|
2004-05-06 19:14:30 +02:00
|
|
|
{ return !(*this == rhs); }
|
2005-02-27 23:11:26 +01:00
|
|
|
bool operator<(const const_iterator& rhs) const
|
|
|
|
{ return (pos < rhs.pos); }
|
2006-02-03 21:36:15 +01:00
|
|
|
iterator& operator+=(difference_type ofs)
|
|
|
|
{ pos += ofs; return *this; }
|
|
|
|
iterator& operator-=(difference_type ofs)
|
|
|
|
{ return (*this += -ofs); }
|
|
|
|
iterator operator+(difference_type ofs) const
|
|
|
|
{ iterator tmp = *this; return (tmp += ofs); }
|
|
|
|
iterator operator-(difference_type ofs) const
|
|
|
|
{ iterator tmp = *this; return (tmp -= ofs); }
|
|
|
|
difference_type operator-(const iterator right) const
|
|
|
|
{ return (difference_type)(pos - right.pos); }
|
2005-02-27 23:11:26 +01:00
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
protected:
|
|
|
|
const T* data;
|
|
|
|
size_t pos;
|
2004-06-27 03:42:17 +02:00
|
|
|
// not mod-N so that begin != end when buffer is full.
|
2004-03-03 00:56:51 +01:00
|
|
|
};
|
|
|
|
|
2006-01-24 09:16:29 +01:00
|
|
|
iterator begin()
|
|
|
|
{
|
2006-02-03 05:02:53 +01:00
|
|
|
return iterator(data, (size_ < n)? 0 : head);
|
2006-01-24 09:16:29 +01:00
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
const_iterator begin() const
|
2004-06-27 03:42:17 +02:00
|
|
|
{
|
2006-02-03 05:02:53 +01:00
|
|
|
return const_iterator(data, (size_ < n)? 0 : head);
|
2004-06-27 03:42:17 +02:00
|
|
|
}
|
2006-01-24 09:16:29 +01:00
|
|
|
iterator end()
|
|
|
|
{
|
2006-02-03 05:02:53 +01:00
|
|
|
return iterator(data, (size_ < n)? size_ : head+n);
|
2006-01-24 09:16:29 +01:00
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
const_iterator end() const
|
2004-06-27 03:42:17 +02:00
|
|
|
{
|
2006-02-03 05:02:53 +01:00
|
|
|
return const_iterator(data, (size_ < n)? size_ : head+n);
|
2004-06-27 03:42:17 +02:00
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
#endif // #ifndef ADTS_H__
|