LLVM API Documentation

Trie.h

Go to the documentation of this file.
00001 //===- llvm/ADT/Trie.h ---- Generic trie structure --------------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This class defines a generic trie structure. The trie structure
00011 // is immutable after creation, but the payload contained within it is not.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #ifndef LLVM_ADT_TRIE_H
00016 #define LLVM_ADT_TRIE_H
00017 
00018 #include "llvm/ADT/GraphTraits.h"
00019 #include "llvm/Support/DOTGraphTraits.h"
00020 
00021 #include <vector>
00022 
00023 namespace llvm {
00024 
00025 // FIXME:
00026 // - Labels are usually small, maybe it's better to use SmallString
00027 // - Should we use char* during construction?
00028 // - Should we templatize Empty with traits-like interface?
00029 
00030 template<class Payload>
00031 class Trie {
00032   friend class GraphTraits<Trie<Payload> >;
00033   friend class DOTGraphTraits<Trie<Payload> >;
00034 public:
00035   class Node {
00036     friend class Trie;
00037 
00038   public:
00039     typedef std::vector<Node*> NodeVectorType;
00040     typedef typename NodeVectorType::iterator iterator;
00041     typedef typename NodeVectorType::const_iterator const_iterator;
00042 
00043   private:
00044     enum QueryResult {
00045       Same           = -3,
00046       StringIsPrefix = -2,
00047       LabelIsPrefix  = -1,
00048       DontMatch      = 0,
00049       HaveCommonPart
00050     };
00051 
00052     struct NodeCmp {
00053       bool operator() (Node* N1, Node* N2) {
00054         return (N1->Label[0] < N2->Label[0]);
00055       }
00056       bool operator() (Node* N, char Id) {
00057         return (N->Label[0] < Id);
00058       }
00059     };
00060 
00061     std::string Label;
00062     Payload Data;
00063     NodeVectorType Children;
00064 
00065     // Do not implement
00066     Node(const Node&);
00067     Node& operator=(const Node&);
00068 
00069     inline void addEdge(Node* N) {
00070       if (Children.empty())
00071         Children.push_back(N);
00072       else {
00073         iterator I = std::lower_bound(Children.begin(), Children.end(),
00074                                       N, NodeCmp());
00075         // FIXME: no dups are allowed
00076         Children.insert(I, N);
00077       }
00078     }
00079 
00080     inline void setEdge(Node* N) {
00081       char Id = N->Label[0];
00082       iterator I = std::lower_bound(Children.begin(), Children.end(),
00083                                      Id, NodeCmp());
00084       assert(I != Children.end() && "Node does not exists!");
00085       *I = N;
00086     }
00087 
00088     QueryResult query(const std::string& s) const {
00089       unsigned i, l;
00090       unsigned l1 = s.length();
00091       unsigned l2 = Label.length();
00092 
00093       // Find the length of common part
00094       l = std::min(l1, l2);
00095       i = 0;
00096       while ((i < l) && (s[i] == Label[i]))
00097         ++i;
00098 
00099       if (i == l) { // One is prefix of another, find who is who
00100         if (l1 == l2)
00101           return Same;
00102         else if (i == l1)
00103           return StringIsPrefix;
00104         else
00105           return LabelIsPrefix;
00106       } else // s and Label have common (possible empty) part, return its length
00107         return (QueryResult)i;
00108     }
00109 
00110   public:
00111     inline explicit Node(const Payload& data, const std::string& label = ""):
00112         Label(label), Data(data) { }
00113 
00114     inline const Payload& data() const { return Data; }
00115     inline void setData(const Payload& data) { Data = data; }
00116 
00117     inline const std::string& label() const { return Label; }
00118 
00119 #if 0
00120     inline void dump() {
00121       std::cerr << "Node: " << this << "\n"
00122                 << "Label: " << Label << "\n"
00123                 << "Children:\n";
00124 
00125       for (iterator I = Children.begin(), E = Children.end(); I != E; ++I)
00126         std::cerr << (*I)->Label << "\n";
00127     }
00128 #endif
00129 
00130     inline Node* getEdge(char Id) {
00131       Node* fNode = NULL;
00132       iterator I = std::lower_bound(Children.begin(), Children.end(),
00133                                           Id, NodeCmp());
00134       if (I != Children.end() && (*I)->Label[0] == Id)
00135         fNode = *I;
00136 
00137       return fNode;
00138     }
00139 
00140     inline iterator       begin()       { return Children.begin(); }
00141     inline const_iterator begin() const { return Children.begin(); }
00142     inline iterator       end  ()       { return Children.end();   }
00143     inline const_iterator end  () const { return Children.end();   }
00144 
00145     inline size_t         size () const { return Children.size();  }
00146     inline bool           empty() const { return Children.empty(); }
00147     inline const Node*   &front() const { return Children.front(); }
00148     inline       Node*   &front()       { return Children.front(); }
00149     inline const Node*   &back()  const { return Children.back();  }
00150     inline       Node*   &back()        { return Children.back();  }
00151 
00152   };
00153 
00154 private:
00155   std::vector<Node*> Nodes;
00156   Payload Empty;
00157 
00158   inline Node* addNode(const Payload& data, const std::string label = "") {
00159     Node* N = new Node(data, label);
00160     Nodes.push_back(N);
00161     return N;
00162   }
00163 
00164   inline Node* splitEdge(Node* N, char Id, size_t index) {
00165     Node* eNode = N->getEdge(Id);
00166     assert(eNode && "Node doesn't exist");
00167 
00168     const std::string &l = eNode->Label;
00169     assert(index > 0 && index < l.length() && "Trying to split too far!");
00170     std::string l1 = l.substr(0, index);
00171     std::string l2 = l.substr(index);
00172 
00173     Node* nNode = addNode(Empty, l1);
00174     N->setEdge(nNode);
00175 
00176     eNode->Label = l2;
00177     nNode->addEdge(eNode);
00178 
00179     return nNode;
00180   }
00181 
00182   // Do not implement
00183   Trie(const Trie&);
00184   Trie& operator=(const Trie&);
00185 
00186 public:
00187   inline explicit Trie(const Payload& empty):Empty(empty) {
00188     addNode(Empty);
00189   }
00190   inline ~Trie() {
00191     for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
00192       delete Nodes[i];
00193   }
00194 
00195   inline Node* getRoot() const { return Nodes[0]; }
00196 
00197   bool addString(const std::string& s, const Payload& data);
00198   const Payload& lookup(const std::string& s) const;
00199 
00200 };
00201 
00202 // Define this out-of-line to dissuade the C++ compiler from inlining it.
00203 template<class Payload>
00204 bool Trie<Payload>::addString(const std::string& s, const Payload& data) {
00205   Node* cNode = getRoot();
00206   Node* tNode = NULL;
00207   std::string s1(s);
00208 
00209   while (tNode == NULL) {
00210     char Id = s1[0];
00211     if (Node* nNode = cNode->getEdge(Id)) {
00212       typename Node::QueryResult r = nNode->query(s1);
00213 
00214       switch (r) {
00215       case Node::Same:
00216       case Node::StringIsPrefix:
00217         // Currently we don't allow to have two strings in the trie one
00218         // being a prefix of another. This should be fixed.
00219         assert(0 && "FIXME!");
00220         return false;
00221       case Node::DontMatch:
00222         assert(0 && "Impossible!");
00223         return false;
00224       case Node::LabelIsPrefix:
00225         s1 = s1.substr(nNode->label().length());
00226         cNode = nNode;
00227         break;
00228       default:
00229         nNode = splitEdge(cNode, Id, r);
00230         tNode = addNode(data, s1.substr(r));
00231         nNode->addEdge(tNode);
00232       }
00233     } else {
00234       tNode = addNode(data, s1);
00235       cNode->addEdge(tNode);
00236     }
00237   }
00238 
00239   return true;
00240 }
00241 
00242 template<class Payload>
00243 const Payload& Trie<Payload>::lookup(const std::string& s) const {
00244   Node* cNode = getRoot();
00245   Node* tNode = NULL;
00246   std::string s1(s);
00247 
00248   while (tNode == NULL) {
00249     char Id = s1[0];
00250     if (Node* nNode = cNode->getEdge(Id)) {
00251       typename Node::QueryResult r = nNode->query(s1);
00252 
00253       switch (r) {
00254       case Node::Same:
00255         tNode = nNode;
00256         break;
00257       case Node::StringIsPrefix:
00258         return Empty;
00259       case Node::DontMatch:
00260         assert(0 && "Impossible!");
00261         return Empty;
00262       case Node::LabelIsPrefix:
00263         s1 = s1.substr(nNode->label().length());
00264         cNode = nNode;
00265         break;
00266       default:
00267         return Empty;
00268       }
00269     } else
00270       return Empty;
00271   }
00272 
00273   return tNode->data();
00274 }
00275 
00276 template<class Payload>
00277 struct GraphTraits<Trie<Payload> > {
00278   typedef Trie<Payload> TrieType;
00279   typedef typename TrieType::Node NodeType;
00280   typedef typename NodeType::iterator ChildIteratorType;
00281 
00282   static inline NodeType *getEntryNode(const TrieType& T) { return T.getRoot(); }
00283 
00284   static inline ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
00285   static inline ChildIteratorType child_end(NodeType *N) { return N->end(); }
00286 
00287   typedef typename std::vector<NodeType*>::const_iterator nodes_iterator;
00288 
00289   static inline nodes_iterator nodes_begin(const TrieType& G) {
00290     return G.Nodes.begin();
00291   }
00292   static inline nodes_iterator nodes_end(const TrieType& G) {
00293     return G.Nodes.end();
00294   }
00295 
00296 };
00297 
00298 template<class Payload>
00299 struct DOTGraphTraits<Trie<Payload> > : public DefaultDOTGraphTraits {
00300   typedef typename Trie<Payload>::Node NodeType;
00301   typedef typename GraphTraits<Trie<Payload> >::ChildIteratorType EdgeIter;
00302 
00303   static std::string getGraphName(const Trie<Payload>& T) {
00304     return "Trie";
00305   }
00306 
00307   static std::string getNodeLabel(NodeType* Node, const Trie<Payload>& T) {
00308     if (T.getRoot() == Node)
00309       return "<Root>";
00310     else
00311       return Node->label();
00312   }
00313 
00314   static std::string getEdgeSourceLabel(NodeType* Node, EdgeIter I) {
00315     NodeType* N = *I;
00316     return N->label().substr(0, 1);
00317   }
00318 
00319   static std::string getNodeAttributes(const NodeType* Node,
00320                                        const Trie<Payload>& T) {
00321     if (Node->data() != T.Empty)
00322       return "color=blue";
00323 
00324     return "";
00325   }
00326 
00327 };
00328 
00329 } // end of llvm namespace
00330 
00331 #endif // LLVM_ADT_TRIE_H