/// <summary> /// Find item in segment. /// </summary> /// <param name="key">Reference to the search key to use.</param> /// <param name="item">Out reference to store the found item in.</param> /// <param name="traits">Object that tells this segment how to treat items and keys.</param> /// <returns>True if an item could be found, otherwise false.</returns> public bool FindItem(ref TSearch key, out TStored item, ConcurrentHashtable <TStored, TSearch> traits) { var searchHash = traits.GetKeyHashCode(ref key); var mask = (UInt32)(_List.Length - 1); var i = searchHash & mask; if (!traits.IsEmpty(ref _List[i])) { var firstHash = traits.GetItemHashCode(ref _List[i]); var storedItemHash = firstHash; var searchHashDiff = (searchHash - firstHash) & mask; do { if (storedItemHash == searchHash && traits.ItemEqualsKey(ref _List[i], ref key)) { item = _List[i]; return(true); } i = (i + 1) & mask; if (traits.IsEmpty(ref _List[i])) { break; } storedItemHash = traits.GetItemHashCode(ref _List[i]); }while (((storedItemHash - firstHash) & mask) <= searchHashDiff); } item = default(TStored); return(false); }
private void IncrementCount(ConcurrentHashtable <TStored, TSearch> traits) { var oldListLength = _List.Length; if (++_Count >= (oldListLength - (oldListLength >> 2))) { //Grow ResizeList(traits); } }
protected void DecrementCount(ConcurrentHashtable <TStored, TSearch> traits, int amount) { var oldListLength = _List.Length; _Count -= amount; if (oldListLength > 4 && _Count < (oldListLength >> 2)) { //Shrink ResizeList(traits); } }
/// <summary> /// Iterate over items in the segment. /// </summary> /// <param name="beyond">Position beyond which the next filled slot will be found and the item in that slot returned. (Starting with -1)</param> /// <param name="item">Out reference where the next item will be stored or default if the end of the segment is reached.</param> /// <param name="traits">Object that tells this segment how to treat items and keys.</param> /// <returns>The index position the next item has been found or -1 otherwise.</returns> public int GetNextItem(int beyond, out TStored item, ConcurrentHashtable <TStored, TSearch> traits) { for (int end = _List.Length; ++beyond < end;) { if (!traits.IsEmpty(ref _List[beyond])) { item = _List[beyond]; return(beyond); } } item = default(TStored); return(-1); }
/// <summary> /// Inserts an item into a *not empty* spot given by position i. It moves items forward until an empty spot is found. /// </summary> /// <param name="mask"></param> /// <param name="i"></param> /// <param name="itemCopy"></param> /// <param name="traits"></param> private void InsertItemAtIndex(UInt32 mask, UInt32 i, TStored itemCopy, ConcurrentHashtable <TStored, TSearch> traits) { do { //swap TStored temp = _List[i]; _List[i] = itemCopy; itemCopy = temp; i = (i + 1) & mask; }while (!traits.IsEmpty(ref _List[i])); _List[i] = itemCopy; }
public void Clear(ConcurrentHashtable <TStored, TSearch> traits) { var oldList = _List; _List = new TStored[4]; var effect = _List.Length - oldList.Length; if (effect != 0) { traits.EffectTotalAllocatedSpace(effect); } _Count = 0; }
protected void RemoveAtIndex(UInt32 index, ConcurrentHashtable <TStored, TSearch> traits) { var mask = (UInt32)(_List.Length - 1); var i = index; var j = (index + 1) & mask; while (!traits.IsEmpty(ref _List[j]) && (traits.GetItemHashCode(ref _List[j]) & mask) != j) { _List[i] = _List[j]; i = j; j = (j + 1) & mask; } _List[i] = default(TStored); }
/// <summary> /// Inserts an item in the segment, possibly replacing an equal existing item. /// </summary> /// <param name="key">A reference to the item to insert.</param> /// <param name="item">An out reference where any replaced item will be written to, if no item was replaced the new item will be written to this reference.</param> /// <param name="traits">Object that tells this segment how to treat items and keys.</param> /// <returns>True if an existing item could be found and is replaced, otherwise false.</returns> public bool InsertItem(ref TStored key, out TStored item, ConcurrentHashtable <TStored, TSearch> traits) { var searchHash = traits.GetItemHashCode(ref key); var mask = (UInt32)(_List.Length - 1); var i = searchHash & mask; if (!traits.IsEmpty(ref _List[i])) { var firstHash = traits.GetItemHashCode(ref _List[i]); var storedItemHash = firstHash; var searchHashDiff = (searchHash - firstHash) & mask; while (true) { if (storedItemHash == searchHash && traits.ItemEqualsItem(ref _List[i], ref key)) { item = _List[i]; _List[i] = key; return(true); } i = (i + 1) & mask; if (traits.IsEmpty(ref _List[i])) { break; } storedItemHash = traits.GetItemHashCode(ref _List[i]); if (((storedItemHash - firstHash) & mask) > searchHashDiff) { //insert InsertItemAtIndex(mask, i, key, traits); IncrementCount(traits); item = key; return(false); } } } item = _List[i] = key; IncrementCount(traits); return(false); }
/// <summary> /// When segment gets removed from hashtable then its allocated space should be subtracted to the /// total allocated space. /// Single threaded access or locking is needed /// </summary> /// <param name="traits"></param> public void Bye(ConcurrentHashtable <TStored, TSearch> traits) { traits.EffectTotalAllocatedSpace(-_List.Length); _List = null; }
/// <summary> /// When segment gets introduced into hashtable then its allocated space should be added to the /// total allocated space. /// Single threaded access or locking is needed /// </summary> /// <param name="traits"></param> public void Welcome(ConcurrentHashtable <TStored, TSearch> traits) { traits.EffectTotalAllocatedSpace(_List.Length); }
/// <summary> /// Remove any excess allocated space /// </summary> /// <param name="traits"></param> internal void Trim(ConcurrentHashtable <TStored, TSearch> traits) { DecrementCount(traits, 0); }
protected void DecrementCount(ConcurrentHashtable <TStored, TSearch> traits) { DecrementCount(traits, 1); }
protected virtual void ResizeList(ConcurrentHashtable <TStored, TSearch> traits) { var oldList = _List; var oldListLength = oldList.Length; var newListLength = 2; while (newListLength < _Count) { newListLength <<= 1; } newListLength <<= 1; if (newListLength != oldListLength) { _List = new TStored[newListLength]; var mask = (UInt32)(newListLength - 1); for (int i = 0; i != oldListLength; ++i) { if (!traits.IsEmpty(ref oldList[i])) { var searchHash = traits.GetItemHashCode(ref oldList[i]); //j is prefered insertion pos in new list. var j = searchHash & mask; if (traits.IsEmpty(ref _List[j])) { _List[j] = oldList[i]; } else { var firstHash = traits.GetItemHashCode(ref _List[j]); var storedItemHash = firstHash; var searchHashDiff = (searchHash - firstHash) & mask; while (true) { j = (j + 1) & mask; if (traits.IsEmpty(ref _List[j])) { _List[j] = oldList[i]; break; } storedItemHash = traits.GetItemHashCode(ref _List[j]); if (((storedItemHash - firstHash) & mask) > searchHashDiff) { InsertItemAtIndex(mask, j, oldList[i], traits); break; } } } } } traits.EffectTotalAllocatedSpace(newListLength - oldListLength); } }