C/C++ nvm::collections::HashSet class -- shared

本文深入解析了HashSet数据结构的内部实现原理,包括其桶和槽的管理方式、元素的添加和删除过程,以及如何处理空间碰撞。同时,文章还详细介绍了HashSet的枚举器类,展示了如何遍历集合中的元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值