2007-12-11 06:53:44 +00:00
|
|
|
//===- llvm/ADT/Trie.h ---- Generic trie structure --------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by Anton Korobeynikov and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This class defines a generic trie structure. The trie structure
|
|
|
|
// is immutable after creation, but the payload contained within it is not.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_ADT_TRIE_H
|
|
|
|
#define LLVM_ADT_TRIE_H
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
// FIXME:
|
|
|
|
// - Labels are usually small, maybe it's better to use SmallString
|
|
|
|
// - Something efficient for child storage
|
|
|
|
// - Should we use char* during construction?
|
2007-12-11 21:55:38 +00:00
|
|
|
// - Should we templatize Empty with traits-like interface?
|
2007-12-11 06:53:44 +00:00
|
|
|
// - GraphTraits interface
|
|
|
|
|
|
|
|
template<class Payload>
|
|
|
|
class Trie {
|
2007-12-11 21:55:38 +00:00
|
|
|
class Node {
|
|
|
|
friend class Trie;
|
2007-12-11 06:53:44 +00:00
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
Same = -3,
|
|
|
|
StringIsPrefix = -2,
|
|
|
|
LabelIsPrefix = -1,
|
|
|
|
DontMatch = 0,
|
|
|
|
HaveCommonPart
|
|
|
|
} QueryResult;
|
|
|
|
|
2007-12-11 21:55:38 +00:00
|
|
|
std::string Label;
|
|
|
|
Payload Data;
|
|
|
|
std::map<char, Node*> Children;
|
|
|
|
public:
|
|
|
|
inline explicit Node(const Payload& data, const std::string& label = ""):
|
|
|
|
Label(label), Data(data) { }
|
|
|
|
|
|
|
|
inline Node(const Node& n) {
|
|
|
|
Data = n.Data;
|
|
|
|
Children = n.Children;
|
|
|
|
Label = n.Label;
|
|
|
|
}
|
|
|
|
inline Node& operator=(const Node& n) {
|
|
|
|
if (&n != this) {
|
|
|
|
Data = n.Data;
|
|
|
|
Children = n.Children;
|
|
|
|
Label = n.Label;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool isLeaf() const { return Children.empty(); }
|
|
|
|
|
|
|
|
inline const Payload& getData() const { return Data; }
|
|
|
|
inline void setData(const Payload& data) { Data = data; }
|
2007-12-11 06:53:44 +00:00
|
|
|
|
|
|
|
inline void setLabel(const std::string& label) { Label = label; }
|
|
|
|
inline const std::string& getLabel() const { return Label; }
|
|
|
|
|
2007-12-11 21:55:38 +00:00
|
|
|
inline bool addEdge(Node* N) {
|
|
|
|
const std::string& Label = N->getLabel();
|
|
|
|
return Children.insert(std::make_pair(Label[0], N)).second;
|
|
|
|
}
|
|
|
|
|
|
|
|
QueryResult query(const std::string& s) const {
|
2007-12-11 06:53:44 +00:00
|
|
|
unsigned i, l;
|
2007-12-11 21:55:38 +00:00
|
|
|
unsigned l1 = s.length();
|
2007-12-11 06:53:44 +00:00
|
|
|
unsigned l2 = Label.length();
|
|
|
|
|
|
|
|
// Find the length of common part
|
|
|
|
l = std::min(l1, l2);
|
|
|
|
i = 0;
|
2007-12-11 21:55:38 +00:00
|
|
|
while ((i < l) && (s[i] == Label[i]))
|
2007-12-11 06:53:44 +00:00
|
|
|
++i;
|
|
|
|
|
|
|
|
if (i == l) { // One is prefix of another, find who is who
|
|
|
|
if (l1 == l2)
|
|
|
|
return Same;
|
|
|
|
else if (i == l1)
|
|
|
|
return StringIsPrefix;
|
|
|
|
else
|
|
|
|
return LabelIsPrefix;
|
2007-12-11 21:55:38 +00:00
|
|
|
} else // s and Label have common (possible empty) part, return its length
|
2007-12-11 06:53:44 +00:00
|
|
|
return (QueryResult)i;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<Node*> Nodes;
|
|
|
|
Payload Empty;
|
|
|
|
|
2007-12-11 21:55:38 +00:00
|
|
|
inline Node* addNode(const Payload& data, const std::string label = "") {
|
|
|
|
Node* N = new Node(data, label);
|
2007-12-11 06:53:44 +00:00
|
|
|
Nodes.push_back(N);
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2007-12-11 21:55:38 +00:00
|
|
|
inline Node* splitEdge(Node* N, char Id, size_t index) {
|
|
|
|
assert(N->Children.count(Id) && "Node doesn't exist");
|
|
|
|
|
|
|
|
Node* eNode = N->Children[Id];
|
2007-12-11 06:53:44 +00:00
|
|
|
|
2007-12-11 21:55:38 +00:00
|
|
|
const std::string &l = eNode->Label;
|
|
|
|
assert(index > 0 && index < l.length() && "Trying to split too far!");
|
2007-12-11 06:53:44 +00:00
|
|
|
std::string l1 = l.substr(0, index);
|
|
|
|
std::string l2 = l.substr(index);
|
|
|
|
|
2007-12-11 21:55:38 +00:00
|
|
|
eNode->Label = l2;
|
|
|
|
|
|
|
|
Node* nNode = addNode(Empty, l1);
|
|
|
|
nNode->addEdge(eNode);
|
|
|
|
|
|
|
|
N->Children[Id] = nNode;
|
2007-12-11 06:53:44 +00:00
|
|
|
|
|
|
|
return nNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
inline explicit Trie(const Payload& empty):Empty(empty) {
|
|
|
|
addNode(Empty);
|
|
|
|
}
|
|
|
|
inline ~Trie() {
|
|
|
|
for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
|
|
|
|
delete Nodes[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Node* getRoot() const { return Nodes[0]; }
|
|
|
|
|
|
|
|
bool addString(const std::string& s, const Payload& data) {
|
|
|
|
Node* cNode = getRoot();
|
2007-12-11 21:55:38 +00:00
|
|
|
Node* tNode = NULL;
|
2007-12-11 06:53:44 +00:00
|
|
|
std::string s1(s);
|
|
|
|
|
2007-12-11 21:55:38 +00:00
|
|
|
while (tNode == NULL) {
|
|
|
|
char Id = s1[0];
|
|
|
|
if (cNode->Children.count(Id)) {
|
|
|
|
Node* nNode = cNode->Children[Id];
|
|
|
|
typename Node::QueryResult r = nNode->query(s1);
|
2007-12-11 06:53:44 +00:00
|
|
|
|
|
|
|
switch (r) {
|
2007-12-11 21:55:38 +00:00
|
|
|
case Node::Same:
|
|
|
|
case Node::StringIsPrefix:
|
|
|
|
// Currently we don't allow to have two strings in the trie one
|
|
|
|
// being a prefix of another. This should be fixed.
|
|
|
|
assert(0 && "FIXME!");
|
|
|
|
return false;
|
|
|
|
case Node::DontMatch:
|
2007-12-11 06:53:44 +00:00
|
|
|
assert(0 && "Impossible!");
|
|
|
|
return false;
|
2007-12-11 21:55:38 +00:00
|
|
|
case Node::LabelIsPrefix:
|
|
|
|
s1 = s1.substr(nNode->getLabel().length());
|
|
|
|
cNode = nNode;
|
2007-12-11 06:53:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
2007-12-11 21:55:38 +00:00
|
|
|
nNode = splitEdge(cNode, Id, r);
|
|
|
|
tNode = addNode(data, s1.substr(r));
|
|
|
|
nNode->addEdge(tNode);
|
2007-12-11 06:53:44 +00:00
|
|
|
}
|
2007-12-11 21:55:38 +00:00
|
|
|
} else {
|
|
|
|
tNode = addNode(data, s1);
|
|
|
|
cNode->addEdge(tNode);
|
|
|
|
}
|
2007-12-11 06:53:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Payload& lookup(const std::string& s) const {
|
|
|
|
Node* cNode = getRoot();
|
|
|
|
Node* tNode = NULL;
|
|
|
|
std::string s1(s);
|
|
|
|
|
|
|
|
while (tNode == NULL) {
|
2007-12-11 21:55:38 +00:00
|
|
|
if (cNode->Children.count(s1[0])) {
|
|
|
|
Node* nNode = cNode->Children[s1[0]];
|
|
|
|
typename Node::QueryResult r = nNode->query(s1);
|
2007-12-11 06:53:44 +00:00
|
|
|
|
|
|
|
switch (r) {
|
2007-12-11 21:55:38 +00:00
|
|
|
case Node::Same:
|
|
|
|
tNode = nNode;
|
2007-12-11 06:53:44 +00:00
|
|
|
break;
|
2007-12-11 21:55:38 +00:00
|
|
|
case Node::StringIsPrefix:
|
2007-12-11 06:53:44 +00:00
|
|
|
return Empty;
|
2007-12-11 21:55:38 +00:00
|
|
|
case Node::DontMatch:
|
2007-12-11 06:53:44 +00:00
|
|
|
assert(0 && "Impossible!");
|
|
|
|
return Empty;
|
2007-12-11 21:55:38 +00:00
|
|
|
case Node::LabelIsPrefix:
|
|
|
|
s1 = s1.substr(nNode->getLabel().length());
|
|
|
|
cNode = nNode;
|
2007-12-11 06:53:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return Empty;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return Empty;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tNode->getData();
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // LLVM_ADT_TRIE_H
|