#pragma once
#ifndef __AUTO_HASHLIST__
#define __AUTO_HASHLIST__
#include "AutoDefs.h"
#include "AutoHashTable.h"
#include <new>
namespace Auto {
template <class T> class HashList : public HashTable {
private:
enum {
hash_list_growth = 256 };
T *_entries; usword_t _length; usword_t _maximum; usword_t _growth;
public:
HashList(usword_t growth = hash_list_growth) : HashTable(), _entries(NULL), _length(0), _maximum(0), _growth(growth) {}
HashList(HashList &original) {
_length = original.length;
_maximum = original.maximum;
_growth = original.growth;
_entries = aux_malloc(_length * sizeof(T));
memmove(_entries, original.entries, length*sizeof(T));
}
~HashList() { dispose(); }
inline void initialize(usword_t growth = hash_list_growth) {
HashTable::initialize();
_entries = NULL;
_length = 0;
_maximum = 0;
_growth = growth;
}
inline void dispose() {
HashTable::dispose();
if (_entries) {
for (usword_t i = 0; i < _length; ++i)
_entries[i].~T();
aux_free(_entries);
}
_entries = NULL;
_length = 0;
_maximum = 0;
}
inline void set_growth(const usword_t growth) { _growth = growth; }
inline void *memory() { return (void *)_entries; }
inline usword_t length() { return _length; }
inline usword_t maximum() { return _maximum; }
inline const size_t index(T *entry) const {
const size_t i = entry - _entries;
ASSERTION(0 <= i && i < _length);
return i;
}
inline T *find(void *address) { return (T *)HashTable::find(address); }
inline T& operator[](const size_t i) {
ASSERTION(0 <= i && i < _length);
return _entries[i];
}
inline T *add() {
if (_length >= _maximum) {
_maximum += _growth;
_entries = (T *)aux_realloc(_entries, _maximum * sizeof(T));
HashTable::clear();
for (usword_t i = 0; i < _length; i++) HashTable::add(_entries + i);
}
return ::new(_entries + _length++) T();
}
inline T *add(T *entry) {
T *slot = add();
*slot = *entry;
HashTable::add(slot);
return slot;
}
inline T *add(T entry) {
T *slot = add();
*slot = entry;
HashTable::add(slot);
return slot;
}
inline T *addRange(Range entry) {
T *slot = add();
*(Range*)slot = entry;
HashTable::add(slot);
return slot;
}
inline void remove(size_t i) {
HashTable::remove(_entries + i);
if (i != --_length) {
HashTable::remove(_entries + _length);
_entries[i] = _entries[_length];
HashTable::add(_entries + i);
}
}
inline void remove(T *entry) { if (entry) remove(index(entry)); }
inline bool is_empty() const { return _length == 0; }
};
};
#endif // __AUTO_HASHLIST__