/* $Id: Trie.h 15564 2013-01-07 14:25:32Z sloot $ $URL: https://ilk.uvt.nl/svn/sources/libticcutils/trunk/include/ticcutils/Trie.h $ Copyright (c) 1998 - 2013 ILK - Tilburg University CLiPS - University of Antwerp This file is part of ticcutils ticcutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ticcutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . For questions and suggestions, see: http://ilk.uvt.nl/software.html or send mail to: timbl@uvt.nl */ #ifndef TICC_TRIE_H #define TICC_TRIE_H #if defined __GNUC__ || __IBMCPP__ #define LTGT <> #else #define LTGT #endif namespace Tries { // A node in the generic trie. template class TrieNode; template std::ostream& operator<< ( std::ostream&, const TrieNode * ); template class TrieNode { friend std::ostream& operator<< LTGT ( std::ostream&, const TrieNode * ); public: TrieNode( char ); ~TrieNode(); Info *add_to_tree( Info *, const std::string& ); Info *scan_tree( const std::string& ) const; void Iterate( void(*)( Info *, void * ), void * ); void Iterate( void(*)( Info * ) ); private: char label; // the label. Info *the_info; // The information at this pnt. TrieNode *next_node; // Pointer to the next node. TrieNode *sub_node; // Pointer to the sub node. TrieNode( const TrieNode& ); TrieNode& operator=( const TrieNode& ); Info *add_to_tree( Info *, const char * ); Info *scan_tree( const char * ) const; }; template inline Info *TrieNode::scan_tree( const char *name ) const { // // returns the info where it is found in the tree or NULL. // TrieNode *subtree = sub_node; // top node has empty label! while ( subtree ) { if ( subtree->label == *name ){ if ( *(++name) == '\0' ) return subtree->the_info; else { subtree = subtree->sub_node; } } else if ( subtree->label > *name ) return NULL; else subtree = subtree->next_node; } return NULL; } template inline Info *TrieNode::scan_tree( const std::string& name ) const { return scan_tree( name.c_str() ); } template inline std::ostream& operator << ( std::ostream& os, const TrieNode *tree ){ // // print an TrieNode sorted on Info // if ( tree ){ os << tree->sub_node; if ( tree->the_info ) os << tree->the_info << std::endl; os << tree->next_node; } return os; } template inline void TrieNode::Iterate( void F( Info * ) ){ // // Do F on each entry in the Trie // if ( the_info ) #pragma omp critical(trie_mod) { F( the_info ); } if ( sub_node ) sub_node->Iterate( F ); if ( next_node ) next_node->Iterate( F ); } template inline void TrieNode::Iterate( void F( Info *, void * ), void *arg ){ // // Do F on each entry in the Trie // if ( the_info ) #pragma omp critical(trie_mod) { F( the_info, arg ); } if ( sub_node ) sub_node->Iterate( F, arg ); if ( next_node ) next_node->Iterate( F, arg ); } template inline TrieNode::TrieNode( char lab ): label(lab), the_info(NULL), next_node(NULL), sub_node(NULL) { } template inline TrieNode::~TrieNode(){ delete the_info; delete sub_node; delete next_node; } template inline Info *TrieNode::add_to_tree( Info *info, const char *lab ){ // If the lab string is empty, we are at the bottom, and // we can store the info. // if ( lab[0] == '\0') { if ( !the_info ) the_info = info; return the_info; } else { // Search all the nodes in the node_list for a // fitting sub node. If found, continue with it. // TrieNode **subNodePtr = &sub_node; // First one. while (*subNodePtr != NULL) { if ( (*subNodePtr)->label == lab[0] ) { return (*subNodePtr)->add_to_tree( info, &lab[1] ); } else if ( (*subNodePtr)->label > lab[0] ) { TrieNode *tmp = *subNodePtr; *subNodePtr = new TrieNode( lab[0] ); (*subNodePtr)->next_node = tmp; return (*subNodePtr)->add_to_tree( info, &lab[1] ); } subNodePtr = &((*subNodePtr)->next_node); } // We don't, so we create a new one, and continue. // *subNodePtr = new TrieNode( lab[0] ); return (*subNodePtr)->add_to_tree( info, &lab[1] ); } } template inline Info *TrieNode::add_to_tree( Info *info, const std::string& lab ){ return add_to_tree( info, lab.c_str() ); } // a generic trie. template class Trie; template std::ostream &operator << ( std::ostream &, const Trie * ); template class Trie{ friend std::ostream &operator << LTGT ( std::ostream &, const Trie * ); public: Trie(): Tree( new TrieNode( '\0' ) ) { }; ~Trie() { delete Tree; }; Info *Store( const std::string& str, Info *info ) { return Tree->add_to_tree( info, str ); }; Info *Retrieve( const std::string& str ) const{ return Tree->scan_tree( str ); }; void ForEachDo( void F( Info *, void * ), void *arg ){ if ( Tree ) Tree->Iterate( F, arg ); }; void ForEachDo( void F( Info * ) ) { if ( Tree ) Tree->Iterate( F ); }; protected: TrieNode *Tree; Trie( const Trie& ); Trie& operator=( const Trie& ); }; template inline std::ostream &operator << ( std::ostream &os, const Trie *T ){ if ( T ) os << T->Tree; return os; } } #endif