usage
#include "object.h"
#include "collections/HashSet.h"
#include "collections/Dictionary.h"
#include "gc/mempoll.h"
using nvm::collections::HashSet;
using nvm::collections::IEnumerator;
int main(int argc, char* argv[])
{
HashSet<int> sets;
for (int i = 1; i < 1024; i++)
{
sets.Add(i);
}
sets.Add(1024); // 模拟空间碰撞
sets.Add(0);
sets.Remove(6);
HashSet<int>::Enumerator enumerator = sets.GetEnumerator();
while (enumerator.MoveNext())
{
printf("%d\n", enumerator.GetCurrent());
}
return getchar();
}
HashSet.h
#ifndef HASHSET_H
#define HASHSET_H
#include "../object.h"
#include "../Array.h"
#include "../IDisposable.h"
#include "../Exception.h"
#include "../gc/mempoll.h"
#include "../Math.h"
#include "../threading/Interlocked.h"
#include "../utils/RuntimeHelpers.h"
#include "IEnumerator.h"
#include "LinkedList.h"
namespace nvm
{
namespace collections
{
template<typename T>
class HashSet :
public Object,
public IDisposable
{
private:
class Slot
{
public:
nvm::UInt32 hash;
Slot* next;
Slot* prev;
nvm::Boolean usage;
T data;
};
class Bucket
{
public:
Slot* slots;
};
volatile nvm::Int32 m_count;
nvm::Boolean m_disposed;
nvm::Int32 m_capacity;
Bucket* m_buckets;
Slot* m_first;
Slot* m_last;
volatile nvm::Int32 m_version;
nvm::Int32 m_slotcapacity;
nvm::Int32 GetBucketCount()
{
if (this->m_buckets == NULL)
{
return 0;
}
if (this->m_capacity <= 0)
{
return 0;
}
return this->m_capacity / m_slotcapacity;
}
Bucket* GetBucketObject(nvm::UInt32 hashcode)
{
if (m_buckets == NULL)
{
return NULL;
}
nvm::Int32 index = GetBucketIndex(hashcode);
if (index >= this->GetBucketCount())
{
return NULL;
}
return &m_buckets[index];
}
nvm::Boolean InternalAddElement(T& item)
{
if (this->m_disposed)
{
throw new ObjectDisposedException("this");
}
nvm::UInt32 hashcode = HashSet<T>::GetHashCode(item);
if (this->m_buckets == NULL)
{
this->EnlargeArrayCapacity(hashcode);
}
Bucket* bucket = this->GetBucketObject(hashcode);
if (bucket == NULL)
{
throw new InvalidOperationException("bucket");
}
Slot* slot = &bucket->slots[this->GetBucketSlotIndex(hashcode)];
if (!slot->usage)
{
slot->usage = true;
slot->data = item;
slot->prev = NULL;
slot->next = NULL;
slot->hash = hashcode;
if (this->m_last == NULL)
{
this->m_last = slot;
if (m_first == NULL)
{
m_first = m_last;
}
}
else
{
slot->prev = m_last;
m_last->next = slot;
this->m_last = slot;
}
this->m_count++;
return true;
}
else if (!nvm::utils::RuntimeHelpers::Equals(slot->data, item)) // 空间碰撞
{
if (slot->hash < hashcode) // negative -
{
this->EnlargeArrayCapacity(hashcode);
}
else // positive +
{
this->EnlargeArrayCapacity(slot->hash);
Bucket* bucket = this->GetBucketObject(slot->hash);
if (bucket == NULL)
{
throw new InvalidOperationException("bucket");
}
Slot* current = &bucket->slots[this->GetBucketSlotIndex(slot->hash)];
if (current == slot)
{
throw new InvalidOperationException("slot");
}
else
{
*current = *slot;
*slot = { 0 };
}
do // 粘合连接点
{
if (slot == this->m_first)
{
this->m_first = current;
}
if (slot == this->m_last)
{
this->m_last = current;
}
slot = current->prev;
if (slot != NULL)
{
slot->next = current;
}
slot = current->next;
if (slot != NULL)
{
slot->prev = current;
}
} while (0, 0);
}
return this->Add(item);
}
return false;
}
nvm::Int32 IncrementOperationVersion()
{
return nvm::threading::Interlocked::Increment(this->m_version);
}
protected:
nvm::Int32 GetBucketIndex(nvm::UInt32 hashcode)
{
if (m_capacity <= 0 || hashcode <= 0)
{
return 0;
}
return (nvm::Int32)((hashcode % m_capacity) / m_slotcapacity);
};
nvm::Int32 GetBucketSlotIndex(nvm::UInt32 hashcode)
{
if (m_capacity <= 0 || hashcode <= 0)
{
return 0;
}
return (nvm::Int32)(hashcode % m_slotcapacity);
}
virtual void EnlargeArrayCapacity(nvm::UInt32 conflict_hashcode)
{
nvm::Int32 capacity = this->GetCapacity();
if (capacity <= 0)
{
capacity = m_slotcapacity;
}
else
{
nvm::Int32 slotindex = (nvm::Int32)(conflict_hashcode % m_slotcapacity);
nvm::Int32 bucketcount = this->GetBucketCount();
while (capacity < ~(1 << 31))
{
if (capacity == 0)
{
break;
}
nvm::Int32 bucketindex = (nvm::Int32)((conflict_hashcode % capacity) /
m_slotcapacity);
if (bucketindex < bucketcount)
{
Bucket* bucket = this->GetBucketObject(bucketindex);
if (bucket != NULL && !bucket->slots[slotindex].usage)
{
break;
}
}
else if ((capacity / m_slotcapacity) > bucketindex)
{
break;
}
capacity *= 2;
}
if (capacity >= ~(1 << 31) || capacity < 0)
{
throw new OutOfMemoryException("this");
}
}
nvm::UInt32 currentbucketcount = (nvm::UInt32)(capacity / m_slotcapacity);
nvm::UInt32 originbucketcount = (nvm::UInt32)(this->GetCapacity() <= 0 ? 0 : this->GetCapacity() / m_slotcapacity);
if (currentbucketcount > originbucketcount)
{
nvm::UInt32 size = currentbucketcount * sizeof(Bucket);
Bucket* origin = m_buckets;
Bucket* current = (Bucket*)nvm::gc::mempoll::Alloc(size);
if (origin != NULL)
{
memcpy(current, origin, size);
nvm::gc::mempoll::Free((nvm::IntPtr)origin);
}
for (nvm::UInt32 i = originbucketcount; i < currentbucketcount; i++)
{
current[i].slots = new Slot[m_slotcapacity]; /*(Slot*)nvm::gc::mempoll::Alloc(size)*/;
}
this->m_buckets = current;
this->m_capacity = capacity;
}
}
public:
class Enumerator :
public Object,
public IEnumerator<T>
{
private:
HashSet<T>* m_set;
Slot* m_first;
Slot* m_last;
Slot* m_current;
nvm::Int32 m_version;
inline nvm::Int32 GetCurrentSetVersion()
{
return nvm::threading::Interlocked::Read(this->m_set->m_version);
}
inline void CheckVersionOrThrowException()
{
if (this->m_version != this->GetCurrentSetVersion())
{
throw new InvalidOperationException("version");
}
}
public:
Enumerator(HashSet<T>* set)
{
if (set == NULL)
{
throw new ArgumentNullException("set");
}
this->m_current = NULL;
this->m_first = NULL;
this->m_last = NULL;
this->m_set = set;
this->m_version = this->GetCurrentSetVersion();
this->Reset();
}
virtual nvm::Boolean MoveNext() override
{
this->CheckVersionOrThrowException();
if (this->m_current == NULL)
{
this->m_current = this->m_first;
}
else
{
this->m_current = this->m_current->next;
}
return this->m_current != NULL;
}
virtual void Reset() override
{
this->CheckVersionOrThrowException();
this->m_last = this->m_set->m_last;
this->m_first = this->m_set->m_first;
}
virtual T& GetCurrent() override
{
this->CheckVersionOrThrowException();
if (this->m_current == NULL)
{
throw new InvalidOperationException("this");
}
return this->m_current->data;
}
};
HashSet() : HashSet<T>(256)
{
}
HashSet(nvm::Int32 slot_capacity)
{
if (slot_capacity <= 0)
{
throw new ArgumentOutOfRangeException("slot_capacity");
}
this->m_disposed = false;
this->m_count = 0;
this->m_first = NULL;
this->m_last = NULL;
this->m_buckets = NULL;
this->m_capacity = 0;
this->m_slotcapacity = slot_capacity;
this->EnlargeArrayCapacity(0);
}
~HashSet()
{
this->Dispose();
}
virtual void Dispose() override
{
if (!this->m_disposed)
{
this->Clear();
this->m_disposed = true;
}
}
inline nvm::Int32 GetCount()
{
return this->m_count;
}
inline nvm::Int32 GetCapacity()
{
return this->m_capacity;
}
inline virtual void Clear()
{
if (!this->m_disposed)
{
this->IncrementOperationVersion();
Bucket* buckets = this->m_buckets;
if (buckets != NULL)
{
nvm::Int32 bucketcount = this->GetBucketCount();
for (nvm::Int32 i = 0; i < bucketcount; i++)
{
Bucket* bucket = &buckets[i];
if (bucket->slots != NULL) // 调用载荷的“析构泛型类”实例的析构函数
{
delete[] bucket->slots; /*nvm::gc::mempoll::Free((nvm::IntPtr)bucket->slots);*/
}
}
nvm::gc::mempoll::Free((nvm::IntPtr)buckets);
}
this->m_count = 0;
this->m_first = NULL;
this->m_last = NULL;
this->m_capacity = 0;
this->m_buckets = NULL;
}
}
inline virtual nvm::Boolean Contains(const T& item)
{
T out_;
return this->TryGetValue(item, out_);
}
inline virtual nvm::Boolean TryGetValue(const T& in_, T& out_)
{
T* r_ = (T*)std::addressof(out_);
nvm::Boolean c_ = this->TryGetValue(in_, r_);
if (r_ != NULL)
{
out_ = *r_;
}
else
{
nvm::utils::RuntimeHelpers::ZeroValue(out_);
}
return c_;
}
inline virtual nvm::Boolean TryGetValue(const T& in_, T*& out_)
{
nvm::utils::RuntimeHelpers::ZeroValue(out_);
if (this->m_disposed || this->m_buckets == NULL)
{
return false;
}
nvm::UInt32 hashcode = GetHashCode(in_);
Bucket* bucket = this->GetBucketObject(hashcode);
if (bucket == NULL)
{
return false;
}
nvm::Int32 slotindex = this->GetBucketSlotIndex(hashcode);
if (slotindex < 0)
{
return false;
}
Slot* slot = &bucket->slots[slotindex];
if (slot != NULL && slot->usage)
{
out_ = (T*)std::addressof(slot->data);
return true;
}
return false;
}
inline virtual nvm::Boolean Add(const T& item)
{
if (!this->InternalAddElement((T&)item))
{
return false;
}
else
{
this->IncrementOperationVersion();
}
return true;
}
inline virtual nvm::Boolean Remove(const T& item)
{
if (this->m_disposed)
{
throw new ObjectDisposedException("this");
}
if (this->m_buckets == NULL)
{
throw new InvalidOperationException("this");
}
nvm::Int32 hashcode = GetHashCode(item);
Bucket* bucket = this->GetBucketObject(hashcode);
if (bucket == NULL)
{
return false;
}
Slot* slot = &bucket->slots[this->GetBucketSlotIndex(hashcode)];
if (!slot->usage)
{
return false;
}
else
{
if (this->m_first == slot)
{
this->m_first = slot->next;
}
if (this->m_last == slot)
{
this->m_last = slot->prev;
}
Slot* prev_slot = slot->prev;
Slot* next_slot = slot->next;
if (prev_slot != NULL)
{
prev_slot->next = next_slot;
if (next_slot != NULL)
{
next_slot->prev = prev_slot;
}
}
if (next_slot != NULL)
{
next_slot->prev = prev_slot;
if (prev_slot != NULL)
{
prev_slot->next = next_slot;
}
}
memset(slot, 0, sizeof(Slot));
this->IncrementOperationVersion();
this->m_count--;
return true;
}
}
static nvm::Int32 GetHashCode(const T& item)
{
return nvm::utils::RuntimeHelpers::GetHashCode(item);
}
virtual Enumerator GetEnumerator()
{
if (this->m_disposed)
{
throw new ObjectDisposedException("this");
}
return Enumerator(this);
}
};
};
}
#endif