LLVM API Documentation
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