summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Sustrik <sustrik@250bpm.com>2011-09-16 16:34:28 +0200
committerMartin Sustrik <sustrik@250bpm.com>2011-09-16 16:34:28 +0200
commite170136a2e00eec2e786441cdc090c3b00a8fbd4 (patch)
tree786ac67e14af4bfc3b5909b2db51935a4f68a206
parent5936379b292dec79efd3a1eaa7cafae4fc6d675a (diff)
More bugs in mtrie fixed
Aside of fixing couple of corner cases this patch turns the 'match' function in mtrie from recursive to iterative. Signed-off-by: Martin Sustrik <sustrik@250bpm.com>
-rw-r--r--src/mtrie.cpp57
-rw-r--r--src/mtrie.hpp2
2 files changed, 30 insertions, 29 deletions
diff --git a/src/mtrie.cpp b/src/mtrie.cpp
index bb20df8..edff336 100644
--- a/src/mtrie.cpp
+++ b/src/mtrie.cpp
@@ -209,33 +209,36 @@ bool zmq::mtrie_t::rm_helper (unsigned char *prefix_, size_t size_,
void zmq::mtrie_t::match (unsigned char *data_, size_t size_,
void (*func_) (pipe_t *pipe_, void *arg_), void *arg_)
{
- match_helper (data_, size_, func_, arg_);
-}
-
-void zmq::mtrie_t::match_helper (unsigned char *data_, size_t size_,
- void (*func_) (pipe_t *pipe_, void *arg_), void *arg_)
-{
- // TODO: This function is on critical path. Rewrite it as iteration
- // rather than recursion.
-
- // Signal the pipes attached to this node.
- for (pipes_t::iterator it = pipes.begin (); it != pipes.end (); ++it)
- func_ (*it, arg_);
-
- // If there are no subnodes in the trie, return.
- if (count == 0)
- return;
-
- // If there's one subnode (optimisation).
- if (count == 1) {
- if (min == data_ [0])
- next.node->match_helper (data_ + 1, size_ - 1, func_, arg_);
- return;
+ mtrie_t *current = this;
+ while (size_) {
+
+ // Signal the pipes attached to this node.
+ for (pipes_t::iterator it = current->pipes.begin ();
+ it != current->pipes.end (); ++it)
+ func_ (*it, arg_);
+
+ // If there are no subnodes in the trie, return.
+ if (current->count == 0)
+ break;
+
+ // If there's one subnode (optimisation).
+ if (current->count == 1) {
+ if (data_ [0] != current->min)
+ break;
+ current = current->next.node;
+ data_++;
+ size_--;
+ continue;
+ }
+
+ // If there are multiple subnodes.
+ if (data_ [0] < min || data_ [0] >= min + count)
+ break;
+ if (!current->next.table [data_ [0] - min])
+ break;
+ current = current->next.table [data_ [0] - min];
+ data_++;
+ size_--;
}
-
- // If there are multiple subnodes.
- if (next.table [data_ [0] - min])
- next.table [data_ [0] - min]->match_helper (data_ + 1, size_ - 1,
- func_, arg_);
}
diff --git a/src/mtrie.hpp b/src/mtrie.hpp
index 68a3f2c..2c2cc32 100644
--- a/src/mtrie.hpp
+++ b/src/mtrie.hpp
@@ -67,8 +67,6 @@ namespace zmq
void *arg_);
bool rm_helper (unsigned char *prefix_, size_t size_,
class pipe_t *pipe_);
- void match_helper (unsigned char *data_, size_t size_,
- void (*func_) (class pipe_t *pipe_, void *arg_), void *arg_);
typedef std::set <class pipe_t*> pipes_t;
pipes_t pipes;