//===- HashTableTest.cpp --------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "HashTableTest.h"
#include <mcld/ADT/HashEntry.h>
#include <mcld/ADT/HashTable.h>
#include <cstdlib>
using namespace std;
using namespace mcld;
using namespace mcldtest;
// Constructor can do set-up work for all test here.
HashTableTest::HashTableTest()
{
}
// Destructor can do clean-up work that doesn't throw exceptions here.
HashTableTest::~HashTableTest()
{
}
// SetUp() will be called immediately before each test.
void HashTableTest::SetUp()
{
}
// TearDown() will be called immediately after each test.
void HashTableTest::TearDown()
{
}
//==========================================================================//
// Testcases
//
struct IntCompare
{
bool operator()(int X, int Y) const
{ return (X==Y); }
};
struct PtrCompare
{
bool operator()(const int* X, const int* Y) const
{ return (X==Y); }
};
struct PtrHash
{
size_t operator()(const int* pKey) const
{
return (unsigned((uintptr_t)pKey) >> 4) ^
(unsigned((uintptr_t)pKey) >> 9);
}
};
struct IntHash
{
size_t operator()(int pKey) const
{ return pKey; }
};
struct IntMod3Hash
{
size_t operator()(int pKey) const
{ return pKey % 3; }
};
TEST_F( HashTableTest, ptr_entry ) {
int A = 1;
int* pA = &A;
typedef HashEntry<int*, int, PtrCompare> HashEntryType;
typedef HashTable<HashEntryType, PtrHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy(0);
bool exist;
HashTableTy::entry_type* entry = 0;
entry = hashTable->insert(pA, exist);
EXPECT_FALSE(hashTable->empty());
HashTableTy::iterator iter;
iter = hashTable->find(NULL);
EXPECT_TRUE(iter==hashTable->end());
delete hashTable;
}
TEST_F( HashTableTest, constructor ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > hashTable(16);
EXPECT_TRUE(17 == hashTable.numOfBuckets());
EXPECT_TRUE(hashTable.empty());
EXPECT_TRUE(0 == hashTable.numOfEntries());
}
TEST_F( HashTableTest, allocattion ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy(22);
bool exist;
int key = 100;
HashTableTy::entry_type* val = hashTable->insert(key, exist);
val->setValue(999);
EXPECT_FALSE(hashTable->empty());
EXPECT_FALSE(exist);
EXPECT_FALSE(NULL == val);
HashTableTy::iterator entry = hashTable->find(key);
EXPECT_EQ(999, entry.getEntry()->value());
delete hashTable;
}
TEST_F( HashTableTest, alloc100 ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy(22);
bool exist;
HashTableTy::entry_type* entry = 0;
for (int key=0; key<100; ++key) {
entry = hashTable->insert(key, exist);
EXPECT_FALSE(hashTable->empty());
EXPECT_FALSE(exist);
EXPECT_FALSE(NULL == entry);
EXPECT_TRUE(key == entry->key());
entry->setValue(key+10);
}
EXPECT_FALSE(hashTable->empty());
EXPECT_TRUE(100 == hashTable->numOfEntries());
EXPECT_TRUE(197 == hashTable->numOfBuckets());
delete hashTable;
}
TEST_F( HashTableTest, erase100 ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy(0);
bool exist;
HashTableTy::entry_type* entry = 0;
for (unsigned int key=0; key<100; ++key)
entry = hashTable->insert(key, exist);
EXPECT_FALSE(hashTable->empty());
int count;
HashTableTy::iterator iter;
for (unsigned int key=0; key<100; ++key) {
count = hashTable->erase(key);
EXPECT_EQ(1, count);
iter = hashTable->find(key);
EXPECT_TRUE(iter == hashTable->end());
}
EXPECT_TRUE(hashTable->empty());
delete hashTable;
}
TEST_F( HashTableTest, clear) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy(22);
bool exist;
HashTableTy::entry_type* entry = 0;
for (unsigned int key=0; key<100; ++key) {
entry = hashTable->insert(key, exist);
}
hashTable->clear();
HashTableTy::iterator iter;
for (unsigned int key=0; key<100; ++key) {
iter = hashTable->find(key);
EXPECT_TRUE(iter == hashTable->end());
}
EXPECT_TRUE(hashTable->empty());
delete hashTable;
}
TEST_F( HashTableTest, tombstone ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntMod3Hash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy();
bool exist;
HashTableTy::entry_type* entry = 0;
for (unsigned int key=0; key<100; ++key) {
entry = hashTable->insert(key, exist);
}
EXPECT_FALSE(hashTable->empty());
int count;
HashTableTy::iterator iter;
for (unsigned int key=0; key<20; ++key) {
count = hashTable->erase(key);
EXPECT_EQ(1, count);
iter = hashTable->find(key);
EXPECT_TRUE(iter == hashTable->end());
}
EXPECT_TRUE(80 == hashTable->numOfEntries());
for (unsigned int key=20; key<100; ++key) {
iter = hashTable->find(key);
EXPECT_TRUE(iter != hashTable->end());
}
for (unsigned int key=0; key<20; ++key) {
entry = hashTable->insert(key, exist);
}
EXPECT_TRUE(100 == hashTable->numOfEntries());
EXPECT_TRUE(197 == hashTable->numOfBuckets());
delete hashTable;
}
TEST_F( HashTableTest, rehash_test ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy(0);
bool exist;
HashTableTy::entry_type* entry = 0;
for (unsigned int key=0; key<400000; ++key) {
entry = hashTable->insert(key, exist);
entry->setValue(key+10);
}
HashTableTy::iterator iter;
for (int key=0; key<400000; ++key) {
iter = hashTable->find(key);
EXPECT_EQ((key+10), iter.getEntry()->value());
}
delete hashTable;
}
TEST_F( HashTableTest, bucket_iterator ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy(0);
bool exist;
HashTableTy::entry_type* entry = 0;
for (unsigned int key=0; key<400000; ++key) {
entry = hashTable->insert(key, exist);
entry->setValue(key+10);
}
HashTableTy::iterator iter, iEnd = hashTable->end();
int counter = 0;
for (iter = hashTable->begin(); iter != iEnd; ++iter) {
EXPECT_EQ(iter.getEntry()->key()+10, iter.getEntry()->value());
++counter;
}
EXPECT_EQ(400000, counter);
delete hashTable;
}
TEST_F( HashTableTest, chain_iterator_single ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy();
bool exist;
HashTableTy::entry_type* entry = 0;
for (int key=0; key<16; ++key) {
entry = hashTable->insert(key*37, exist);
entry->setValue(key+10);
}
for (int key=0; key<16; ++key) {
int counter = 0;
HashTableTy::chain_iterator iter, iEnd = hashTable->end(key*37);
for (iter = hashTable->begin(key*37); iter != iEnd; ++iter) {
EXPECT_EQ(key+10, iter.getEntry()->value());
++counter;
}
EXPECT_EQ(1, counter);
}
delete hashTable;
}
struct FixHash
{
size_t operator()(int pKey) const {
return 10;
}
};
TEST_F( HashTableTest, chain_iterator_list ) {
typedef HashEntry<int, int, IntCompare> HashEntryType;
typedef HashTable<HashEntryType, FixHash, EntryFactory<HashEntryType> > HashTableTy;
HashTableTy *hashTable = new HashTableTy();
bool exist;
HashTableTy::entry_type* entry = 0;
for (unsigned int key=0; key<16; ++key) {
entry = hashTable->insert(key, exist);
ASSERT_FALSE(exist);
entry->setValue(key);
}
ASSERT_TRUE(16 == hashTable->numOfEntries());
ASSERT_TRUE(37 == hashTable->numOfBuckets());
unsigned int key = 0;
int count = 0;
HashTableTy::chain_iterator iter, iEnd = hashTable->end(key);
for (iter = hashTable->begin(key); iter != iEnd; ++iter) {
count++;
}
ASSERT_EQ(16, count);
delete hashTable;
}