Пример #1
0
        /// <summary>
        ///     Add key to the trie. Returns true if this is a new item in the trie
        ///     rather than a duplicate.
        /// </summary>
        /// <param name="prefix"></param>
        /// <param name="start"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public bool Add([NotNull] byte[] prefix, int start, int size)
        {
            // We are at the node corresponding to the prefix. We are done.
            if (size == 0)
            {
                ++this.m_referenceCount;
                return(this.m_referenceCount == 1);
            }

            byte currentCharacter = prefix[start];

            if (currentCharacter < this.m_minCharacter || currentCharacter >= this.m_minCharacter + this.m_count)
            {
                // The character is out of range of currently handled
                // characters. We have to extend the table.
                if (this.m_count == 0)
                {
                    this.m_minCharacter = currentCharacter;
                    this.m_count        = 1;
                    this.m_next         = null;
                }
                else if (this.m_count == 1)
                {
                    byte oldc = this.m_minCharacter;
                    Trie oldp = this.m_next[0];
                    this.m_count        = (short)((this.m_minCharacter < currentCharacter ? currentCharacter - this.m_minCharacter : this.m_minCharacter - currentCharacter) + 1);
                    this.m_next         = new Trie[this.m_count];
                    this.m_minCharacter = Math.Min(this.m_minCharacter, currentCharacter);
                    this.m_next[oldc - this.m_minCharacter] = oldp;
                }
                else if (this.m_minCharacter < currentCharacter)
                {
                    // The new character is above the current character range.
                    this.m_count = (short)(currentCharacter - this.m_minCharacter + 1);
                    this.m_next  = this.m_next.Resize(this.m_count, true);
                }
                else
                {
                    // The new character is below the current character range.
                    this.m_count        = (short)(this.m_minCharacter + this.m_count - currentCharacter);
                    this.m_next         = this.m_next.Resize(this.m_count, false);
                    this.m_minCharacter = currentCharacter;
                }
            }

            // If next node does not exist, create one.
            if (this.m_count == 1)
            {
                if (this.m_next == null)
                {
                    this.m_next    = new Trie[1];
                    this.m_next[0] = new Trie();
                    ++this.m_liveNodes;
                    //alloc_Debug.Assert(next.node);
                }

                return(this.m_next[0].Add(prefix, start + 1, size - 1));
            }

            if (this.m_next[currentCharacter - this.m_minCharacter] == null)
            {
                this.m_next[currentCharacter - this.m_minCharacter] = new Trie();
                ++this.m_liveNodes;
                //alloc_Debug.Assert(next.table [c - min]);
            }

            return(this.m_next[currentCharacter - this.m_minCharacter].Add(prefix, start + 1, size - 1));
        }
Пример #2
0
        /// <summary>
        ///     Remove key from the trie. Returns true if the item is actually
        ///     removed from the trie.
        /// </summary>
        /// <param name="prefix"></param>
        /// <param name="start"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public bool Remove([NotNull] byte[] prefix, int start, int size)
        {
            if (size == 0)
            {
                if (this.m_referenceCount == 0)
                {
                    return(false);
                }

                this.m_referenceCount--;
                return(this.m_referenceCount == 0);
            }

            byte currentCharacter = prefix[start];

            if (this.m_count == 0 || currentCharacter < this.m_minCharacter || currentCharacter >= this.m_minCharacter + this.m_count)
            {
                return(false);
            }

            Trie nextNode = this.m_count == 1 ? this.m_next[0] : this.m_next[currentCharacter - this.m_minCharacter];

            if (nextNode == null)
            {
                return(false);
            }

            bool wasRemoved = nextNode.Remove(prefix, start + 1, size - 1);

            if (nextNode.IsRedundant())
            {
                //delete next_node;
                Debug.Assert(this.m_count > 0);

                if (this.m_count == 1)
                {
                    this.m_next  = null;
                    this.m_count = 0;
                    --this.m_liveNodes;
                    Debug.Assert(this.m_liveNodes == 0);
                }
                else
                {
                    this.m_next[currentCharacter - this.m_minCharacter] = null;
                    Debug.Assert(this.m_liveNodes > 1);
                    --this.m_liveNodes;

                    // Compact the table if possible
                    if (this.m_liveNodes == 1)
                    {
                        // If there's only one live node in the table we can
                        // switch to using the more compact single-node
                        // representation
                        Trie node = null;
                        for (short i = 0; i < this.m_count; ++i)
                        {
                            if (this.m_next[i] != null)
                            {
                                node = this.m_next[i];
                                this.m_minCharacter = (byte)(i + this.m_minCharacter);
                                break;
                            }
                        }

                        Debug.Assert(node != null);

                        this.m_next  = null;
                        this.m_next  = new[] { node };
                        this.m_count = 1;
                    }
                    else if (currentCharacter == this.m_minCharacter)
                    {
                        // We can compact the table "from the left"
                        byte newMin = this.m_minCharacter;
                        for (short i = 1; i < this.m_count; ++i)
                        {
                            if (this.m_next[i] != null)
                            {
                                newMin = (byte)(i + this.m_minCharacter);
                                break;
                            }
                        }

                        Debug.Assert(newMin != this.m_minCharacter);

                        Debug.Assert(newMin > this.m_minCharacter);
                        Debug.Assert(this.m_count > newMin - this.m_minCharacter);
                        this.m_count = (short)(this.m_count - (newMin - this.m_minCharacter));

                        this.m_next = this.m_next.Resize(this.m_count, false);

                        this.m_minCharacter = newMin;
                    }
                    else if (currentCharacter == this.m_minCharacter + this.m_count - 1)
                    {
                        // We can compact the table "from the right"
                        short newCount = this.m_count;
                        for (short i = 1; i < this.m_count; ++i)
                        {
                            if (this.m_next[this.m_count - 1 - i] != null)
                            {
                                newCount = (short)(this.m_count - i);
                                break;
                            }
                        }

                        Debug.Assert(newCount != this.m_count);
                        this.m_count = newCount;

                        this.m_next = this.m_next.Resize(this.m_count, true);
                    }
                }
            }

            return(wasRemoved);
        }