OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @constructor |
| 7 */ |
| 8 WebInspector.Trie = function() |
| 9 { |
| 10 this.clear(); |
| 11 } |
| 12 |
| 13 WebInspector.Trie.prototype = { |
| 14 /** |
| 15 * @param {string} word |
| 16 */ |
| 17 add: function(word) |
| 18 { |
| 19 var node = this._root; |
| 20 ++this._wordsInSubtree[this._root]; |
| 21 for (var i = 0; i < word.length; ++i) { |
| 22 var edge = word[i]; |
| 23 var next = this._edges[node][edge]; |
| 24 if (!next) { |
| 25 if (this._freeNodes.length) { |
| 26 // No need to reset any fields since they were properly clea
ned up in remove(). |
| 27 next = this._freeNodes.pop(); |
| 28 } else { |
| 29 next = this._size++; |
| 30 this._isWord.push(false); |
| 31 this._wordsInSubtree.push(0); |
| 32 this._edges.push({ __proto__: null }); |
| 33 } |
| 34 this._edges[node][edge] = next; |
| 35 } |
| 36 ++this._wordsInSubtree[next]; |
| 37 node = next; |
| 38 } |
| 39 this._isWord[node] = true; |
| 40 }, |
| 41 |
| 42 /** |
| 43 * @param {string} word |
| 44 * @return {boolean} |
| 45 */ |
| 46 remove: function(word) |
| 47 { |
| 48 if (!this.has(word)) |
| 49 return false; |
| 50 var node = this._root; |
| 51 --this._wordsInSubtree[this._root]; |
| 52 for (var i = 0; i < word.length; ++i) { |
| 53 var edge = word[i]; |
| 54 var next = this._edges[node][edge]; |
| 55 if (!--this._wordsInSubtree[next]) { |
| 56 delete this._edges[node][edge]; |
| 57 this._freeNodes.push(next); |
| 58 } |
| 59 node = next; |
| 60 } |
| 61 this._isWord[node] = false; |
| 62 return true; |
| 63 }, |
| 64 |
| 65 /** |
| 66 * @param {string} word |
| 67 * @return {boolean} |
| 68 */ |
| 69 has: function(word) |
| 70 { |
| 71 var node = this._root; |
| 72 for (var i = 0; i < word.length; ++i) { |
| 73 node = this._edges[node][word[i]]; |
| 74 if (!node) |
| 75 return false; |
| 76 } |
| 77 return this._isWord[node]; |
| 78 }, |
| 79 |
| 80 /** |
| 81 * @param {string=} prefix |
| 82 * @return {!Array<string>} |
| 83 */ |
| 84 words: function(prefix) |
| 85 { |
| 86 prefix = prefix || ""; |
| 87 var node = this._root; |
| 88 for (var i = 0; i < prefix.length; ++i) { |
| 89 node = this._edges[node][prefix[i]]; |
| 90 if (!node) |
| 91 return []; |
| 92 } |
| 93 var results = []; |
| 94 this._dfs(node, prefix, results); |
| 95 return results; |
| 96 }, |
| 97 |
| 98 /** |
| 99 * @param {number} node |
| 100 * @param {string} prefix |
| 101 * @param {!Array<string>} results |
| 102 */ |
| 103 _dfs: function(node, prefix, results) |
| 104 { |
| 105 if (this._isWord[node]) |
| 106 results.push(prefix); |
| 107 var edges = this._edges[node]; |
| 108 for (var edge in edges) |
| 109 this._dfs(edges[edge], prefix + edge, results); |
| 110 }, |
| 111 |
| 112 /** |
| 113 * @param {string} word |
| 114 * @param {boolean} fullWordOnly |
| 115 * @return {string} |
| 116 */ |
| 117 longestPrefix: function(word, fullWordOnly) |
| 118 { |
| 119 var node = this._root; |
| 120 var wordIndex = 0; |
| 121 for (var i = 0; i < word.length; ++i) { |
| 122 if (!fullWordOnly || this._isWord[node]) |
| 123 wordIndex = i; |
| 124 node = this._edges[node][word[i]]; |
| 125 if (!node) |
| 126 break; |
| 127 } |
| 128 return word.substring(0, wordIndex); |
| 129 }, |
| 130 |
| 131 clear: function() |
| 132 { |
| 133 this._size = 1; |
| 134 this._root = 0; |
| 135 /** @type {!Array<!Object<string, number>>} */ |
| 136 this._edges = [{ __proto__: null }]; |
| 137 /** @type {!Array<boolean>} */ |
| 138 this._isWord = [false]; |
| 139 /** @type {!Array<number>} */ |
| 140 this._wordsInSubtree = [0]; |
| 141 /** @type {!Array<number>} */ |
| 142 this._freeNodes = []; |
| 143 } |
| 144 } |
OLD | NEW |