llvm.org GIT mirror llvm / 64735cc
Add first and really dirty version of generic Trie structure git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44851 91177308-0d34-0410-b5e6-96231b3b80d8 Anton Korobeynikov 12 years ago
1 changed file(s) with 223 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===- llvm/ADT/Trie.h ---- Generic trie structure --------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file was developed by Anton Korobeynikov and is distributed under
5 // the University of Illinois Open Source License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This class defines a generic trie structure. The trie structure
10 // is immutable after creation, but the payload contained within it is not.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_ADT_TRIE_H
15 #define LLVM_ADT_TRIE_H
16
17 #include
18 #include
19
20 namespace llvm {
21
22 // FIXME:
23 // - Labels are usually small, maybe it's better to use SmallString
24 // - Something efficient for child storage
25 // - Should we use char* during construction?
26 // - GraphTraits interface
27 // - Eliminate Edge class, which is ok for debugging, but not for end code
28
29 template
30 class Trie {
31 class Edge;
32 class Node;
33
34 class Edge {
35 std::string Label;
36 Node *Parent, *Child;
37
38 public:
39 typedef enum {
40 Same = -3,
41 StringIsPrefix = -2,
42 LabelIsPrefix = -1,
43 DontMatch = 0,
44 HaveCommonPart
45 } QueryResult;
46
47 inline explicit Edge(std::string label = "",
48 Node* parent = NULL, Node* child = NULL):
49 Label(label), Parent(parent), Child(child) { }
50
51 inline void setParent(Node* parent) { Parent = parent; }
52 inline Node* getParent() const { return Parent; }
53 inline void setChild(Node* child) { Child = child; }
54 inline Node* getChild() const { return Child; }
55 inline void setLabel(const std::string& label) { Label = label; }
56 inline const std::string& getLabel() const { return Label; }
57
58 QueryResult query(const std::string& string) const {
59 unsigned i, l;
60 unsigned l1 = string.length();
61 unsigned l2 = Label.length();
62
63 // Find the length of common part
64 l = std::min(l1, l2);
65 i = 0;
66 while ((i < l) && (string[i] == Label[i]))
67 ++i;
68
69 if (i == l) { // One is prefix of another, find who is who
70 if (l1 == l2)
71 return Same;
72 else if (i == l1)
73 return StringIsPrefix;
74 else
75 return LabelIsPrefix;
76 } else // String and Label just have common part, return its length
77 return (QueryResult)i;
78 }
79 };
80
81 class Node {
82 friend class Trie;
83
84 std::map Edges;
85 Payload Data;
86 public:
87 inline explicit Node(const Payload& data):Data(data) { }
88 inline Node(const Node& n) {
89 Data = n.Data;
90 Edges = n.Edges;
91 }
92 inline Node& operator=(const Node& n) {
93 if (&n != this) {
94 Data = n.Data;
95 Edges = n.Edges;
96 }
97
98 return *this;
99 }
100
101 inline bool isLeaf() const { return Edges.empty(); }
102
103 inline const Payload& getData() const { return Data; }
104 inline void setData(const Payload& data) { Data = data; }
105
106 inline Edge* addEdge(const std::string& Label) {
107 if (!Edges.insert(std::make_pair(Label[0],
108 Edge(Label, this))).second) {
109 assert(0 && "Edge already exists!");
110 return NULL;
111 } else
112 return &Edges[Label[0]];
113 }
114 };
115
116 std::vector Nodes;
117 Payload Empty;
118
119 inline Node* addNode(const Payload& data) {
120 Node* N = new Node(data);
121 Nodes.push_back(N);
122 return N;
123 }
124
125 inline Node* splitEdge(Edge& cEdge, size_t index) {
126 const std::string& l = cEdge.getLabel();
127 assert(index < l.length() && "Trying to split too far!");
128
129 std::string l1 = l.substr(0, index);
130 std::string l2 = l.substr(index);
131
132 Node* nNode = addNode(Empty);
133 Edge* nEdge = nNode->addEdge(l2);
134 nEdge->setChild(cEdge.getChild());
135 cEdge.setChild(nNode);
136 cEdge.setLabel(l1);
137
138 return nNode;
139 }
140
141 public:
142 inline explicit Trie(const Payload& empty):Empty(empty) {
143 addNode(Empty);
144 }
145 inline ~Trie() {
146 for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
147 delete Nodes[i];
148 }
149
150 inline Node* getRoot() const { return Nodes[0]; }
151
152 bool addString(const std::string& s, const Payload& data) {
153 Node* cNode = getRoot();
154 Edge* nEdge = NULL;
155 std::string s1(s);
156
157 while (nEdge == NULL) {
158 if (cNode->Edges.count(s1[0])) {
159 Edge& cEdge = cNode->Edges[s1[0]];
160 typename Edge::QueryResult r = cEdge.query(s1);
161
162 switch (r) {
163 case Edge::Same:
164 case Edge::StringIsPrefix:
165 case Edge::DontMatch:
166 assert(0 && "Impossible!");
167 return false;
168 case Edge::LabelIsPrefix:
169 s1 = s1.substr(cEdge.getLabel().length());
170 cNode = cEdge.getChild();
171 break;
172 default:
173 nEdge = splitEdge(cEdge, r)->addEdge(s1.substr(r));
174 }
175 } else
176 nEdge = cNode->addEdge(s1);
177 }
178
179 Node* tNode = addNode(data);
180 nEdge->setChild(tNode);
181
182 return true;
183 }
184
185 const Payload& lookup(const std::string& s) const {
186 Node* cNode = getRoot();
187 Node* tNode = NULL;
188 std::string s1(s);
189
190 while (tNode == NULL) {
191 if (cNode->Edges.count(s1[0])) {
192 Edge& cEdge = cNode->Edges[s1[0]];
193 typename Edge::QueryResult r = cEdge.query(s1);
194
195 switch (r) {
196 case Edge::Same:
197 tNode = cEdge.getChild();
198 break;
199 case Edge::StringIsPrefix:
200 return Empty;
201 case Edge::DontMatch:
202 assert(0 && "Impossible!");
203 return Empty;
204 case Edge::LabelIsPrefix:
205 s1 = s1.substr(cEdge.getLabel().length());
206 cNode = cEdge.getChild();
207 break;
208 default:
209 return Empty;
210 }
211 } else
212 return Empty;
213 }
214
215 return tNode->getData();
216 }
217
218 };
219
220 }
221
222 #endif // LLVM_ADT_TRIE_H