Codebase list mozc / 25b997d
Refactor LOUDS trie by introducing a new API set for traversal Louds::Node structure is introduced to represent the position in the tree during traversal. Three basic movements are implemented: 1) go to the first child, 2) go to the next sibling, and 3) go to the parent. This new design brings a few benefits: * Intermediate traversal state can be saved (e.g., incremental search can be implemented). * Similar pieces of code in ExactSearcher, PrefixSearcher and PredictiveSearcher are factored out, so new code looks more concise and intuitive. * New APIs take StringPiece instead of const char*. Using the new APIs, LoudsTrie::HasKey is introduced, which is a faster modification of LoudsTrie::ExactSearch to test the existence of key, where one Rank1 operation is saved compared to ExactSearch. This is nice because HasKey is called more often than before, e.g., from LanguageAwareRewriter. Also, in LoudsTrie::Reverse, which is renamed to LoudsTrie::RestoreKeyString, one Rank0 operation is eliminated in the loop of key string reconstruction. Namely, N operations are saved for keys of length N. Benchmark shows no performance regression. Also, this is just a code refactoring, no behavior change is intended. BUG=none TEST=unittest,benchmark git-svn-id: https://mozc.googlecode.com/svn/trunk@524 a6090854-d499-a067-5803-1114d4e51264 Noriyuki Takahashi authored 9 years ago Yohei Yukawa committed 9 years ago
6 changed file(s) with 599 addition(s) and 424 deletion(s). Raw diff Collapse all Expand all
295295
296296 void LookupValue(int id, string *value) const {
297297 char buffer[LoudsTrie::kMaxDepth + 1];
298 const char *encoded_value = value_trie_->Reverse(id, buffer);
299 const size_t encoded_value_len =
300 LoudsTrie::kMaxDepth - (encoded_value - buffer);
301 DCHECK_EQ(encoded_value_len, strlen(encoded_value));
302 codec_->DecodeValue(StringPiece(encoded_value, encoded_value_len), value);
298 const StringPiece encoded_value = value_trie_->RestoreKeyString(id, buffer);
299 codec_->DecodeValue(encoded_value, value);
303300 }
304301
305302 const SystemDictionaryCodecInterface *codec_;
659656 bool SystemDictionary::HasKey(StringPiece key) const {
660657 string encoded_key;
661658 codec_->EncodeKey(key, &encoded_key);
662 return (key_trie_->ExactSearch(encoded_key) != -1);
659 return key_trie_->HasKey(encoded_key);
663660 }
664661
665662 bool SystemDictionary::HasValue(StringPiece value) const {
666663 string encoded_value;
667664 codec_->EncodeValue(value, &encoded_value);
668 if (value_trie_->ExactSearch(encoded_value) != -1) {
665 if (value_trie_->HasKey(encoded_value)) {
669666 return true;
670667 }
671668
893890 const KeyExpansionTable &table =
894891 use_kana_modifier_insensitive_lookup ?
895892 hiragana_expansion_table_ : KeyExpansionTable::GetDefaultInstance();
896 key_trie_->PredictiveSearchWithKeyExpansion(lookup_key_str.c_str(), table,
893 key_trie_->PredictiveSearchWithKeyExpansion(lookup_key_str, table,
897894 &collector);
898895
899896 string decoded_key, actual_key;
10591056 const KeyExpansionTable &table = use_kana_modifier_insensitive_lookup ?
10601057 hiragana_expansion_table_ : KeyExpansionTable::GetDefaultInstance();
10611058 key_trie_->PrefixSearchWithKeyExpansion(
1062 original_encoded_key.c_str(), table, &traverser);
1059 original_encoded_key, table, &traverser);
10631060 }
10641061
10651062 void SystemDictionary::LookupExact(StringPiece key, Callback *callback) const {
11571154 const StringPiece suffix(str, pos);
11581155 string lookup_key;
11591156 codec_->EncodeValue(suffix, &lookup_key);
1160 value_trie_->PrefixSearch(lookup_key.c_str(), &id_collector);
1157 value_trie_->PrefixSearch(lookup_key, &id_collector);
11611158 pos += Util::OneCharLen(suffix.data());
11621159 }
11631160 // Collect tokens for all IDs.
12361233 T13nPrefixTraverser traverser(token_array_.get(), value_trie_.get(), codec_,
12371234 frequent_pos_, original_encoded_key, callback);
12381235 key_trie_->PrefixSearchWithKeyExpansion(
1239 original_encoded_key.c_str(), KeyExpansionTable::GetDefaultInstance(),
1236 original_encoded_key, KeyExpansionTable::GetDefaultInstance(),
12401237 &traverser);
12411238 }
12421239
12471244 codec_->EncodeValue(value, &lookup_key);
12481245
12491246 IdCollector id_collector;
1250 value_trie_->PrefixSearch(lookup_key.c_str(), &id_collector);
1247 value_trie_->PrefixSearch(lookup_key, &id_collector);
12511248 const set<int> &id_set = id_collector.id_set();
12521249
12531250 const bool has_cache = (allocator != NULL &&
13121309 ++result_itr) {
13131310 const ReverseLookupResult &reverse_result = result_itr->second;
13141311
1315 const char *encoded_key =
1316 key_trie_->Reverse(reverse_result.id_in_key_trie, buffer);
1317 const size_t encoded_key_len =
1318 LoudsTrie::kMaxDepth - (encoded_key - buffer);
1319 DCHECK_EQ(encoded_key_len, strlen(encoded_key));
1312 const StringPiece encoded_key =
1313 key_trie_->RestoreKeyString(reverse_result.id_in_key_trie, buffer);
13201314 string tokens_key;
1321 codec_->DecodeKey(StringPiece(encoded_key, encoded_key_len), &tokens_key);
1315 codec_->DecodeKey(encoded_key, &tokens_key);
13221316 if (callback->OnKey(tokens_key) !=
13231317 SystemDictionary::Callback::TRAVERSE_CONTINUE) {
13241318 continue;
00 MAJOR=2
11 MINOR=16
2 BUILD=2040
2 BUILD=2041
33 REVISION=102
44 # NACL_DICTIONARY_VERSION is the target version of the system dictionary to be
55 # downloaded by NaCl Mozc.
3636 namespace storage {
3737 namespace louds {
3838
39 // Implementation of the LOUDS (Level-Ordered Unary degree sequence).
40 // LOUDS is a representation of tree by bit sequence, which supports "rank"
41 // and "select" operations.
42 // The representation of each node is "n 1-bits, followed by a 0-bit," where
43 // n is the number of its children.
44 // So, for example, if a node has two children, the erepresentation of
45 // the node is "110". Another example is that a leaf is represented by "0".
46 // The nodes are stored in breadth first order, and each node has its id
47 // (0-origin, i.e. the root node is '0', the first child of the root is '1'
48 // and so on).
49 // This class provides some utilities between the "index of the bit array
50 // representation" and "node id of the tree".
51 // In this representation, we can think that each '1'-bit is corresponding
52 // to an edge.
39 // Implementation of the Level-Ordered Unary Degree Sequence (LOUDS).
40 //
41 // LOUDS represents a tree structure using a bit sequence. A node having N
42 // children is represented by N 1's and one trailing 0. For example, "110"
43 // represents a node with 2 children, while "0" represents a leaf. The bit
44 // sequence starts with the representation of super-root, "10", and is followed
45 // by representations of nodes in order of breadth first manner; see the
46 // following example:
47 //
48 // 0 (super root)
49 // |
50 // 1 (root)
51 // / \ .
52 // 2 3
53 // / \ .
54 // 4 5
55 //
56 // Node: 0 1 2 3 4 5
57 // LOUDS: 10 110 0 110 0 0
58 //
59 // This class provides basic APIs to traverse a tree structure.
5360 class Louds {
5461 public:
55 Louds() {
62 // Represents and stores location (tree node) for tree traversal. By storing
63 // instances of this class, traversal state can be restored. This class is
64 // copy-efficient.
65 class Node {
66 public:
67 // Default instance represents the root node (not the super-root).
68 Node() : edge_index_(0), node_id_(1) {}
69 Node(const Node &n) : edge_index_(n.edge_index_), node_id_(n.node_id_) {}
70
71 int node_id() const { return node_id_; }
72
73 friend bool operator==(const Node &x, const Node &y) {
74 return x.edge_index_ == y.edge_index_ && x.node_id_ == y.node_id_;
75 }
76
77 private:
78 int edge_index_;
79 int node_id_;
80 friend class Louds;
81 };
82
83 Louds() {}
84 ~Louds() {}
85
86 // Initializes this LOUDS from bit array.
87 void Init(const uint8 *image, int length) {
88 index_.Init(image, length);
5689 }
5790
58 void Open(const uint8 *image, int length) {
59 index_.Init(image, length);
60 }
61 void Close() {
91 // Explicitly clears the internal bit array.
92 void Reset() {
6293 index_.Reset();
6394 }
6495
65 // Returns true, if the corresponding bit represents an edge.
66 // TODO(hidehiko): Check the performance of the conversion between int and
67 // bool, because this method should be invoked so many times.
68 inline bool IsEdgeBit(int bit_index) const {
69 return (index_.Get(bit_index) != 0);
96 // APIs for traversal (all the methods are inline for performance).
97
98 // Initializes a Node instance from node ID.
99 // Note: to get the root node, just allocate a default Node instance.
100 void InitNodeFromNodeId(int node_id, Node *node) const {
101 node->node_id_ = node_id;
102 node->edge_index_ = index_.Select1(node->node_id_);
70103 }
71104
72 // Returns the child node id of the edge corresponding to the given bit
73 // index.
74 // Note: the bit at the given index must be '1'.
75 inline int GetChildNodeId(int bit_index) const {
76 return index_.Rank1(bit_index) + 1;
105 // Returns true if the given node is the root.
106 static bool IsRoot(const Node &node) {
107 return node.node_id_ == 1;
77108 }
78109
79 // Returns the parent node id of the edge corresponding to the given bit
80 // index.
81 // Note: this takes the bit index (as the argument variable name),
82 // so it is OK to pass the bit index even if the bit is '0'.
83 inline int GetParentNodeId(int bit_index) const {
84 return index_.Rank0(bit_index);
110 // Moves the given node to its first (most left) child. If |node| is a leaf,
111 // the resulting node becomes invalid. For example, in the above diagram of
112 // tree, moves are as follows:
113 // * node 1 -> node 2
114 // * node 3 -> node 4
115 // * node 4 -> invalid node
116 // REQUIRES: |node| is valid.
117 void MoveToFirstChild(Node *node) const {
118 node->edge_index_ = index_.Select0(node->node_id_) + 1;
119 node->node_id_ = node->edge_index_ - node->node_id_ + 1;
85120 }
86121
87 // Returns the bit index corresponding to the node's first edge.
88 inline int GetFirstEdgeBitIndex(int node_id) const {
89 return index_.Select0(node_id) + 1;
122 // Moves the given node to its next (right) sibling. If there's no sibling
123 // for |node|, the resulting node becomes invalid. For example, in the above
124 // diagram of tree, moves are as follows:
125 // * node 1 -> invalid node
126 // * node 2 -> node 3
127 // * node 5 -> invalid node
128 // REQUIRES: |node| is valid.
129 static void MoveToNextSibling(Node *node) {
130 ++node->edge_index_;
131 ++node->node_id_;
90132 }
91133
92 // Returns the bit index corresponding to "the node to its parent" edge.
93 // Note: the root node has no parent, so node_id must > 0.
94 inline int GetParentEdgeBitIndex(int node_id) const {
95 return index_.Select1(node_id);
134 // Moves the given node to its unique parent. For example, in the above
135 // diagram of tree, moves are as follows:
136 // * node 2 -> node 1
137 // * node 3 -> node 1
138 // * node 5 -> node 3
139 // REQUIRES: |node| is valid and not root.
140 void MoveToParent(Node *node) const {
141 node->node_id_ = node->edge_index_ - node->node_id_ + 1;
142 node->edge_index_ = index_.Select1(node->node_id_);
96143 }
97144
98 // Returns the node id for the first child node of the given node.
99 // The bit_index must be the bit index of the first edge bit index of the
100 // node. This method calculates the id effectively, at least more effective
101 // than calculating by Rank.
102 static inline int GetChildNodeId(int node_id, int bit_index) {
103 // Note: node_id == Rank0(bit_index),
104 // so "bit_index - node_id" == Rank1(bit_index).
105 // The first child_node_id is "Rank1(bit_index) + 1".
106 return bit_index - node_id + 1;
145 // Returns true if |node| is in a valid state.
146 bool IsValidNode(const Node &node) const {
147 return index_.Get(node.edge_index_) != 0;
107148 }
108149
109150 private:
2828
2929 #include "storage/louds/louds_trie.h"
3030
31 #include <cstring>
32
3331 #include "base/logging.h"
3432 #include "base/port.h"
3533 #include "storage/louds/louds.h"
4139
4240 namespace {
4341 inline int32 ReadInt32(const uint8 *data) {
44 // TODO(hidehiko): static assertion for the endian.
42 // TODO(noriyukit): static assertion for the endian.
4543 return *reinterpret_cast<const int32*>(data);
4644 }
4745 } // namespace
6967 // [3]
7068 // In this case, [0] and [1] are not terminal (as the original words contains
7169 // neither "" nor "a"), and [2] and [3] are terminal.
72 const int trie_size = ReadInt32(image);
70 const int louds_size = ReadInt32(image);
7371 const int terminal_size = ReadInt32(image + 4);
7472 const int num_character_bits = ReadInt32(image + 8);
7573 const int edge_character_size = ReadInt32(image + 12);
7674 CHECK_EQ(num_character_bits, 8);
7775 CHECK_GT(edge_character_size, 0);
7876
79 const uint8 *trie_image = image + 16;
80 const uint8 *terminal_image = trie_image + trie_size;
77 const uint8 *louds_image = image + 16;
78 const uint8 *terminal_image = louds_image + louds_size;
8179 const uint8 *edge_character = terminal_image + terminal_size;
8280
83 trie_.Open(trie_image, trie_size);
81 louds_.Init(louds_image, louds_size);
8482 terminal_bit_vector_.Init(terminal_image, terminal_size);
8583 edge_character_ = reinterpret_cast<const char*>(edge_character);
8684
8886 }
8987
9088 void LoudsTrie::Close() {
91 trie_.Close();
89 louds_.Reset();
9290 terminal_bit_vector_.Reset();
93 edge_character_ = NULL;
91 edge_character_ = nullptr;
92 }
93
94 bool LoudsTrie::Traverse(StringPiece key, Node *node) const {
95 for (auto iter = key.begin(); iter != key.end(); ++iter) {
96 // Check all the children to find an edge with label |*iter|.
97 for (louds_.MoveToFirstChild(node); ; louds_.MoveToNextSibling(node)) {
98 if (!louds_.IsValidNode(*node)) {
99 return false;
100 }
101 if (GetEdgeLabelToParentNode(*node) == *iter) {
102 break;
103 }
104 }
105 }
106 return true;
107 }
108
109 int LoudsTrie::ExactSearch(StringPiece key) const {
110 Node node; // Root
111 if (Traverse(key, &node) && IsTerminalNode(node)) {
112 return GetKeyIdOfTerminalNode(node);
113 }
114 return -1;
94115 }
95116
96117 namespace {
97118
98 // Implementation of exact search.
99 class ExactSearcher {
100 public:
101 ExactSearcher(const Louds *trie,
102 const SimpleSuccinctBitVectorIndex *terminal_bit_vector,
103 const char *edge_character)
104 : trie_(trie),
105 terminal_bit_vector_(terminal_bit_vector),
106 edge_character_(edge_character) {
107 }
108
109 // Returns the ID of |key| if it's in the trie. Returns -1 if it doesn't
110 // exist.
111 int Search(const StringPiece key) const {
112 int node_id = 1; // Node id of the root node.
113 int bit_index = 2; // Bit index of the root node.
114 for (StringPiece::const_iterator key_iter = key.begin();
115 key_iter != key.end(); ++key_iter) {
116 node_id = trie_->GetChildNodeId(bit_index); // First child node
117 while (true) {
118 if (!trie_->IsEdgeBit(bit_index)) {
119 // No more edge at this node, meaning that key doesn't exist in this
120 // trie.
121 return -1;
122 }
123 if (edge_character_[node_id - 1] == *key_iter) {
124 // Found the key character currently searching for. Continue the
125 // search for the next key character by setting |bit_index| to the
126 // first edge of the current node.
127 bit_index = trie_->GetFirstEdgeBitIndex(node_id);
128 break;
129 }
130 // Search the next child. Because of the louds representation, all the
131 // child bits are consecutive (as all bits are output by BFS order). So
132 // we can move to the next child by simply incrementing node id and bit
133 // index.
134 ++node_id;
135 ++bit_index;
136 }
137 }
138 // Found a node corresponding to |key|. If this node is terminal, return the
139 // index corresponding to this key.
140 return terminal_bit_vector_->Get(node_id - 1) ?
141 terminal_bit_vector_->Rank1(node_id - 1) : -1;
142 }
143
144 private:
145 const Louds *trie_;
146 const SimpleSuccinctBitVectorIndex *terminal_bit_vector_;
147 const char *edge_character_;
148
149 DISALLOW_COPY_AND_ASSIGN(ExactSearcher);
150 };
119 // Recursively traverses the trie in DFS order and runs |callback| at terminal
120 // nodes. Returns true if traversal is done to exit recursion.
121 bool PrefixSearchWithKeyExpansionImpl(
122 const LoudsTrie &trie,
123 StringPiece key,
124 const KeyExpansionTable &key_expansion_table,
125 LoudsTrie::Callback *callback,
126 LoudsTrie::Node node,
127 char *key_buffer,
128 StringPiece::size_type key_len) {
129 if (trie.IsTerminalNode(node)) {
130 const LoudsTrie::Callback::ResultType result =
131 callback->Run(key_buffer, key_len, trie.GetKeyIdOfTerminalNode(node));
132 switch (result) {
133 case LoudsTrie::Callback::SEARCH_DONE:
134 return true;
135 case LoudsTrie::Callback::SEARCH_CULL:
136 return false;
137 default:
138 break;
139 }
140 }
141
142 if (key_len == key.size()) {
143 return false;
144 }
145
146 const char target_char = key[key_len];
147 const ExpandedKey &chars = key_expansion_table.ExpandKey(target_char);
148 for (trie.MoveToFirstChild(&node); trie.IsValidNode(node);
149 trie.MoveToNextSibling(&node)) {
150 const char c = trie.GetEdgeLabelToParentNode(node);
151 if (chars.IsHit(c)) {
152 key_buffer[key_len] = c;
153 if (PrefixSearchWithKeyExpansionImpl(trie, key, key_expansion_table,
154 callback, node,
155 key_buffer, key_len + 1)) {
156 return true;
157 }
158 }
159 }
160 return false;
161 }
151162
152163 } // namespace
153164
154 int LoudsTrie::ExactSearch(const StringPiece key) const {
155 ExactSearcher searcher(&trie_, &terminal_bit_vector_, edge_character_);
156 return searcher.Search(key);
165 void LoudsTrie::PrefixSearchWithKeyExpansion(
166 StringPiece key, const KeyExpansionTable &key_expansion_table,
167 Callback *callback) const {
168 char key_buffer[kMaxDepth + 1];
169 PrefixSearchWithKeyExpansionImpl(*this, key, key_expansion_table,
170 callback,
171 Node(), // Root
172 key_buffer, 0);
157173 }
158174
159175 namespace {
160176
161 // This class is the implementation of prefix search.
162 class PrefixSearcher {
163 public:
164 PrefixSearcher(const Louds *trie,
165 const SimpleSuccinctBitVectorIndex *terminal_bit_vector,
166 const char *edge_character,
167 const KeyExpansionTable *key_expansion_table,
168 const char *key,
169 LoudsTrie::Callback *callback)
170 : trie_(trie),
171 terminal_bit_vector_(terminal_bit_vector),
172 edge_character_(edge_character),
173 key_expansion_table_(key_expansion_table),
174 key_(key),
175 callback_(callback) {
176 }
177
178 // Returns true if we shouldn't continue to search any more.
179 bool Search(size_t key_index, size_t bit_index) {
180 const char key_char = key_[key_index];
181 if (key_char == '\0') {
182 // The end of search key. Do nothing.
183 return false;
184 }
185
186 if (!trie_->IsEdgeBit(bit_index)) {
187 // This is leaf. Do nothing.
188 return false;
189 }
190
191 // Then traverse the children.
192 int child_node_id = trie_->GetChildNodeId(bit_index);
193 const ExpandedKey &expanded_key =
194 key_expansion_table_->ExpandKey(key_char);
195 do {
196 const char character = edge_character_[child_node_id - 1];
197 do {
198 if (expanded_key.IsHit(character)) {
199 buffer_[key_index] = character;
200 // Hit the annotated character to the key char.
201 if (terminal_bit_vector_->Get(child_node_id - 1)) {
202 // The child node is terminal, so invoke the callback.
203 LoudsTrie::Callback::ResultType callback_result =
204 callback_->Run(buffer_, key_index + 1,
205 terminal_bit_vector_->Rank1(child_node_id - 1));
206 if (callback_result != LoudsTrie::Callback::SEARCH_CONTINUE) {
207 if (callback_result == LoudsTrie::Callback::SEARCH_DONE) {
208 return true;
209 }
210 DCHECK_EQ(callback_result, LoudsTrie::Callback::SEARCH_CULL);
211 // If the callback returns "culling", we do not search
212 // the child, but continue to search the sibling edges.
213 break;
214 }
215 }
216
217 // Search to the next child.
218 // Note: we use recursive callback, instead of the just simple loop
219 // here, in order to support key-expansion (in future).
220 const int child_index = trie_->GetFirstEdgeBitIndex(child_node_id);
221 if (Search(key_index + 1, child_index)) {
222 return true;
223 }
224 }
225 } while (false);
226
227 // Note: Because of the representation of LOUDS, the child node id is
228 // consecutive. So we don't need to invoke GetChildNodeId.
229 ++bit_index;
230 ++child_node_id;
231 } while (trie_->IsEdgeBit(bit_index));
232
233 return false;
234 }
235
236 private:
237 const Louds *trie_;
238 const SimpleSuccinctBitVectorIndex *terminal_bit_vector_;
239 const char *edge_character_;
240 const KeyExpansionTable *key_expansion_table_;
241
242 const char *key_;
243 char buffer_[LoudsTrie::kMaxDepth + 1];
244 LoudsTrie::Callback *callback_;
245
246 DISALLOW_COPY_AND_ASSIGN(PrefixSearcher);
247 };
177 // Traverses the subtree rooted at |node| in DFS order and runs |callback| at
178 // each terminal node. Returns true if traversal should be stopped.
179 bool TraverseSubTree(
180 const LoudsTrie &trie,
181 const KeyExpansionTable &key_expansion_table,
182 LoudsTrie::Callback *callback,
183 LoudsTrie::Node node,
184 char *key_buffer,
185 StringPiece::size_type key_len) {
186 if (trie.IsTerminalNode(node)) {
187 const LoudsTrie::Callback::ResultType result =
188 callback->Run(key_buffer, key_len, trie.GetKeyIdOfTerminalNode(node));
189 switch (result) {
190 case LoudsTrie::Callback::SEARCH_DONE:
191 return true;
192 case LoudsTrie::Callback::SEARCH_CULL:
193 return false;
194 default:
195 break;
196 }
197 }
198
199 for (trie.MoveToFirstChild(&node); trie.IsValidNode(node);
200 trie.MoveToNextSibling(&node)) {
201 key_buffer[key_len] = trie.GetEdgeLabelToParentNode(node);
202 if (TraverseSubTree(trie, key_expansion_table, callback, node,
203 key_buffer, key_len + 1)) {
204 return true;
205 }
206 }
207 return false;
208 }
209
210 // Recursively traverses the trie in DFS order until terminal nodes for each
211 // expanded key is found. Then TraverseSubTree() is called at each terminal
212 // node. Returns true if traversal should be stopped.
213 bool PredictiveSearchWithKeyExpansionImpl(
214 const LoudsTrie &trie,
215 StringPiece key,
216 const KeyExpansionTable &key_expansion_table,
217 LoudsTrie::Callback *callback,
218 LoudsTrie::Node node,
219 char *key_buffer,
220 StringPiece::size_type key_len) {
221 if (key_len == key.size()) {
222 return TraverseSubTree(trie, key_expansion_table, callback, node,
223 key_buffer, key_len);
224 }
225
226 const char target_char = key[key_len];
227 const ExpandedKey &chars = key_expansion_table.ExpandKey(target_char);
228 for (trie.MoveToFirstChild(&node); trie.IsValidNode(node);
229 trie.MoveToNextSibling(&node)) {
230 const char c = trie.GetEdgeLabelToParentNode(node);
231 if (chars.IsHit(c)) {
232 key_buffer[key_len] = c;
233 if (PredictiveSearchWithKeyExpansionImpl(trie, key, key_expansion_table,
234 callback, node,
235 key_buffer, key_len + 1)) {
236 return true;
237 }
238 }
239 }
240 return false;
241 }
242
248243 } // namespace
249244
250 void LoudsTrie::PrefixSearchWithKeyExpansion(
251 const char *key, const KeyExpansionTable &key_expansion_table,
245 void LoudsTrie::PredictiveSearchWithKeyExpansion(
246 StringPiece key, const KeyExpansionTable &key_expansion_table,
252247 Callback *callback) const {
253 PrefixSearcher searcher(
254 &trie_, &terminal_bit_vector_, edge_character_, &key_expansion_table,
255 key, callback);
256
257 // The bit index of the root node is '2'.
258 searcher.Search(0, 2);
259 }
260
261 namespace {
262 class PredictiveSearcher {
263 public:
264 PredictiveSearcher(const Louds *trie,
265 const SimpleSuccinctBitVectorIndex *terminal_bit_vector,
266 const char *edge_character,
267 const KeyExpansionTable *key_expansion_table,
268 const char *key,
269 LoudsTrie::Callback *callback)
270 : trie_(trie),
271 terminal_bit_vector_(terminal_bit_vector),
272 edge_character_(edge_character),
273 key_expansion_table_(key_expansion_table),
274 key_(key),
275 callback_(callback) {
276 }
277
278 // Returns true if we shouldn't continue to search any more.
279 bool Search(size_t key_index, int node_id, size_t bit_index) {
280 const char key_char = key_[key_index];
281 if (key_char == '\0') {
282 // Hit the end of the key. Start traverse.
283 return Traverse(key_index, node_id, &bit_index);
284 }
285
286 if (!trie_->IsEdgeBit(bit_index)) {
287 // This is leaf. Do nothing.
288 return false;
289 }
290
291 // Then traverse the children.
292 int child_node_id = trie_->GetChildNodeId(bit_index);
293 const ExpandedKey &expanded_key =
294 key_expansion_table_->ExpandKey(key_char);
295 do {
296 const char character = edge_character_[child_node_id - 1];
297 if (expanded_key.IsHit(character)) {
298 buffer_[key_index] = character;
299 const int child_index = trie_->GetFirstEdgeBitIndex(child_node_id);
300 if (Search(key_index + 1, child_node_id, child_index)) {
301 return true;
302 }
303 }
304
305 // Note: Because of the representation of LOUDS, the child node id is
306 // consecutive. So we don't need to invoke GetChildNodeId.
307 ++bit_index;
308 ++child_node_id;
309 } while (trie_->IsEdgeBit(bit_index));
310
311 return false;
312 }
313
314 private:
315 const Louds *trie_;
316 const SimpleSuccinctBitVectorIndex *terminal_bit_vector_;
317 const char *edge_character_;
318 const KeyExpansionTable *key_expansion_table_;
319
320 const char *key_;
321 char buffer_[LoudsTrie::kMaxDepth + 1];
322 LoudsTrie::Callback *callback_;
323
324 // Returns true if the caller should NOT continue the traversing.
325 // *bit_index should store the current bit index for the traversing.
326 // After the invocation of Traverse is done;
327 // *bit_index is the last traversed bit index if Traverse returns false, or
328 // undefined if Traverse returns true.
329 bool Traverse(size_t key_index, int node_id, size_t *bit_index) {
330 if (terminal_bit_vector_->Get(node_id - 1)) {
331 // Invoke callback, if the node is terminal.
332 LoudsTrie::Callback::ResultType callback_result = callback_->Run(
333 buffer_, key_index, terminal_bit_vector_->Rank1(node_id - 1));
334 if (callback_result != LoudsTrie::Callback::SEARCH_CONTINUE) {
335 if (callback_result == LoudsTrie::Callback::SEARCH_DONE) {
336 return true;
337 }
338
339 // Move the bit_index to the end of this node.
340 // Note that we may be able to make this operation faster by checking
341 // non-zero bits.
342 while (trie_->IsEdgeBit(*bit_index)) {
343 ++*bit_index;
344 }
345 return false;
346 }
347 }
348
349 if (!trie_->IsEdgeBit(*bit_index)) {
350 return false;
351 }
352
353 // Then traverse the children.
354 int child_node_id = Louds::GetChildNodeId(node_id, *bit_index);
355
356 // Because of the louds representation, all the child bits should be
357 // consecutive (as all bits are output by BFS order).
358 // So, we can skip the consecutive child bit index searching.
359 // Note: we probably can do this more efficiently, by caching the last
360 // bit index for each level.
361 size_t child_bit_index = trie_->GetFirstEdgeBitIndex(child_node_id);
362 do {
363 buffer_[key_index] = edge_character_[child_node_id - 1];
364 if (Traverse(key_index + 1, child_node_id, &child_bit_index)) {
365 return true;
366 }
367 ++*bit_index;
368 ++child_bit_index;
369 ++child_node_id;
370 } while (trie_->IsEdgeBit(*bit_index));
371
372 return false;
373 }
374
375 DISALLOW_COPY_AND_ASSIGN(PredictiveSearcher);
376 };
377 } // namespace
378
379 void LoudsTrie::PredictiveSearchWithKeyExpansion(
380 const char *key, const KeyExpansionTable &key_expansion_table,
381 Callback *callback) const {
382 PredictiveSearcher searcher(
383 &trie_, &terminal_bit_vector_, edge_character_, &key_expansion_table,
384 key, callback);
385
386 searcher.Search(0, 1, 2);
387 }
388
389 const char *LoudsTrie::Reverse(int key_id, char *buffer) const {
248 char key_buffer[kMaxDepth + 1];
249 PredictiveSearchWithKeyExpansionImpl(
250 *this, key, key_expansion_table, callback,
251 Node(), // Root
252 key_buffer, 0);
253 }
254
255 StringPiece LoudsTrie::RestoreKeyString(int key_id, char *buf) const {
256 // TODO(noriyukit): Check if it's really necessary to handle this case.
390257 if (key_id < 0) {
391 // Just for rx compatibility.
392 buffer[0] = '\0';
393 return buffer;
394 }
395
396 // Calculate node_id from key_id.
397 int node_id = terminal_bit_vector_.Select1(key_id + 1) + 1;
398
399 // Terminate by '\0'.
400 char *ptr = buffer + kMaxDepth;
401 *ptr = '\0';
402
403 // Traverse the trie from leaf to root.
404 while (node_id > 1) {
405 --ptr;
406 *ptr = edge_character_[node_id - 1];
407 const int bit_index = trie_.GetParentEdgeBitIndex(node_id);
408 node_id = trie_.GetParentNodeId(bit_index);
409 }
410 return ptr;
258 return StringPiece();
259 }
260
261 // Ensure the returned StringPiece is null-terminated.
262 char *const buf_end = buf + kMaxDepth;
263 *buf_end = '\0';
264
265 // Climb up the trie to the root and fill |buf| backward.
266 char *ptr = buf_end;
267 Node node;
268 GetTerminalNodeFromKeyId(key_id, &node);
269 for (; !louds_.IsRoot(node); louds_.MoveToParent(&node)) {
270 *--ptr = GetEdgeLabelToParentNode(node);
271 }
272 return StringPiece(ptr, buf_end - ptr);
411273 }
412274
413275 } // namespace louds
3939 namespace storage {
4040 namespace louds {
4141
42 // Implementation of a trie, based on the LOUDS (Level-Ordered Unary Degree
43 // Sequence) data structure.
44 // The "string" this class can handle as a key is c-style string
45 // (i.e. '\0'-terminated char array).
46 // TODO(hidehiko): Parametrize succinct bit vector implementation.
4742 class LoudsTrie {
4843 public:
4944 // The max depth of the trie.
5045 static const size_t kMaxDepth = 256;
46
47 // This class stores a traversal state.
48 using Node = Louds::Node;
5149
5250 // Interface which is called back when the result is found.
5351 class Callback {
7573 Callback() {}
7674 };
7775
78 LoudsTrie() : edge_character_(NULL) {
79 }
80 ~LoudsTrie() {
81 }
76 LoudsTrie() : edge_character_(nullptr) {}
77 ~LoudsTrie() {}
8278
8379 // Opens the binary image, and constructs the data structure.
8480 // This method doesn't own the "data", so it is caller's reponsibility
8682 // See .cc file for the detailed format of the binary image.
8783 bool Open(const uint8 *data);
8884
89 // Destructs the internal data structure.
85 // Destructs the internal data structure explicitly (the destructor will do
86 // clean up too).
9087 void Close();
9188
92 // Searches the trie for the key that exactly matches the given key. Returns
93 // -1 if the key doesn't exist.
94 // TODO(noriyukit): Implement a callback style method if necessary.
95 int ExactSearch(const StringPiece key) const;
89 // Generic APIs for tree traversal, some of which are delegated from Louds
90 // class; see louds.h.
91
92 // Returns true if |node| is in a valid state (returns true both for terminal
93 // and non-terminal nodes).
94 bool IsValidNode(const Node &node) const { return louds_.IsValidNode(node); }
95
96 // Returns true if |node| is a terminal node.
97 bool IsTerminalNode(const Node &node) const {
98 return terminal_bit_vector_.Get(node.node_id() - 1);
99 }
100
101 // Returns the label of the edge from |node|'s parent (predecessor) to |node|.
102 char GetEdgeLabelToParentNode(const Node &node) const {
103 return edge_character_[node.node_id() - 1];
104 }
105
106 // Computes the ID of key that reaches to |node|.
107 // REQUIRES: |node| is a terminal node.
108 int GetKeyIdOfTerminalNode(const Node &node) const {
109 return terminal_bit_vector_.Rank1(node.node_id() - 1);
110 }
111
112 // Initializes a node corresponding to |key_id|.
113 // REQUIRES: |key_id| is a valid ID.
114 void GetTerminalNodeFromKeyId(int key_id, Node *node) const {
115 const int node_id = terminal_bit_vector_.Select1(key_id + 1) + 1;
116 louds_.InitNodeFromNodeId(node_id, node);
117 }
118 Node GetTerminalNodeFromKeyId(int key_id) const {
119 Node node;
120 GetTerminalNodeFromKeyId(key_id, &node);
121 return node;
122 }
123
124 // Restores the key string corresponding to |key_id|. The caller is
125 // responsible for allocating a buffer for the result StringPiece, which needs
126 // to be passed in |buf|. The returned StringPiece points to a piece of
127 // |buf|.
128 // REQUIRES: |buf| is longer than kMaxDepth + 1.
129 StringPiece RestoreKeyString(int key_id, char *buf) const;
130
131 // Methods for moving node exported from Louds class; see louds.h.
132 void MoveToFirstChild(Node *node) const {
133 louds_.MoveToFirstChild(node);
134 }
135 Node MoveToFirstChild(Node node) const {
136 MoveToFirstChild(&node);
137 return node;
138 }
139 static void MoveToNextSibling(Node *node) {
140 Louds::MoveToNextSibling(node);
141 }
142 static Node MoveToNextSibling(Node node) {
143 MoveToNextSibling(&node);
144 return node;
145 }
146
147 // Traverses a trie for |key|, starting from |node|, and modifies |node| to
148 // the destination terminal node. Here, |node| is not necessarily the root.
149 // Returns false if there's no node reachable by |key|.
150 bool Traverse(StringPiece key, Node *node) const;
151
152 // Higher level APIs.
153
154 // Returns true if |key| is in this trie.
155 bool HasKey(StringPiece key) const {
156 Node node; // Root
157 return Traverse(key, &node) && IsTerminalNode(node);
158 }
159
160 // Searches this trie for the key that exactly matches the given key. Returns
161 // -1 if such key doesn't exist.
162 // NOTE: When you only need to check if |key| is in this trie, use HasKey()
163 // method, which is more efficient.
164 int ExactSearch(StringPiece key) const;
165
166 // TODO(noriyukit): The following search methods rely on Callback. However,
167 // this results in the nested callback to implement SystemDictionary's lookup
168 // methods (i.e., inside implementations of DictionaryInterface::Callback,
169 // LoudsTrie::Callback needs to be called; see system_dictionary.cc. This is
170 // somewhat inefficient because both requires virtual method calls.
171 // Therefore, it'd be better to implement the following search methods
172 // directly in system_dictionary.cc using more generic APIs defined above.
96173
97174 // Searches the trie structure, and invokes callback->Run when for each word
98175 // which is a prefix of the key is found.
99 void PrefixSearch(const char *key, Callback *callback) const {
176 void PrefixSearch(StringPiece key, Callback *callback) const {
100177 PrefixSearchWithKeyExpansion(
101178 key, KeyExpansionTable::GetDefaultInstance(), callback);
102179 }
180
103181 void PrefixSearchWithKeyExpansion(
104 const char *key, const KeyExpansionTable &key_expansion_table,
182 StringPiece key, const KeyExpansionTable &key_expansion_table,
105183 Callback *callback) const;
106
107184
108185 // Searches the trie structure, and invokes callback->Run when for each word
109186 // which begins with key is found.
110 void PredictiveSearch(const char *key, Callback *callback) const {
187 void PredictiveSearch(StringPiece key, Callback *callback) const {
111188 PredictiveSearchWithKeyExpansion(
112189 key, KeyExpansionTable::GetDefaultInstance(), callback);
113190 }
191
114192 void PredictiveSearchWithKeyExpansion(
115 const char *key, const KeyExpansionTable &key_expansion_table,
193 StringPiece key, const KeyExpansionTable &key_expansion_table,
116194 Callback *callback) const;
117195
118
119 // Traverses the trie from leaf to root and store the characters annotated to
120 // the edges. The size of the buffer should be larger than kMaxDepth. Returns
121 // the pointer to the first character.
122 const char *Reverse(int key_id, char *buf) const;
123
124196 private:
125 // Tree-structure represented in LOUDS.
126 Louds trie_;
197 Louds louds_; // Tree structure representation by LOUDS.
127198
128199 // Bit-vector to represent whether each node in LOUDS tree is terminal.
129200 // This bit vector doesn't include "super root" in the LOUDS.
130 // In other words, id=1 in trie_ corresponds to id=0 in terminal_bit_vector_,
131 // id=10 in trie_ corresponds to id=9 in terminal_bit_vector_, and so on.
132 // TODO(hidehiko): Simplify the id-mapping by introducing a bit for the
201 // In other words, id=1 in louds_ corresponds to id=0 in terminal_bit_vector_,
202 // id=10 in louds_ corresponds to id=9 in terminal_bit_vector_, and so on.
203 // TODO(noriyukit): Simplify the id-mapping by introducing a bit for the
133204 // super root in this bit vector.
134205 SimpleSuccinctBitVectorIndex terminal_bit_vector_;
135206
136207 // A sequence of characters, annotated to each edge.
137208 // This array also doesn't have an entry for super root.
138 // In other words, id=2 in trie_ corresponds to edge_character_[1].
209 // In other words, id=2 in louds_ corresponds to edge_character_[1].
139210 const char *edge_character_;
140211
141212 DISALLOW_COPY_AND_ASSIGN(LoudsTrie);
9595 DISALLOW_COPY_AND_ASSIGN(TestCallback);
9696 };
9797
98 TEST_F(LoudsTrieTest, NodeBasedApis) {
99 // Create the following trie (* stands for non-terminal nodes):
100 //
101 // * Key ID
102 // a/ \b ---------
103 // 0 * a 0
104 // a/ \b \d aa 1
105 // 1 2 3 ab 2
106 // c/ \d bd 3
107 // * 4 abd 4
108 // d| abcd 5
109 // 5
110 LoudsTrieBuilder builder;
111 builder.Add("a");
112 builder.Add("aa");
113 builder.Add("ab");
114 builder.Add("abcd");
115 builder.Add("abd");
116 builder.Add("bd");
117 builder.Build();
118
119 LoudsTrie trie;
120 trie.Open(reinterpret_cast<const uint8 *>(builder.image().data()));
121
122 char buf[LoudsTrie::kMaxDepth + 1]; // for RestoreKeyString().
123
124 // Walk the trie in BFS order and check properties at each node.
125
126 // Root node
127 const LoudsTrie::Node root;
128 ASSERT_TRUE(trie.IsValidNode(root));
129 EXPECT_FALSE(trie.IsTerminalNode(root));
130 {
131 LoudsTrie::Node node;
132 EXPECT_TRUE(trie.Traverse("", &node));
133 EXPECT_EQ(root, node);
134 }
135
136 // There's no right sibling for root.
137 EXPECT_FALSE(trie.IsValidNode(trie.MoveToNextSibling(root)));
138
139 // Terminal node for "a".
140 const LoudsTrie::Node node_a = trie.MoveToFirstChild(root);
141 ASSERT_TRUE(trie.IsValidNode(node_a));
142 ASSERT_TRUE(trie.IsTerminalNode(node_a));
143 EXPECT_EQ('a', trie.GetEdgeLabelToParentNode(node_a));
144 EXPECT_EQ(0, trie.GetKeyIdOfTerminalNode(node_a));
145 EXPECT_EQ(node_a, trie.GetTerminalNodeFromKeyId(0));
146 EXPECT_EQ("a", trie.RestoreKeyString(0, buf));
147 {
148 LoudsTrie::Node node;
149 EXPECT_TRUE(trie.Traverse("a", &node));
150 EXPECT_EQ(node_a, node);
151 }
152
153 // Non-terminal node for "b".
154 const LoudsTrie::Node node_b = trie.MoveToNextSibling(node_a);
155 ASSERT_TRUE(trie.IsValidNode(node_b));
156 EXPECT_FALSE(trie.IsTerminalNode(node_b));
157 EXPECT_EQ('b', trie.GetEdgeLabelToParentNode(node_b));
158 {
159 LoudsTrie::Node node;
160 EXPECT_TRUE(trie.Traverse("b", &node));
161 EXPECT_EQ(node_b, node);
162 }
163
164 // There's no right sibling for "b".
165 EXPECT_FALSE(trie.IsValidNode(trie.MoveToNextSibling(node_b)));
166
167 // Terminal node (leaf) for "aa".
168 const LoudsTrie::Node node_aa = trie.MoveToFirstChild(node_a);
169 ASSERT_TRUE(trie.IsValidNode(node_aa));
170 ASSERT_TRUE(trie.IsTerminalNode(node_aa));
171 EXPECT_EQ('a', trie.GetEdgeLabelToParentNode(node_aa));
172 EXPECT_EQ(1, trie.GetKeyIdOfTerminalNode(node_aa));
173 EXPECT_EQ(node_aa, trie.GetTerminalNodeFromKeyId(1));
174 EXPECT_EQ("aa", trie.RestoreKeyString(1, buf));
175 {
176 LoudsTrie::Node node;
177 EXPECT_TRUE(trie.Traverse("aa", &node));
178 EXPECT_EQ(node_aa, node);
179 }
180
181 // There's no child for "aa".
182 EXPECT_FALSE(trie.IsValidNode(trie.MoveToFirstChild(node_aa)));
183
184 // Terminal node for "ab".
185 const LoudsTrie::Node node_ab = trie.MoveToNextSibling(node_aa);
186 ASSERT_TRUE(trie.IsValidNode(node_ab));
187 ASSERT_TRUE(trie.IsTerminalNode(node_ab));
188 EXPECT_EQ('b', trie.GetEdgeLabelToParentNode(node_ab));
189 EXPECT_EQ(2, trie.GetKeyIdOfTerminalNode(node_ab));
190 EXPECT_EQ(node_ab, trie.GetTerminalNodeFromKeyId(2));
191 EXPECT_EQ("ab", trie.RestoreKeyString(2, buf));
192 {
193 LoudsTrie::Node node;
194 EXPECT_TRUE(trie.Traverse("ab", &node));
195 EXPECT_EQ(node_ab, node);
196 }
197
198 // There's no right sibling for "ab".
199 EXPECT_FALSE(trie.IsValidNode(trie.MoveToNextSibling(node_ab)));
200
201 // Terminal node (leaf) for "bd".
202 const LoudsTrie::Node node_bd = trie.MoveToFirstChild(node_b);
203 ASSERT_TRUE(trie.IsValidNode(node_bd));
204 ASSERT_TRUE(trie.IsTerminalNode(node_bd));
205 EXPECT_EQ('d', trie.GetEdgeLabelToParentNode(node_bd));
206 EXPECT_EQ(3, trie.GetKeyIdOfTerminalNode(node_bd));
207 EXPECT_EQ(node_bd, trie.GetTerminalNodeFromKeyId(3));
208 EXPECT_EQ("bd", trie.RestoreKeyString(3, buf));
209 {
210 LoudsTrie::Node node;
211 EXPECT_TRUE(trie.Traverse("bd", &node));
212 EXPECT_EQ(node_bd, node);
213 }
214
215 // There is no child nor right sibling for "bd".
216 EXPECT_FALSE(trie.IsValidNode(trie.MoveToFirstChild(node_bd)));
217 EXPECT_FALSE(trie.IsValidNode(trie.MoveToNextSibling(node_bd)));
218
219 // Non-terminal node for "abc".
220 const LoudsTrie::Node node_abc = trie.MoveToFirstChild(node_ab);
221 ASSERT_TRUE(trie.IsValidNode(node_abc));
222 EXPECT_FALSE(trie.IsTerminalNode(node_abc));
223 EXPECT_EQ('c', trie.GetEdgeLabelToParentNode(node_abc));
224 {
225 LoudsTrie::Node node;
226 EXPECT_TRUE(trie.Traverse("abc", &node));
227 EXPECT_EQ(node_abc, node);
228 }
229
230 // Terminal node (leaf) for "abd".
231 const LoudsTrie::Node node_abd = trie.MoveToNextSibling(node_abc);
232 ASSERT_TRUE(trie.IsValidNode(node_abd));
233 ASSERT_TRUE(trie.IsTerminalNode(node_abd));
234 EXPECT_EQ('d', trie.GetEdgeLabelToParentNode(node_abd));
235 EXPECT_EQ(4, trie.GetKeyIdOfTerminalNode(node_abd));
236 EXPECT_EQ(node_abd, trie.GetTerminalNodeFromKeyId(4));
237 EXPECT_EQ("abd", trie.RestoreKeyString(4, buf));
238 {
239 LoudsTrie::Node node;
240 EXPECT_TRUE(trie.Traverse("abd", &node));
241 EXPECT_EQ(node_abd, node);
242 }
243
244 // There is no child nor right sibling for "abd".
245 EXPECT_FALSE(trie.IsValidNode(trie.MoveToFirstChild(node_abd)));
246 EXPECT_FALSE(trie.IsValidNode(trie.MoveToNextSibling(node_abd)));
247
248 // Terminal node (leaf) for "abcd".
249 const LoudsTrie::Node node_abcd = trie.MoveToFirstChild(node_abc);
250 ASSERT_TRUE(trie.IsValidNode(node_abcd));
251 ASSERT_TRUE(trie.IsTerminalNode(node_abcd));
252 EXPECT_EQ('d', trie.GetEdgeLabelToParentNode(node_abcd));
253 EXPECT_EQ(5, trie.GetKeyIdOfTerminalNode(node_abcd));
254 EXPECT_EQ(node_abcd, trie.GetTerminalNodeFromKeyId(5));
255 EXPECT_EQ("abcd", trie.RestoreKeyString(5, buf));
256 {
257 LoudsTrie::Node node;
258 EXPECT_TRUE(trie.Traverse("abcd", &node));
259 EXPECT_EQ(node_abcd, node);
260 }
261
262 // There is no child nor right sibling for "abcd".
263 EXPECT_FALSE(trie.IsValidNode(trie.MoveToFirstChild(node_abcd)));
264 EXPECT_FALSE(trie.IsValidNode(trie.MoveToNextSibling(node_abcd)));
265
266 // Traverse for some non-existing keys.
267 LoudsTrie::Node node;
268 EXPECT_FALSE(trie.Traverse("x", &node));
269 EXPECT_FALSE(trie.Traverse("xyz", &node));
270 }
271
272 TEST_F(LoudsTrieTest, HasKey) {
273 LoudsTrieBuilder builder;
274 builder.Add("a");
275 builder.Add("abc");
276 builder.Add("abcd");
277 builder.Add("ae");
278 builder.Add("aecd");
279 builder.Add("b");
280 builder.Add("bcx");
281
282 builder.Build();
283 LoudsTrie trie;
284 trie.Open(reinterpret_cast<const uint8 *>(builder.image().data()));
285
286 EXPECT_TRUE(trie.HasKey("a"));
287 EXPECT_TRUE(trie.HasKey("abc"));
288 EXPECT_TRUE(trie.HasKey("abcd"));
289 EXPECT_TRUE(trie.HasKey("ae"));
290 EXPECT_TRUE(trie.HasKey("aecd"));
291 EXPECT_TRUE(trie.HasKey("b"));
292 EXPECT_TRUE(trie.HasKey("bcx"));
293 EXPECT_FALSE(trie.HasKey(""));
294 EXPECT_FALSE(trie.HasKey("ab"));
295 EXPECT_FALSE(trie.HasKey("aa"));
296 EXPECT_FALSE(trie.HasKey("aec"));
297 EXPECT_FALSE(trie.HasKey("aecx"));
298 EXPECT_FALSE(trie.HasKey("aecdf"));
299 EXPECT_FALSE(trie.HasKey("abcdefghi"));
300 EXPECT_FALSE(trie.HasKey("bc"));
301 EXPECT_FALSE(trie.HasKey("bca"));
302 EXPECT_FALSE(trie.HasKey("bcxyz"));
303 }
304
98305 TEST_F(LoudsTrieTest, ExactSearch) {
99306 LoudsTrieBuilder builder;
100307 builder.Add("a");
517724 trie.Close();
518725 }
519726
520 TEST_F(LoudsTrieTest, Reverse) {
727 TEST_F(LoudsTrieTest, RestoreKeyString) {
521728 LoudsTrieBuilder builder;
522729 builder.Add("aa");
523730 builder.Add("ab");
535742 trie.Open(reinterpret_cast<const uint8 *>(builder.image().data()));
536743
537744 char buffer[LoudsTrie::kMaxDepth + 1];
538 EXPECT_STREQ("aa", trie.Reverse(builder.GetId("aa"), buffer));
539 EXPECT_STREQ("ab", trie.Reverse(builder.GetId("ab"), buffer));
540 EXPECT_STREQ("abc", trie.Reverse(builder.GetId("abc"), buffer));
541 EXPECT_STREQ("abcd", trie.Reverse(builder.GetId("abcd"), buffer));
542 EXPECT_STREQ("abcde", trie.Reverse(builder.GetId("abcde"), buffer));
543 EXPECT_STREQ("abcdef", trie.Reverse(builder.GetId("abcdef"), buffer));
544 EXPECT_STREQ("abcea", trie.Reverse(builder.GetId("abcea"), buffer));
545 EXPECT_STREQ("abcef", trie.Reverse(builder.GetId("abcef"), buffer));
546 EXPECT_STREQ("abd", trie.Reverse(builder.GetId("abd"), buffer));
547 EXPECT_STREQ("ebd", trie.Reverse(builder.GetId("ebd"), buffer));
548 EXPECT_STREQ("", trie.Reverse(-1, buffer));
745 EXPECT_EQ("aa", trie.RestoreKeyString(builder.GetId("aa"), buffer));
746 EXPECT_EQ("ab", trie.RestoreKeyString(builder.GetId("ab"), buffer));
747 EXPECT_EQ("abc", trie.RestoreKeyString(builder.GetId("abc"), buffer));
748 EXPECT_EQ("abcd", trie.RestoreKeyString(builder.GetId("abcd"), buffer));
749 EXPECT_EQ("abcde", trie.RestoreKeyString(builder.GetId("abcde"), buffer));
750 EXPECT_EQ("abcdef", trie.RestoreKeyString(builder.GetId("abcdef"), buffer));
751 EXPECT_EQ("abcea", trie.RestoreKeyString(builder.GetId("abcea"), buffer));
752 EXPECT_EQ("abcef", trie.RestoreKeyString(builder.GetId("abcef"), buffer));
753 EXPECT_EQ("abd", trie.RestoreKeyString(builder.GetId("abd"), buffer));
754 EXPECT_EQ("ebd", trie.RestoreKeyString(builder.GetId("ebd"), buffer));
755 EXPECT_EQ("", trie.RestoreKeyString(-1, buffer));
549756 trie.Close();
550757 }
551758