private void AddSharedEntry(int hashCode, SharedEntryValue e) { var arr = _sharedTableInst; int idx = SharedIdxFromHash(hashCode); // try finding an empty spot in the bucket // we use quadratic probing here // bucket positions are (n^2 + n)/2 relative to the masked hashcode int curIdx = idx; for (int i = 1; i < SharedBucketSize + 1; i++) { if (arr[curIdx].Entry == null) { idx = curIdx; goto foundIdx; } curIdx = (curIdx + i) & SharedSizeMask; } // or pick a random victim within the bucket range // and replace with new entry var i1 = NextRandom() & SharedBucketSizeMask; idx = (idx + ((i1 * i1 + i1) / 2)) & SharedSizeMask; foundIdx: arr[idx].HashCode = hashCode; Volatile.Write(ref arr[idx].Entry, e); }
private SharedEntryValue FindSharedEntry(char[] chars, int start, int len, int hashCode) { var arr = _sharedTableInst; int idx = SharedIdxFromHash(hashCode); SharedEntryValue e = null; // we use quadratic probing here // bucket positions are (n^2 + n)/2 relative to the masked hashcode for (int i = 1; i < SharedBucketSize + 1; i++) { e = arr[idx].Entry; int hash = arr[idx].HashCode; if (e != null) { if (hash == hashCode && StringTable.TextEquals(e.Text, chars, start, len)) { break; } // this is not e we are looking for e = null; } else { // once we see unfilled entry, the rest of the bucket will be empty break; } idx = (idx + i) & SharedSizeMask; } return(e); }
internal T FindItem(char[] chars, int start, int len, int hashCode) { // capture array to avoid extra range checks var arr = _localTable; var idx = LocalIdxFromHash(hashCode); var text = arr[idx].Text; if (text != null && arr[idx].HashCode == hashCode) { if (StringTable.TextEquals(text, chars, start, len)) { return(arr[idx].Item); } } SharedEntryValue e = FindSharedEntry(chars, start, len, hashCode); if (e != null) { // PERF: the following code does element-wise assignment of a struct // because current JIT produces better code compared to // arr[idx] = new LocalEntry(...) arr[idx].HashCode = hashCode; arr[idx].Text = e.Text; var tk = e.Item; arr[idx].Item = tk; return(tk); } return(null); }
internal void AddItem(char[] chars, int start, int len, int hashCode, T item) { var text = _strings.Add(chars, start, len); // add to the shared table first (in case someone looks for same item) var e = new SharedEntryValue(text, item); AddSharedEntry(hashCode, e); // add to the local table too var arr = _localTable; var idx = LocalIdxFromHash(hashCode); arr[idx].HashCode = hashCode; arr[idx].Text = text; arr[idx].Item = item; }