From 223df3fb9168796af50eadf9c1ed87cc1c9ec5e8 Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Fri, 5 Dec 2025 16:25:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=80=A7=E8=83=BD=E5=AE=B9?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Modules/ObjectPoolManager.cs | 1 + .../[Runtime]/Convention.Collections.cs | 982 ++++++++++++++++++ 2 files changed, 983 insertions(+) diff --git a/Convention/[Architecture]/Modules/ObjectPoolManager.cs b/Convention/[Architecture]/Modules/ObjectPoolManager.cs index 06916fb..8576ed0 100644 --- a/Convention/[Architecture]/Modules/ObjectPoolManager.cs +++ b/Convention/[Architecture]/Modules/ObjectPoolManager.cs @@ -109,6 +109,7 @@ namespace Convention.Experimental.Modules } else { + Debug.LogError("This object does not belong to any pool.", instance); throw new PublicType.GameException("This object does not belong to any pool."); } } diff --git a/Convention/[Runtime]/Convention.Collections.cs b/Convention/[Runtime]/Convention.Collections.cs index ec79408..cf7838f 100644 --- a/Convention/[Runtime]/Convention.Collections.cs +++ b/Convention/[Runtime]/Convention.Collections.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; +using Unity.Collections; namespace Convention.Collections { @@ -453,4 +454,985 @@ namespace Convention.Collections } } } + + namespace Cache + { + /// + /// Native LRUCache - 基于Unity.Collections的高性能最近最少使用缓存 + /// Burst兼容,需要手动Dispose + /// + /// 键类型(必须是unmanaged类型) + /// 值类型(必须是unmanaged类型) + public struct NativeLRUCache : IDisposable + where TKey : unmanaged, IEquatable + where TValue : unmanaged + { + // 链表节点 + private struct Node + { + public TKey key; + public TValue value; + public int prevIndex; // 前一个节点索引 + public int nextIndex; // 后一个节点索引 + } + + private NativeList nodes; // 节点池 + private readonly NativeHashMap hashMap; // key -> 节点索引 + private readonly NativeList freeList; // 空闲节点索引池 + + private readonly int capacity; + private int headIndex; // 链表头(最久未使用) + private int tailIndex; // 链表尾(最近使用) + private int count; + + // 是否为有效节点索引 + private readonly bool IsValidIndex(int index) => index >= 0; + + public NativeLRUCache(int capacity, Allocator allocator) + { + this.capacity = capacity; + this.count = 0; + this.headIndex = -1; + this.tailIndex = -1; + + hashMap = new NativeHashMap(capacity, allocator); + nodes = new NativeList(capacity, allocator); + freeList = new NativeList(capacity, allocator); + + // 预分配节点池 + nodes.Length = capacity; + for (int i = capacity - 1; i >= 0; i--) + { + freeList.Add(i); + } + } + + /// + /// 获取缓存值 + /// + public bool TryGetValue(TKey key, out TValue value) + { + if (hashMap.TryGetValue(key, out int nodeIndex)) + { + MoveToTail(nodeIndex); // 移动到尾部(最近使用) + value = nodes[nodeIndex].value; + return true; + } + + value = default; + return false; + } + + /// + /// 添加或更新缓存 + /// + public void Put(TKey key, TValue value) + { + // 已存在则更新并移动到尾部 + if (hashMap.TryGetValue(key, out int nodeIndex)) + { + Node node = nodes[nodeIndex]; + node.value = value; + nodes[nodeIndex] = node; + MoveToTail(nodeIndex); + return; + } + + // 容量已满,淘汰头部节点 + if (count >= capacity) + { + EvictHead(); + } + + // 创建新节点 + nodeIndex = AllocateNode(); + nodes[nodeIndex] = new Node + { + key = key, + value = value, + prevIndex = tailIndex, + nextIndex = -1 + }; + + hashMap.Add(key, nodeIndex); + AddToTail(nodeIndex); + count++; + } + + /// + /// 删除缓存项 + /// + public bool Remove(TKey key) + { + if (!hashMap.TryGetValue(key, out int nodeIndex)) + return false; + + hashMap.Remove(key); + RemoveFromList(nodeIndex); + FreeNode(nodeIndex); + count--; + return true; + } + + /// + /// 清空缓存 + /// + public void Clear() + { + hashMap.Clear(); + + // 重置所有节点到空闲列表 + freeList.Clear(); + for (int i = 0; i < capacity; i++) + { + freeList.Add(i); + } + + headIndex = -1; + tailIndex = -1; + count = 0; + } + + // 分配节点索引 + private readonly int AllocateNode() + { + int index = freeList[^1]; + freeList.RemoveAtSwapBack(freeList.Length - 1); + return index; + } + + // 释放节点索引 + private readonly void FreeNode(int index) + { + freeList.Add(index); + } + + // 将节点移动到链表尾部(标记为最近使用) + private void MoveToTail(int nodeIndex) + { + if (nodeIndex == tailIndex) + return; + + RemoveFromList(nodeIndex); + AddToTail(nodeIndex); + } + + // 将节点添加到尾部 + private void AddToTail(int nodeIndex) + { + Node node = nodes[nodeIndex]; + node.prevIndex = tailIndex; + node.nextIndex = -1; + nodes[nodeIndex] = node; + + if (IsValidIndex(tailIndex)) + { + Node tail = nodes[tailIndex]; + tail.nextIndex = nodeIndex; + nodes[tailIndex] = tail; + } + + tailIndex = nodeIndex; + + // 如果链表为空,头尾指向同一节点 + if (!IsValidIndex(headIndex)) + { + headIndex = nodeIndex; + } + } + + // 从链表中移除节点 + private void RemoveFromList(int nodeIndex) + { + Node node = nodes[nodeIndex]; + + // 更新前一个节点的next指针 + if (IsValidIndex(node.prevIndex)) + { + Node prev = nodes[node.prevIndex]; + prev.nextIndex = node.nextIndex; + nodes[node.prevIndex] = prev; + } + else + { + // 没有前一个节点,说明是头节点 + headIndex = node.nextIndex; + } + + // 更新后一个节点的prev指针 + if (IsValidIndex(node.nextIndex)) + { + Node next = nodes[node.nextIndex]; + next.prevIndex = node.prevIndex; + nodes[node.nextIndex] = next; + } + else + { + // 没有后一个节点,说明是尾节点 + tailIndex = node.prevIndex; + } + } + + // 淘汰头部节点(最久未使用) + private void EvictHead() + { + if (!IsValidIndex(headIndex)) return; + + int oldHead = headIndex; + Node headNode = nodes[oldHead]; + + hashMap.Remove(headNode.key); + headIndex = headNode.nextIndex; + + if (IsValidIndex(headIndex)) + { + Node newHead = nodes[headIndex]; + newHead.prevIndex = -1; + nodes[headIndex] = newHead; + } + else + { + tailIndex = -1; // 链表为空 + } + + FreeNode(oldHead); + count--; + } + + public void Dispose() + { + if (hashMap.IsCreated) hashMap.Dispose(); + if (nodes.IsCreated) nodes.Dispose(); + if (freeList.IsCreated) freeList.Dispose(); + + headIndex = -1; + tailIndex = -1; + count = 0; + } + + // 属性访问器 + public readonly int Count => count; + public readonly int Capacity => capacity; + public readonly bool IsCreated => hashMap.IsCreated; + } + + /// + /// Native LFUCache - 基于Unity.Collections的高性能最不频繁使用缓存 + /// Burst兼容,需要手动Dispose + /// + /// 键类型(必须是unmanaged类型) + /// 值类型(必须是unmanaged类型) + public struct NativeLFUCache : IDisposable + where TKey : unmanaged, IEquatable + where TValue : unmanaged + { + // 缓存节点 + private struct Node + { + public TKey key; + public TValue value; + public int frequency; // 访问频率 + public int prevIndex; // 同频率链表中的前一个节点 + public int nextIndex; // 同频率链表中的后一个节点 + } + + // 频率链表头尾 + private struct FrequencyList + { + public int headIndex; // 该频率链表的头节点(最久未使用) + public int tailIndex; // 该频率链表的尾节点(最近使用) + + public readonly bool IsEmpty => headIndex == -1; + } + + private readonly NativeHashMap keyToNodeIndex; // key -> nodeIndex + private NativeList nodes; // 节点池 + private readonly NativeList freeList; // 空闲节点索引 + private NativeHashMap freqToList; // frequency -> FrequencyList + + private readonly int capacity; + private int count; + private int minFrequency; // 当前最小频率 + + public NativeLFUCache(int capacity, Allocator allocator) + { + this.capacity = capacity; + this.count = 0; + this.minFrequency = 0; + + keyToNodeIndex = new NativeHashMap(capacity, allocator); + nodes = new NativeList(capacity, allocator); + freeList = new NativeList(capacity, allocator); + freqToList = new NativeHashMap(capacity, allocator); + + // 预分配节点池 + nodes.Length = capacity; + for (int i = capacity - 1; i >= 0; i--) + { + freeList.Add(i); + } + } + + /// + /// 获取缓存值并增加频率 + /// + public bool TryGetValue(TKey key, out TValue value) + { + if (keyToNodeIndex.TryGetValue(key, out int nodeIndex)) + { + // 增加访问频率 + IncreaseFrequency(nodeIndex); + + value = nodes[nodeIndex].value; + return true; + } + + value = default; + return false; + } + + /// + /// 添加或更新缓存 + /// + public void Put(TKey key, TValue value) + { + // 更新现有值 + if (keyToNodeIndex.TryGetValue(key, out int nodeIndex)) + { + Node node = nodes[nodeIndex]; + node.value = value; + nodes[nodeIndex] = node; + + IncreaseFrequency(nodeIndex); + return; + } + + // 容量已满,淘汰最小频率的节点 + if (count >= capacity) + { + EvictMinFrequencyNode(); + } + + // 创建新节点,初始频率为1 + nodeIndex = AllocateNode(); + nodes[nodeIndex] = new Node + { + key = key, + value = value, + frequency = 1, + prevIndex = -1, + nextIndex = -1 + }; + + keyToNodeIndex.Add(key, nodeIndex); + AddToFrequencyList(nodeIndex, 1); + + // 更新最小频率 + if (minFrequency == 0) + { + minFrequency = 1; + } + + count++; + } + + /// + /// 删除缓存项 + /// + public bool Remove(TKey key) + { + if (!keyToNodeIndex.TryGetValue(key, out int nodeIndex)) + return false; + + RemoveNode(nodeIndex); + return true; + } + + /// + /// 清空缓存 + /// + public void Clear() + { + keyToNodeIndex.Clear(); + freqToList.Clear(); + + // 重置所有节点到空闲列表 + freeList.Clear(); + for (int i = 0; i < capacity; i++) + { + freeList.Add(i); + } + + minFrequency = 0; + count = 0; + } + + /// + /// 释放所有内存 + /// + public void Dispose() + { + if (keyToNodeIndex.IsCreated) keyToNodeIndex.Dispose(); + if (nodes.IsCreated) nodes.Dispose(); + if (freeList.IsCreated) freeList.Dispose(); + if (freqToList.IsCreated) freqToList.Dispose(); + + minFrequency = 0; + count = 0; + } + + #region 内部辅助方法 + + private int AllocateNode() + { + int index = freeList[^1]; + freeList.RemoveAtSwapBack(freeList.Length - 1); + return index; + } + + private void FreeNode(int index) + { + freeList.Add(index); + } + + /// + /// 增加节点的访问频率 + /// + private void IncreaseFrequency(int nodeIndex) + { + Node node = nodes[nodeIndex]; + int oldFreq = node.frequency; + int newFreq = oldFreq + 1; + + // 从旧频率链表移除 + RemoveFromFrequencyList(nodeIndex, oldFreq); + + // 检查是否需要更新最小频率 + if (oldFreq == minFrequency && GetFrequencyListHead(oldFreq) == -1) + { + minFrequency = newFreq; + } + + // 更新节点频率 + node.frequency = newFreq; + nodes[nodeIndex] = node; + + // 添加到新频率链表 + AddToFrequencyList(nodeIndex, newFreq); + } + + /// + /// 从频率链表中移除节点 + /// + private void RemoveFromFrequencyList(int nodeIndex, int frequency) + { + if (!freqToList.TryGetValue(frequency, out var list)) + return; + + Node node = nodes[nodeIndex]; + + // 如果是头节点 + if (node.prevIndex == -1) + { + list.headIndex = node.nextIndex; + } + else + { + // 更新前一个节点的next指针 + Node prevNode = nodes[node.prevIndex]; + prevNode.nextIndex = node.nextIndex; + nodes[node.prevIndex] = prevNode; + } + + // 如果是尾节点 + if (node.nextIndex == -1) + { + list.tailIndex = node.prevIndex; + } + else + { + // 更新后一个节点的prev指针 + Node nextNode = nodes[node.nextIndex]; + nextNode.prevIndex = node.prevIndex; + nodes[node.nextIndex] = nextNode; + } + + // 如果链表变空,移除该频率 + if (list.headIndex == -1) + { + freqToList.Remove(frequency); + } + else + { + freqToList[frequency] = list; + } + } + + /// + /// 将节点添加到频率链表尾部 + /// + private void AddToFrequencyList(int nodeIndex, int frequency) + { + if (!freqToList.TryGetValue(frequency, out var list)) + { + // 创建新的频率链表 + list = new FrequencyList { headIndex = nodeIndex, tailIndex = nodeIndex }; + freqToList.Add(frequency, list); + + // 设置节点指针 + Node node = nodes[nodeIndex]; + node.prevIndex = -1; + node.nextIndex = -1; + nodes[nodeIndex] = node; + } + else + { + // 添加到链表尾部 + int oldTail = list.tailIndex; + + // 更新原尾节点 + Node oldTailNode = nodes[oldTail]; + oldTailNode.nextIndex = nodeIndex; + nodes[oldTail] = oldTailNode; + + // 设置新节点 + Node newNode = nodes[nodeIndex]; + newNode.prevIndex = oldTail; + newNode.nextIndex = -1; + nodes[nodeIndex] = newNode; + + // 更新链表尾 + list.tailIndex = nodeIndex; + freqToList[frequency] = list; + } + } + + /// + /// 获取频率链表的头节点 + /// + private int GetFrequencyListHead(int frequency) + { + if (freqToList.TryGetValue(frequency, out var list)) + { + return list.headIndex; + } + return -1; + } + + /// + /// 淘汰最小频率的节点(淘汰该频率链表的头节点) + /// + private void EvictMinFrequencyNode() + { + // 找到有节点的最小频率 + while (minFrequency <= capacity && GetFrequencyListHead(minFrequency) == -1) + { + minFrequency++; + } + + if (minFrequency > capacity) return; + + int headIndex = GetFrequencyListHead(minFrequency); + if (headIndex == -1) return; + + RemoveNode(headIndex); + } + + /// + /// 移除完整节点(从所有数据结构中删除) + /// + private void RemoveNode(int nodeIndex) + { + Node node = nodes[nodeIndex]; + + // 从频率链表移除 + RemoveFromFrequencyList(nodeIndex, node.frequency); + + // 从主HashMap移除 + keyToNodeIndex.Remove(node.key); + + // 回收节点 + FreeNode(nodeIndex); + count--; + } + + #endregion + + // 属性访问器 + public readonly int Count => count; + public readonly int Capacity => capacity; + public readonly bool IsCreated => keyToNodeIndex.IsCreated; + } + + public struct NativeARCCache : IDisposable + where TKey : unmanaged, IEquatable + where TValue : unmanaged + { + private const int LIST_T1 = 0, LIST_T2 = 1, LIST_B1 = 2, LIST_B2 = 3; + + private struct Node + { + public TKey key; + public TValue value; + public byte listType; + public int prevIndex; + public int nextIndex; + } + + private NativeHashMap keyToNode; + private NativeList nodes; + private NativeList freeList; + + // 四个链表头尾指针 + private int t1Head, t1Tail, t2Head, t2Tail, b1Head, b1Tail, b2Head, b2Tail; + + private int capacity, t1Count, t2Count, b1Count, b2Count, p; + + public NativeARCCache(int capacity, Allocator allocator) + { + this.capacity = capacity; + this.t1Count = this.t2Count = this.b1Count = this.b2Count = 0; + this.p = 0; + + t1Head = t1Tail = t2Head = t2Tail = -1; + b1Head = b1Tail = b2Head = b2Tail = -1; + + int totalNodes = capacity * 2; + keyToNode = new NativeHashMap(totalNodes, allocator); + nodes = new NativeList(totalNodes, allocator); + freeList = new NativeList(totalNodes, allocator); + + nodes.Length = totalNodes; + for (int i = totalNodes - 1; i >= 0; i--) + { + freeList.Add(i); + } + } + + public bool TryGetValue(TKey key, out TValue value) + { + if (keyToNode.TryGetValue(key, out int nodeIndex)) + { + Node node = nodes[nodeIndex]; // 先读取 + + if (node.listType == LIST_T1 || node.listType == LIST_T2) + { + MoveToMRU(nodeIndex, LIST_T2); + value = node.value; + return true; + } + + if (node.listType == LIST_B1) + { + node = ComputeNewPAndReplace(node, b2Count, b1Count, true); + b1Count--; t2Count++; + value = node.value; + return true; + } + + if (node.listType == LIST_B2) + { + node = ComputeNewPAndReplace(node, b1Count, b2Count, false); + b2Count--; t2Count++; + value = node.value; + return true; + } + } + + value = default; + return false; + } + + public void Put(TKey key, TValue value) + { + if (keyToNode.TryGetValue(key, out int nodeIndex)) + { + Node node = nodes[nodeIndex]; + node.value = value; + + if (node.listType == LIST_T1 || node.listType == LIST_T2) + { + MoveToMRU(nodeIndex, LIST_T2); + } + else if (node.listType == LIST_B1) + { + node = ComputeNewPAndReplace(node, b2Count, b1Count, true); + b1Count--; t2Count++; + } + else if (node.listType == LIST_B2) + { + node = ComputeNewPAndReplace(node, b1Count, b2Count, false); + b2Count--; t2Count++; + } + + nodes[nodeIndex] = node; // 写回 + return; + } + + // 容量满,执行Replace + int totalSize = t1Count + t2Count; + if (totalSize >= capacity) + { + Replace(); + } + + // 创建新节点到T1 + nodeIndex = AllocateNode(); + nodes[nodeIndex] = new Node + { + key = key, + value = value, + listType = LIST_T1, + prevIndex = -1, + nextIndex = -1 + }; + + keyToNode.Add(key, nodeIndex); + AddToHead(nodeIndex, LIST_T1); + t1Count++; + } + + private Node ComputeNewPAndReplace(Node node, int oppositeCount, int sameCount, bool isB1) + { + int delta = (oppositeCount >= sameCount) ? 1 : oppositeCount / sameCount + 1; + + // 先修改p值 + if (isB1) p = Math.Min(p + delta, capacity); + else p = Math.Max(p - delta, 0); + + // 执行替换 + Replace(); + + // 移动节点 + MoveBetweenLists(node.prevIndex, node.listType, LIST_T2); + node.listType = LIST_T2; + + return node; + } + + private void Replace() + { + if (t1Count > 0 && (t1Count > p || (b2Count > 0 && t1Count == p))) + { + MoveBetweenLists(t1Head, LIST_T1, LIST_B1); + t1Count--; b1Count++; + + if (b1Count > capacity) + { + int old = b1Head; Node n = nodes[old]; + RemoveFromList(old); + keyToNode.Remove(n.key); + FreeNode(old); + b1Count--; + } + } + else + { + MoveBetweenLists(t2Head, LIST_T2, LIST_B2); + t2Count--; b2Count++; + + if (b2Count > capacity) + { + int old = b2Head; Node n = nodes[old]; + RemoveFromList(old); + keyToNode.Remove(n.key); + FreeNode(old); + b2Count--; + } + } + } + + #region 链表操作 + + private void MoveToMRU(int nodeIndex, byte targetList) + { + RemoveFromList(nodeIndex); + AddToHead(nodeIndex, targetList); + } + + private void MoveBetweenLists(int nodeIndex, byte fromList, byte toList) + { + RemoveFromList(nodeIndex); + AddToHead(nodeIndex, toList); + } + + private void AddToHead(int nodeIndex, byte listType) + { + Node node = nodes[nodeIndex]; // 读取 + node.listType = listType; + node.prevIndex = -1; + + switch (listType) + { + case LIST_T1: + node.nextIndex = t1Head; + nodes[nodeIndex] = node; // 写回 + if (t1Head != -1) + { + Node headNode = nodes[t1Head]; + headNode.prevIndex = nodeIndex; + nodes[t1Head] = headNode; // 写回 + } + t1Head = nodeIndex; + if (t1Tail == -1) t1Tail = nodeIndex; + break; + + case LIST_T2: + node.nextIndex = t2Head; + nodes[nodeIndex] = node; // 写回 + if (t2Head != -1) + { + Node headNode = nodes[t2Head]; + headNode.prevIndex = nodeIndex; + nodes[t2Head] = headNode; // 写回 + } + t2Head = nodeIndex; + if (t2Tail == -1) t2Tail = nodeIndex; + break; + + case LIST_B1: + node.nextIndex = b1Head; + nodes[nodeIndex] = node; // 写回 + if (b1Head != -1) + { + Node headNode = nodes[b1Head]; + headNode.prevIndex = nodeIndex; + nodes[b1Head] = headNode; // 写回 + } + b1Head = nodeIndex; + if (b1Tail == -1) b1Tail = nodeIndex; + break; + + case LIST_B2: + node.nextIndex = b2Head; + nodes[nodeIndex] = node; // 写回 + if (b2Head != -1) + { + Node headNode = nodes[b2Head]; + headNode.prevIndex = nodeIndex; + nodes[b2Head] = headNode; // 写回 + } + b2Head = nodeIndex; + if (b2Tail == -1) b2Tail = nodeIndex; + break; + } + } + + private void RemoveFromList(int nodeIndex) + { + Node node = nodes[nodeIndex]; // 读取 + int prev = node.prevIndex; + int next = node.nextIndex; + + // 根据类型更新头尾指针 + switch (node.listType) + { + case LIST_T1: + if (nodeIndex == t1Head) t1Head = next; + if (nodeIndex == t1Tail) t1Tail = prev; + break; + case LIST_T2: + if (nodeIndex == t2Head) t2Head = next; + if (nodeIndex == t2Tail) t2Tail = prev; + break; + case LIST_B1: + if (nodeIndex == b1Head) b1Head = next; + if (nodeIndex == b1Tail) b1Tail = prev; + break; + case LIST_B2: + if (nodeIndex == b2Head) b2Head = next; + if (nodeIndex == b2Tail) b2Tail = prev; + break; + } + + // 更新邻居 + if (prev != -1) + { + Node prevNode = nodes[prev]; + prevNode.nextIndex = next; + nodes[prev] = prevNode; // 写回 + } + if (next != -1) + { + Node nextNode = nodes[next]; + nextNode.prevIndex = prev; + nodes[next] = nextNode; // 写回 + } + + node.prevIndex = node.nextIndex = -1; + nodes[nodeIndex] = node; // 写回 + } + + #endregion + + private int AllocateNode() + { + int index = freeList[^1]; + freeList.RemoveAtSwapBack(freeList.Length - 1); + return index; + } + + private void FreeNode(int index) + { + freeList.Add(index); + } + + public bool Remove(TKey key) + { + if (!keyToNode.TryGetValue(key, out int nodeIndex)) + return false; + + Node node = nodes[nodeIndex]; // 读取 + + // 更新计数 + if (node.listType == LIST_T1) t1Count--; + else if (node.listType == LIST_T2) t2Count--; + else if (node.listType == LIST_B1) b1Count--; + else if (node.listType == LIST_B2) b2Count--; + + RemoveFromList(nodeIndex); + keyToNode.Remove(key); + FreeNode(nodeIndex); + + return true; + } + + public void Clear() + { + keyToNode.Clear(); + + freeList.Clear(); + for (int i = 0; i < nodes.Length; i++) + { + freeList.Add(i); + } + + t1Head = t1Tail = t2Head = t2Tail = -1; + b1Head = b1Tail = b2Head = b2Tail = -1; + + t1Count = t2Count = b1Count = b2Count = 0; + p = 0; + } + + public void Dispose() + { + if (keyToNode.IsCreated) keyToNode.Dispose(); + if (nodes.IsCreated) nodes.Dispose(); + if (freeList.IsCreated) freeList.Dispose(); + + t1Head = t1Tail = t2Head = t2Tail = -1; + b1Head = b1Tail = b2Head = b2Tail = -1; + + t1Count = t2Count = b1Count = b2Count = 0; + p = 0; + } + + public int Count => t1Count + t2Count; + public int Capacity => capacity; + public bool IsCreated => keyToNode.IsCreated; + public int T1Count => t1Count; + public int T2Count => t2Count; + public int PValue => p; + } + } } \ No newline at end of file