Пример #1
0
        /// <summary>
        /// Signal all the matching pipes.
        /// </summary>
        public void Match(Span <byte> data, [NotNull] MultiTrieDelegate func, [CanBeNull] object arg)
        {
            MultiTrie current = this;

            int index = 0;
            int size  = data.Length;

            while (true)
            {
                // Signal the pipes attached to this node.
                if (current.m_pipes != null)
                {
                    foreach (Pipe it in current.m_pipes)
                    {
                        func(it, null, 0, arg);
                    }
                }

                // If we are at the end of the message, there's nothing more to match.
                if (size == 0)
                {
                    break;
                }

                // If there are no subnodes in the trie, return.
                if (current.m_count == 0)
                {
                    break;
                }

                byte c = data[index];
                // If there's one subnode (optimisation).
                if (current.m_count == 1)
                {
                    if (c != current.m_minCharacter)
                    {
                        break;
                    }
                    current = current.m_next[0];
                    index++;
                    size--;
                    continue;
                }

                // If there are multiple subnodes.
                if (c < current.m_minCharacter || c >=
                    current.m_minCharacter + current.m_count)
                {
                    break;
                }
                if (current.m_next[c - current.m_minCharacter] == null)
                {
                    break;
                }
                current = current.m_next[c - current.m_minCharacter];
                index++;
                size--;
            }
        }
Пример #2
0
        private bool RemoveHelper([NotNull] Pipe pipe, [NotNull] byte[] buffer, int bufferSize, int maxBufferSize, [NotNull] MultiTrieDelegate func, [CanBeNull] object arg)
        {
            // Remove the subscription from this node.
            if (m_pipes != null && m_pipes.Remove(pipe) && m_pipes.Count == 0)
            {
                func(pipe, buffer, bufferSize, arg);
                m_pipes = null;
            }

            // Adjust the buffer.
            if (bufferSize >= maxBufferSize)
            {
                maxBufferSize = bufferSize + 256;
                Array.Resize(ref buffer, maxBufferSize);
            }

            // If there are no subnodes in the trie, return.
            if (m_count == 0)
            {
                return(true);
            }

            // If there's one subnode (optimisation).
            if (m_count == 1)
            {
                buffer[bufferSize] = (byte)m_minCharacter;
                bufferSize++;
                m_next[0].RemoveHelper(pipe, buffer, bufferSize, maxBufferSize, func, arg);

                // Prune the node if it was made redundant by the removal
                if (m_next[0].IsRedundant)
                {
                    m_next  = null;
                    m_count = 0;
                    --m_liveNodes;
                    Debug.Assert(m_liveNodes == 0);
                }
                return(true);
            }

            // If there are multiple subnodes.

            // New min non-null character in the node table after the removal
            int newMin = m_minCharacter + m_count - 1;

            // New max non-null character in the node table after the removal
            int newMax = m_minCharacter;

            for (int currentCharacter = 0; currentCharacter != m_count; currentCharacter++)
            {
                buffer[bufferSize] = (byte)(m_minCharacter + currentCharacter);
                if (m_next[currentCharacter] != null)
                {
                    m_next[currentCharacter].RemoveHelper(pipe, buffer, bufferSize + 1,
                                                          maxBufferSize, func, arg);

                    // Prune redundant nodes from the mtrie
                    if (m_next[currentCharacter].IsRedundant)
                    {
                        m_next[currentCharacter] = null;

                        Debug.Assert(m_liveNodes > 0);
                        --m_liveNodes;
                    }
                    else
                    {
                        // The node is not redundant, so it's a candidate for being
                        // the new min/max node.
                        //
                        // We loop through the node array from left to right, so the
                        // first non-null, non-redundant node encountered is the new
                        // minimum index. Conversely, the last non-redundant, non-null
                        // node encountered is the new maximum index.
                        if (currentCharacter + m_minCharacter < newMin)
                        {
                            newMin = currentCharacter + m_minCharacter;
                        }

                        if (currentCharacter + m_minCharacter > newMax)
                        {
                            newMax = currentCharacter + m_minCharacter;
                        }
                    }
                }
            }

            Debug.Assert(m_count > 1);

            // Free the node table if it's no longer used.
            if (m_liveNodes == 0)
            {
                m_next  = null;
                m_count = 0;
            }
            // Compact the node table if possible
            else if (m_liveNodes == 1)
            {
                // If there's only one live node in the table we can
                // switch to using the more compact single-node
                // representation
                Debug.Assert(newMin == newMax);
                Debug.Assert(newMin >= m_minCharacter && newMin < m_minCharacter + m_count);

                MultiTrie node = m_next[newMin - m_minCharacter];

                Debug.Assert(node != null);

                m_next         = null;
                m_next         = new[] { node };
                m_count        = 1;
                m_minCharacter = newMin;
            }
            else if (m_liveNodes > 1 && (newMin > m_minCharacter || newMax < m_minCharacter + m_count - 1))
            {
                Debug.Assert(newMax - newMin + 1 > 1);

                MultiTrie[] oldTable = m_next;
                Debug.Assert(newMin > m_minCharacter || newMax < m_minCharacter + m_count - 1);
                Debug.Assert(newMin >= m_minCharacter);
                Debug.Assert(newMax <= m_minCharacter + m_count - 1);
                Debug.Assert(newMax - newMin + 1 < m_count);
                m_count = newMax - newMin + 1;
                m_next  = new MultiTrie[m_count];

                Array.Copy(oldTable, (newMin - m_minCharacter), m_next, 0, m_count);

                m_minCharacter = newMin;
            }
            return(true);
        }
Пример #3
0
 /// <summary>
 /// Remove all subscriptions for a specific peer from the trie.
 /// If there are no subscriptions left on some topics, invoke the
 /// supplied callback function.
 /// </summary>
 /// <param name="pipe"></param>
 /// <param name="func"></param>
 /// <param name="arg"></param>
 /// <returns></returns>
 public bool RemoveHelper([NotNull] Pipe pipe, [NotNull] MultiTrieDelegate func, [CanBeNull] object arg)
 {
     return(RemoveHelper(pipe, EmptyArray <byte> .Instance, 0, 0, func, arg));
 }
Пример #4
0
 /// <summary>
 /// Remove all subscriptions for a specific peer from the trie.
 /// If there are no subscriptions left on some topics, invoke the
 /// supplied callback function.
 /// </summary>
 /// <param name="pipe"></param>
 /// <param name="func"></param>
 /// <param name="arg"></param>
 /// <returns></returns>
 public bool RemoveHelper([NotNull] Pipe pipe, [NotNull] MultiTrieDelegate func, [CanBeNull] object arg)
 {
     return(RemoveHelper(pipe, new byte[0], 0, 0, func, arg));
 }
Пример #5
0
 /// <summary>
 /// Remove all subscriptions for a specific peer from the trie.
 ///  If there are no subscriptions left on some topics, invoke the
 ///  supplied callback function.
 /// </summary>
 /// <param name="pipe"></param>
 /// <param name="func"></param>
 /// <param name="arg"></param>
 /// <returns></returns>
 public bool RemoveHelper(Pipe pipe, MultiTrieDelegate func, Object arg)
 {
     return(RemoveHelper(pipe, new byte[0], 0, 0, func, arg));
 }
Пример #6
0
        /// <summary>
        /// Signal all the matching pipes.
        /// </summary>
        public void Match( byte[] data, int offset, int size,  MultiTrieDelegate func,  object arg)
        {
            MultiTrie current = this;

            int index = offset;

            while (true)
            {
                // Signal the pipes attached to this node.
                if (current.m_pipes != null)
                {
                    foreach (Pipe it in current.m_pipes)
                        func(it, null, 0, arg);
                }

                // If we are at the end of the message, there's nothing more to match.
                if (size == 0)
                    break;

                // If there are no subnodes in the trie, return.
                if (current.m_count == 0)
                    break;

                byte c = data[index];
                // If there's one subnode (optimisation).
                if (current.m_count == 1)
                {
                    if (c != current.m_minCharacter)
                        break;
                    current = current.m_next[0];
                    index++;
                    size--;
                    continue;
                }

                // If there are multiple subnodes.
                if (c < current.m_minCharacter || c >=
                    current.m_minCharacter + current.m_count)
                    break;
                if (current.m_next[c - current.m_minCharacter] == null)
                    break;
                current = current.m_next[c - current.m_minCharacter];
                index++;
                size--;
            }
        }
Пример #7
0
        private bool RemoveHelper( Pipe pipe,  byte[] buffer, int bufferSize, int maxBufferSize,  MultiTrieDelegate func,  object arg)
        {
            // Remove the subscription from this node.
            if (m_pipes != null && m_pipes.Remove(pipe) && m_pipes.Count == 0)
            {
                func(pipe, buffer, bufferSize, arg);
                m_pipes = null;
            }

            // Adjust the buffer.
            if (bufferSize >= maxBufferSize)
            {
                maxBufferSize = bufferSize + 256;
                Array.Resize(ref buffer, maxBufferSize);
            }

            // If there are no subnodes in the trie, return.
            if (m_count == 0)
                return true;

            // If there's one subnode (optimisation).
            if (m_count == 1)
            {
                buffer[bufferSize] = (byte)m_minCharacter;
                bufferSize++;
                m_next[0].RemoveHelper(pipe, buffer, bufferSize, maxBufferSize, func, arg);

                // Prune the node if it was made redundant by the removal
                if (m_next[0].IsRedundant)
                {
                    m_next = null;
                    m_count = 0;
                    --m_liveNodes;
                    Debug.Assert(m_liveNodes == 0);
                }
                return true;
            }

            // If there are multiple subnodes.

            // New min non-null character in the node table after the removal
            int newMin = m_minCharacter + m_count - 1;

            // New max non-null character in the node table after the removal
            int newMax = m_minCharacter;

            for (int currentCharacter = 0; currentCharacter != m_count; currentCharacter++)
            {
                buffer[bufferSize] = (byte)(m_minCharacter + currentCharacter);
                if (m_next[currentCharacter] != null)
                {
                    m_next[currentCharacter].RemoveHelper(pipe, buffer, bufferSize + 1,
                        maxBufferSize, func, arg);

                    // Prune redundant nodes from the mtrie
                    if (m_next[currentCharacter].IsRedundant)
                    {
                        m_next[currentCharacter] = null;

                        Debug.Assert(m_liveNodes > 0);
                        --m_liveNodes;
                    }
                    else
                    {
                        // The node is not redundant, so it's a candidate for being
                        // the new min/max node.
                        //
                        // We loop through the node array from left to right, so the
                        // first non-null, non-redundant node encountered is the new
                        // minimum index. Conversely, the last non-redundant, non-null
                        // node encountered is the new maximum index.
                        if (currentCharacter + m_minCharacter < newMin)
                            newMin = currentCharacter + m_minCharacter;

                        if (currentCharacter + m_minCharacter > newMax)
                            newMax = currentCharacter + m_minCharacter;
                    }
                }
            }

            Debug.Assert(m_count > 1);

            // Free the node table if it's no longer used.
            if (m_liveNodes == 0)
            {
                m_next = null;
                m_count = 0;
            }
            // Compact the node table if possible
            else if (m_liveNodes == 1)
            {
                // If there's only one live node in the table we can
                // switch to using the more compact single-node
                // representation
                Debug.Assert(newMin == newMax);
                Debug.Assert(newMin >= m_minCharacter && newMin < m_minCharacter + m_count);

                MultiTrie node = m_next[newMin - m_minCharacter];

                Debug.Assert(node != null);

                m_next = null;
                m_next = new[] { node };
                m_count = 1;
                m_minCharacter = newMin;
            }
            else if (m_liveNodes > 1 && (newMin > m_minCharacter || newMax < m_minCharacter + m_count - 1))
            {
                Debug.Assert(newMax - newMin + 1 > 1);

                MultiTrie[] oldTable = m_next;
                Debug.Assert(newMin > m_minCharacter || newMax < m_minCharacter + m_count - 1);
                Debug.Assert(newMin >= m_minCharacter);
                Debug.Assert(newMax <= m_minCharacter + m_count - 1);
                Debug.Assert(newMax - newMin + 1 < m_count);
                m_count = newMax - newMin + 1;
                m_next = new MultiTrie[m_count];

                Array.Copy(oldTable, (newMin - m_minCharacter), m_next, 0, m_count);

                m_minCharacter = newMin;
            }
            return true;
        }
Пример #8
0
 /// <summary>
 /// Remove all subscriptions for a specific peer from the trie.
 /// If there are no subscriptions left on some topics, invoke the
 /// supplied callback function.
 /// </summary>
 /// <param name="pipe"></param>
 /// <param name="func"></param>
 /// <param name="arg"></param>
 /// <returns></returns>
 public bool RemoveHelper( Pipe pipe,  MultiTrieDelegate func,  object arg)
 {
     return RemoveHelper(pipe, EmptyArray<byte>.Instance, 0, 0, func, arg);
 }
Пример #9
0
 /// <summary>
 /// Remove all subscriptions for a specific peer from the trie.
 /// If there are no subscriptions left on some topics, invoke the
 /// supplied callback function.
 /// </summary>
 /// <param name="pipe"></param>
 /// <param name="func"></param>
 /// <param name="arg"></param>
 /// <returns></returns>
 public bool RemoveHelper(Pipe pipe, MultiTrieDelegate func, object arg)
 {
     return(RemoveHelper(pipe, EmptyArray <byte> .Instance, 0, 0, func, arg));
 }