• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Trie.h

Go to the documentation of this file.
00001 /** @file
00002 
00003     Trie implementation for 8-bit string keys.
00004 
00005     @section license License
00006 
00007     Licensed to the Apache Software Foundation (ASF) under one
00008     or more contributor license agreements.  See the NOTICE file
00009     distributed with this work for additional information
00010     regarding copyright ownership.  The ASF licenses this file
00011     to you under the Apache License, Version 2.0 (the
00012     "License"); you may not use this file except in compliance
00013     with the License.  You may obtain a copy of the License at
00014 
00015     http://www.apache.org/licenses/LICENSE-2.0
00016 
00017     Unless required by applicable law or agreed to in writing, software
00018     distributed under the License is distributed on an "AS IS" BASIS,
00019     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020     See the License for the specific language governing permissions and
00021     limitations under the License.
00022 */
00023 #ifndef _TRIE_H
00024 #define _TRIE_H
00025 
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 
00030 #include "List.h"
00031 
00032 // Note that you should provide the class to use here, but we'll store
00033 // pointers to such objects internally.
00034 template<typename T>
00035 class Trie
00036 {
00037 public:
00038   Trie()
00039     {
00040       m_root.Clear();
00041     }
00042 
00043   // will return false for duplicates; key should be NULL-terminated
00044   // if key_len is defaulted to -1
00045   bool Insert(const char *key, T *value, int rank, int key_len = -1);
00046 
00047   // will return false if not found; else value_ptr will point to found value
00048   T* Search(const char *key, int key_len = -1) const;
00049   void Clear();
00050   void Print();
00051 
00052   bool Empty() const { return m_value_list.empty(); }
00053 
00054   virtual ~Trie() { Clear(); }
00055 
00056 private:
00057   static const int N_NODE_CHILDREN = 256;
00058 
00059   class Node
00060   {
00061   public:
00062     T* value;
00063     bool occupied;
00064     int rank;
00065 
00066     void Clear() {
00067       value = NULL;
00068       occupied = false;
00069       rank = 0;
00070       ink_zero(children);
00071     }
00072 
00073     void Print(const char *debug_tag) const;
00074     inline Node* GetChild(char index) const { return children[static_cast<unsigned char>(index)]; }
00075     inline Node* AllocateChild(char index) {
00076       Node * &child = children[static_cast<unsigned char>(index)];
00077       ink_assert(child == NULL);
00078       child = static_cast<Node*>(ats_malloc(sizeof(Node)));
00079       child->Clear();
00080       return child;
00081     }
00082 
00083   private:
00084     Node *children[N_NODE_CHILDREN];
00085   };
00086 
00087   Node m_root;
00088   Queue<T> m_value_list;
00089 
00090   void _CheckArgs(const char *key, int &key_len) const;
00091   void _Clear(Node *node);
00092 
00093   // make copy-constructor and assignment operator private
00094   // till we properly implement them
00095   Trie(const Trie<T> &rhs) { };
00096   Trie &operator =(const Trie<T> &rhs) { return *this; }
00097 };
00098 
00099 template<typename T>
00100 void
00101 Trie<T>::_CheckArgs(const char *key, int &key_len) const
00102 {
00103   if (!key) {
00104     key_len = 0;
00105   }
00106   else if (key_len == -1) {
00107     key_len = strlen(key);
00108   }
00109 }
00110 
00111 template<typename T>
00112 bool
00113 Trie<T>::Insert(const char *key, T* value, int rank, int key_len /* = -1 */)
00114 {
00115   _CheckArgs(key, key_len);
00116 
00117   Node *next_node;
00118   Node *curr_node = &m_root;
00119   int i = 0;
00120 
00121   while (true) {
00122     if (is_debug_tag_set("Trie::Insert")) {
00123       Debug("Trie::Insert", "Visiting Node...");
00124       curr_node->Print("Trie::Insert");
00125     }
00126 
00127     if (i == key_len) {
00128       break;
00129     }
00130 
00131     next_node = curr_node->GetChild(key[i]);
00132     if (!next_node) {
00133       while (i < key_len) {
00134         Debug("Trie::Insert", "Creating child node for char %c (%d)", key[i], key[i]);
00135         curr_node = curr_node->AllocateChild(key[i]);
00136         ++i;
00137       }
00138       break;
00139     }
00140     curr_node = next_node;
00141     ++i;
00142   }
00143 
00144   if (curr_node->occupied) {
00145     Debug("Trie::Insert", "Cannot insert duplicate!");
00146     return false;
00147   }
00148 
00149   curr_node->occupied = true;
00150   curr_node->value = value;
00151   curr_node->rank = rank;
00152   m_value_list.enqueue(curr_node->value);
00153   Debug("Trie::Insert", "inserted new element!");
00154   return true;
00155 }
00156 
00157 template<typename T>
00158 T*
00159 Trie<T>::Search(const char *key, int key_len /* = -1 */) const
00160 {
00161   _CheckArgs(key, key_len);
00162 
00163   const Node *found_node = 0;
00164   const Node *curr_node = &m_root;
00165   int i = 0;
00166 
00167   while (curr_node) {
00168     if (is_debug_tag_set("Trie::Search")) {
00169       Debug("Trie::Search", "Visiting node...");
00170       curr_node->Print("Trie::Search");
00171     }
00172     if (curr_node->occupied) {
00173       if (!found_node || curr_node->rank <= found_node->rank) {
00174         found_node = curr_node;
00175       }
00176     }
00177     if (i == key_len) {
00178       break;
00179     }
00180     curr_node = curr_node->GetChild(key[i]);
00181     ++i;
00182   }
00183 
00184   if (found_node) {
00185     Debug("Trie::Search", "Returning element with rank %d", found_node->rank);
00186     return found_node->value;
00187   }
00188 
00189   return NULL;
00190 }
00191 
00192 
00193 template<typename T>
00194 void
00195 Trie<T>::_Clear(Node *node)
00196 {
00197   Node *child;
00198 
00199   for (int i = 0; i < N_NODE_CHILDREN; ++i) {
00200     child = node->GetChild(i);
00201     if (child) {
00202       _Clear(child);
00203       ats_free(child);
00204     }
00205   }
00206 }
00207 
00208 template<typename T>
00209 void
00210 Trie<T>::Clear()
00211 {
00212   T* iter;
00213   while (NULL != (iter = m_value_list.pop()))
00214     delete iter;
00215 
00216   _Clear(&m_root);
00217   m_root.Clear();
00218 }
00219 
00220 template<typename T>
00221 void
00222 Trie<T>::Print() {
00223   // The class we contain must provide a ::Print() method.
00224   forl_LL(T, iter, m_value_list)
00225     iter->Print();
00226 }
00227 
00228 template<typename T>
00229 void
00230 Trie<T>::Node::Print(const char *debug_tag) const
00231 {
00232   if (occupied) {
00233     Debug(debug_tag, "Node is occupied");
00234     Debug(debug_tag, "Node has rank %d", rank);
00235   } else {
00236     Debug(debug_tag, "Node is not occupied");
00237   }
00238 
00239   for (int i = 0; i < N_NODE_CHILDREN; ++i) {
00240     if (GetChild(i)) {
00241       Debug(debug_tag, "Node has child for char %c", static_cast<char>(i));
00242     }
00243   }
00244 }
00245 
00246 #endif // _TRIE_H

Generated by  doxygen 1.7.1