blob: 9e1076faf8c7e88b636af818e1f3fbe542294ea1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Roman S. Bushmanov
*/
#if !defined(__SIMPLE_HASH_TABLE_H_)
#define __SIMPLE_HASH_TABLE_H_
#include <memory.h>
struct PairEntry{
PairEntry(void* key_, int value_, void *value1_ = NULL):
key(key_), value1(value1_), value(value_), next(NULL){
}
void *key;
void *value1;
int value;
PairEntry *next;
};
struct SimpleHashtable{
public:
SimpleHashtable(int bkt_count_): bkt_count(bkt_count_), _size(0), iter(NULL){
buckets = new PairEntry*[bkt_count];
memset((void*)buckets, 0, bkt_count*sizeof(void*));
}
~SimpleHashtable()
{
PairEntry *pe, *pe_tmp;
for (int i = 0; i < bkt_count; i++)
{
pe = buckets[i];
while (pe != NULL)
{
pe_tmp = pe;
pe = pe->next;
delete pe_tmp;
}
}
delete[] buckets;
}
short hash(void* key){
// For 32-bit architectures k3 & k4 will be 0 and have no effect on the hash
// Avoid compilation warnings on IA-32 Linux.
uint16 k1 = (uint16)(((POINTER_SIZE_INT)key >> 0) & 0xFFFF);
uint16 k2 = (uint16)(((POINTER_SIZE_INT)key >> 16) & 0xFFFF);
#ifdef _IPF_
uint16 k3 = (uint16)(((POINTER_SIZE_INT)key >> 32) & 0xFFFF);
uint16 k4 = (uint16)(((POINTER_SIZE_INT)key >> 48) & 0xFFFF);
uint16 index = k1 ^ k2 ^ k3 ^ k4;
#else // !_IPF_
uint16 index = (uint16)(k1 ^ k2 ^ 0 ^ 0);
#endif // !_IPF_
uint16 hash = (uint16)(index % bkt_count);
assert(hash<bkt_count); // Alexei hash is unsigned, so it is positive
return hash;
} //hash
void add(void* key, int value = 1, void* value1 = NULL){
short index = hash(key);
if (buckets[index] == NULL){
PairEntry *pe = new PairEntry(key, value, value1);
++_size;
buckets[index] = pe;
}else{
PairEntry *pe0 = NULL, *pe = buckets[index];
while (pe != NULL){
if (pe->key == key)
break;
pe0 = pe;
pe = pe->next;
}
if (pe != NULL)
pe->value += value;
else{
pe = new PairEntry(key, value, value1);
++_size;
pe0->next = pe;
}
}
} //add
bool lookup(void* key, int *value_ptr, void** value1_ptr) {
short index = hash(key);
*value_ptr = 0;
*value1_ptr = NULL;
if (buckets[index] == NULL) {
return false;
} else {
PairEntry *pe = buckets[index];
while (pe != NULL) {
if (pe->key == key) {
break;
}
pe = pe->next;
}
if (pe != NULL) {
*value_ptr = pe->value;
*value1_ptr = pe->value1;
return true;
} else {
return false;
}
}
} //lookup
int* lookup_or_add(void* key, int init_value, void* init_value1)
{
short index = hash(key);
if (!buckets[index]) {
PairEntry *pe = new PairEntry(key, init_value, init_value1);
++_size;
buckets[index] = pe;
return &pe->value;
} else {
PairEntry *pe0 = NULL, *pe = buckets[index];
while (pe) {
if (pe->key == key)
break;
pe0 = pe;
pe = pe->next;
}
if (!pe) {
pe = new PairEntry(key, init_value, init_value1);
++_size;
pe0->next = pe;
}
return &pe->value;
}
}
class Iterator{
public:
Iterator(SimpleHashtable *owner_):
owner(owner_), cursor(NULL), curidx(-1){
}
PairEntry* next(){
if (cursor == NULL){
++curidx;
for (; curidx < owner->bkt_count; curidx++)
if (owner->buckets[curidx] != NULL)
break;
if (curidx == owner->bkt_count)
return NULL;
cursor = owner->buckets[curidx];
}
PairEntry* ret = cursor;
cursor = cursor->next;
return ret;
}
void reset() {
cursor = NULL;
curidx = -1;
}
private:
SimpleHashtable *owner;
PairEntry *cursor;
int curidx;
};
friend class Iterator;
Iterator *iterator(){
if (iter == NULL)
iter = new Iterator(this);
return iter;
}
int size() { return _size; }
private:
PairEntry** buckets;
int bkt_count;
int _size;
Iterator *iter;
};
inline void swap(void*& a, void*& b)
{
void *t = a;
a = b;
b = t;
}
inline void quick_sort(PairEntry* _list[], int left, int right)
{
int pivot, left_arrow, right_arrow;
left_arrow = left;
right_arrow = right;
pivot = _list[(left + right)/2]->value;
do
{
while (_list[right_arrow]->value > pivot)
right_arrow--;
while (_list[left_arrow]->value < pivot)
left_arrow++;
if (left_arrow <= right_arrow)
{
swap((void*&)_list[left_arrow], (void*&)_list[right_arrow]);
left_arrow++;
right_arrow--;
}
}
while (right_arrow >= left_arrow);
if (left < right_arrow)
quick_sort(_list, left, right_arrow);
if (left_arrow < right)
quick_sort(_list, left_arrow, right);
}
inline bool dump(SimpleHashtable &sht, PairEntry **buffer, int &len, int threshold)
{
if (sht.size() > len) return false;
SimpleHashtable::Iterator *iter = sht.iterator();
iter->reset();
PairEntry *pe;
len = 0;
while((pe = iter->next()) != NULL){
if (pe->value < threshold)continue;
buffer[len++] = pe;
}
return true;
}
#endif