/// <summary> /// Adds a string to the set if it does not already exist. /// </summary> /// <param name="chars">A pointer to the string you want to add.</param> /// <param name="count">The length of the string (in chars).</param> /// <param name="str">The string object representation of the characters. A new string is only allocated when it does not already exist in the set.</param> /// <param name="knownHashValue">(optional) If the StringHash has already been calculated, you can provide it here to save re-calculation.</param> /// <returns>True if the string was added. False if the string already existed in the set.</returns> public unsafe bool Add(char *chars, int count, out string str, StringHash knownHashValue = default(StringHash)) { if (knownHashValue == default(StringHash)) { knownHashValue = StringHash.GetHash(chars, count); } str = GetExistingString(chars, count, knownHashValue); if (str != null) { return(false); // didn't add anything } // an existing string wasn't found, we need to add it to the hash lock (_writeLock) { // first, check one more time to see if it exists str = GetExistingString(chars, count, knownHashValue); if (str == null) { // it definitely doesn't exist. Let's add it str = new string(chars, 0, count); AddImpl(str, knownHashValue); return(true); } return(false); } }
void AddImpl(string s, StringHash hash) { var data = _data; if (data.NextAvailableSlotIndex == data.Slots.Length) { Grow(); data = _data; } var slots = data.Slots; var buckets = data.Buckets; var bucket = hash.Value % slots.Length; var slotIndex = data.NextAvailableSlotIndex; data.NextAvailableSlotIndex++; slots[slotIndex].Value = s; slots[slotIndex].HashCode = hash; slots[slotIndex].Next = buckets[bucket] - 1; // The hash set would no longer be thread-safe on reads if somehow the bucket got reassigned before the slot was setup Thread.MemoryBarrier(); buckets[bucket] = slotIndex + 1; }
/// <summary> /// Adds a string to the set if it does not already exist. /// </summary> /// <param name="buffer">The character array which represents the string you want to add.</param> /// <param name="start">The index in the character array where your string starts.</param> /// <param name="count">The length of the string you want to add.</param> /// <param name="str">The string object representation of the characters. A new string is only allocated when it does not already exist in the set.</param> /// <param name="knownHashValue">(optional) If the StringHash has already been calculated, you can provide it here to save re-calculation.</param> /// <returns>True if the string was added. False if the string already existed in the set.</returns> public bool Add(char[] buffer, int start, int count, out string str, StringHash knownHashValue = default(StringHash)) { if (knownHashValue == default(StringHash)) { knownHashValue = StringHash.GetHash(buffer, start, count); } else { StringHash.AssertBufferArgumentsAreSane(buffer.Length, start, count); } str = GetExistingStringImpl(buffer, start, count, knownHashValue); if (str != null) { return(false); // didn't add anything } // an existing string wasn't found, we need to add it to the hash lock (_writeLock) { // first, check one more time to see if it exists str = GetExistingStringImpl(buffer, start, count, knownHashValue); if (str == null) { // it definitely doesn't exist. Let's add it str = new string(buffer, start, count); AddImpl(str, knownHashValue); return(true); } return(false); } }
/// <summary> /// Uses the characters from a buffer to check whether a string exists in the set, and retrieve it if so. /// </summary> /// <param name="buffer">The character array which represents the string you want to check for.</param> /// <param name="start">The index in the character array where your string starts.</param> /// <param name="count">The length of the string you want to check for.</param> /// <param name="knownHashValue">(optional) If the StringHash has already been calculated, you can provide it here to save re-calculation.</param> /// <returns>If found in the set, the existing string is returned. If not found, null is returned.</returns> public string GetExistingString(char[] buffer, int start, int count, StringHash knownHashValue = default(StringHash)) { if (knownHashValue == default(StringHash)) { knownHashValue = StringHash.GetHash(buffer, start, count); } else { StringHash.AssertBufferArgumentsAreSane(buffer.Length, start, count); } return(GetExistingStringImpl(buffer, start, count, knownHashValue)); }
bool ContainsString(string str, StringHash hash) { var cursor = GetSearchCursor(hash); while (cursor.MightHaveMore) { if (str == cursor.NextString()) { return(true); } } return(false); }
string GetExistingStringImpl(char[] buffer, int start, int length, StringHash hash) { var cursor = GetSearchCursor(hash); while (cursor.MightHaveMore) { var value = cursor.NextString(); if (value != null && UnsafeStringComparer.AreEqual(value, buffer, start, length)) { return(value); } } return(null); }
/// <summary> /// Returns a search cursor which allows you to iterate over every string in the set with the same StringHash. /// </summary> public StringSearchCursor GetSearchCursor(StringHash hash) { var data = _data; var cursor = new StringSearchCursor(); cursor.Slots = data.Slots; cursor.Hash = hash; var buckets = data.Buckets; var bucket = hash.Value % buckets.Length; cursor.SlotIndex = buckets[bucket] - 1; return(cursor); }
/// <summary> /// Uses the characters from a buffer to check whether a string exists in the set, and retrieve it if so. /// </summary> /// <param name="chars">A pointer to the string to search for.</param> /// <param name="count">The length of the string (in chars).</param> /// <param name="knownHashValue">(optional) If the StringHash has already been calculated, you can provide it here to save re-calculation.</param> /// <returns>If found in the set, the existing string is returned. If not found, null is returned.</returns> public unsafe string GetExistingString(char *chars, int count, StringHash knownHashValue = default(StringHash)) { if (knownHashValue == default(StringHash)) { knownHashValue = StringHash.GetHash(chars, count); } var cursor = GetSearchCursor(knownHashValue); while (cursor.MightHaveMore) { var value = cursor.NextString(); if (value != null && UnsafeStringComparer.AreEqual(value, chars, count)) { return(value); } } return(null); }
/// <summary> /// Adds a string to the set if it does not already exist. /// </summary> /// <param name="str">The string to add to the set.</param> /// <param name="knownHashValue">(optional) If the StringHash for str has already been calculated, you can provide it here to save re-calculation.</param> /// <returns>True if the string was added. False if the string already existed in the set.</returns> public bool Add(string str, StringHash knownHashValue = default(StringHash)) { if (knownHashValue == default(StringHash)) { knownHashValue = StringHash.GetHash(str); } if (!ContainsString(str, knownHashValue)) { lock (_writeLock) { if (!ContainsString(str, knownHashValue)) { AddImpl(str, knownHashValue); return(true); } } } return(false); }