diff options
-rw-r--r-- | src/prefix_filter.cpp | 387 | ||||
-rw-r--r-- | src/prefix_filter.hpp | 75 |
2 files changed, 178 insertions, 284 deletions
diff --git a/src/prefix_filter.cpp b/src/prefix_filter.cpp index 5d21fb6..9ee18d2 100644 --- a/src/prefix_filter.cpp +++ b/src/prefix_filter.cpp @@ -20,129 +20,36 @@ */ #include <new> +#include <map> +#include <stddef.h> +#include <stdlib.h> #include "../include/xs.h" #include "prefix_filter.hpp" #include "err.hpp" -xs::prefix_filter_t::prefix_filter_t () +struct pfx_node_t { - init (&root); -} - -xs::prefix_filter_t::~prefix_filter_t () -{ - close (&root); -} - -int xs::prefix_filter_t::subscribe (void *core_, void *subscriber_, - const unsigned char *data_, size_t size_) -{ - return add (&root, data_, size_, subscriber_) ? 1 : 0; -} - -int xs::prefix_filter_t::unsubscribe (void *core_, void *subscriber_, - const unsigned char *data_, size_t size_) -{ - return rm (&root, data_, size_, subscriber_) ? 1 : 0; -} - -void xs::prefix_filter_t::unsubscribe_all (void *core_, void *subscriber_) -{ - rm (&root, subscriber_, core_); -} - -void xs::prefix_filter_t::enumerate (void *core_) -{ - unsigned char *buff = NULL; - list (&root, &buff, 0, 0, core_); - free (buff); -} - -int xs::prefix_filter_t::match (void *core_, - const unsigned char *data_, size_t size_) -{ - // This function is on critical path. It deliberately doesn't use - // recursion to get a bit better performance. - node_t *current = &root; - while (true) { - - // We've found a corresponding subscription! - if (current->subscribers) - return 1; - - // We've checked all the data and haven't found matching subscription. - if (!size_) - return 0; - - // If there's no corresponding slot for the first character - // of the prefix, the message does not match. - unsigned char c = *data_; - if (c < current->min || c >= current->min + current->count) - return 0; - - // Move to the next character. - if (current->count == 1) - current = current->next.node; - else { - current = current->next.table [c - current->min]; - if (!current) - return 0; - } - data_++; - size_--; - } - -} + // Pointer to particular subscriber associated with the reference count. + typedef std::map <void*, int> subscribers_t; + subscribers_t *subscribers; + + unsigned char min; + unsigned short count; + unsigned short live_nodes; + union { + struct pfx_node_t *node; + struct pfx_node_t **table; + } next; +}; -void xs::prefix_filter_t::match_all (void *core_, - const unsigned char *data_, size_t size_) +static bool pfx_is_redundant (pfx_node_t *node_) { - node_t *current = &root; - while (true) { - - // Signal the subscribers attached to this node. - if (current->subscribers) { - for (node_t::subscribers_t::iterator it = - current->subscribers->begin (); - it != current->subscribers->end (); ++it) { - int rc = xs_filter_matching (core_, it->first); - errno_assert (rc == 0); - } - } - - // If we are at the end of the message, there's nothing more to match. - if (!size_) - break; - - // 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] < current->min || data_ [0] >= - current->min + current->count) - break; - if (!current->next.table [data_ [0] - current->min]) - break; - current = current->next.table [data_ [0] - current->min]; - data_++; - size_--; - } + return !node_->subscribers && node_->live_nodes == 0; } -void xs::prefix_filter_t::init (node_t *node_) +static void pfx_init (pfx_node_t *node_) { node_->subscribers = NULL; node_->min = 0; @@ -150,7 +57,7 @@ void xs::prefix_filter_t::init (node_t *node_) node_->live_nodes = 0; } -void xs::prefix_filter_t::close (node_t *node_) +static void pfx_close (pfx_node_t *node_) { if (node_->subscribers) { delete node_->subscribers; @@ -159,30 +66,30 @@ void xs::prefix_filter_t::close (node_t *node_) if (node_->count == 1) { xs_assert (node_->next.node); - close (node_->next.node); - delete node_->next.node; + pfx_close (node_->next.node); + free (node_->next.node); node_->next.node = NULL; } else if (node_->count > 1) { for (unsigned short i = 0; i != node_->count; ++i) if (node_->next.table [i]) { - close (node_->next.table [i]); - delete node_->next.table [i]; + pfx_close (node_->next.table [i]); + free (node_->next.table [i]); } free (node_->next.table); } } -bool xs::prefix_filter_t::add (node_t *node_, const unsigned char *prefix_, - size_t size_, void *subscriber_) +static bool pfx_add (pfx_node_t *node_, + const unsigned char *prefix_, size_t size_, void *subscriber_) { // We are at the node corresponding to the prefix. We are done. if (!size_) { bool result = !node_->subscribers; if (!node_->subscribers) - node_->subscribers = new (std::nothrow) node_t::subscribers_t; - node_t::subscribers_t::iterator it = node_->subscribers->insert ( - node_t::subscribers_t::value_type (subscriber_, 0)).first; + node_->subscribers = new (std::nothrow) pfx_node_t::subscribers_t; + pfx_node_t::subscribers_t::iterator it = node_->subscribers->insert ( + pfx_node_t::subscribers_t::value_type (subscriber_, 0)).first; ++it->second; return result; } @@ -199,11 +106,11 @@ bool xs::prefix_filter_t::add (node_t *node_, const unsigned char *prefix_, } else if (node_->count == 1) { unsigned char oldc = node_->min; - node_t *oldp = node_->next.node; + pfx_node_t *oldp = node_->next.node; node_->count = (node_->min < c ? c - node_->min : node_->min - c) + 1; - node_->next.table = (node_t**) - malloc (sizeof (node_t*) * node_->count); + node_->next.table = (pfx_node_t**) + malloc (sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); for (unsigned short i = 0; i != node_->count; ++i) node_->next.table [i] = 0; @@ -215,8 +122,9 @@ bool xs::prefix_filter_t::add (node_t *node_, const unsigned char *prefix_, // The new character is above the current character range. unsigned short old_count = node_->count; node_->count = c - node_->min + 1; - node_->next.table = (node_t**) realloc ((void*) node_->next.table, - sizeof (node_t*) * node_->count); + node_->next.table = + (pfx_node_t**) realloc ((void*) node_->next.table, + sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); for (unsigned short i = old_count; i != node_->count; i++) node_->next.table [i] = NULL; @@ -226,11 +134,12 @@ bool xs::prefix_filter_t::add (node_t *node_, const unsigned char *prefix_, // The new character is below the current character range. unsigned short old_count = node_->count; node_->count = (node_->min + old_count) - c; - node_->next.table = (node_t**) realloc ((void*) node_->next.table, - sizeof (node_t*) * node_->count); + node_->next.table = + (pfx_node_t**) realloc ((void*) node_->next.table, + sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); memmove (node_->next.table + node_->min - c, node_->next.table, - old_count * sizeof (node_t*)); + old_count * sizeof (pfx_node_t*)); for (unsigned short i = 0; i != node_->min - c; i++) node_->next.table [i] = NULL; node_->min = c; @@ -240,41 +149,34 @@ bool xs::prefix_filter_t::add (node_t *node_, const unsigned char *prefix_, // If next node does not exist, create one. if (node_->count == 1) { if (!node_->next.node) { - node_->next.node = new (std::nothrow) node_t; + node_->next.node = (pfx_node_t*) malloc (sizeof (pfx_node_t)); alloc_assert (node_->next.node); - init (node_->next.node); + pfx_init (node_->next.node); ++node_->live_nodes; xs_assert (node_->next.node); } - return add (node_->next.node, prefix_ + 1, size_ - 1, subscriber_); + return pfx_add (node_->next.node, prefix_ + 1, size_ - 1, subscriber_); } else { if (!node_->next.table [c - node_->min]) { - node_->next.table [c - node_->min] = new (std::nothrow) node_t; + node_->next.table [c - node_->min] = + (pfx_node_t*) malloc (sizeof (pfx_node_t)); alloc_assert (node_->next.table [c - node_->min]); - init (node_->next.table [c - node_->min]); + pfx_init (node_->next.table [c - node_->min]); ++node_->live_nodes; xs_assert (node_->next.table [c - node_->min]); } - return add (node_->next.table [c - node_->min], prefix_ + 1, size_ - 1, - subscriber_); + return pfx_add (node_->next.table [c - node_->min], + prefix_ + 1, size_ - 1, subscriber_); } } - -void xs::prefix_filter_t::rm (node_t *node_, void *subscriber_, void *arg_) -{ - unsigned char *buff = NULL; - rm_helper (node_, subscriber_, &buff, 0, 0, arg_); - free (buff); -} - -void xs::prefix_filter_t::rm_helper (node_t *node_, void *subscribers_, +static void pfx_rm_all (pfx_node_t *node_, void *subscribers_, unsigned char **buff_, size_t buffsize_, size_t maxbuffsize_, void *arg_) { // Remove the subscription from this node. if (node_->subscribers) { - node_t::subscribers_t::iterator it = + pfx_node_t::subscribers_t::iterator it = node_->subscribers->find (subscribers_); if (it != node_->subscribers->end ()) { xs_assert (it->second); @@ -306,13 +208,13 @@ void xs::prefix_filter_t::rm_helper (node_t *node_, void *subscribers_, if (node_->count == 1) { (*buff_) [buffsize_] = node_->min; buffsize_++; - rm_helper (node_->next.node, subscribers_, buff_, buffsize_, + pfx_rm_all (node_->next.node, subscribers_, buff_, buffsize_, maxbuffsize_, arg_); // Prune the node if it was made redundant by the removal - if (is_redundant (node_->next.node)) { - close (node_->next.node); - delete node_->next.node; + if (pfx_is_redundant (node_->next.node)) { + pfx_close (node_->next.node); + free (node_->next.node); node_->next.node = 0; node_->count = 0; --node_->live_nodes; @@ -322,21 +224,22 @@ void xs::prefix_filter_t::rm_helper (node_t *node_, void *subscribers_, } // If there are multiple subnodes. - // + // New min non-null character in the node table after the removal. unsigned char new_min = node_->min; + // New max non-null character in the node table after the removal. unsigned char new_max = node_->min + node_->count - 1; for (unsigned short c = 0; c != node_->count; c++) { (*buff_) [buffsize_] = node_->min + c; if (node_->next.table [c]) { - rm_helper (node_->next.table [c], subscribers_, buff_, + pfx_rm_all (node_->next.table [c], subscribers_, buff_, buffsize_ + 1, maxbuffsize_, arg_); // Prune redudant nodes from the the trie. - if (is_redundant (node_->next.table [c])) { - close (node_->next.table [c]); - delete node_->next.table [c]; + if (pfx_is_redundant (node_->next.table [c])) { + pfx_close (node_->next.table [c]); + free (node_->next.table [c]); node_->next.table [c] = 0; xs_assert (node_->live_nodes > 0); @@ -362,7 +265,7 @@ void xs::prefix_filter_t::rm_helper (node_t *node_, void *subscribers_, xs_assert (new_min == new_max); xs_assert (new_min >= node_->min && new_min < node_->min + node_->count); - node_t *node = node_->next.table [new_min - node_->min]; + pfx_node_t *node = node_->next.table [new_min - node_->min]; xs_assert (node); free (node_->next.table); node_->next.node = node; @@ -373,7 +276,7 @@ void xs::prefix_filter_t::rm_helper (node_t *node_, void *subscribers_, (new_min > node_->min || new_max < node_->min + node_->count - 1)) { xs_assert (new_max - new_min + 1 > 1); - node_t **old_table = node_->next.table; + pfx_node_t **old_table = node_->next.table; xs_assert (new_min > node_->min || new_max < node_->min + node_->count - 1); xs_assert (new_min >= node_->min); @@ -381,25 +284,26 @@ void xs::prefix_filter_t::rm_helper (node_t *node_, void *subscribers_, xs_assert (new_max - new_min + 1 < node_->count); node_->count = new_max - new_min + 1; - node_->next.table = (node_t**) malloc (sizeof (node_t*) * node_->count); + node_->next.table = + (pfx_node_t**) malloc (sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); memmove (node_->next.table, old_table + (new_min - node_->min), - sizeof (node_t*) * node_->count); + sizeof (pfx_node_t*) * node_->count); free (old_table); node_->min = new_min; } } -bool xs::prefix_filter_t::rm (node_t *node_, const unsigned char *prefix_, +static bool pfx_rm (pfx_node_t *node_, const unsigned char *prefix_, size_t size_, void *subscriber_) { if (!size_) { // Remove the subscription from this node. if (node_->subscribers) { - node_t::subscribers_t::iterator it = + pfx_node_t::subscribers_t::iterator it = node_->subscribers->find (subscriber_); if (it != node_->subscribers->end ()) { xs_assert (it->second); @@ -420,17 +324,17 @@ bool xs::prefix_filter_t::rm (node_t *node_, const unsigned char *prefix_, if (!node_->count || c < node_->min || c >= node_->min + node_->count) return false; - node_t *next_node = node_->count == 1 ? node_->next.node : + pfx_node_t *next_node = node_->count == 1 ? node_->next.node : node_->next.table [c - node_->min]; if (!next_node) return false; - bool ret = rm (next_node, prefix_ + 1, size_ - 1, subscriber_); + bool ret = pfx_rm (next_node, prefix_ + 1, size_ - 1, subscriber_); - if (is_redundant (next_node)) { - close (next_node); - delete next_node; + if (pfx_is_redundant (next_node)) { + pfx_close (next_node); + free (next_node); xs_assert (node_->count > 0); if (node_->count == 1) { @@ -449,7 +353,7 @@ bool xs::prefix_filter_t::rm (node_t *node_, const unsigned char *prefix_, // If there's only one live node in the table we can // switch to using the more compact single-node // representation - node_t *node = 0; + pfx_node_t *node = 0; for (unsigned short i = 0; i < node_->count; ++i) { if (node_->next.table [i]) { node = node_->next.table [i]; @@ -475,17 +379,17 @@ bool xs::prefix_filter_t::rm (node_t *node_, const unsigned char *prefix_, } xs_assert (new_min != node_->min); - node_t **old_table = node_->next.table; + pfx_node_t **old_table = node_->next.table; xs_assert (new_min > node_->min); xs_assert (node_->count > new_min - node_->min); node_->count = node_->count - (new_min - node_->min); - node_->next.table = - (node_t**) malloc (sizeof (node_t*) * node_->count); + node_->next.table = (pfx_node_t**) + malloc (sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); memmove (node_->next.table, old_table + (new_min - node_->min), - sizeof (node_t*) * node_->count); + sizeof (pfx_node_t*) * node_->count); free (old_table); node_->min = new_min; @@ -503,13 +407,13 @@ bool xs::prefix_filter_t::rm (node_t *node_, const unsigned char *prefix_, xs_assert (new_count != node_->count); node_->count = new_count; - node_t **old_table = node_->next.table; - node_->next.table = - (node_t**) malloc (sizeof (node_t*) * node_->count); + pfx_node_t **old_table = node_->next.table; + node_->next.table = (pfx_node_t**) + malloc (sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); memmove (node_->next.table, old_table, - sizeof (node_t*) * node_->count); + sizeof (pfx_node_t*) * node_->count); free (old_table); } } @@ -518,7 +422,7 @@ bool xs::prefix_filter_t::rm (node_t *node_, const unsigned char *prefix_, return ret; } -void xs::prefix_filter_t::list (node_t *node_, unsigned char **buff_, +static void pfx_list (pfx_node_t *node_, unsigned char **buff_, size_t buffsize_, size_t maxbuffsize_, void *arg_) { // If this node is a subscription, apply the function. @@ -542,7 +446,7 @@ void xs::prefix_filter_t::list (node_t *node_, unsigned char **buff_, if (node_->count == 1) { (*buff_) [buffsize_] = node_->min; buffsize_++; - list (node_->next.node, buff_, buffsize_, maxbuffsize_, arg_); + pfx_list (node_->next.node, buff_, buffsize_, maxbuffsize_, arg_); return; } @@ -550,18 +454,12 @@ void xs::prefix_filter_t::list (node_t *node_, unsigned char **buff_, for (unsigned short c = 0; c != node_->count; c++) { (*buff_) [buffsize_] = node_->min + c; if (node_->next.table [c]) - list (node_->next.table [c], buff_, buffsize_ + 1, maxbuffsize_, - arg_); + pfx_list (node_->next.table [c], buff_, buffsize_ + 1, + maxbuffsize_, arg_); } } -bool xs::prefix_filter_t::is_redundant (node_t *node_) -{ - return !node_->subscribers && node_->live_nodes == 0; -} - -// Implementation of the C interface of the filter. -// Following functions convert raw C calls into calls to C++ object methods. +// Implementation of the public filter interface. static int id (void *core_) { @@ -570,79 +468,150 @@ static int id (void *core_) static void *pf_create (void *core_) { - void *pf = (void*) new (std::nothrow) xs::prefix_filter_t; - alloc_assert (pf); - return pf; + pfx_node_t *root = (pfx_node_t*) malloc (sizeof (pfx_node_t*)); + alloc_assert (root); + pfx_init (root); + return (void*) root; } static void pf_destroy (void *core_, void *pf_) { - delete (xs::prefix_filter_t*) pf_; + pfx_close ((pfx_node_t*) pf_); } static int pf_subscribe (void *core_, void *pf_, void *subscriber_, const unsigned char *data_, size_t size_) { - return ((xs::prefix_filter_t*) pf_)->subscribe (core_, subscriber_, - data_, size_); + return pfx_add ((pfx_node_t*) pf_, data_, size_, subscriber_) ? 1 : 0; } static int pf_unsubscribe (void *core_, void *pf_, void *subscriber_, const unsigned char *data_, size_t size_) { - return ((xs::prefix_filter_t*) pf_)->unsubscribe (core_, subscriber_, - data_, size_); + return pfx_rm ((pfx_node_t*) pf_, data_, size_, subscriber_) ? 1 : 0; } static void pf_unsubscribe_all (void *core_, void *pf_, void *subscriber_) { - ((xs::prefix_filter_t*) pf_)->unsubscribe_all (core_, subscriber_); + unsigned char *buff = NULL; + pfx_rm_all ((pfx_node_t*) pf_, subscriber_, &buff, 0, 0, core_); + free (buff); } static void pf_match (void *core_, void *pf_, const unsigned char *data_, size_t size_) { - ((xs::prefix_filter_t*) pf_)->match_all (core_, data_, size_); + pfx_node_t *current = (pfx_node_t*) pf_; + while (true) { + + // Signal the subscribers attached to this node. + if (current->subscribers) { + for (pfx_node_t::subscribers_t::iterator it = + current->subscribers->begin (); + it != current->subscribers->end (); ++it) { + int rc = xs_filter_matching (core_, it->first); + errno_assert (rc == 0); + } + } + + // If we are at the end of the message, there's nothing more to match. + if (!size_) + break; + + // 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] < current->min || data_ [0] >= + current->min + current->count) + break; + if (!current->next.table [data_ [0] - current->min]) + break; + current = current->next.table [data_ [0] - current->min]; + data_++; + size_--; + } } static void *sf_create (void *core_) { - void *sf = (void*) new (std::nothrow) xs::prefix_filter_t; - alloc_assert (sf); - return sf; + pfx_node_t *root = (pfx_node_t*) malloc (sizeof (pfx_node_t*)); + alloc_assert (root); + pfx_init (root); + return (void*) root; } static void sf_destroy (void *core_, void *sf_) { - delete (xs::prefix_filter_t*) sf_; + pfx_close ((pfx_node_t*) sf_); } static int sf_subscribe (void *core_, void *sf_, const unsigned char *data_, size_t size_) { - return ((xs::prefix_filter_t*) sf_)->subscribe (core_, NULL, - data_, size_); + return pfx_add ((pfx_node_t*) sf_, data_, size_, NULL) ? 1 : 0; } static int sf_unsubscribe (void *core_, void *sf_, const unsigned char *data_, size_t size_) { - return ((xs::prefix_filter_t*) sf_)->unsubscribe (core_, NULL, - data_, size_); + return pfx_rm ((pfx_node_t*) sf_, data_, size_, NULL) ? 1 : 0; } static void sf_enumerate (void *core_, void *sf_) { - ((xs::prefix_filter_t*) sf_)->enumerate (core_); + unsigned char *buff = NULL; + pfx_list ((pfx_node_t*) sf_, &buff, 0, 0, core_); + free (buff); } static int sf_match (void *core_, void *sf_, const unsigned char *data_, size_t size_) { - return ((xs::prefix_filter_t*) sf_)->match (core_, data_, size_); + // This function is on critical path. It deliberately doesn't use + // recursion to get a bit better performance. + pfx_node_t *current = (pfx_node_t*) sf_; + while (true) { + + // We've found a corresponding subscription! + if (current->subscribers) + return 1; + + // We've checked all the data and haven't found matching subscription. + if (!size_) + return 0; + + // If there's no corresponding slot for the first character + // of the prefix, the message does not match. + unsigned char c = *data_; + if (c < current->min || c >= current->min + current->count) + return 0; + + // Move to the next character. + if (current->count == 1) + current = current->next.node; + else { + current = current->next.table [c - current->min]; + if (!current) + return 0; + } + data_++; + size_--; + } } -static xs_filter_t filter = { +static xs_filter_t pfx_filter = { XS_PLUGIN_FILTER, 1, id, @@ -660,5 +629,5 @@ static xs_filter_t filter = { sf_match, }; -void *xs::prefix_filter = (void*) &filter; +void *xs::prefix_filter = (void*) &pfx_filter; diff --git a/src/prefix_filter.hpp b/src/prefix_filter.hpp index 0faa865..63bc409 100644 --- a/src/prefix_filter.hpp +++ b/src/prefix_filter.hpp @@ -22,87 +22,12 @@ #ifndef __XS_PREFIX_FILTER_HPP_INCLUDED__ #define __XS_PREFIX_FILTER_HPP_INCLUDED__ -#include <stddef.h> -#include <map> - -#include "stdint.hpp" - namespace xs { // Canonical extension object. extern void *prefix_filter; - class prefix_filter_t - { - public: - - prefix_filter_t (); - ~prefix_filter_t (); - - int subscribe (void *core_, void *subscriber_, - const unsigned char *data_, size_t size_); - int unsubscribe (void *core_, void *subscriber_, - const unsigned char *data_, size_t size_); - void unsubscribe_all (void *core_, void *subscriber_); - void enumerate (void *core_); - int match (void *core_, const unsigned char *data_, size_t size_); - void match_all (void *core_, const unsigned char *data_, size_t size_); - - private: - - struct node_t - { - // Pointer to particular subscriber associated with - // the reference count. - typedef std::map <void*, int> subscribers_t; - subscribers_t *subscribers; - - unsigned char min; - unsigned short count; - unsigned short live_nodes; - union { - struct node_t *node; - struct node_t **table; - } next; - - }; - - static void init (node_t *node_); - static void close (node_t *node_); - - // Add key to the trie. Returns true if it's a new subscription - // rather than a duplicate. - static bool add (node_t *node_, const unsigned char *prefix_, - size_t size_, void *subscriber_); - - // Remove specific subscription from the trie. Return true is it - // was actually removed rather than de-duplicated. - static bool rm (node_t *node_, const unsigned char *prefix_, - size_t size_, void *subscriber_); - - // Remove all subscriptions for a specific peer from the trie. - // If there are no subscriptions left on some topics, invoke the - // supplied callback function. - static void rm (node_t *node_, void *subscriber_, void *arg_); - - static void rm_helper (node_t *node_, void *subscriber_, - unsigned char **buff_, size_t buffsize_, size_t maxbuffsize_, - void *arg_); - - // Lists all the subscriptions in the trie. - static void list (node_t *node_, unsigned char **buff_, - size_t buffsize_, size_t maxbuffsize_, void *arg_); - - // Checks whether node can be safely removed. - static bool is_redundant (node_t *node_); - - node_t root; - - prefix_filter_t (const prefix_filter_t&); - const prefix_filter_t &operator = (const prefix_filter_t&); - }; - } #endif |