1
//--------------------------------------------------------------------------------
2
// sort of the 'QuietDune Template Library' ;)
3
// Various implementations of arrays, linked lists, hashtables, tree's, etc..
4
// Originally contained even more variations of each, but now only what is
5
// actually used in the program. Should really each be moved to its own file.
6
// Was mostly created for possibly easier specialized optimization issues vs. stl.
7
// But didn't really get around to that, so all of these could be thrown out
8
// and use the stl instead. But it was useful as a learning experience anyway...
9
//--------------------------------------------------------------------------------
15
#pragma warning(disable : 4996)
28
fsArray_t():array(NULL), _size(0) {}
29
fsArray_t(size_t Size):array(NULL), _size(0) { resize(Size); }
30
fsArray_t(const fsArray_t &fa):array(NULL), _size(0) { copy(fa); }
31
~fsArray_t() { _free(); }
32
fsArray_t& operator=(const fsArray_t& fa) { copy(fa); return *this; }
33
void resize(size_t Size) { _free(); _size = Size; array = new T [_size]; }
34
T& operator[](size_t i) { return array[i]; }
35
T& operator[](size_t i) const { return array[i]; }
36
size_t size() const { return _size; }
37
bool empty() const { return (_size == 0); }
39
typedef const T* const_iterator;
40
iterator begin() { return array; }
41
iterator end() { return array + _size; }
42
const_iterator begin() const { return array; }
43
const_iterator end() const { return array + _size; }
45
void _free() { if (array) delete[] array; array = NULL; _size = _size = 0; }
46
void copy(const fsArray_t& fa)
48
_free(); resize(fa._size);
49
for (size_t i=0; i<_size; ++i) array[i] = fa.array[i];
55
// generic growable array class, similar to STL vector, can be used as stack/list as well,
60
//array_t(const array_t& a);
61
//array_t& operator=(const array_t& a);
63
array_t():array(NULL), curidx(0), maxidx(0) {}
64
array_t(const array_t& a)
66
array = new T [a.maxidx];
67
for (size_t i=0; i<a.maxidx; ++i) array[i] = a.array[i];
71
array_t(size_t initsize)
73
curidx = maxidx = initsize;
74
array = new T [maxidx];
75
memset(array, 0, maxidx*sizeof(T));
84
array_t& operator=(const array_t& a)
86
// don't delete if enough space already
87
if (array && (a.maxidx <= maxidx)) {
88
for (size_t i=0; i<a.curidx; ++i) array[i] = a.array[i];
92
if (array) delete[] array;
93
array = new T [a.maxidx];
94
for (size_t i=0; i<a.maxidx; ++i) array[i] = a.array[i];
99
void clear() { curidx = 0; } // no delete, just set index back to 0
100
void resize(size_t newsize)
102
// do nothing if newsize less or equal to already allocated space
103
if (array && (newsize <= maxidx)) return;
105
T* na = new T [maxidx];
106
memset(na, 0, maxidx*sizeof(T));
108
for (size_t i=0; i<curidx; ++i) na[i] = array[i];
114
// as above, but does not copy old contents
115
void resize_clear(size_t newsize)
117
// only clear if newsize less or equal to already allocated space (if any)
118
if (array && (newsize <= maxidx)) { curidx = 0; return; }
120
if (array) delete[] array;
121
array = new T [maxidx];
125
void push_back(const T& item) { checkCapacity(); array[curidx++] = item; }
127
// returns reference to first item
128
T& front() const { return array[0]; }
129
// pops first item from the array, does not do anything if array empty
130
void pop_front() { if (curidx) { curidx--; memmove(array, array+1, curidx*sizeof(T)); } }
131
// returns reference to last item
132
T& back() const { return array[curidx-1]; }
133
// pops last item from the array, does not do anything if array empty
134
void pop_back() { if (curidx) curidx--; }
135
// pops and returns last item from the array, aborts if array empty
136
T& pop() { assert(curidx!=0); return array[--curidx]; }
138
// array access, DOES NO BOUNDS CHECKING!!!!
139
T& operator[](size_t i) { return array[i]; }
140
T& operator[](size_t i) const { return array[i]; }
141
// same, but does check bounds, aborts if trying to access array beyond bounds
142
T& at(size_t i) { assert(i<curidx); return array[i]; }
143
bool empty() const { return (curidx==0); }
144
size_t size() const { return curidx; }
145
size_t capacity() const { return maxidx; }
146
// returns true if item is contained in array
147
bool contains(const T& item) const
149
for (size_t i=0; i<curidx; ++i)
150
if (array[i] == item) return true;
153
// returns index number of item in array, if not found, returns -1
154
int index(const T& item) const
156
for (size_t i = 0; i<curidx; ++i)
157
if (array[i] == item) return i;
160
// for iterator emulation
162
typedef const T* const_iterator;
163
iterator begin() { return &array[0]; }
164
iterator end() { return &array[curidx]; }
165
const_iterator begin() const { return &array[0]; }
166
const_iterator end() const { return &array[curidx]; }
168
// check if more memory needed
171
if (curidx >= maxidx) {
172
maxidx = (maxidx==0) ? 1 : (maxidx << 1);
173
T* na = new T [maxidx];
175
for (size_t i=0; i<curidx; ++i) na[i] = array[i];
182
size_t curidx, maxidx;
184
//------------------------------------------------------------------------------
186
// associative linked list
187
template<typename keytype, typename datatype>
191
alist_t(const alist_t& L);
192
alist_t& operator=(const alist_t& L);
194
alist_t() : list(NULL), maxitems(0) {}
195
~alist_t() { clear(); }
196
void insert(const keytype& k, const datatype& item)
198
list = new link_t(k, item, list);
201
// remove item, search by item key,
202
// returns false if item was not found, does not delete data!
203
bool remove(const keytype& k)
205
for (link_t *L=list, *pL=NULL; L!=NULL; pL=L, L=L->next) {
218
datatype* find(const keytype& k) const
220
for (link_t* L=list; L!=NULL; L=L->next)
221
if (L->k == k) return &L->d;
224
size_t size() const { return maxitems; }
229
link_t* tmp = L->next;
236
// if list has allocated data, use this to delete it properly.
237
// just for convenience, probably should really leave it to user though...
242
link_t* tmp = it->next;
250
// as above, array version
251
void clear_delete_array()
255
link_t* tmp = it->next;
266
link_t(const keytype& _k, const datatype& _d, link_t* n):k(_k), d(_d), next(n) {}
275
// as above, for string keys
276
template<typename datatype>
280
sklist_t(const sklist_t& L);
281
sklist_t& operator=(const sklist_t& L);
283
sklist_t():list(NULL), curitem(NULL), maxitems(0) {}
284
~sklist_t() { clear(); }
289
link_t* pL = L->next;
294
list = curitem = NULL;
297
void insert(const char* name, const datatype& item)
299
link_t* L = new link_t;
300
L->name = new char[strlen(name) + 1];
301
strcpy(L->name, name);
307
datatype* find(const char* name) const
309
for (link_t* L=list; L!=NULL; L=L->next)
310
if (!strcmp(name, L->name)) return &L->data;
313
void remove(const char* name, datatype& dt)
315
for (link_t *L=list, *pL=NULL; L!=NULL; pL=L, L=L->next)
316
if (!strcmp(name, L->name)) {
328
inline bool empty() const { return (maxitems == 0); }
329
inline size_t size() const { return maxitems; }
330
inline datatype* first() { return ((curitem = list)==NULL) ? NULL : &curitem->data; }
331
inline datatype* next()
333
return (curitem==NULL) ? NULL : (((curitem = curitem->next)==NULL) ? NULL : &curitem->data);
335
// returns key string, use with first/next
336
inline char* getName() { return (curitem==NULL) ? NULL : curitem->name; }
344
link_t *list, *curitem;
348
//------------------------------------------------------------------------------
350
// more experiments, Andersson tree, C++ implementation of Jullienne Walker's jsw_atree library
351
// see http://eternallyconfuzzled.com/jsw_home.aspx
352
// Works quite well, could possibly be used as replacement for map<>
353
template<typename keytype, typename datatype>
357
aatree_t():numitems(0) { nil.link[0] = nil.link[1] = root = &nil; }
358
~aatree_t() { clear(); }
362
node_t *save, *it = root;
364
if (it->link[0] == &nil) {
370
it->link[0] = save->link[1];
380
node_t *save, *it = root;
382
if (it->link[0] == &nil) {
389
it->link[0] = save->link[1];
397
datatype* find(const keytype& key) const
401
if (it->key == key) return &it->data;
402
it = it->link[it->key < key];
406
void insert(const keytype& key, const datatype& data)
408
if (root == &nil) // Empty tree case
409
root = new node_t(1, key, data, &nil);
411
// if key already exists, replace item
412
node_t *it = root, *path[64];
414
// Find a spot and save the path
418
dir = (it->key < key);
419
if (it->link[dir] == &nil) break;
423
it->link[dir] = new node_t(1, key, data, &nil);
424
// Walk back and rebalance
427
if (top != 0) dir = ((path[top - 1]->link[1] == path[top]));
432
path[top - 1]->link[dir] = path[top];
439
// remove item, does not delete data!
440
bool remove(const keytype& key)
442
if (root == &nil) return false;
444
node_t *it = root, *path[64];
447
/* Find node to remove and save path */
451
if (it == &nil) return false;
452
if (it->key == key) break;
453
dir = (it->key < key);
457
// Remove the found node
458
if ((it->link[0] == &nil) || (it->link[1] == &nil))
461
int dir2 = (it->link[0] == &nil);
465
path[top - 1]->link[dir] = it->link[dir2];
473
node_t *heir = it->link[1], *prev = it;
475
while (heir->link[0] != &nil) {
477
path[top++] = prev = heir;
478
heir = heir->link[0];
481
// Order is important!
482
// (free item, replace item, free heir)
484
it->data = heir->data;
485
prev->link[prev == it] = heir->link[1];
489
/* Walk back up and rebalance */
491
node_t *up = path[top];
494
dir = (path[top - 1]->link[1] == up);
496
// Rebalance (aka. black magic)
497
if ((up->link[0]->level < up->level - 1) || (up->link[1]->level < up->level - 1))
499
if (up->link[1]->level > --up->level)
500
up->link[1]->level = up->level;
502
// Order is important!
505
skew(up->link[1]->link[1]);
512
path[top - 1]->link[dir] = up;
520
bool empty() const { return (numitems == 0); }
521
size_t size() const { return numitems; }
522
size_t nodesize() const { return sizeof(node_t); }
526
node_t():level(0) { link[0] = link[1] = NULL; }
527
node_t(int L, const keytype &K, const datatype &D, node_t* il):level(L), key(K), data(D) { link[0] = link[1] = il; }
534
// Remove left horizontal links
535
inline void skew(node_t* &t)
537
if ((t->link[0]->level == t->level) && (t->level != 0)) {
538
node_t *save = t->link[0];
539
t->link[0] = save->link[1];
544
// Remove consecutive horizontal links
545
inline void split(node_t* &t)
547
if ((t->link[1]->link[1]->level == t->level) && (t->level != 0)) {
548
node_t *save = t->link[1];
549
t->link[1] = save->link[0];
560
//------------------------------------------------------------------------------
563
unsigned int hashfunc(const unsigned char* data, unsigned int len);
565
// simple generic hashtable
566
template<typename hashtype, typename datatype, unsigned int log2_size=10> // default of 1024 buckets
570
hashtable_t():numitems(0) {}
572
void insert(const hashtype& key, const datatype& data)
575
values[hashfunc(reinterpret_cast<const unsigned char*>(&key), sizeof(key)) & ((1 << log2_size)-1)].insert(key, data);
577
datatype* find(const hashtype& key) const
579
return values[hashfunc(reinterpret_cast<const unsigned char*>(&key), sizeof(key)) & ((1 << log2_size)-1)].find(key);
581
bool remove(const hashtype& key)
583
if (values[hashfunc(reinterpret_cast<const unsigned char*>(&key), sizeof(key)) & ((1 << log2_size)-1)].remove(key)) {
592
for (unsigned int n=0; n<(1 << log2_size); n++)
597
// used for case where items are allocated when added
600
for (unsigned int n=0; n<(1 << log2_size); n++)
601
values[n].clear_delete();
604
size_t size() const { return numitems; }
605
bool empty() const { return (numitems == 0); }
608
int minbk=0x7fffffff, maxbk=-1;
609
int minit=0x7fffffff, maxit=-1;
610
for (unsigned int n=0; n<(1 << log2_size); n++) {
611
const int sz = (int)values[n].size();
612
if (sz < minit) { minbk = n; minit = sz; }
613
if (sz > maxit) { maxbk = n; maxit = sz; }
615
printf("hashtable_t() bucket %d has least items %d\n", minbk, minit);
616
printf("hashtable_t() bucket %d has most items %d\n", maxbk, maxit);
619
alist_t<hashtype, datatype> values[1 << log2_size];
624
// as above, strings as key
625
template<typename datatype, unsigned int log2_size=10> // default of 1024 buckets
629
hashmap_t():maxitems(0), curbk(0) {}
631
void insert(const char* name, const datatype &data)
633
values[hashfunc(reinterpret_cast<const unsigned char*>(name),
634
(unsigned int)strlen(name)) & ((1 << log2_size)-1)].insert(name, data);
637
datatype* find(const char* name) const
639
return values[hashfunc(reinterpret_cast<const unsigned char*>(name),
640
(unsigned int)strlen(name)) & ((1 << log2_size)-1)].find(name);
642
void remove(const char* name, datatype& dt)
644
values[hashfunc(reinterpret_cast<const unsigned char*>(name),
645
(unsigned int)strlen(name)) & ((1 << log2_size)-1)].remove(name, dt);
648
size_t size() const { return maxitems; }
651
for (unsigned int i=0; i<(1 << log2_size); ++i)
656
// first non-empty bucket
658
if (maxitems == 0) return NULL;
659
while (values[curbk].empty())
660
if (++curbk == (1 << log2_size)) return NULL;
661
return values[curbk].first();
665
if (curbk == (1 << log2_size)) return NULL;
666
datatype* dt = values[curbk].next();
667
if (dt == NULL) { // next non-empty bucket
669
while (values[curbk].empty())
670
if (++curbk == (1 << log2_size)) return NULL;
671
dt = values[curbk].first();
675
// returns key name string, use with first/next
676
inline char* getName()
678
if (curbk == (1 << log2_size)) return NULL;
679
return values[curbk].getName();
682
sklist_t<datatype> values[1 << log2_size];