Пример #1
0
        /// <summary>
        /// Try to store the entry into its Hash2 location.  If that
        /// fails then kick the entry in Hash2 to that entry's Hash2
        /// location.  Recurse until we either find an empty Hash2 slot
        /// or try to kick an entry that is already in its Hash2
        /// location into its Hash2 location (which would cause an
        /// infinite loop).
        /// </summary>
        /// <param name="hashEntry">The hash entry to store.</param>
        /// <returns>true if the hash entry was stored at its Hash2
        /// location; false if storing the hash entry at its Hash2
        /// location would cause an infinite loop.</returns>
        private bool TryAssignAndKickOutIfNeeded(CuckooHashEntry hashEntry)
        {
            // Success is immediate if the Hash2 location is unused.
            if (!this.hashTable.ContainsKey(hashEntry.Hash2))
            {
                this.NumValuesStoredAtSecondHash++;
                this.hashTable[hashEntry.Hash2] = hashEntry;
                return(true);
            }

            // Get the kicked out entry and fail if we have already seen
            // that entry.
            var kickedOutEntry = this.hashTable[hashEntry.Hash2];

            if (kickedOutEntry.Seen)
            {
                return(false);
            }

            // Put the new word in the kicked out word's spot.
            this.hashTable[hashEntry.Hash2] = hashEntry;
            hashEntry.Seen = true;
            this.NumValuesStoredAtFirstHash--;
            this.NumValuesStoredAtSecondHash++;

            // Try to store the kicked out entry in its Hash2 location,
            // kicking out additional words as necessary.
            kickedOutEntry.Seen = true;
            return(this.TryAssignAndKickOutIfNeeded(kickedOutEntry));
        }
Пример #2
0
        /// <summary>
        /// Try to add a value to the hash table.  The hash functions
        /// must be rebuilt if the add operation fails (and assuming
        /// that you want to be able to add this value to the table).
        /// The table must be cleared after rebuilding the hash
        /// functions if the same CuckooHashTable object will be reused.
        /// </summary>
        /// <param name="value">The value to add to the hash
        /// table.</param>
        /// <returns>true if the value was added to the table; false if
        /// trying to add the value caused an infinite loop.</returns>
        public bool TryAddValue(TValue value)
        {
            // Wrap the value in a CuckooHashEntry.
            var hashEntry = new CuckooHashEntry(this.chf1(value), this.chf2(value), value);

            // Try to put the value in its first position.
            if (!this.hashTable.ContainsKey(hashEntry.Hash1))
            {
                this.hashTable[hashEntry.Hash1] = hashEntry;
                this.NumValuesStoredAtFirstHash++;
            }
            else
            {
                // We need to kick the entry in our Hash1 position into
                // its Hash2 position.  This could cause other entries
                // to be kicked out of position, which could be an
                // infinite loop.  As such, we track the seen state of
                // all of the entries and exit the loop if we try to
                // kick out an object that has already been seen.  The
                // first step in this process is thus to clear the seen
                // state for all of the entries.
                foreach (var entry in this.hashTable.Values)
                {
                    entry.Seen = false;
                }

                // Try to put the entry into its Hash2 location.  If
                // that fails then kick the entry in Hash2 to that
                // entry's Hash2 location.  Repeat until we either find
                // an empty Hash2 slot or try to kick an entry that is
                // already in its Hash2 location into its Hash2 location
                // (which would cause an infinite loop).
                if (!this.TryAssignAndKickOutIfNeeded(hashEntry))
                {
                    return(false);
                }
            }

            // We were successful in adding this entry to the hash table.
            return(true);
        }