C++程序  |  327行  |  8.51 KB

//===- 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;
}