Unified member names in container/storage classes Array, HashMap and String: _storage, _size, _capacity
svn-id: r34052
This commit is contained in:
parent
47429f2197
commit
a79e9385a1
5 changed files with 195 additions and 196 deletions
|
@ -35,7 +35,7 @@ class Array {
|
|||
protected:
|
||||
uint _capacity;
|
||||
uint _size;
|
||||
T *_data;
|
||||
T *_storage;
|
||||
|
||||
public:
|
||||
typedef T *iterator;
|
||||
|
@ -44,41 +44,41 @@ public:
|
|||
typedef T value_type;
|
||||
|
||||
public:
|
||||
Array() : _capacity(0), _size(0), _data(0) {}
|
||||
Array(const Array<T> &array) : _capacity(0), _size(0), _data(0) {
|
||||
Array() : _capacity(0), _size(0), _storage(0) {}
|
||||
Array(const Array<T> &array) : _capacity(0), _size(0), _storage(0) {
|
||||
_size = array._size;
|
||||
_capacity = _size + 32;
|
||||
_data = new T[_capacity];
|
||||
copy(array._data, array._data + _size, _data);
|
||||
_storage = new T[_capacity];
|
||||
copy(array._storage, array._storage + _size, _storage);
|
||||
}
|
||||
|
||||
~Array() {
|
||||
delete[] _data;
|
||||
delete[] _storage;
|
||||
}
|
||||
|
||||
void push_back(const T &element) {
|
||||
ensureCapacity(_size + 1);
|
||||
_data[_size++] = element;
|
||||
_storage[_size++] = element;
|
||||
}
|
||||
|
||||
void push_back(const Array<T> &array) {
|
||||
ensureCapacity(_size + array._size);
|
||||
copy(array._data, array._data + array._size, _data + _size);
|
||||
copy(array._storage, array._storage + array._size, _storage + _size);
|
||||
_size += array._size;
|
||||
}
|
||||
|
||||
void insert_at(int idx, const T &element) {
|
||||
assert(idx >= 0 && (uint)idx <= _size);
|
||||
ensureCapacity(_size + 1);
|
||||
copy_backward(_data + idx, _data + _size, _data + _size + 1);
|
||||
_data[idx] = element;
|
||||
copy_backward(_storage + idx, _storage + _size, _storage + _size + 1);
|
||||
_storage[idx] = element;
|
||||
_size++;
|
||||
}
|
||||
|
||||
T remove_at(int idx) {
|
||||
assert(idx >= 0 && (uint)idx < _size);
|
||||
T tmp = _data[idx];
|
||||
copy(_data + idx + 1, _data + _size, _data + idx);
|
||||
T tmp = _storage[idx];
|
||||
copy(_storage + idx + 1, _storage + _size, _storage + idx);
|
||||
_size--;
|
||||
return tmp;
|
||||
}
|
||||
|
@ -87,23 +87,23 @@ public:
|
|||
|
||||
T& operator[](int idx) {
|
||||
assert(idx >= 0 && (uint)idx < _size);
|
||||
return _data[idx];
|
||||
return _storage[idx];
|
||||
}
|
||||
|
||||
const T& operator[](int idx) const {
|
||||
assert(idx >= 0 && (uint)idx < _size);
|
||||
return _data[idx];
|
||||
return _storage[idx];
|
||||
}
|
||||
|
||||
Array<T>& operator=(const Array<T> &array) {
|
||||
if (this == &array)
|
||||
return *this;
|
||||
|
||||
delete[] _data;
|
||||
delete[] _storage;
|
||||
_size = array._size;
|
||||
_capacity = _size + 32;
|
||||
_data = new T[_capacity];
|
||||
copy(array._data, array._data + _size, _data);
|
||||
_storage = new T[_capacity];
|
||||
copy(array._storage, array._storage + _size, _storage);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -113,8 +113,8 @@ public:
|
|||
}
|
||||
|
||||
void clear() {
|
||||
delete[] _data;
|
||||
_data = 0;
|
||||
delete[] _storage;
|
||||
_storage = 0;
|
||||
_size = 0;
|
||||
_capacity = 0;
|
||||
}
|
||||
|
@ -125,33 +125,33 @@ public:
|
|||
|
||||
|
||||
iterator begin() {
|
||||
return _data;
|
||||
return _storage;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return _data + _size;
|
||||
return _storage + _size;
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return _data;
|
||||
return _storage;
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return _data + _size;
|
||||
return _storage + _size;
|
||||
}
|
||||
|
||||
void reserve(uint newCapacity) {
|
||||
if (newCapacity <= _capacity)
|
||||
return;
|
||||
|
||||
T *old_data = _data;
|
||||
T *old_storage = _storage;
|
||||
_capacity = newCapacity;
|
||||
_data = new T[newCapacity];
|
||||
_storage = new T[newCapacity];
|
||||
|
||||
if (old_data) {
|
||||
if (old_storage) {
|
||||
// Copy old data
|
||||
copy(old_data, old_data + _size, _data);
|
||||
delete[] old_data;
|
||||
copy(old_storage, old_storage + _size, _storage);
|
||||
delete[] old_storage;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,14 +159,14 @@ public:
|
|||
if (newSize == _size)
|
||||
return;
|
||||
|
||||
T *old_data = _data;
|
||||
T *old_storage = _storage;
|
||||
_capacity = newSize;
|
||||
_data = new T[newSize];
|
||||
if (old_data) {
|
||||
_storage = new T[newSize];
|
||||
if (old_storage) {
|
||||
// Copy old data
|
||||
int cnt = (_size < newSize ? _size : newSize);
|
||||
copy(old_data, old_data + cnt, _data);
|
||||
delete[] old_data;
|
||||
copy(old_storage, old_storage + cnt, _storage);
|
||||
delete[] old_storage;
|
||||
}
|
||||
_size = newSize;
|
||||
}
|
||||
|
|
|
@ -94,9 +94,9 @@ static double
|
|||
g_collisions = 0,
|
||||
g_lookups = 0,
|
||||
g_collPerLook = 0,
|
||||
g_arrsize = 0,
|
||||
g_nele = 0;
|
||||
static int g_max_arrsize = 0, g_max_nele = 0;
|
||||
g_capacity = 0,
|
||||
g_size = 0;
|
||||
static int g_max_capacity = 0, g_max_size = 0;
|
||||
static int g_totalHashmaps = 0;
|
||||
|
||||
void updateHashCollisionStats(int collisions, int lookups, int arrsize, int nele) {
|
||||
|
@ -104,20 +104,20 @@ void updateHashCollisionStats(int collisions, int lookups, int arrsize, int nele
|
|||
g_lookups += lookups;
|
||||
if (lookups)
|
||||
g_collPerLook += (double)collisions / (double)lookups;
|
||||
g_arrsize += arrsize;
|
||||
g_nele += nele;
|
||||
g_capacity += arrsize;
|
||||
g_size += nele;
|
||||
g_totalHashmaps++;
|
||||
|
||||
g_max_arrsize = MAX(g_max_arrsize, arrsize);
|
||||
g_max_nele = MAX(g_max_nele, nele);
|
||||
g_max_capacity = MAX(g_max_capacity, arrsize);
|
||||
g_max_size = MAX(g_max_size, nele);
|
||||
|
||||
fprintf(stdout, "%d hashmaps: colls %.1f; lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n",
|
||||
g_totalHashmaps,
|
||||
g_collisions / g_totalHashmaps,
|
||||
g_lookups / g_totalHashmaps,
|
||||
100 * g_collPerLook / g_totalHashmaps,
|
||||
g_nele / g_totalHashmaps, g_max_nele,
|
||||
g_arrsize / g_totalHashmaps, g_max_arrsize);
|
||||
g_size / g_totalHashmaps, g_max_size,
|
||||
g_capacity / g_totalHashmaps, g_max_capacity);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
181
common/hashmap.h
181
common/hashmap.h
|
@ -136,8 +136,9 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
Node **_arr; // hashtable of size arrsize.
|
||||
uint _arrsize, _nele;
|
||||
Node **_storage; // hashtable of size arrsize.
|
||||
uint _capacity;
|
||||
uint _size;
|
||||
|
||||
HashFunc _hash;
|
||||
EqualFunc _equal;
|
||||
|
@ -174,8 +175,8 @@ public:
|
|||
|
||||
NodeType *deref() const {
|
||||
assert(_hashmap != 0);
|
||||
assert(_idx < _hashmap->_arrsize);
|
||||
Node *node = _hashmap->_arr[_idx];
|
||||
assert(_idx < _hashmap->_capacity);
|
||||
Node *node = _hashmap->_storage[_idx];
|
||||
assert(node != 0);
|
||||
return node;
|
||||
}
|
||||
|
@ -195,8 +196,8 @@ public:
|
|||
assert(_hashmap);
|
||||
do {
|
||||
_idx++;
|
||||
} while (_idx < _hashmap->_arrsize && _hashmap->_arr[_idx] == 0);
|
||||
if (_idx >= _hashmap->_arrsize)
|
||||
} while (_idx < _hashmap->_capacity && _hashmap->_storage[_idx] == 0);
|
||||
if (_idx >= _hashmap->_capacity)
|
||||
_idx = (uint)-1;
|
||||
|
||||
return *this;
|
||||
|
@ -223,7 +224,7 @@ public:
|
|||
|
||||
// Remove the previous content and ...
|
||||
clear();
|
||||
delete[] _arr;
|
||||
delete[] _storage;
|
||||
// ... copy the new stuff.
|
||||
assign(map);
|
||||
return *this;
|
||||
|
@ -242,12 +243,12 @@ public:
|
|||
|
||||
void erase(const Key &key);
|
||||
|
||||
uint size() const { return _nele; }
|
||||
uint size() const { return _size; }
|
||||
|
||||
iterator begin() {
|
||||
// Find and return the _key non-empty entry
|
||||
for (uint ctr = 0; ctr < _arrsize; ++ctr) {
|
||||
if (_arr[ctr])
|
||||
for (uint ctr = 0; ctr < _capacity; ++ctr) {
|
||||
if (_storage[ctr])
|
||||
return iterator(ctr, this);
|
||||
}
|
||||
return end();
|
||||
|
@ -258,8 +259,8 @@ public:
|
|||
|
||||
const_iterator begin() const {
|
||||
// Find and return the first non-empty entry
|
||||
for (uint ctr = 0; ctr < _arrsize; ++ctr) {
|
||||
if (_arr[ctr])
|
||||
for (uint ctr = 0; ctr < _capacity; ++ctr) {
|
||||
if (_storage[ctr])
|
||||
return const_iterator(ctr, this);
|
||||
}
|
||||
return end();
|
||||
|
@ -270,14 +271,14 @@ public:
|
|||
|
||||
iterator find(const Key &key) {
|
||||
uint ctr = lookup(key);
|
||||
if (_arr[ctr])
|
||||
if (_storage[ctr])
|
||||
return iterator(ctr, this);
|
||||
return end();
|
||||
}
|
||||
|
||||
const_iterator find(const Key &key) const {
|
||||
uint ctr = lookup(key);
|
||||
if (_arr[ctr])
|
||||
if (_storage[ctr])
|
||||
return const_iterator(ctr, this);
|
||||
return end();
|
||||
}
|
||||
|
@ -285,7 +286,7 @@ public:
|
|||
// TODO: insert() method?
|
||||
|
||||
bool empty() const {
|
||||
return (_nele == 0);
|
||||
return (_size == 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -301,12 +302,12 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap() :
|
|||
_nodePool(sizeof(Node)),
|
||||
#endif
|
||||
_defaultVal() {
|
||||
_arrsize = nextTableSize(0);
|
||||
_arr = new Node *[_arrsize];
|
||||
assert(_arr != NULL);
|
||||
memset(_arr, 0, _arrsize * sizeof(Node *));
|
||||
_capacity = nextTableSize(0);
|
||||
_storage = new Node *[_capacity];
|
||||
assert(_storage != NULL);
|
||||
memset(_storage, 0, _capacity * sizeof(Node *));
|
||||
|
||||
_nele = 0;
|
||||
_size = 0;
|
||||
|
||||
#ifdef DEBUG_HASH_COLLISIONS
|
||||
_collisions = 0;
|
||||
|
@ -333,14 +334,14 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
|
|||
*/
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() {
|
||||
for (uint ctr = 0; ctr < _arrsize; ++ctr)
|
||||
if (_arr[ctr] != NULL)
|
||||
freeNode(_arr[ctr]);
|
||||
for (uint ctr = 0; ctr < _capacity; ++ctr)
|
||||
if (_storage[ctr] != NULL)
|
||||
freeNode(_storage[ctr]);
|
||||
|
||||
delete[] _arr;
|
||||
delete[] _storage;
|
||||
#ifdef DEBUG_HASH_COLLISIONS
|
||||
extern void updateHashCollisionStats(int, int, int, int);
|
||||
updateHashCollisionStats(_collisions, _lookups, _arrsize, _nele);
|
||||
updateHashCollisionStats(_collisions, _lookups, _capacity, _size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -353,95 +354,95 @@ HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() {
|
|||
*/
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
|
||||
_arrsize = map._arrsize;
|
||||
_arr = new Node *[_arrsize];
|
||||
assert(_arr != NULL);
|
||||
memset(_arr, 0, _arrsize * sizeof(Node *));
|
||||
_capacity = map._capacity;
|
||||
_storage = new Node *[_capacity];
|
||||
assert(_storage != NULL);
|
||||
memset(_storage, 0, _capacity * sizeof(Node *));
|
||||
|
||||
// Simply clone the map given to us, one by one.
|
||||
_nele = 0;
|
||||
for (uint ctr = 0; ctr < _arrsize; ++ctr) {
|
||||
if (map._arr[ctr] != NULL) {
|
||||
_arr[ctr] = allocNode(map._arr[ctr]->_key);
|
||||
_arr[ctr]->_value = map._arr[ctr]->_value;
|
||||
_nele++;
|
||||
_size = 0;
|
||||
for (uint ctr = 0; ctr < _capacity; ++ctr) {
|
||||
if (map._storage[ctr] != NULL) {
|
||||
_storage[ctr] = allocNode(map._storage[ctr]->_key);
|
||||
_storage[ctr]->_value = map._storage[ctr]->_value;
|
||||
_size++;
|
||||
}
|
||||
}
|
||||
// Perform a sanity check (to help track down hashmap corruption)
|
||||
assert(_nele == map._nele);
|
||||
assert(_size == map._size);
|
||||
}
|
||||
|
||||
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) {
|
||||
for (uint ctr = 0; ctr < _arrsize; ++ctr) {
|
||||
if (_arr[ctr] != NULL) {
|
||||
freeNode(_arr[ctr]);
|
||||
_arr[ctr] = NULL;
|
||||
for (uint ctr = 0; ctr < _capacity; ++ctr) {
|
||||
if (_storage[ctr] != NULL) {
|
||||
freeNode(_storage[ctr]);
|
||||
_storage[ctr] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (shrinkArray && _arrsize > nextTableSize(0)) {
|
||||
delete[] _arr;
|
||||
if (shrinkArray && _capacity > nextTableSize(0)) {
|
||||
delete[] _storage;
|
||||
|
||||
_arrsize = nextTableSize(0);
|
||||
_arr = new Node *[_arrsize];
|
||||
assert(_arr != NULL);
|
||||
memset(_arr, 0, _arrsize * sizeof(Node *));
|
||||
_capacity = nextTableSize(0);
|
||||
_storage = new Node *[_capacity];
|
||||
assert(_storage != NULL);
|
||||
memset(_storage, 0, _capacity * sizeof(Node *));
|
||||
}
|
||||
|
||||
_nele = 0;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
void HashMap<Key, Val, HashFunc, EqualFunc>::expand_array(uint newsize) {
|
||||
assert(newsize > _arrsize);
|
||||
assert(newsize > _capacity);
|
||||
uint ctr, dex;
|
||||
|
||||
const uint old_nele = _nele;
|
||||
const uint old_arrsize = _arrsize;
|
||||
Node **old_arr = _arr;
|
||||
const uint old_size = _size;
|
||||
const uint old_capacity = _capacity;
|
||||
Node **old_storage = _storage;
|
||||
|
||||
// allocate a new array
|
||||
_nele = 0;
|
||||
_arrsize = newsize;
|
||||
_arr = new Node *[_arrsize];
|
||||
assert(_arr != NULL);
|
||||
memset(_arr, 0, _arrsize * sizeof(Node *));
|
||||
_size = 0;
|
||||
_capacity = newsize;
|
||||
_storage = new Node *[_capacity];
|
||||
assert(_storage != NULL);
|
||||
memset(_storage, 0, _capacity * sizeof(Node *));
|
||||
|
||||
// rehash all the old elements
|
||||
for (ctr = 0; ctr < old_arrsize; ++ctr) {
|
||||
if (old_arr[ctr] == NULL)
|
||||
for (ctr = 0; ctr < old_capacity; ++ctr) {
|
||||
if (old_storage[ctr] == NULL)
|
||||
continue;
|
||||
|
||||
// Insert the element from the old table into the new table.
|
||||
// Since we know that no key exists twice in the old table, we
|
||||
// can do this slightly better than by calling lookup, since we
|
||||
// don't have to call _equal().
|
||||
dex = _hash(old_arr[ctr]->_key) % _arrsize;
|
||||
while (_arr[dex] != NULL) {
|
||||
dex = (dex + 1) % _arrsize;
|
||||
dex = _hash(old_storage[ctr]->_key) % _capacity;
|
||||
while (_storage[dex] != NULL) {
|
||||
dex = (dex + 1) % _capacity;
|
||||
}
|
||||
|
||||
_arr[dex] = old_arr[ctr];
|
||||
_nele++;
|
||||
_storage[dex] = old_storage[ctr];
|
||||
_size++;
|
||||
}
|
||||
|
||||
// Perform a sanity check: Old number of elements should match the new one!
|
||||
// This check will fail if some previous operation corrupted this hashmap.
|
||||
assert(_nele == old_nele);
|
||||
assert(_size == old_size);
|
||||
|
||||
delete[] old_arr;
|
||||
delete[] old_storage;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
|
||||
uint ctr = _hash(key) % _arrsize;
|
||||
uint ctr = _hash(key) % _capacity;
|
||||
|
||||
while (_arr[ctr] != NULL && !_equal(_arr[ctr]->_key, key)) {
|
||||
ctr = (ctr + 1) % _arrsize;
|
||||
while (_storage[ctr] != NULL && !_equal(_storage[ctr]->_key, key)) {
|
||||
ctr = (ctr + 1) % _capacity;
|
||||
|
||||
#ifdef DEBUG_HASH_COLLISIONS
|
||||
_collisions++;
|
||||
|
@ -452,7 +453,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
|
|||
_lookups++;
|
||||
fprintf(stderr, "collisions %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
|
||||
_collisions, _lookups, ((double) _collisions / (double)_lookups),
|
||||
(const void *)this, _arrsize, _nele);
|
||||
(const void *)this, _capacity, _size);
|
||||
#endif
|
||||
|
||||
return ctr;
|
||||
|
@ -462,13 +463,13 @@ template<class Key, class Val, class HashFunc, class EqualFunc>
|
|||
int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) {
|
||||
uint ctr = lookup(key);
|
||||
|
||||
if (_arr[ctr] == NULL) {
|
||||
_arr[ctr] = allocNode(key);
|
||||
_nele++;
|
||||
if (_storage[ctr] == NULL) {
|
||||
_storage[ctr] = allocNode(key);
|
||||
_size++;
|
||||
|
||||
// Keep the load factor below 75%.
|
||||
if (_nele > _arrsize * 75 / 100) {
|
||||
expand_array(nextTableSize(_arrsize));
|
||||
if (_size > _capacity * 75 / 100) {
|
||||
expand_array(nextTableSize(_capacity));
|
||||
ctr = lookup(key);
|
||||
}
|
||||
}
|
||||
|
@ -480,7 +481,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &
|
|||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
bool HashMap<Key, Val, HashFunc, EqualFunc>::contains(const Key &key) const {
|
||||
uint ctr = lookup(key);
|
||||
return (_arr[ctr] != NULL);
|
||||
return (_storage[ctr] != NULL);
|
||||
}
|
||||
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
|
@ -496,15 +497,15 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::operator[](const Key &key) co
|
|||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) {
|
||||
uint ctr = lookupAndCreateIfMissing(key);
|
||||
assert(_arr[ctr] != NULL);
|
||||
return _arr[ctr]->_value;
|
||||
assert(_storage[ctr] != NULL);
|
||||
return _storage[ctr]->_value;
|
||||
}
|
||||
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const {
|
||||
uint ctr = lookup(key);
|
||||
if (_arr[ctr] != NULL)
|
||||
return _arr[ctr]->_value;
|
||||
if (_storage[ctr] != NULL)
|
||||
return _storage[ctr]->_value;
|
||||
else
|
||||
return _defaultVal;
|
||||
}
|
||||
|
@ -512,38 +513,38 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const
|
|||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &val) {
|
||||
uint ctr = lookupAndCreateIfMissing(key);
|
||||
assert(_arr[ctr] != NULL);
|
||||
_arr[ctr]->_value = val;
|
||||
assert(_storage[ctr] != NULL);
|
||||
_storage[ctr]->_value = val;
|
||||
}
|
||||
|
||||
template<class Key, class Val, class HashFunc, class EqualFunc>
|
||||
void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) {
|
||||
// This is based on code in the Wikipedia article on Hash tables.
|
||||
uint i = lookup(key);
|
||||
if (_arr[i] == NULL)
|
||||
if (_storage[i] == NULL)
|
||||
return; // key wasn't present, so no work has to be done
|
||||
// If we remove a key, we must check all subsequent keys and possibly
|
||||
// reinsert them.
|
||||
uint j = i;
|
||||
freeNode(_arr[i]);
|
||||
_arr[i] = NULL;
|
||||
freeNode(_storage[i]);
|
||||
_storage[i] = NULL;
|
||||
while (true) {
|
||||
// Look at the next table slot
|
||||
j = (j + 1) % _arrsize;
|
||||
j = (j + 1) % _capacity;
|
||||
// If the next slot is empty, we are done
|
||||
if (_arr[j] == NULL)
|
||||
if (_storage[j] == NULL)
|
||||
break;
|
||||
// Compute the slot where the content of the next slot should normally be,
|
||||
// assuming an empty table, and check whether we have to move it.
|
||||
uint k = _hash(_arr[j]->_key) % _arrsize;
|
||||
uint k = _hash(_storage[j]->_key) % _capacity;
|
||||
if ((j > i && (k <= i || k > j)) ||
|
||||
(j < i && (k <= i && k > j)) ) {
|
||||
_arr[i] = _arr[j];
|
||||
_storage[i] = _storage[j];
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
_arr[i] = NULL;
|
||||
_nele--;
|
||||
_storage[i] = NULL;
|
||||
_size--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
106
common/str.cpp
106
common/str.cpp
|
@ -43,19 +43,19 @@ static int computeCapacity(int len) {
|
|||
return ((len + 32 - 1) & ~0x1F) - 1;
|
||||
}
|
||||
|
||||
String::String(const char *str) : _len(0), _str(_storage) {
|
||||
String::String(const char *str) : _size(0), _str(_storage) {
|
||||
if (str == 0) {
|
||||
_storage[0] = 0;
|
||||
_len = 0;
|
||||
_size = 0;
|
||||
} else
|
||||
initWithCStr(str, strlen(str));
|
||||
}
|
||||
|
||||
String::String(const char *str, uint32 len) : _len(0), _str(_storage) {
|
||||
String::String(const char *str, uint32 len) : _size(0), _str(_storage) {
|
||||
initWithCStr(str, len);
|
||||
}
|
||||
|
||||
String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) {
|
||||
String::String(const char *beginP, const char *endP) : _size(0), _str(_storage) {
|
||||
assert(endP >= beginP);
|
||||
initWithCStr(beginP, endP - beginP);
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ void String::initWithCStr(const char *str, uint32 len) {
|
|||
// for GCC 2.95.x compatibility (see also tracker item #1602879).
|
||||
_storage[0] = 0;
|
||||
|
||||
_len = len;
|
||||
_size = len;
|
||||
|
||||
if (len >= _builtinCapacity) {
|
||||
// Not enough internal storage, so allocate more
|
||||
|
@ -83,7 +83,7 @@ void String::initWithCStr(const char *str, uint32 len) {
|
|||
}
|
||||
|
||||
String::String(const String &str)
|
||||
: _len(str._len), _str(str.isStorageIntern() ? _storage : str._str) {
|
||||
: _size(str._size), _str(str.isStorageIntern() ? _storage : str._str) {
|
||||
if (str.isStorageIntern()) {
|
||||
// String in internal storage: just copy it
|
||||
memcpy(_storage, str._storage, _builtinCapacity);
|
||||
|
@ -97,14 +97,14 @@ String::String(const String &str)
|
|||
}
|
||||
|
||||
String::String(char c)
|
||||
: _len(0), _str(_storage) {
|
||||
: _size(0), _str(_storage) {
|
||||
|
||||
_storage[0] = c;
|
||||
_storage[1] = 0;
|
||||
|
||||
// TODO/FIXME: There is no reason for the following check -- we *do*
|
||||
// allow strings to contain 0 bytes!
|
||||
_len = (c == 0) ? 0 : 1;
|
||||
_size = (c == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
String::~String() {
|
||||
|
@ -112,16 +112,16 @@ String::~String() {
|
|||
}
|
||||
|
||||
void String::makeUnique() {
|
||||
ensureCapacity(_len, true);
|
||||
ensureCapacity(_size, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that enough storage is available to store at least new_len
|
||||
* Ensure that enough storage is available to store at least new_size
|
||||
* characters plus a null byte. In addition, if we currently share
|
||||
* the storage with another string, unshare it, so that we can safely
|
||||
* write to the storage.
|
||||
*/
|
||||
void String::ensureCapacity(uint32 new_len, bool keep_old) {
|
||||
void String::ensureCapacity(uint32 new_size, bool keep_old) {
|
||||
bool isShared;
|
||||
uint32 curCapacity, newCapacity;
|
||||
char *newStorage;
|
||||
|
@ -137,10 +137,10 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) {
|
|||
|
||||
// Special case: If there is enough space, and we do not share
|
||||
// the storage, then there is nothing to do.
|
||||
if (!isShared && new_len <= curCapacity)
|
||||
if (!isShared && new_size <= curCapacity)
|
||||
return;
|
||||
|
||||
if (isShared && new_len <= _builtinCapacity - 1) {
|
||||
if (isShared && new_size <= _builtinCapacity - 1) {
|
||||
// We share the storage, but there is enough internal storage: Use that.
|
||||
newStorage = _storage;
|
||||
newCapacity = _builtinCapacity - 1;
|
||||
|
@ -148,7 +148,7 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) {
|
|||
// We need to allocate storage on the heap!
|
||||
|
||||
// Compute a suitable new capacity limit
|
||||
newCapacity = computeCapacity(new_len);
|
||||
newCapacity = computeCapacity(new_size);
|
||||
|
||||
// Allocate new storage
|
||||
newStorage = (char *)malloc(newCapacity+1);
|
||||
|
@ -157,10 +157,10 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) {
|
|||
|
||||
// Copy old data if needed, elsewise reset the new storage.
|
||||
if (keep_old) {
|
||||
assert(_len <= newCapacity);
|
||||
memcpy(newStorage, _str, _len + 1);
|
||||
assert(_size <= newCapacity);
|
||||
memcpy(newStorage, _str, _size + 1);
|
||||
} else {
|
||||
_len = 0;
|
||||
_size = 0;
|
||||
newStorage[0] = 0;
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,7 @@ void String::decRefCount(int *oldRefCount) {
|
|||
String& String::operator =(const char *str) {
|
||||
uint32 len = strlen(str);
|
||||
ensureCapacity(len, false);
|
||||
_len = len;
|
||||
_size = len;
|
||||
memmove(_str, str, len + 1);
|
||||
return *this;
|
||||
}
|
||||
|
@ -221,16 +221,16 @@ String &String::operator =(const String &str) {
|
|||
|
||||
if (str.isStorageIntern()) {
|
||||
decRefCount(_extern._refCount);
|
||||
_len = str._len;
|
||||
_size = str._size;
|
||||
_str = _storage;
|
||||
memcpy(_str, str._str, _len + 1);
|
||||
memcpy(_str, str._str, _size + 1);
|
||||
} else {
|
||||
str.incRefCount();
|
||||
decRefCount(_extern._refCount);
|
||||
|
||||
_extern._refCount = str._extern._refCount;
|
||||
_extern._capacity = str._extern._capacity;
|
||||
_len = str._len;
|
||||
_size = str._size;
|
||||
_str = str._str;
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ String &String::operator =(const String &str) {
|
|||
String& String::operator =(char c) {
|
||||
decRefCount(_extern._refCount);
|
||||
_str = _storage;
|
||||
_len = 1;
|
||||
_size = 1;
|
||||
_str[0] = c;
|
||||
_str[1] = 0;
|
||||
return *this;
|
||||
|
@ -249,30 +249,30 @@ String& String::operator =(char c) {
|
|||
String &String::operator +=(const char *str) {
|
||||
int len = strlen(str);
|
||||
if (len > 0) {
|
||||
ensureCapacity(_len + len, true);
|
||||
ensureCapacity(_size + len, true);
|
||||
|
||||
memcpy(_str + _len, str, len + 1);
|
||||
_len += len;
|
||||
memcpy(_str + _size, str, len + 1);
|
||||
_size += len;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator +=(const String &str) {
|
||||
int len = str._len;
|
||||
int len = str._size;
|
||||
if (len > 0) {
|
||||
ensureCapacity(_len + len, true);
|
||||
ensureCapacity(_size + len, true);
|
||||
|
||||
memcpy(_str + _len, str._str, len + 1);
|
||||
_len += len;
|
||||
memcpy(_str + _size, str._str, len + 1);
|
||||
_size += len;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator +=(char c) {
|
||||
ensureCapacity(_len + 1, true);
|
||||
ensureCapacity(_size + 1, true);
|
||||
|
||||
_str[_len++] = c;
|
||||
_str[_len] = 0;
|
||||
_str[_size++] = c;
|
||||
_str[_size] = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -293,10 +293,10 @@ bool String::hasPrefix(const char *x) const {
|
|||
bool String::hasSuffix(const char *x) const {
|
||||
assert(x != 0);
|
||||
// Compare x with the end of _str.
|
||||
const uint32 x_len = strlen(x);
|
||||
if (x_len > _len)
|
||||
const uint32 x_size = strlen(x);
|
||||
if (x_size > _size)
|
||||
return false;
|
||||
const char *y = c_str() + _len - x_len;
|
||||
const char *y = c_str() + _size - x_size;
|
||||
while (*x && *x == *y) {
|
||||
++x;
|
||||
++y;
|
||||
|
@ -316,65 +316,65 @@ bool String::contains(char x) const {
|
|||
}
|
||||
|
||||
void String::deleteLastChar() {
|
||||
deleteChar(_len - 1);
|
||||
deleteChar(_size - 1);
|
||||
}
|
||||
|
||||
void String::deleteChar(uint32 p) {
|
||||
assert(p < _len);
|
||||
assert(p < _size);
|
||||
|
||||
makeUnique();
|
||||
while (p++ < _len)
|
||||
while (p++ < _size)
|
||||
_str[p-1] = _str[p];
|
||||
_len--;
|
||||
_size--;
|
||||
}
|
||||
|
||||
void String::clear() {
|
||||
decRefCount(_extern._refCount);
|
||||
|
||||
_len = 0;
|
||||
_size = 0;
|
||||
_str = _storage;
|
||||
_storage[0] = 0;
|
||||
}
|
||||
|
||||
void String::setChar(char c, uint32 p) {
|
||||
assert(p <= _len);
|
||||
assert(p <= _size);
|
||||
|
||||
makeUnique();
|
||||
_str[p] = c;
|
||||
}
|
||||
|
||||
void String::insertChar(char c, uint32 p) {
|
||||
assert(p <= _len);
|
||||
assert(p <= _size);
|
||||
|
||||
ensureCapacity(_len + 1, true);
|
||||
_len++;
|
||||
for (uint32 i = _len; i > p; --i)
|
||||
ensureCapacity(_size + 1, true);
|
||||
_size++;
|
||||
for (uint32 i = _size; i > p; --i)
|
||||
_str[i] = _str[i-1];
|
||||
_str[p] = c;
|
||||
}
|
||||
|
||||
void String::toLowercase() {
|
||||
makeUnique();
|
||||
for (uint32 i = 0; i < _len; ++i)
|
||||
for (uint32 i = 0; i < _size; ++i)
|
||||
_str[i] = tolower(_str[i]);
|
||||
}
|
||||
|
||||
void String::toUppercase() {
|
||||
makeUnique();
|
||||
for (uint32 i = 0; i < _len; ++i)
|
||||
for (uint32 i = 0; i < _size; ++i)
|
||||
_str[i] = toupper(_str[i]);
|
||||
}
|
||||
|
||||
void String::trim() {
|
||||
if (_len == 0)
|
||||
if (_size == 0)
|
||||
return;
|
||||
|
||||
makeUnique();
|
||||
|
||||
// Trim trailing whitespace
|
||||
while (_len >= 1 && isspace(_str[_len-1]))
|
||||
_len--;
|
||||
_str[_len] = 0;
|
||||
while (_size >= 1 && isspace(_str[_size-1]))
|
||||
_size--;
|
||||
_str[_size] = 0;
|
||||
|
||||
// Trim leading whitespace
|
||||
char *t = _str;
|
||||
|
@ -382,8 +382,8 @@ void String::trim() {
|
|||
t++;
|
||||
|
||||
if (t != _str) {
|
||||
_len -= t - _str;
|
||||
memmove(_str, t, _len + 1);
|
||||
_size -= t - _str;
|
||||
memmove(_str, t, _size + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
20
common/str.h
20
common/str.h
|
@ -61,7 +61,7 @@ protected:
|
|||
* a lot. Yes, we limit ourselves to strings shorter than 4GB --
|
||||
* on purpose :-).
|
||||
*/
|
||||
uint32 _len;
|
||||
uint32 _size;
|
||||
|
||||
/**
|
||||
* Pointer to the actual string storage. Either points to _storage,
|
||||
|
@ -97,7 +97,7 @@ public:
|
|||
#endif
|
||||
|
||||
/** Construct a new empty string. */
|
||||
String() : _len(0), _str(_storage) { _storage[0] = 0; }
|
||||
String() : _size(0), _str(_storage) { _storage[0] = 0; }
|
||||
|
||||
/** Construct a new string from the given NULL-terminated C string. */
|
||||
String(const char *str);
|
||||
|
@ -150,13 +150,13 @@ public:
|
|||
bool contains(char x) const;
|
||||
|
||||
inline const char *c_str() const { return _str; }
|
||||
inline uint size() const { return _len; }
|
||||
inline uint size() const { return _size; }
|
||||
|
||||
inline bool empty() const { return (_len == 0); }
|
||||
char lastChar() const { return (_len > 0) ? _str[_len-1] : 0; }
|
||||
inline bool empty() const { return (_size == 0); }
|
||||
char lastChar() const { return (_size > 0) ? _str[_size-1] : 0; }
|
||||
|
||||
char operator [](int idx) const {
|
||||
assert(_str && idx >= 0 && idx < (int)_len);
|
||||
assert(_str && idx >= 0 && idx < (int)_size);
|
||||
return _str[idx];
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,7 @@ public:
|
|||
|
||||
protected:
|
||||
void makeUnique();
|
||||
void ensureCapacity(uint32 new_len, bool keep_old);
|
||||
void ensureCapacity(uint32 new_size, bool keep_old);
|
||||
void incRefCount() const;
|
||||
void decRefCount(int *oldRefCount);
|
||||
void initWithCStr(const char *str, uint32 len);
|
||||
|
@ -230,13 +230,11 @@ extern char *trim(char *t);
|
|||
class StringList : public Array<String> {
|
||||
public:
|
||||
void push_back(const char *str) {
|
||||
ensureCapacity(_size + 1);
|
||||
_data[_size++] = str;
|
||||
Array<String>::push_back(str);
|
||||
}
|
||||
|
||||
void push_back(const String &str) {
|
||||
ensureCapacity(_size + 1);
|
||||
_data[_size++] = str;
|
||||
Array<String>::push_back(str);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue