#ifndef STRINGSET_H #define STRINGSET_H #include #include #include #include #ifdef __WXMSW__ #include #endif template class StringSetNode { public: StringSetNode(T *keyParameter, size_t lenParameter) { next = NULL; len = lenParameter; key = new T[len]; memcpy(key, keyParameter, len * sizeof(T)); } ~StringSetNode() { delete[] key; } StringSetNode *next; T *key; size_t len; }; template class StringSet { public: StringSet( int hashSizePower = 19 ); ~StringSet(); StringSet(const StringSet&); StringSet& operator=(const StringSet&); inline bool empty(); inline int count(); StringSetNode *insert(std::basic_string &s); StringSetNode *insert(T *s, size_t len, uint32_t hash = UINT_MAX); StringSetNode *find(std::basic_string &s); StringSetNode *find(T *s, size_t len, uint32_t hash = UINT_MAX); void clear(); private: bool emptyFlag; uint32_t hashSize, hashMask, nodeCount; StringSetNode **table; uint32_t hash(const char *s, size_t len); void allocateHashTable(uint32_t hashSize); }; template StringSet::StringSet(int hashSizePower) { if (hashSizePower < 1) throw std::runtime_error("StringSet: invalid parameter"); hashSize = (int)pow((double)2, (double)hashSizePower); hashMask = hashSize - 1; nodeCount = 0; allocateHashTable(hashSize); } template StringSet::~StringSet() { if (!empty()) clear(); delete[] table; } template StringSet::StringSet(const StringSet& d) { hashSize = d.hashSize; hashMask = hashSize - 1; nodeCount = 0; allocateHashTable(hashSize); StringSetNode *np; for (uint32_t i = 0; i < d.hashSize; ++i) for (np = d.table[i]; np != NULL; np = np->next) insert(np->key, np->len, i); } template StringSet& StringSet::operator=(const StringSet& d) { if (this != &d) { clear(); StringSetNode *np; for (uint32_t i = 0; i < d.hashSize; ++i) for (np = d.table[i]; np != NULL; np = np->next) insert(np->key, np->len, i); } return *this; } // see 'one-at-a-time hash' (http://burtleburtle.net/bob/hash/doobs.html) template uint32_t StringSet::hash(const char *key, size_t len) { uint32_t hash; for (hash = 0; len--; ++key) { hash += *key; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return (hash & hashMask); } template StringSetNode *StringSet::find(std::basic_string &s) { return find((T *)s.data(), s.size()); } template StringSetNode *StringSet::find(T *s, size_t len, uint32_t hashValue) { if (hashValue == UINT_MAX) hashValue = hash((const char*)s, len * sizeof(T)); StringSetNode *np; for (np = table[hashValue]; np != NULL; np = np->next) if (len == np->len && (memcmp(s, np->key, len) == 0)) return np; return NULL; } template StringSetNode *StringSet::insert(std::basic_string &s) { return insert((T *)s.data(), s.size()); } template StringSetNode *StringSet::insert(T *s, size_t len, uint32_t hashValue) { if (hashValue == UINT_MAX) hashValue = hash((const char*)s, len * sizeof(T)); StringSetNode *np; if ((np = find(s, len, hashValue)) == NULL) { np = new StringSetNode(s, len); np->next = table[hashValue]; table[hashValue] = np; ++nodeCount; } return np; } template void StringSet::clear() { if (!nodeCount) return; StringSetNode *np, *memory; for (uint32_t i = 0; i < hashSize; ++i) { for (np = table[i]; np != NULL; np = memory) { memory = np->next; delete np; } table[i] = NULL; } nodeCount = 0; } template int StringSet::count() { return nodeCount; } template bool StringSet::empty() { return (nodeCount) ? false : true; } template void StringSet::allocateHashTable(uint32_t hashSize) { table = new StringSetNode *[hashSize]; memset(table, 0, sizeof(StringSetNode *) * hashSize); } #endif