/// <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--; } }
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); }
/// <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)); }
/// <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)); }
/// <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)); }
/// <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--; } }
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; }
/// <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); }
/// <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)); }