class PtrHashSet : public bslalg::HashTableAnchor {
typedef bsls::Types::UintPtr UintPtr;
typedef bslalg::BidirectionalNode<void *> Node;
typedef bslalg::HashTableBucket Bucket;
typedef bslalg::BidirectionalLinkListUtil Util;
double d_maxLoadFactor;
unsigned d_numNodes;
bslma::Allocator *d_allocator_p;
void grow();
bool checkInvariants() const;
bool find(Node **node, Bucket **bucket, const void *ptr) const;
private:
PtrHashSet(const PtrHashSet&, bslma::Allocator *);
PtrHashSet& operator=(const PtrHashSet&);
public:
explicit
PtrHashSet(bslma::Allocator *allocator = 0);
~PtrHashSet();
bool insert(void *ptr);
bool erase(void *ptr);
std::size_t count(void *ptr) const;
std::size_t size() const;
};
void PtrHashSet::grow()
{
std::size_t newBucketArraySize = bucketArraySize() * 2 + 1;
std::size_t newBucketArraySizeInBytes =
newBucketArraySize * sizeof(Bucket);
memset(bucketArrayAddress(), 0x5a, size() * sizeof(Bucket));
d_allocator_p->deallocate(bucketArrayAddress());
setBucketArrayAddressAndSize(
(Bucket *) d_allocator_p->allocate(newBucketArraySizeInBytes),
newBucketArraySize);
memset(bucketArrayAddress(), 0, newBucketArraySizeInBytes);
Node *newListRootAddress = 0;
unsigned numNodes = 0;
for (Node *node = (Node *) listRootAddress(); node; ++numNodes) {
Node *rippedOut = node;
node = (Node *) node->nextLink();
std::size_t index =
(UintPtr) rippedOut->value() % bucketArraySize();
Bucket& bucket = bucketArrayAddress()[index];
if (bucket.first()) {
if (0 == bucket.first()->previousLink()) {
newListRootAddress = rippedOut;
}
Util::insertLinkBeforeTarget(rippedOut, bucket.first());
bucket.setFirst(rippedOut);
}
else {
Util::insertLinkBeforeTarget(rippedOut,
newListRootAddress);
newListRootAddress = rippedOut;
bucket.setFirstAndLast(rippedOut, rippedOut);
}
}
assert(size() == numNodes);
setListRootAddress(newListRootAddress);
checkInvariants();
}
bool PtrHashSet::checkInvariants() const
{
bool ok;
unsigned numNodes = 0;
Node *prev = 0;
for (Node *node = (Node *) listRootAddress(); node;
prev = node, node = (Node *) node->nextLink()) {
ok = node->previousLink() == prev;
assert(ok && "node->previousLink() == prev");
if (!ok) return false;
++numNodes;
}
ok = size() == numNodes;
assert(ok && "size() == numNodes");
if (!ok) return false;
numNodes = 0;
for (unsigned i = 0; i < bucketArraySize(); ++i) {
Bucket& bucket = bucketArrayAddress()[i];
if (bucket.first()) {
++numNodes;
for (Node *node = (Node *) bucket.first();
bucket.last() != node;
node = (Node *) node->nextLink()) {
++numNodes;
}
}
else {
ok = !bucket.last();
assert(ok && "!bucket.last()");
if (!ok) return false;
}
}
ok = size() == numNodes;
assert(ok && "size() == numNodes");
return ok;
}
bool PtrHashSet::find(Node **node, Bucket **bucket, const void *ptr) const
{
Node *dummyNodePtr;
Bucket *dummyBucketPtr;
if (!node ) node = &dummyNodePtr;
if (!bucket) bucket = &dummyBucketPtr;
Node *& nodePtrRef = *node;
unsigned index = (UintPtr) ptr % bucketArraySize();
Bucket& bucketRef = bucketArrayAddress()[index];
*bucket = &bucketRef;
if (bucketRef.first()) {
Node *begin = (Node *) bucketRef.first();
Node * const end = (Node *) bucketRef.last()->nextLink();
for (Node *n = begin; end != n; n = (Node *) n->nextLink()) {
if (n->value() == ptr) {
nodePtrRef = n;
return true;
}
}
nodePtrRef = begin;
return false;
}
nodePtrRef = (Node *) listRootAddress();
return false;
}
PtrHashSet::PtrHashSet(bslma::Allocator *allocator)
: HashTableAnchor(0, 0, 0)
, d_maxLoadFactor(0.4)
, d_numNodes(0)
{
enum { NUM_BUCKETS = 3 };
d_allocator_p = bslma::Default::allocator(allocator);
std::size_t bucketArraySizeInBytes = NUM_BUCKETS * sizeof(Bucket);
setBucketArrayAddressAndSize(
(Bucket *) d_allocator_p->allocate(bucketArraySizeInBytes),
NUM_BUCKETS);
memset(bucketArrayAddress(), 0, bucketArraySizeInBytes);
}
PtrHashSet::~PtrHashSet()
{
BSLS_ASSERT_SAFE(checkInvariants());
for (Node *node = (Node *) listRootAddress(); node; ) {
Node *toDelete = node;
node = (Node *) node->nextLink();
memset(toDelete, 0x5a, sizeof(*toDelete));
d_allocator_p->deallocate(toDelete);
}
d_allocator_p->deallocate(bucketArrayAddress());
}
bool PtrHashSet::erase(void *ptr)
{
Bucket *bucket;
Node *node;
if (!find(&node, &bucket, ptr)) {
return false;
}
if (bucket->first() == node) {
if (bucket->last() == node) {
bucket->reset();
}
else {
bucket->setFirst(node->nextLink());
}
}
else if (bucket->last() == node) {
bucket->setLast(node->previousLink());
}
--d_numNodes;
Util::unlink(node);
d_allocator_p->deallocate(node);
checkInvariants();
return true;
}
bool PtrHashSet::insert(void *ptr)
{
Bucket *bucket;
Node *insertionPoint;
if (find(&insertionPoint, &bucket, ptr)) {
return false;
}
if (bucketArraySize() * d_maxLoadFactor < d_numNodes + 1) {
grow();
bool found = find(&insertionPoint, &bucket, ptr);
BSLS_ASSERT_SAFE(!found);
}
++d_numNodes;
Node *node = (Node *) d_allocator_p->allocate(sizeof(Node));
Util::insertLinkBeforeTarget(node, insertionPoint);
node->value() = ptr;
if (listRootAddress() == insertionPoint) {
BSLS_ASSERT_SAFE(0 == node->previousLink());
setListRootAddress(node);
}
if (bucket->first()) {
BSLS_ASSERT_SAFE(bucket->first() == insertionPoint);
bucket->setFirst(node);
}
else {
BSLS_ASSERT_SAFE(!bucket->last());
bucket->setFirstAndLast(node, node);
}
assert(count(ptr));
checkInvariants();
return true;
}
std::size_t PtrHashSet::count(void *ptr) const
{
return find(0, 0, ptr);
}
std::size_t PtrHashSet::size() const
{
return d_numNodes;
}
Then, in if (verbose) {
printf("sevens = %u, killed = %u, phs.size() = %u\n", sevens,
killed, (unsigned) phs.size());
}
Now, we iterate through every element of the