├── .babelrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── dist ├── packed-trie.js ├── packed-trie.js.map ├── packed-trie.min.js ├── tiny-trie.js ├── tiny-trie.js.map └── tiny-trie.min.js ├── docs ├── assets │ ├── css │ │ ├── main.css │ │ └── main.css.map │ ├── images │ │ ├── icons.png │ │ ├── icons@2x.png │ │ ├── widgets.png │ │ └── widgets@2x.png │ └── js │ │ ├── main.js │ │ └── search.js ├── classes │ ├── _binarystring_.binarystring.html │ ├── _packedtrie_.packedtrie.html │ └── _trie_.trie.html ├── globals.html ├── index.html ├── interfaces │ ├── _basetrie_.isearchopts.html │ ├── _basetrie_.itestopts.html │ ├── _basetrie_.itrie.html │ ├── _trie_.ichunk.html │ ├── _trie_.inode.html │ └── _trie_.inodemeta.html └── modules │ ├── _base64_.html │ ├── _basetrie_.html │ ├── _binarystring_.html │ ├── _constants_.html │ ├── _floor_log2_.html │ ├── _index_.html │ ├── _packedtrie_.html │ └── _trie_.html ├── lib ├── BaseTrie.d.ts ├── BaseTrie.js ├── BaseTrie.js.map ├── BinaryString.d.ts ├── BinaryString.js ├── BinaryString.js.map ├── PackedTrie.d.ts ├── PackedTrie.js ├── PackedTrie.js.map ├── Trie.d.ts ├── Trie.js ├── Trie.js.map ├── base64.d.ts ├── base64.js ├── base64.js.map ├── constants.d.ts ├── constants.js ├── constants.js.map ├── floor_log2.d.ts ├── floor_log2.js ├── floor_log2.js.map ├── index.d.ts ├── index.js └── index.js.map ├── package-lock.json ├── package.json ├── src ├── BaseTrie.ts ├── BinaryString.test.ts ├── BinaryString.ts ├── PackedTrie.test.ts ├── PackedTrie.ts ├── Trie.test.ts ├── Trie.ts ├── base64.ts ├── constants.ts ├── floor_log2.test.ts ├── floor_log2.ts ├── index.test.ts └── index.ts ├── tsconfig.json ├── tslint.json └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .DS_Store 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | docs/ 3 | src/ 4 | .babelrc 5 | .travis.yml 6 | package-lock.json 7 | README.md 8 | tsconfig.json 9 | tslint.json 10 | webpack.config.js 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | - "9.8.0" 5 | - "8.9.4" 6 | - "7.10.1" 7 | - "6.14.1" 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tiny-trie 2 | === 3 | 4 | Trie / DAWG implementation for JavaScript. 5 | 6 | [![Build Status](https://travis-ci.org/jnu/tiny-trie.svg?branch=master)](https://travis-ci.org/jnu/tiny-trie) 7 | 8 | ## About 9 | 10 | Construct a trie out of a list of words for efficient searches. The trie 11 | provides a `#freeze` method to dedupe its suffixes, turning it into a directed 12 | acyclic word graph (DAWG). 13 | 14 | More excitingly, there is a `Trie#encode` method which outputs the trie in a 15 | succinct binary format. (The trie does not need to be DAWG-ified in order to 16 | encode it, but it usually makes sense to do so.) The binary format is output in 17 | Base-64 and can be transmitted as JSON. 18 | 19 | To use an encoded trie, there is a `PackedTrie` class. This class can make 20 | queries against the trie without ever having to parse the binary file. This 21 | class has virtually no initialization cost and low memory overhead without 22 | sacrificing lookup speed. 23 | 24 | There are no specific character or size constraints on the Trie input. Unicode 25 | input should work, provided you treat the encoded string as unicode (it will 26 | contain the unicode characters somewhere in it.) 27 | 28 | ### Features 29 | Both `Trie` and `PackedTrie` support `test` and `search` methods which support 30 | fuzzy-matching (i.e., wildcards) and prefix search. 31 | 32 | ## Docs 33 | 34 | See complete docs at https://jnu.github.io/tiny-trie/ 35 | 36 | ## Quick Usage 37 | 38 | ```js 39 | const words = ['spit', 'spat', 'spot', 'spits', 'spats', 'spots']; 40 | 41 | const trie = new Trie(); 42 | 43 | words.forEach(word => trie.insert(word)); 44 | 45 | // test membership 46 | trie.test('spit'); 47 | // -> true 48 | trie.test('split'); 49 | // -> false 50 | trie.search('sp*t', {wildcard: '*'}); 51 | // -> ['spit', 'spat', 'spot'] 52 | trie.search('spi', {prefix: true}); 53 | // -> ['spit', 'spits'] 54 | 55 | // finalize the trie, turning it into a DAWG 56 | trie.freeze(); 57 | 58 | // encode the trie 59 | let encoded = trie.encode(); 60 | // -> 'A4AAAAMEspiaotI0NmhqfPzcsQLwwrCCcBAQE' 61 | 62 | // This string describes the DAWG in a concise binary format. This format can 63 | // be interpreted by the `PackedTrie` class. 64 | const smallDawg = new PackedTrie(encoded); 65 | 66 | smallDawg.test('spit'); 67 | // -> true 68 | smallDawg.test('split'); 69 | // -> false 70 | smallDawg.search('sp*t', {wildcard: '*'}); 71 | // -> ['spit', 'spat', 'spot'] 72 | smallDawg.search('spi', {prefix: true}); 73 | // -> ['spit', 'spits'] 74 | ``` 75 | 76 | ### Including in a project 77 | 78 | #### Installed in `node_modules`: 79 | ```js 80 | import {TinyTrie} from 'tiny-trie'; 81 | import PackedTrie from 'tiny-trie/lib/PackedTrie'; 82 | ``` 83 | 84 | The default module export also provides some convenience functional tools: 85 | 86 | ```js 87 | import tinyTrie from 'tiny-trie'; 88 | 89 | tinyTrie.createSync(['foo', 'bar']); 90 | // equivalent to: 91 | // > var t = new Trie(); 92 | // > ['foo', 'bar'].forEach(word => t.insert(word)); 93 | 94 | tinyTrie.createFrozenSync(['foo', 'bar']); 95 | // equivalent to: 96 | // > var t = new Trie(); 97 | // > ['foo', 'bar'].forEach(word => t.insert(word)); 98 | // > t.freeze(); 99 | ``` 100 | 101 | #### Standalone files 102 | Bundled, ES5-compatible equivalents to the above are in `./dist`. 103 | 104 | ```js 105 | // tiny-trie[.min].js 106 | TinyTrie.Trie 107 | TinyTrie.createSync 108 | TinyTrie.createFrozenSync 109 | 110 | // packed-trie[.min].js 111 | PackedTrie 112 | ``` 113 | 114 | ## Benchmarks 115 | 116 | Quick benchmarks with the initial implementation on an MBP, node v5.0.0. 117 | 118 | Using `dictionary.txt`, a Scrabble dictionary with 178,692 words. 119 | 120 | ```js 121 | var words = fs.readFileSync('./dictionary.txt', 'utf8').split('\n'); 122 | ``` 123 | 124 | ### Speed 125 | 126 | Gives an idea roughly how long things take. 127 | 128 | ```js 129 | > var trie = TinyTrie.createSync(words); 130 | // 846 milliseconds 131 | 132 | > trie.test(...); 133 | // avg: 0.05 milliseconds 134 | 135 | > trie.freeze(); 136 | // 124 seconds 137 | 138 | > var encoded = trie.encode(); 139 | // 936 milliseconds 140 | 141 | > var packed = new PackedTrie(encoded); 142 | // 0.06 milliseconds (compare `new Set(words)`, which takes about 1s) 143 | 144 | > packed.test(...); 145 | // avg: 0.05 milliseconds (not significantly different from the unpacked trie!) 146 | ``` 147 | 148 | The init time of almost 1s is not acceptable for a client-side application. 149 | The goal of running `Trie#freeze(); Trie#encode();` at build time is to 150 | produce a packed version of the DAWG that has virtually *no* init time - and it 151 | can still be queried directly, with speeds approaching the full `Trie`'s very 152 | fast 50 microsecond times. 153 | 154 | ### Memory 155 | 156 | ```js 157 | > words.join('').length 158 | // 1584476 (bytes) 159 | 160 | > encoded.length 161 | // 698518 (bytes) 162 | 163 | > encoded.length / words.join('').length 164 | // 0.44085110787414894 165 | ``` 166 | 167 | The encoded trie uses just 44% of the bytes as the full dictionary. Gzipping 168 | gives a trie of 483kb, compared with 616kb for the dictionary. 169 | 170 | ## TODO 171 | 172 | * Real benchmarks, comparison with other implementations 173 | 174 | * Optimize in `PackedTrie` - reduce size, increase perf. Node order could 175 | probably be revised to shrink pointer field width. 176 | 177 | * Spec out limitations on encoding inputs 178 | -------------------------------------------------------------------------------- /dist/packed-trie.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["TinyTrie"] = factory(); 8 | else 9 | root["TinyTrie"] = factory(); 10 | })(window, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { 50 | /******/ configurable: false, 51 | /******/ enumerable: true, 52 | /******/ get: getter 53 | /******/ }); 54 | /******/ } 55 | /******/ }; 56 | /******/ 57 | /******/ // define __esModule on exports 58 | /******/ __webpack_require__.r = function(exports) { 59 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 60 | /******/ }; 61 | /******/ 62 | /******/ // getDefaultExport function for compatibility with non-harmony modules 63 | /******/ __webpack_require__.n = function(module) { 64 | /******/ var getter = module && module.__esModule ? 65 | /******/ function getDefault() { return module['default']; } : 66 | /******/ function getModuleExports() { return module; }; 67 | /******/ __webpack_require__.d(getter, 'a', getter); 68 | /******/ return getter; 69 | /******/ }; 70 | /******/ 71 | /******/ // Object.prototype.hasOwnProperty.call 72 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 73 | /******/ 74 | /******/ // __webpack_public_path__ 75 | /******/ __webpack_require__.p = ""; 76 | /******/ 77 | /******/ 78 | /******/ // Load entry module and return exports 79 | /******/ return __webpack_require__(__webpack_require__.s = "./src/PackedTrie.ts"); 80 | /******/ }) 81 | /************************************************************************/ 82 | /******/ ({ 83 | 84 | /***/ "./src/PackedTrie.ts": 85 | /*!***************************!*\ 86 | !*** ./src/PackedTrie.ts ***! 87 | \***************************/ 88 | /*! no static exports found */ 89 | /***/ (function(module, exports, __webpack_require__) { 90 | 91 | "use strict"; 92 | 93 | 94 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 95 | 96 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 97 | 98 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 99 | 100 | Object.defineProperty(exports, "__esModule", { value: true }); 101 | var base64_1 = __webpack_require__(/*! ./base64 */ "./src/base64.ts"); 102 | var constants_1 = __webpack_require__(/*! ./constants */ "./src/constants.ts"); 103 | function readBits(binary, start, len) { 104 | var startChar = ~~(start / 6); 105 | var startBitOffset = start % 6; 106 | var endBit = startBitOffset + len; 107 | var charLen = Math.ceil(endBit / 6); 108 | var mask = (0x1 << len) - 1; 109 | var chunk = 0; 110 | for (var i = 0; i < charLen; i++) { 111 | chunk <<= 6; 112 | chunk |= base64_1.BASE64_CHAR_TO_INT[binary[startChar + i]]; 113 | } 114 | var rightPadding = endBit % 6; 115 | if (rightPadding) { 116 | chunk >>= 6 - rightPadding; 117 | } 118 | return chunk & mask; 119 | } 120 | 121 | var PackedTrie = function () { 122 | function PackedTrie(binary) { 123 | _classCallCheck(this, PackedTrie); 124 | 125 | this.lastMask = 0x1; 126 | this.pointerShift = 1; 127 | var ptr = 0; 128 | var headerCharCount = readBits(binary, ptr, constants_1.HEADER_WIDTH_FIELD); 129 | ptr += constants_1.HEADER_WIDTH_FIELD; 130 | var header = binary.substr(0, headerCharCount); 131 | var version = readBits(binary, ptr, constants_1.VERSION_FIELD); 132 | ptr += constants_1.VERSION_FIELD; 133 | if (version !== constants_1.VERSION) { 134 | throw new Error("Version mismatch! Binary: " + version + ", Reader: " + constants_1.VERSION); 135 | } 136 | this.data = binary.substr(headerCharCount); 137 | var offsetSign = readBits(header, ptr, constants_1.OFFSET_SIGN_FIELD); 138 | ptr += constants_1.OFFSET_SIGN_FIELD; 139 | var offset = readBits(header, ptr, constants_1.OFFSET_VAL_FIELD); 140 | ptr += constants_1.OFFSET_VAL_FIELD; 141 | if (offsetSign) { 142 | offset = -offset; 143 | } 144 | this.offset = offset; 145 | var charWidth = readBits(header, ptr, constants_1.CHAR_WIDTH_FIELD); 146 | ptr += constants_1.CHAR_WIDTH_FIELD; 147 | var pointerWidth = readBits(header, ptr, constants_1.POINTER_WIDTH_FIELD); 148 | ptr += constants_1.POINTER_WIDTH_FIELD; 149 | var headerFieldChars = Math.ceil(ptr / 6); 150 | var charTable = header.substr(headerFieldChars); 151 | this.table = charTable.split('').reduce(function (agg, char, i) { 152 | agg[char] = i + 1; 153 | return agg; 154 | }, _defineProperty({}, constants_1.TERMINAL, 0)); 155 | this.inverseTable = [constants_1.TERMINAL].concat(charTable.split('')); 156 | this.wordWidth = charWidth + pointerWidth + 1; 157 | this.pointerMask = (0x1 << pointerWidth) - 1; 158 | this.charMask = (0x1 << charWidth) - 1; 159 | this.charShift = 1 + pointerWidth; 160 | } 161 | 162 | _createClass(PackedTrie, [{ 163 | key: "test", 164 | value: function test(str) { 165 | var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { wildcard: null, prefix: false }, 166 | wildcard = _ref.wildcard, 167 | prefix = _ref.prefix; 168 | 169 | return this.search(str, { wildcard: wildcard, prefix: prefix, first: true }) !== null; 170 | } 171 | }, { 172 | key: "search", 173 | value: function search(str) { 174 | var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { wildcard: null, prefix: false, first: false }, 175 | wildcard = _ref2.wildcard, 176 | prefix = _ref2.prefix, 177 | first = _ref2.first; 178 | 179 | if (wildcard && wildcard.length !== 1) { 180 | throw new Error("Wilcard must be a single character; got " + wildcard); 181 | } 182 | var data = this.data, 183 | offset = this.offset, 184 | table = this.table, 185 | inverseTable = this.inverseTable, 186 | wordWidth = this.wordWidth, 187 | lastMask = this.lastMask, 188 | pointerShift = this.pointerShift, 189 | pointerMask = this.pointerMask, 190 | charShift = this.charShift, 191 | charMask = this.charMask; 192 | 193 | var matches = []; 194 | var queue = [{ pointer: 0, memo: '', depth: 0 }]; 195 | var lastDepth = str.length; 196 | while (queue.length) { 197 | var node = queue.shift(); 198 | var isLast = node.depth >= lastDepth; 199 | var token = isLast ? constants_1.TERMINAL : str[node.depth]; 200 | var isWild = token === wildcard || prefix && isLast; 201 | var wordPointer = node.pointer; 202 | while (true) { 203 | if (!isWild && !table.hasOwnProperty(token)) { 204 | break; 205 | } 206 | var bits = wordPointer * wordWidth; 207 | var chunk = readBits(data, bits, wordWidth); 208 | var charIdx = chunk >> charShift & charMask; 209 | if (isWild || charIdx === table[token]) { 210 | var pointer = chunk >> pointerShift & pointerMask; 211 | var newChar = inverseTable[charIdx]; 212 | if (isLast && newChar === constants_1.TERMINAL) { 213 | if (first) { 214 | return node.memo; 215 | } 216 | matches.push(node.memo); 217 | if (!isWild) { 218 | break; 219 | } 220 | } 221 | if (newChar !== constants_1.TERMINAL) { 222 | queue.push({ 223 | pointer: wordPointer + offset + pointer, 224 | depth: node.depth + 1, 225 | memo: node.memo + newChar 226 | }); 227 | } 228 | } 229 | var last = chunk & lastMask; 230 | if (last) { 231 | break; 232 | } else { 233 | wordPointer += 1; 234 | } 235 | } 236 | } 237 | return first ? null : matches; 238 | } 239 | }]); 240 | 241 | return PackedTrie; 242 | }(); 243 | 244 | exports.PackedTrie = PackedTrie; 245 | 246 | /***/ }), 247 | 248 | /***/ "./src/base64.ts": 249 | /*!***********************!*\ 250 | !*** ./src/base64.ts ***! 251 | \***********************/ 252 | /*! no static exports found */ 253 | /***/ (function(module, exports, __webpack_require__) { 254 | 255 | "use strict"; 256 | 257 | 258 | Object.defineProperty(exports, "__esModule", { value: true }); 259 | exports.BASE64_INT_TO_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(''); 260 | exports.BASE64_CHAR_TO_INT = exports.BASE64_INT_TO_CHAR.reduce(function (agg, char, i) { 261 | agg[char] = i; 262 | return agg; 263 | }, {}); 264 | 265 | /***/ }), 266 | 267 | /***/ "./src/constants.ts": 268 | /*!**************************!*\ 269 | !*** ./src/constants.ts ***! 270 | \**************************/ 271 | /*! no static exports found */ 272 | /***/ (function(module, exports, __webpack_require__) { 273 | 274 | "use strict"; 275 | 276 | 277 | Object.defineProperty(exports, "__esModule", { value: true }); 278 | exports.TERMINAL = '\0'; 279 | exports.TERMINUS = Object.create(null); 280 | exports.VERSION = 0; 281 | exports.HEADER_WIDTH_FIELD = 10; 282 | exports.VERSION_FIELD = 10; 283 | exports.OFFSET_SIGN_FIELD = 1; 284 | exports.OFFSET_VAL_FIELD = 21; 285 | exports.CHAR_WIDTH_FIELD = 8; 286 | exports.POINTER_WIDTH_FIELD = 8; 287 | 288 | /***/ }) 289 | 290 | /******/ }); 291 | }); 292 | //# sourceMappingURL=packed-trie.js.map -------------------------------------------------------------------------------- /dist/packed-trie.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.TinyTrie=t():e.TinyTrie=t()}(window,function(){return function(e){var t={};function r(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:i})},r.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TERMINAL="\0",t.TERMINUS=Object.create(null),t.VERSION=0,t.HEADER_WIDTH_FIELD=10,t.VERSION_FIELD=10,t.OFFSET_SIGN_FIELD=1,t.OFFSET_VAL_FIELD=21,t.CHAR_WIDTH_FIELD=8,t.POINTER_WIDTH_FIELD=8},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BASE64_INT_TO_CHAR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),t.BASE64_CHAR_TO_INT=t.BASE64_INT_TO_CHAR.reduce(function(e,t,r){return e[t]=r,e},{})},,,function(e,t,r){"use strict";var i=function(){function e(e,t){for(var r=0;r>=6-c),u&s}var s=function(){function e(t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.lastMask=1,this.pointerShift=1;var r=0,i=a(t,r,o.HEADER_WIDTH_FIELD);r+=o.HEADER_WIDTH_FIELD;var n=t.substr(0,i),s=a(t,r,o.VERSION_FIELD);if(r+=o.VERSION_FIELD,s!==o.VERSION)throw new Error("Version mismatch! Binary: "+s+", Reader: "+o.VERSION);this.data=t.substr(i);var u=a(n,r,o.OFFSET_SIGN_FIELD),f=a(n,r+=o.OFFSET_SIGN_FIELD,o.OFFSET_VAL_FIELD);r+=o.OFFSET_VAL_FIELD,u&&(f=-f),this.offset=f;var c=a(n,r,o.CHAR_WIDTH_FIELD),l=a(n,r+=o.CHAR_WIDTH_FIELD,o.POINTER_WIDTH_FIELD);r+=o.POINTER_WIDTH_FIELD;var h,_,E,d=Math.ceil(r/6),p=n.substr(d);this.table=p.split("").reduce(function(e,t,r){return e[t]=r+1,e},(h={},_=o.TERMINAL,E=0,_ in h?Object.defineProperty(h,_,{value:E,enumerable:!0,configurable:!0,writable:!0}):h[_]=E,h)),this.inverseTable=[o.TERMINAL].concat(p.split("")),this.wordWidth=c+l+1,this.pointerMask=(1<1&&void 0!==arguments[1]?arguments[1]:{wildcard:null,prefix:!1},r=t.wildcard,i=t.prefix;return null!==this.search(e,{wildcard:r,prefix:i,first:!0})}},{key:"search",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{wildcard:null,prefix:!1,first:!1},r=t.wildcard,i=t.prefix,n=t.first;if(r&&1!==r.length)throw new Error("Wilcard must be a single character; got "+r);for(var s=this.data,u=this.offset,f=this.table,c=this.inverseTable,l=this.wordWidth,h=this.lastMask,_=this.pointerShift,E=this.pointerMask,d=this.charShift,p=this.charMask,I=[],T=[{pointer:0,memo:"",depth:0}],v=e.length;T.length;)for(var b=T.shift(),D=b.depth>=v,F=D?o.TERMINAL:e[b.depth],O=F===r||i&&D,L=b.pointer;O||f.hasOwnProperty(F);){var R=a(s,L*l,l),S=R>>d&p;if(O||S===f[F]){var A=R>>_&E,N=c[S];if(D&&N===o.TERMINAL){if(n)return b.memo;if(I.push(b.memo),!O)break}N!==o.TERMINAL&&T.push({pointer:L+u+A,depth:b.depth+1,memo:b.memo+N})}if(R&h)break;L+=1}return n?null:I}}]),e}();t.PackedTrie=s}])}); -------------------------------------------------------------------------------- /dist/tiny-trie.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.TinyTrie=t():e.TinyTrie=t()}(window,function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=6)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TERMINAL="\0",t.TERMINUS=Object.create(null),t.VERSION=0,t.HEADER_WIDTH_FIELD=10,t.VERSION_FIELD=10,t.OFFSET_SIGN_FIELD=1,t.OFFSET_VAL_FIELD=21,t.CHAR_WIDTH_FIELD=8,t.POINTER_WIDTH_FIELD=8},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BASE64_INT_TO_CHAR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),t.BASE64_CHAR_TO_INT=t.BASE64_INT_TO_CHAR.reduce(function(e,t,r){return e[t]=r,e},{})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.floor_log2=function(e){for(var t=0;e>>=1;)t++;return t}},function(e,t,r){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i=function(){function e(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:{};!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.root=t,this.frozen=!1}return i(e,[{key:"insert",value:function(e){if(this.frozen)throw new SyntaxError("Can't insert into frozen Trie");return e.split("").reduce(function(e,t){if(t===f.TERMINAL)throw new TypeError("Illegal string character "+f.TERMINAL);return e.hasOwnProperty(t)?e[t]:e[t]={}},this.root)[f.TERMINAL]=f.TERMINUS,this}},{key:"test",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{wildcard:null,prefix:!1},r=t.wildcard,n=t.prefix;if(!r){var i=this.root;return!!e.split("").every(function(e){return!!(i=i[e])})&&(n||i.hasOwnProperty(f.TERMINAL))}return!!this.search(e,{wildcard:r,prefix:n,first:!0})}},{key:"search",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{wildcard:null,prefix:!1,first:!1},r=t.wildcard,i=t.prefix,o=t.first;if(r&&1!==r.length)throw new Error("Wildcard length must be 1; got "+r.length);for(var u=[],a=[{data:this.root,depth:0,memo:""}],c=e.length,s=function(){var t=a.shift();if(t.depth>=c){if(t.data.hasOwnProperty(f.TERMINAL)){if(o)return{v:t.memo};u.push(t.memo)}if(!i)return"continue"}var n=i&&t.depth>=c,s=e[t.depth];s===r||n?Object.keys(t.data).forEach(function(e){e!==f.TERMINAL&&a.push({data:t.data[e],depth:t.depth+1,memo:t.memo+e})}):t.data.hasOwnProperty(s)&&a.push({data:t.data[s],depth:t.depth+1,memo:t.memo+s})};a.length;){var l=s();switch(l){case"continue":continue;default:if("object"===(void 0===l?"undefined":n(l)))return l.v}}return o?null:u}},{key:"clone",value:function(){return new e(this.toJSON())}},{key:"freeze",value:function(){if(this.frozen)return this;for(var e={},t=this.root,r=[],n=[t];n.length;)t=n.pop(),Object.keys(t).forEach(function(e){if("_"!==e[1]){var i=t[e];r.push({current:i,char:e,parent:t}),n.push(i)}});for(var i=function(){var t=r.pop(),n=t.char,i=t.parent,o=t.current;if(e.hasOwnProperty(n)){var u=e[n],f=u.find(function(e){var t=Object.keys(e),r=Object.keys(o);return t.length===r.length&&t.every(function(t){return e[t]===o[t]})});f?i[n]=f:u.push(o)}else e[n]=[o]};r.length;)i();return this.frozen=!0,this}},{key:"encode",value:function(){for(var e=[],t=[this.root],r=new Set,n=Date.now(),i=1/0,a=-1/0,c=function(){var o=t.shift(),u=Object.keys(o).filter(function(e){return"_"!==e[1]}),f=u.length;o.__visited__=n;var c=o.__idx__=e.length;o.__parents__&&o.__parents__.forEach(function(e){var t=e.offset=c-e.idx;ta&&(a=t)}),u.forEach(function(u,c){var s=o[u],l=e.length,_={char:u,idx:l,offset:null,last:c===f-1};if(s.__visited__===n){var h=s.__idx__,p=_.offset=h-l;pa&&(a=p)}else s.__willVisit__===n?s.__parents__.push(_):(s.__willVisit__=n,s.__parents__=[_]),t.push(s);e.push(_),r.add(u)})};t.length;)c();var s,l,_,h=Array.from(r).filter(function(e){return e!==f.TERMINAL}),p=h.reduce(function(e,t,r){return e[t]=r+1,e},(s={},l=f.TERMINAL,_=0,l in s?Object.defineProperty(s,l,{value:_,enumerable:!0,configurable:!0,writable:!0}):s[l]=_,s)),d=o.floor_log2(h.length)+1,v=a-i,y=o.floor_log2(v)+1,E=new u.BinaryString;e.forEach(function(e){var t=e.char,r=e.offset,n=e.last;E.write(p[t],d),E.write(r-i,y),E.write(+n,1)}),E.flush();var I=new u.BinaryString,b=h.join(""),T=Math.ceil((f.HEADER_WIDTH_FIELD+f.VERSION_FIELD+f.OFFSET_SIGN_FIELD+f.OFFSET_VAL_FIELD+f.CHAR_WIDTH_FIELD+f.POINTER_WIDTH_FIELD)/6)+b.length,w=+(i<0);return I.write(T,f.HEADER_WIDTH_FIELD),I.write(f.VERSION,f.VERSION_FIELD),I.write(w,f.OFFSET_SIGN_FIELD),I.write(w?-i:i,f.OFFSET_VAL_FIELD),I.write(d,f.CHAR_WIDTH_FIELD),I.write(y,f.POINTER_WIDTH_FIELD),I.flush(),""+I.getData()+b+E.getData()}},{key:"toJSON",value:function(){var e=JSON.stringify(this.root,function(e,t){if("_"!==e[1])return t});return JSON.parse(e)}}]),e}();t.Trie=a},,function(e,t,r){"use strict";var n=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:null,r=this.buffer,n=t||i.floor_log2(e)+1;if(t&&e>=1<=6;){var n=t-6,i=e>>n;e^=i< 2 | 3 | 4 | 5 | 6 | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 59 |

tiny-trie

60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Index

68 |
69 |
70 |
71 |

External modules

72 | 82 |
83 |
84 |
85 |
86 |
87 | 124 |
125 |
126 |
127 |
128 |

Legend

129 |
130 |
    131 |
  • Module
  • 132 |
  • Object literal
  • 133 |
  • Variable
  • 134 |
  • Function
  • 135 |
  • Function with type parameter
  • 136 |
  • Index signature
  • 137 |
  • Type alias
  • 138 |
139 |
    140 |
  • Enumeration
  • 141 |
  • Enumeration member
  • 142 |
  • Property
  • 143 |
  • Method
  • 144 |
145 |
    146 |
  • Interface
  • 147 |
  • Interface with type parameter
  • 148 |
  • Constructor
  • 149 |
  • Property
  • 150 |
  • Method
  • 151 |
  • Index signature
  • 152 |
153 |
    154 |
  • Class
  • 155 |
  • Class with type parameter
  • 156 |
  • Constructor
  • 157 |
  • Property
  • 158 |
  • Method
  • 159 |
  • Accessor
  • 160 |
  • Index signature
  • 161 |
162 |
    163 |
  • Inherited constructor
  • 164 |
  • Inherited property
  • 165 |
  • Inherited method
  • 166 |
  • Inherited accessor
  • 167 |
168 |
    169 |
  • Protected property
  • 170 |
  • Protected method
  • 171 |
  • Protected accessor
  • 172 |
173 |
    174 |
  • Private property
  • 175 |
  • Private method
  • 176 |
  • Private accessor
  • 177 |
178 |
    179 |
  • Static property
  • 180 |
  • Static method
  • 181 |
182 |
183 |
184 |
185 |
186 |

Generated using TypeDoc

187 |
188 |
189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /docs/interfaces/_basetrie_.itestopts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ITestOpts | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 65 |

Interface ITestOpts

66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |

Options to refine membership test queries.

76 |
77 |
78 |
79 |
80 |

Hierarchy

81 |
    82 |
  • 83 | ITestOpts 84 |
  • 85 |
86 |
87 |
88 |

Index

89 |
90 |
91 |
92 |

Properties

93 | 97 |
98 |
99 |
100 |
101 |
102 |

Properties

103 |
104 | 105 |

Optional prefix

106 |
prefix: boolean
107 | 112 |
113 |
114 | 115 |

Optional wildcard

116 |
wildcard: string
117 | 122 |
123 |
124 |
125 | 183 |
184 |
185 |
186 |
187 |

Legend

188 |
189 |
    190 |
  • Module
  • 191 |
  • Object literal
  • 192 |
  • Variable
  • 193 |
  • Function
  • 194 |
  • Function with type parameter
  • 195 |
  • Index signature
  • 196 |
  • Type alias
  • 197 |
198 |
    199 |
  • Enumeration
  • 200 |
  • Enumeration member
  • 201 |
  • Property
  • 202 |
  • Method
  • 203 |
204 |
    205 |
  • Interface
  • 206 |
  • Interface with type parameter
  • 207 |
  • Constructor
  • 208 |
  • Property
  • 209 |
  • Method
  • 210 |
  • Index signature
  • 211 |
212 |
    213 |
  • Class
  • 214 |
  • Class with type parameter
  • 215 |
  • Constructor
  • 216 |
  • Property
  • 217 |
  • Method
  • 218 |
  • Accessor
  • 219 |
  • Index signature
  • 220 |
221 |
    222 |
  • Inherited constructor
  • 223 |
  • Inherited property
  • 224 |
  • Inherited method
  • 225 |
  • Inherited accessor
  • 226 |
227 |
    228 |
  • Protected property
  • 229 |
  • Protected method
  • 230 |
  • Protected accessor
  • 231 |
232 |
    233 |
  • Private property
  • 234 |
  • Private method
  • 235 |
  • Private accessor
  • 236 |
237 |
    238 |
  • Static property
  • 239 |
  • Static method
  • 240 |
241 |
242 |
243 |
244 |
245 |

Generated using TypeDoc

246 |
247 |
248 | 249 | 250 | 251 | -------------------------------------------------------------------------------- /docs/interfaces/_trie_.inode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | INode | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 65 |

Interface INode

66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |

Trie node.

76 |
77 |
78 |
79 |
80 |

Hierarchy

81 |
    82 |
  • 83 | INode 84 |
  • 85 |
86 |
87 |
88 |

Indexable

89 |
[key: string]: INode
90 |
91 |
92 |

Trie node.

93 |
94 |
95 |
96 |
97 | 153 |
154 |
155 |
156 |
157 |

Legend

158 |
159 |
    160 |
  • Module
  • 161 |
  • Object literal
  • 162 |
  • Variable
  • 163 |
  • Function
  • 164 |
  • Function with type parameter
  • 165 |
  • Index signature
  • 166 |
  • Type alias
  • 167 |
168 |
    169 |
  • Enumeration
  • 170 |
  • Enumeration member
  • 171 |
  • Property
  • 172 |
  • Method
  • 173 |
174 |
    175 |
  • Interface
  • 176 |
  • Interface with type parameter
  • 177 |
  • Constructor
  • 178 |
  • Property
  • 179 |
  • Method
  • 180 |
  • Index signature
  • 181 |
182 |
    183 |
  • Class
  • 184 |
  • Class with type parameter
  • 185 |
  • Constructor
  • 186 |
  • Property
  • 187 |
  • Method
  • 188 |
  • Accessor
  • 189 |
  • Index signature
  • 190 |
191 |
    192 |
  • Inherited constructor
  • 193 |
  • Inherited property
  • 194 |
  • Inherited method
  • 195 |
  • Inherited accessor
  • 196 |
197 |
    198 |
  • Protected property
  • 199 |
  • Protected method
  • 200 |
  • Protected accessor
  • 201 |
202 |
    203 |
  • Private property
  • 204 |
  • Private method
  • 205 |
  • Private accessor
  • 206 |
207 |
    208 |
  • Static property
  • 209 |
  • Static method
  • 210 |
211 |
212 |
213 |
214 |
215 |

Generated using TypeDoc

216 |
217 |
218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /docs/modules/_base64_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "base64" | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "base64"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
file
73 |

Lookup tables for Base64 conversions

74 |
75 |
76 |
77 |
78 |
79 |

Index

80 |
81 |
82 |
83 |

Variables

84 | 88 |
89 |
90 |
91 |
92 |
93 |

Variables

94 |
95 | 96 |

Const BASE64_CHAR_TO_INT

97 |
BASE64_CHAR_TO_INT: object = BASE64_INT_TO_CHAR.reduce((agg, char, i) => {agg[char] = i;return agg;}, {} as {[key: string]: number})
98 | 103 |
104 |
105 |

Inverse lookup table for transformating a Base-64 ASCII character into the 106 | corresponding integer value.

107 |
108 |
109 |
constant
110 |

{Object}

111 |
112 |
113 |
114 |
115 |

Type declaration

116 |
    117 |
  • 118 |
    [key: string]: number
    119 |
  • 120 |
121 |
122 |
123 |
124 | 125 |

Const BASE64_INT_TO_CHAR

126 |
BASE64_INT_TO_CHAR: string[] = `\ABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyz\0123456789\+/\`.split('')
127 | 132 |
133 |
134 |

Lookup table for transforming a 6-bit binary integer into a Base-64 ASCII 135 | character.

136 |
137 |
138 |
constant
139 |

{String[]}

140 |
141 |
142 |
143 |
144 |
145 |
146 | 189 |
190 |
191 |
192 |
193 |

Legend

194 |
195 |
    196 |
  • Module
  • 197 |
  • Object literal
  • 198 |
  • Variable
  • 199 |
  • Function
  • 200 |
  • Function with type parameter
  • 201 |
  • Index signature
  • 202 |
  • Type alias
  • 203 |
204 |
    205 |
  • Enumeration
  • 206 |
  • Enumeration member
  • 207 |
  • Property
  • 208 |
  • Method
  • 209 |
210 |
    211 |
  • Interface
  • 212 |
  • Interface with type parameter
  • 213 |
  • Constructor
  • 214 |
  • Property
  • 215 |
  • Method
  • 216 |
  • Index signature
  • 217 |
218 |
    219 |
  • Class
  • 220 |
  • Class with type parameter
  • 221 |
  • Constructor
  • 222 |
  • Property
  • 223 |
  • Method
  • 224 |
  • Accessor
  • 225 |
  • Index signature
  • 226 |
227 |
    228 |
  • Inherited constructor
  • 229 |
  • Inherited property
  • 230 |
  • Inherited method
  • 231 |
  • Inherited accessor
  • 232 |
233 |
    234 |
  • Protected property
  • 235 |
  • Protected method
  • 236 |
  • Protected accessor
  • 237 |
238 |
    239 |
  • Private property
  • 240 |
  • Private method
  • 241 |
  • Private accessor
  • 242 |
243 |
    244 |
  • Static property
  • 245 |
  • Static method
  • 246 |
247 |
248 |
249 |
250 |
251 |

Generated using TypeDoc

252 |
253 |
254 | 255 | 256 | 257 | -------------------------------------------------------------------------------- /docs/modules/_basetrie_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "BaseTrie" | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "BaseTrie"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Interfaces

75 | 80 |
81 |
82 |
83 |
84 |
85 | 131 |
132 |
133 |
134 |
135 |

Legend

136 |
137 |
    138 |
  • Module
  • 139 |
  • Object literal
  • 140 |
  • Variable
  • 141 |
  • Function
  • 142 |
  • Function with type parameter
  • 143 |
  • Index signature
  • 144 |
  • Type alias
  • 145 |
146 |
    147 |
  • Enumeration
  • 148 |
  • Enumeration member
  • 149 |
  • Property
  • 150 |
  • Method
  • 151 |
152 |
    153 |
  • Interface
  • 154 |
  • Interface with type parameter
  • 155 |
  • Constructor
  • 156 |
  • Property
  • 157 |
  • Method
  • 158 |
  • Index signature
  • 159 |
160 |
    161 |
  • Class
  • 162 |
  • Class with type parameter
  • 163 |
  • Constructor
  • 164 |
  • Property
  • 165 |
  • Method
  • 166 |
  • Accessor
  • 167 |
  • Index signature
  • 168 |
169 |
    170 |
  • Inherited constructor
  • 171 |
  • Inherited property
  • 172 |
  • Inherited method
  • 173 |
  • Inherited accessor
  • 174 |
175 |
    176 |
  • Protected property
  • 177 |
  • Protected method
  • 178 |
  • Protected accessor
  • 179 |
180 |
    181 |
  • Private property
  • 182 |
  • Private method
  • 183 |
  • Private accessor
  • 184 |
185 |
    186 |
  • Static property
  • 187 |
  • Static method
  • 188 |
189 |
190 |
191 |
192 |
193 |

Generated using TypeDoc

194 |
195 |
196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /docs/modules/_binarystring_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "BinaryString" | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "BinaryString"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |
81 |
82 |
83 | 123 |
124 |
125 |
126 |
127 |

Legend

128 |
129 |
    130 |
  • Module
  • 131 |
  • Object literal
  • 132 |
  • Variable
  • 133 |
  • Function
  • 134 |
  • Function with type parameter
  • 135 |
  • Index signature
  • 136 |
  • Type alias
  • 137 |
138 |
    139 |
  • Enumeration
  • 140 |
  • Enumeration member
  • 141 |
  • Property
  • 142 |
  • Method
  • 143 |
144 |
    145 |
  • Interface
  • 146 |
  • Interface with type parameter
  • 147 |
  • Constructor
  • 148 |
  • Property
  • 149 |
  • Method
  • 150 |
  • Index signature
  • 151 |
152 |
    153 |
  • Class
  • 154 |
  • Class with type parameter
  • 155 |
  • Constructor
  • 156 |
  • Property
  • 157 |
  • Method
  • 158 |
  • Accessor
  • 159 |
  • Index signature
  • 160 |
161 |
    162 |
  • Inherited constructor
  • 163 |
  • Inherited property
  • 164 |
  • Inherited method
  • 165 |
  • Inherited accessor
  • 166 |
167 |
    168 |
  • Protected property
  • 169 |
  • Protected method
  • 170 |
  • Protected accessor
  • 171 |
172 |
    173 |
  • Private property
  • 174 |
  • Private method
  • 175 |
  • Private accessor
  • 176 |
177 |
    178 |
  • Static property
  • 179 |
  • Static method
  • 180 |
181 |
182 |
183 |
184 |
185 |

Generated using TypeDoc

186 |
187 |
188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /docs/modules/_floor_log2_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "floor_log2" | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "floor_log2"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
file
73 |

Provides a fast floor_log2 function

74 |
75 |
76 |
77 |
78 |
79 |

Index

80 |
81 |
82 |
83 |

Functions

84 | 87 |
88 |
89 |
90 |
91 |
92 |

Functions

93 |
94 | 95 |

floor_log2

96 |
    97 |
  • floor_log2(x: number): number
  • 98 |
99 |
    100 |
  • 101 | 106 |
    107 |
    108 |

    Fast floor(log2(x)) operation

    109 |
    110 |
    111 |

    Parameters

    112 |
      113 |
    • 114 |
      x: number
      115 |
    • 116 |
    117 |

    Returns number

    118 |
  • 119 |
120 |
121 |
122 |
123 | 163 |
164 |
165 |
166 |
167 |

Legend

168 |
169 |
    170 |
  • Module
  • 171 |
  • Object literal
  • 172 |
  • Variable
  • 173 |
  • Function
  • 174 |
  • Function with type parameter
  • 175 |
  • Index signature
  • 176 |
  • Type alias
  • 177 |
178 |
    179 |
  • Enumeration
  • 180 |
  • Enumeration member
  • 181 |
  • Property
  • 182 |
  • Method
  • 183 |
184 |
    185 |
  • Interface
  • 186 |
  • Interface with type parameter
  • 187 |
  • Constructor
  • 188 |
  • Property
  • 189 |
  • Method
  • 190 |
  • Index signature
  • 191 |
192 |
    193 |
  • Class
  • 194 |
  • Class with type parameter
  • 195 |
  • Constructor
  • 196 |
  • Property
  • 197 |
  • Method
  • 198 |
  • Accessor
  • 199 |
  • Index signature
  • 200 |
201 |
    202 |
  • Inherited constructor
  • 203 |
  • Inherited property
  • 204 |
  • Inherited method
  • 205 |
  • Inherited accessor
  • 206 |
207 |
    208 |
  • Protected property
  • 209 |
  • Protected method
  • 210 |
  • Protected accessor
  • 211 |
212 |
    213 |
  • Private property
  • 214 |
  • Private method
  • 215 |
  • Private accessor
  • 216 |
217 |
    218 |
  • Static property
  • 219 |
  • Static method
  • 220 |
221 |
222 |
223 |
224 |
225 |

Generated using TypeDoc

226 |
227 |
228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /docs/modules/_index_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "index" | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "index"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Functions

75 | 79 |
80 |
81 |
82 |
83 |
84 |

Functions

85 |
86 | 87 |

createFrozenSync

88 |
    89 |
  • createFrozenSync(words: string[]): Trie
  • 90 |
91 |
    92 |
  • 93 | 98 |
    99 |
    100 |

    Create a frozen Trie out of given words

    101 |
    102 |
    103 |

    Parameters

    104 |
      105 |
    • 106 |
      words: string[]
      107 |
    • 108 |
    109 |

    Returns Trie

    110 |
  • 111 |
112 |
113 |
114 | 115 |

createSync

116 |
    117 |
  • createSync(strings: string[]): Trie
  • 118 |
119 |
    120 |
  • 121 | 126 |
    127 |
    128 |

    Synchronously construct a new Trie out of the given strings.

    129 |
    130 |
    131 |

    Parameters

    132 |
      133 |
    • 134 |
      strings: string[]
      135 |
    • 136 |
    137 |

    Returns Trie

    138 |
  • 139 |
140 |
141 |
142 |
143 | 186 |
187 |
188 |
189 |
190 |

Legend

191 |
192 |
    193 |
  • Module
  • 194 |
  • Object literal
  • 195 |
  • Variable
  • 196 |
  • Function
  • 197 |
  • Function with type parameter
  • 198 |
  • Index signature
  • 199 |
  • Type alias
  • 200 |
201 |
    202 |
  • Enumeration
  • 203 |
  • Enumeration member
  • 204 |
  • Property
  • 205 |
  • Method
  • 206 |
207 |
    208 |
  • Interface
  • 209 |
  • Interface with type parameter
  • 210 |
  • Constructor
  • 211 |
  • Property
  • 212 |
  • Method
  • 213 |
  • Index signature
  • 214 |
215 |
    216 |
  • Class
  • 217 |
  • Class with type parameter
  • 218 |
  • Constructor
  • 219 |
  • Property
  • 220 |
  • Method
  • 221 |
  • Accessor
  • 222 |
  • Index signature
  • 223 |
224 |
    225 |
  • Inherited constructor
  • 226 |
  • Inherited property
  • 227 |
  • Inherited method
  • 228 |
  • Inherited accessor
  • 229 |
230 |
    231 |
  • Protected property
  • 232 |
  • Protected method
  • 233 |
  • Protected accessor
  • 234 |
235 |
    236 |
  • Private property
  • 237 |
  • Private method
  • 238 |
  • Private accessor
  • 239 |
240 |
    241 |
  • Static property
  • 242 |
  • Static method
  • 243 |
244 |
245 |
246 |
247 |
248 |

Generated using TypeDoc

249 |
250 |
251 | 252 | 253 | 254 | -------------------------------------------------------------------------------- /docs/modules/_packedtrie_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "PackedTrie" | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "PackedTrie"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |

Functions

81 | 84 |
85 |
86 |
87 |
88 |
89 |

Functions

90 |
91 | 92 |

readBits

93 |
    94 |
  • readBits(binary: string, start: number, len: number): number
  • 95 |
96 |
    97 |
  • 98 | 103 |
    104 |
    105 |

    Extract a window of bits from a Base64 encoded sequence

    106 |
    107 |
    108 |

    Parameters

    109 |
      110 |
    • 111 |
      binary: string
      112 |
      113 |

      base64 encoded sequence

      114 |
      115 |
    • 116 |
    • 117 |
      start: number
      118 |
      119 |

      first bit to read

      120 |
      121 |
    • 122 |
    • 123 |
      len: number
      124 |
      125 |

      number of bits to read

      126 |
      127 |
    • 128 |
    129 |

    Returns number

    130 |
      131 |
    • bits from string, as number
    • 132 |
    133 |
  • 134 |
135 |
136 |
137 |
138 | 181 |
182 |
183 |
184 |
185 |

Legend

186 |
187 |
    188 |
  • Module
  • 189 |
  • Object literal
  • 190 |
  • Variable
  • 191 |
  • Function
  • 192 |
  • Function with type parameter
  • 193 |
  • Index signature
  • 194 |
  • Type alias
  • 195 |
196 |
    197 |
  • Enumeration
  • 198 |
  • Enumeration member
  • 199 |
  • Property
  • 200 |
  • Method
  • 201 |
202 |
    203 |
  • Interface
  • 204 |
  • Interface with type parameter
  • 205 |
  • Constructor
  • 206 |
  • Property
  • 207 |
  • Method
  • 208 |
  • Index signature
  • 209 |
210 |
    211 |
  • Class
  • 212 |
  • Class with type parameter
  • 213 |
  • Constructor
  • 214 |
  • Property
  • 215 |
  • Method
  • 216 |
  • Accessor
  • 217 |
  • Index signature
  • 218 |
219 |
    220 |
  • Inherited constructor
  • 221 |
  • Inherited property
  • 222 |
  • Inherited method
  • 223 |
  • Inherited accessor
  • 224 |
225 |
    226 |
  • Protected property
  • 227 |
  • Protected method
  • 228 |
  • Protected accessor
  • 229 |
230 |
    231 |
  • Private property
  • 232 |
  • Private method
  • 233 |
  • Private accessor
  • 234 |
235 |
    236 |
  • Static property
  • 237 |
  • Static method
  • 238 |
239 |
240 |
241 |
242 |
243 |

Generated using TypeDoc

244 |
245 |
246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /docs/modules/_trie_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "Trie" | tiny-trie 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "Trie"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |

Interfaces

81 | 86 |
87 |
88 |

Type aliases

89 | 92 |
93 |
94 |
95 |
96 |
97 |

Type aliases

98 |
99 | 100 |

IInternalNode

101 |
IInternalNode: INode & INodeMeta
102 | 107 |
108 |
109 |

Interface of a node as it is being processed in the trie.

110 |
111 |
112 |
113 |
114 |
115 | 167 |
168 |
169 |
170 |
171 |

Legend

172 |
173 |
    174 |
  • Module
  • 175 |
  • Object literal
  • 176 |
  • Variable
  • 177 |
  • Function
  • 178 |
  • Function with type parameter
  • 179 |
  • Index signature
  • 180 |
  • Type alias
  • 181 |
182 |
    183 |
  • Enumeration
  • 184 |
  • Enumeration member
  • 185 |
  • Property
  • 186 |
  • Method
  • 187 |
188 |
    189 |
  • Interface
  • 190 |
  • Interface with type parameter
  • 191 |
  • Constructor
  • 192 |
  • Property
  • 193 |
  • Method
  • 194 |
  • Index signature
  • 195 |
196 |
    197 |
  • Class
  • 198 |
  • Class with type parameter
  • 199 |
  • Constructor
  • 200 |
  • Property
  • 201 |
  • Method
  • 202 |
  • Accessor
  • 203 |
  • Index signature
  • 204 |
205 |
    206 |
  • Inherited constructor
  • 207 |
  • Inherited property
  • 208 |
  • Inherited method
  • 209 |
  • Inherited accessor
  • 210 |
211 |
    212 |
  • Protected property
  • 213 |
  • Protected method
  • 214 |
  • Protected accessor
  • 215 |
216 |
    217 |
  • Private property
  • 218 |
  • Private method
  • 219 |
  • Private accessor
  • 220 |
221 |
    222 |
  • Static property
  • 223 |
  • Static method
  • 224 |
225 |
226 |
227 |
228 |
229 |

Generated using TypeDoc

230 |
231 |
232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /lib/BaseTrie.d.ts: -------------------------------------------------------------------------------- 1 | export interface ITestOpts { 2 | wildcard?: string; 3 | prefix?: boolean; 4 | } 5 | export interface ISearchOpts { 6 | wildcard?: string; 7 | prefix?: boolean; 8 | first?: boolean; 9 | } 10 | export interface ITrie { 11 | test: (s: string, opts?: ITestOpts) => boolean; 12 | search: (s: string, opts?: ISearchOpts) => string | string[]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/BaseTrie.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=BaseTrie.js.map -------------------------------------------------------------------------------- /lib/BaseTrie.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"BaseTrie.js","sourceRoot":"","sources":["../src/BaseTrie.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /lib/BinaryString.d.ts: -------------------------------------------------------------------------------- 1 | export declare class BinaryString { 2 | private buffer; 3 | private pointer; 4 | private data; 5 | write(val: number, width?: number): void; 6 | flush(): void; 7 | getData(): string; 8 | _digest(): void; 9 | } 10 | -------------------------------------------------------------------------------- /lib/BinaryString.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const floor_log2_1 = require("./floor_log2"); 4 | const base64_1 = require("./base64"); 5 | class BinaryString { 6 | constructor() { 7 | this.buffer = 0; 8 | this.pointer = 0; 9 | this.data = ''; 10 | } 11 | write(val, width = null) { 12 | let buf = this.buffer; 13 | let len = width || floor_log2_1.floor_log2(val) + 1; 14 | if (width && val >= (0x1 << width)) { 15 | throw new Error(`Can't write ${val} in only ${width} bits`); 16 | } 17 | this.buffer = (buf << len) | val; 18 | this.pointer += len; 19 | this._digest(); 20 | } 21 | flush() { 22 | let buffer = this.buffer; 23 | let pointer = this.pointer; 24 | while (pointer && pointer < 6) { 25 | buffer <<= 1; 26 | pointer += 1; 27 | } 28 | this.pointer = pointer; 29 | this.buffer = buffer; 30 | this._digest(); 31 | } 32 | getData() { 33 | this.flush(); 34 | return this.data; 35 | } 36 | _digest() { 37 | let buffer = this.buffer; 38 | let pointer = this.pointer; 39 | let newData = ''; 40 | while (pointer >= 6) { 41 | let remainder = (pointer - 6); 42 | let code = buffer >> remainder; 43 | buffer = buffer ^ (code << remainder); 44 | pointer = remainder; 45 | newData += base64_1.BASE64_INT_TO_CHAR[code]; 46 | } 47 | this.pointer = pointer; 48 | this.buffer = buffer; 49 | this.data += newData; 50 | } 51 | } 52 | exports.BinaryString = BinaryString; 53 | //# sourceMappingURL=BinaryString.js.map -------------------------------------------------------------------------------- /lib/BinaryString.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"BinaryString.js","sourceRoot":"","sources":["../src/BinaryString.ts"],"names":[],"mappings":";;AAKA,6CAAwC;AACxC,qCAA4C;AAM5C;IAAA;QAMY,WAAM,GAAG,CAAC,CAAC;QASX,YAAO,GAAG,CAAC,CAAC;QAMZ,SAAI,GAAG,EAAE,CAAC;IA6EtB,CAAC;IAlEG,KAAK,CAAC,GAAW,EAAE,QAAgB,IAAI;QACnC,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,IAAI,GAAG,GAAG,KAAK,IAAI,uBAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEvC,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,eAAe,GAAG,YAAY,KAAK,OAAO,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC;QACjC,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC;QAEpB,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAMD,KAAK;QACD,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAE3B,OAAO,OAAO,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,CAAC,CAAC;YACb,OAAO,IAAI,CAAC,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAOD,OAAO;QACH,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAWD,OAAO;QACH,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC3B,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,OAAO,OAAO,IAAI,CAAC,EAAE,CAAC;YAClB,IAAI,SAAS,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;YAC9B,IAAI,IAAI,GAAG,MAAM,IAAI,SAAS,CAAC;YAC/B,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;YACtC,OAAO,GAAG,SAAS,CAAC;YACpB,OAAO,IAAI,2BAAkB,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;IACzB,CAAC;CAEJ;AAlGD,oCAkGC"} -------------------------------------------------------------------------------- /lib/PackedTrie.d.ts: -------------------------------------------------------------------------------- 1 | import { ITrie, ISearchOpts, ITestOpts } from './BaseTrie'; 2 | export declare class PackedTrie implements ITrie { 3 | data: string; 4 | private offset; 5 | private table; 6 | private inverseTable; 7 | private wordWidth; 8 | private lastMask; 9 | private pointerMask; 10 | private pointerShift; 11 | private charMask; 12 | private charShift; 13 | constructor(binary: string); 14 | test(str: string, {wildcard, prefix}?: ITestOpts): boolean; 15 | search(str: string, {wildcard, prefix, first}?: ISearchOpts): string | string[]; 16 | } 17 | -------------------------------------------------------------------------------- /lib/PackedTrie.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const base64_1 = require("./base64"); 4 | const constants_1 = require("./constants"); 5 | function readBits(binary, start, len) { 6 | const startChar = ~~(start / 6); 7 | const startBitOffset = start % 6; 8 | const endBit = startBitOffset + len; 9 | const charLen = Math.ceil(endBit / 6); 10 | const mask = (0x1 << len) - 1; 11 | let chunk = 0; 12 | for (let i = 0; i < charLen; i++) { 13 | chunk <<= 6; 14 | chunk |= base64_1.BASE64_CHAR_TO_INT[binary[startChar + i]]; 15 | } 16 | let rightPadding = endBit % 6; 17 | if (rightPadding) { 18 | chunk >>= (6 - rightPadding); 19 | } 20 | return chunk & mask; 21 | } 22 | class PackedTrie { 23 | constructor(binary) { 24 | this.lastMask = 0x1; 25 | this.pointerShift = 1; 26 | let ptr = 0; 27 | const headerCharCount = readBits(binary, ptr, constants_1.HEADER_WIDTH_FIELD); 28 | ptr += constants_1.HEADER_WIDTH_FIELD; 29 | const header = binary.substr(0, headerCharCount); 30 | const version = readBits(binary, ptr, constants_1.VERSION_FIELD); 31 | ptr += constants_1.VERSION_FIELD; 32 | if (version !== constants_1.VERSION) { 33 | throw new Error(`Version mismatch! Binary: ${version}, Reader: ${constants_1.VERSION}`); 34 | } 35 | this.data = binary.substr(headerCharCount); 36 | const offsetSign = readBits(header, ptr, constants_1.OFFSET_SIGN_FIELD); 37 | ptr += constants_1.OFFSET_SIGN_FIELD; 38 | let offset = readBits(header, ptr, constants_1.OFFSET_VAL_FIELD); 39 | ptr += constants_1.OFFSET_VAL_FIELD; 40 | if (offsetSign) { 41 | offset = -offset; 42 | } 43 | this.offset = offset; 44 | let charWidth = readBits(header, ptr, constants_1.CHAR_WIDTH_FIELD); 45 | ptr += constants_1.CHAR_WIDTH_FIELD; 46 | let pointerWidth = readBits(header, ptr, constants_1.POINTER_WIDTH_FIELD); 47 | ptr += constants_1.POINTER_WIDTH_FIELD; 48 | let headerFieldChars = Math.ceil(ptr / 6); 49 | let charTable = header.substr(headerFieldChars); 50 | this.table = charTable.split('').reduce((agg, char, i) => { 51 | agg[char] = i + 1; 52 | return agg; 53 | }, { [constants_1.TERMINAL]: 0 }); 54 | this.inverseTable = [constants_1.TERMINAL].concat(charTable.split('')); 55 | this.wordWidth = charWidth + pointerWidth + 1; 56 | this.pointerMask = (0x1 << pointerWidth) - 1; 57 | this.charMask = (0x1 << charWidth) - 1; 58 | this.charShift = 1 + pointerWidth; 59 | } 60 | test(str, { wildcard, prefix } = { wildcard: null, prefix: false }) { 61 | return this.search(str, { wildcard, prefix, first: true }) !== null; 62 | } 63 | search(str, { wildcard, prefix, first } = { wildcard: null, prefix: false, first: false }) { 64 | if (wildcard && wildcard.length !== 1) { 65 | throw new Error(`Wilcard must be a single character; got ${wildcard}`); 66 | } 67 | const { data, offset, table, inverseTable, wordWidth, lastMask, pointerShift, pointerMask, charShift, charMask } = this; 68 | const matches = []; 69 | const queue = [{ pointer: 0, memo: '', depth: 0 }]; 70 | const lastDepth = str.length; 71 | while (queue.length) { 72 | const node = queue.shift(); 73 | const isLast = node.depth >= lastDepth; 74 | const token = isLast ? constants_1.TERMINAL : str[node.depth]; 75 | const isWild = token === wildcard || (prefix && isLast); 76 | let wordPointer = node.pointer; 77 | while (true) { 78 | if (!isWild && !table.hasOwnProperty(token)) { 79 | break; 80 | } 81 | const bits = wordPointer * wordWidth; 82 | const chunk = readBits(data, bits, wordWidth); 83 | const charIdx = (chunk >> charShift) & charMask; 84 | if (isWild || charIdx === table[token]) { 85 | const pointer = (chunk >> pointerShift) & pointerMask; 86 | const newChar = inverseTable[charIdx]; 87 | if (isLast && newChar === constants_1.TERMINAL) { 88 | if (first) { 89 | return node.memo; 90 | } 91 | matches.push(node.memo); 92 | if (!isWild) { 93 | break; 94 | } 95 | } 96 | if (newChar !== constants_1.TERMINAL) { 97 | queue.push({ 98 | pointer: wordPointer + offset + pointer, 99 | depth: node.depth + 1, 100 | memo: node.memo + newChar, 101 | }); 102 | } 103 | } 104 | const last = chunk & lastMask; 105 | if (last) { 106 | break; 107 | } 108 | else { 109 | wordPointer += 1; 110 | } 111 | } 112 | } 113 | return first ? null : matches; 114 | } 115 | } 116 | exports.PackedTrie = PackedTrie; 117 | //# sourceMappingURL=PackedTrie.js.map -------------------------------------------------------------------------------- /lib/PackedTrie.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"PackedTrie.js","sourceRoot":"","sources":["../src/PackedTrie.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/Trie.d.ts: -------------------------------------------------------------------------------- 1 | import { ITrie, ITestOpts, ISearchOpts } from './BaseTrie'; 2 | export interface INode { 3 | [key: string]: INode; 4 | } 5 | export declare class Trie implements ITrie { 6 | root: INode; 7 | frozen: boolean; 8 | constructor(tree?: INode); 9 | insert(str: string): this; 10 | test(str: string, {wildcard, prefix}?: ITestOpts): boolean; 11 | search(str: string, {wildcard, prefix, first}?: ISearchOpts): string | string[]; 12 | clone(): Trie; 13 | freeze(): this; 14 | encode(): string; 15 | toJSON(): any; 16 | } 17 | -------------------------------------------------------------------------------- /lib/Trie.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const floor_log2_1 = require("./floor_log2"); 4 | const BinaryString_1 = require("./BinaryString"); 5 | const constants_1 = require("./constants"); 6 | class Trie { 7 | constructor(tree = {}) { 8 | this.root = tree; 9 | this.frozen = false; 10 | } 11 | insert(str) { 12 | if (this.frozen) { 13 | throw new SyntaxError(`Can't insert into frozen Trie`); 14 | } 15 | const lastNode = str.split('').reduce((node, char) => { 16 | if (char === constants_1.TERMINAL) { 17 | throw new TypeError(`Illegal string character ${constants_1.TERMINAL}`); 18 | } 19 | let nextNode = node.hasOwnProperty(char) ? 20 | node[char] : 21 | (node[char] = {}); 22 | return nextNode; 23 | }, this.root); 24 | lastNode[constants_1.TERMINAL] = constants_1.TERMINUS; 25 | return this; 26 | } 27 | test(str, { wildcard, prefix } = { wildcard: null, prefix: false }) { 28 | if (!wildcard) { 29 | let node = this.root; 30 | const match = str.split('').every(char => !!(node = node[char])); 31 | return !!match && (prefix || node.hasOwnProperty(constants_1.TERMINAL)); 32 | } 33 | return !!this.search(str, { wildcard, prefix, first: true }); 34 | } 35 | search(str, { wildcard, prefix, first } = { wildcard: null, prefix: false, first: false }) { 36 | if (wildcard && wildcard.length !== 1) { 37 | throw new Error(`Wildcard length must be 1; got ${wildcard.length}`); 38 | } 39 | const matches = []; 40 | const queue = [{ data: this.root, depth: 0, memo: '' }]; 41 | const lastDepth = str.length; 42 | while (queue.length) { 43 | const node = queue.shift(); 44 | if (node.depth >= lastDepth) { 45 | if (node.data.hasOwnProperty(constants_1.TERMINAL)) { 46 | if (first) { 47 | return node.memo; 48 | } 49 | matches.push(node.memo); 50 | } 51 | if (!prefix) { 52 | continue; 53 | } 54 | } 55 | const isPfXOverflow = prefix && node.depth >= lastDepth; 56 | const token = str[node.depth]; 57 | if (token === wildcard || isPfXOverflow) { 58 | Object.keys(node.data).forEach(n => { 59 | if (n !== constants_1.TERMINAL) { 60 | queue.push({ 61 | data: node.data[n], 62 | depth: node.depth + 1, 63 | memo: node.memo + n, 64 | }); 65 | } 66 | }); 67 | } 68 | else { 69 | if (node.data.hasOwnProperty(token)) { 70 | queue.push({ 71 | data: node.data[token], 72 | depth: node.depth + 1, 73 | memo: node.memo + token, 74 | }); 75 | } 76 | } 77 | } 78 | return first ? null : matches; 79 | } 80 | clone() { 81 | return new Trie(this.toJSON()); 82 | } 83 | freeze() { 84 | if (this.frozen) { 85 | return this; 86 | } 87 | const suffixTree = {}; 88 | let node = this.root; 89 | let stack = []; 90 | let depthStack = [node]; 91 | while (depthStack.length) { 92 | node = depthStack.pop(); 93 | Object.keys(node).forEach(char => { 94 | if (char[1] === '_') { 95 | return; 96 | } 97 | let current = node[char]; 98 | stack.push({ 99 | current: current, 100 | char: char, 101 | parent: node 102 | }); 103 | depthStack.push(current); 104 | }); 105 | } 106 | while (stack.length) { 107 | let { char, parent, current } = stack.pop(); 108 | if (suffixTree.hasOwnProperty(char)) { 109 | let suffixMeta = suffixTree[char]; 110 | let match = suffixMeta.find(other => { 111 | let oKeys = Object.keys(other); 112 | let cKeys = Object.keys(current); 113 | return (oKeys.length === cKeys.length && 114 | oKeys.every(key => other[key] === current[key])); 115 | }); 116 | if (match) { 117 | parent[char] = match; 118 | } 119 | else { 120 | suffixMeta.push(current); 121 | } 122 | } 123 | else { 124 | suffixTree[char] = [current]; 125 | } 126 | } 127 | this.frozen = true; 128 | return this; 129 | } 130 | encode() { 131 | const chunks = []; 132 | const queue = [this.root]; 133 | const charTable = new Set(); 134 | const visitCode = Date.now(); 135 | let offsetMin = Infinity; 136 | let offsetMax = -Infinity; 137 | while (queue.length) { 138 | let node = queue.shift(); 139 | let keys = Object.keys(node).filter(k => k[1] !== '_'); 140 | let n = keys.length; 141 | node.__visited__ = visitCode; 142 | let nodeChunkIndex = node.__idx__ = chunks.length; 143 | if (node.__parents__) { 144 | node.__parents__.forEach(chunk => { 145 | let offset = chunk.offset = nodeChunkIndex - chunk.idx; 146 | if (offset < offsetMin) { 147 | offsetMin = offset; 148 | } 149 | if (offset > offsetMax) { 150 | offsetMax = offset; 151 | } 152 | }); 153 | } 154 | keys.forEach((char, i) => { 155 | let child = node[char]; 156 | let chunkIdx = chunks.length; 157 | let lastInLevel = i === n - 1; 158 | let newChunk = { 159 | char: char, 160 | idx: chunkIdx, 161 | offset: null, 162 | last: lastInLevel 163 | }; 164 | if (child.__visited__ === visitCode) { 165 | let idx = child.__idx__; 166 | let offset = newChunk.offset = idx - chunkIdx; 167 | if (offset < offsetMin) { 168 | offsetMin = offset; 169 | } 170 | if (offset > offsetMax) { 171 | offsetMax = offset; 172 | } 173 | } 174 | else { 175 | if (child.__willVisit__ === visitCode) { 176 | child.__parents__.push(newChunk); 177 | } 178 | else { 179 | child.__willVisit__ = visitCode; 180 | child.__parents__ = [newChunk]; 181 | } 182 | queue.push(child); 183 | } 184 | chunks.push(newChunk); 185 | charTable.add(char); 186 | }); 187 | } 188 | const charTableAsArray = Array.from(charTable) 189 | .filter(char => char !== constants_1.TERMINAL); 190 | const charMap = charTableAsArray.reduce((agg, char, i) => { 191 | agg[char] = i + 1; 192 | return agg; 193 | }, { [constants_1.TERMINAL]: 0 }); 194 | const charEncodingWidth = floor_log2_1.floor_log2(charTableAsArray.length) + 1; 195 | const pointerRange = offsetMax - offsetMin; 196 | const pointerEncodingWidth = floor_log2_1.floor_log2(pointerRange) + 1; 197 | const encodedTrie = new BinaryString_1.BinaryString(); 198 | chunks.forEach(chunk => { 199 | let { char, offset, last } = chunk; 200 | encodedTrie.write(charMap[char], charEncodingWidth); 201 | encodedTrie.write(offset - offsetMin, pointerEncodingWidth); 202 | encodedTrie.write(+last, 1); 203 | }); 204 | encodedTrie.flush(); 205 | const headerString = new BinaryString_1.BinaryString(); 206 | const outputCharTable = charTableAsArray.join(''); 207 | const headerWidth = Math.ceil((constants_1.HEADER_WIDTH_FIELD + 208 | constants_1.VERSION_FIELD + 209 | constants_1.OFFSET_SIGN_FIELD + 210 | constants_1.OFFSET_VAL_FIELD + 211 | constants_1.CHAR_WIDTH_FIELD + 212 | constants_1.POINTER_WIDTH_FIELD) / 6) + outputCharTable.length; 213 | const offsetSign = +(offsetMin < 0); 214 | headerString.write(headerWidth, constants_1.HEADER_WIDTH_FIELD); 215 | headerString.write(constants_1.VERSION, constants_1.VERSION_FIELD); 216 | headerString.write(offsetSign, constants_1.OFFSET_SIGN_FIELD); 217 | headerString.write(offsetSign ? -offsetMin : offsetMin, constants_1.OFFSET_VAL_FIELD); 218 | headerString.write(charEncodingWidth, constants_1.CHAR_WIDTH_FIELD); 219 | headerString.write(pointerEncodingWidth, constants_1.POINTER_WIDTH_FIELD); 220 | headerString.flush(); 221 | return `${headerString.getData()}${outputCharTable}${encodedTrie.getData()}`; 222 | } 223 | toJSON() { 224 | let str = JSON.stringify(this.root, (k, v) => { 225 | if (k[1] === '_') { 226 | return undefined; 227 | } 228 | return v; 229 | }); 230 | return JSON.parse(str); 231 | } 232 | } 233 | exports.Trie = Trie; 234 | //# sourceMappingURL=Trie.js.map -------------------------------------------------------------------------------- /lib/Trie.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Trie.js","sourceRoot":"","sources":["../src/Trie.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/base64.d.ts: -------------------------------------------------------------------------------- 1 | export declare const BASE64_INT_TO_CHAR: string[]; 2 | export declare const BASE64_CHAR_TO_INT: { 3 | [key: string]: number; 4 | }; 5 | -------------------------------------------------------------------------------- /lib/base64.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.BASE64_INT_TO_CHAR = `\ 4 | ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 5 | abcdefghijklmnopqrstuvwxyz\ 6 | 0123456789\ 7 | +/\ 8 | `.split(''); 9 | exports.BASE64_CHAR_TO_INT = exports.BASE64_INT_TO_CHAR.reduce((agg, char, i) => { 10 | agg[char] = i; 11 | return agg; 12 | }, {}); 13 | //# sourceMappingURL=base64.js.map -------------------------------------------------------------------------------- /lib/base64.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"base64.js","sourceRoot":"","sources":["../src/base64.ts"],"names":[],"mappings":";;AASa,QAAA,kBAAkB,GAAG;;;;;CAKjC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAOC,QAAA,kBAAkB,GAAG,0BAAkB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE;IACzE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,MAAM,CAAC,GAAG,CAAC;AACf,CAAC,EAAE,EAA6B,CAAC,CAAC"} -------------------------------------------------------------------------------- /lib/constants.d.ts: -------------------------------------------------------------------------------- 1 | export declare const TERMINAL = "\0"; 2 | export declare const TERMINUS: any; 3 | export declare const VERSION = 0; 4 | export declare const HEADER_WIDTH_FIELD = 10; 5 | export declare const VERSION_FIELD = 10; 6 | export declare const OFFSET_SIGN_FIELD = 1; 7 | export declare const OFFSET_VAL_FIELD = 21; 8 | export declare const CHAR_WIDTH_FIELD = 8; 9 | export declare const POINTER_WIDTH_FIELD = 8; 10 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.TERMINAL = '\0'; 4 | exports.TERMINUS = Object.create(null); 5 | exports.VERSION = 0; 6 | exports.HEADER_WIDTH_FIELD = 10; 7 | exports.VERSION_FIELD = 10; 8 | exports.OFFSET_SIGN_FIELD = 1; 9 | exports.OFFSET_VAL_FIELD = 21; 10 | exports.CHAR_WIDTH_FIELD = 8; 11 | exports.POINTER_WIDTH_FIELD = 8; 12 | //# sourceMappingURL=constants.js.map -------------------------------------------------------------------------------- /lib/constants.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;AAQa,QAAA,QAAQ,GAAG,IAAI,CAAC;AAMhB,QAAA,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAM/B,QAAA,OAAO,GAAG,CAAC,CAAC;AAOZ,QAAA,kBAAkB,GAAG,EAAE,CAAC;AAMxB,QAAA,aAAa,GAAG,EAAE,CAAC;AAMnB,QAAA,iBAAiB,GAAG,CAAC,CAAC;AAMtB,QAAA,gBAAgB,GAAG,EAAE,CAAC;AAMtB,QAAA,gBAAgB,GAAG,CAAC,CAAC;AAMrB,QAAA,mBAAmB,GAAG,CAAC,CAAC"} -------------------------------------------------------------------------------- /lib/floor_log2.d.ts: -------------------------------------------------------------------------------- 1 | export declare function floor_log2(x: number): number; 2 | -------------------------------------------------------------------------------- /lib/floor_log2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | function floor_log2(x) { 4 | let n = 0; 5 | while (x >>= 1) { 6 | n++; 7 | } 8 | return n; 9 | } 10 | exports.floor_log2 = floor_log2; 11 | //# sourceMappingURL=floor_log2.js.map -------------------------------------------------------------------------------- /lib/floor_log2.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"floor_log2.js","sourceRoot":"","sources":["../src/floor_log2.ts"],"names":[],"mappings":";;AASA,oBAA2B,CAAS;IAChC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACb,CAAC,EAAE,CAAC;IACR,CAAC;IACD,MAAM,CAAC,CAAC,CAAC;AACb,CAAC;AAND,gCAMC"} -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Trie } from './Trie'; 2 | export { Trie } from './Trie'; 3 | export declare function createSync(strings: string[]): Trie; 4 | export declare function createFrozenSync(words: string[]): Trie; 5 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Trie_1 = require("./Trie"); 4 | var Trie_2 = require("./Trie"); 5 | exports.Trie = Trie_2.Trie; 6 | function createSync(strings) { 7 | const trie = new Trie_1.Trie(); 8 | strings.forEach(s => trie.insert(s)); 9 | return trie; 10 | } 11 | exports.createSync = createSync; 12 | function createFrozenSync(words) { 13 | return createSync(words).freeze(); 14 | } 15 | exports.createFrozenSync = createFrozenSync; 16 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /lib/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAIA,iCAA4B;AAC5B,+BAA4B;AAApB,sBAAA,IAAI,CAAA;AAOZ,oBAA2B,OAAiB;IACxC,MAAM,IAAI,GAAG,IAAI,WAAI,EAAE,CAAC;IAExB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAErC,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC;AAND,gCAMC;AAOD,0BAAiC,KAAe;IAC5C,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;AACtC,CAAC;AAFD,4CAEC"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiny-trie", 3 | "version": "0.2.6", 4 | "description": "JS Trie / DAWG classes", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "scripts": { 8 | "lint": "$(npm bin)/tslint src/**/*.ts", 9 | "build": "rm -rf lib/ && $(npm bin)/tsc --declaration", 10 | "build-dist": "$(npm bin)/webpack", 11 | "build-min": "NODE_ENV=production $(npm bin)/webpack", 12 | "build-doc": "$(npm bin)/typedoc --out docs/", 13 | "build-all": "npm run build && npm run build-dist && npm run build-min && npm run build-doc", 14 | "test": "npm run lint && $(npm bin)/mocha --compilers ts:ts-node/register src/*.test.ts" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/jnu/tiny-trie.git" 19 | }, 20 | "keywords": [ 21 | "trie", 22 | "dawg", 23 | "dict", 24 | "dictionary", 25 | "wordlist" 26 | ], 27 | "author": "Joe Nudell", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/jnu/tiny-trie/issues" 31 | }, 32 | "homepage": "https://github.com/jnu/tiny-trie#readme", 33 | "devDependencies": { 34 | "@types/chai": "^4.1.2", 35 | "@types/mocha": "^2.2.48", 36 | "babel": "^6.23.0", 37 | "babel-cli": "^6.26.0", 38 | "babel-core": "^6.26.0", 39 | "babel-loader": "^7.1.4", 40 | "babel-preset-es2015": "^6.0.15", 41 | "benchmark": "^1.0.0", 42 | "chai": "^4.1.2", 43 | "mocha": "^2.3.3", 44 | "tap": "^2.2.0", 45 | "ts-loader": "^4.0.1", 46 | "ts-node": "^5.0.1", 47 | "tslint": "^5.9.1", 48 | "typedoc": "^0.11.1", 49 | "typescript": "^2.7.2", 50 | "webpack": "^4.1.1", 51 | "webpack-cli": "^2.0.12" 52 | }, 53 | "dependencies": {} 54 | } 55 | -------------------------------------------------------------------------------- /src/BaseTrie.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Options to refine membership test queries. 3 | */ 4 | export interface ITestOpts { 5 | wildcard?: string; 6 | prefix?: boolean; 7 | } 8 | 9 | /** 10 | * Options to refine search queries. 11 | */ 12 | export interface ISearchOpts { 13 | wildcard?: string; 14 | prefix?: boolean; 15 | first?: boolean; 16 | } 17 | 18 | /** 19 | * Base Trie interface that supports testing and searching. 20 | */ 21 | export interface ITrie { 22 | /** 23 | * Test that a string exists in a trie. 24 | * @param {string} s 25 | * @param {ITestOpts} opts 26 | * @returns {boolean} 27 | */ 28 | test: (s: string, opts?: ITestOpts) => boolean; 29 | 30 | /** 31 | * Query a trie for membership of a string, optionally using wildcards and/or prefix matching. 32 | * @param {string} s 33 | * @param {ISearchOpts} opts 34 | * @returns {string | string[]} 35 | */ 36 | search: (s: string, opts?: ISearchOpts) => string | string[]; 37 | } -------------------------------------------------------------------------------- /src/BinaryString.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | import {BinaryString} from './BinaryString'; 3 | import {assert} from 'chai'; 4 | 5 | describe('BinaryString', () => { 6 | 7 | describe('constructor', () => { 8 | it('creates an empty binary string', () => { 9 | let bs = new BinaryString(); 10 | 11 | assert.strictEqual(bs['buffer'], 0); 12 | assert.strictEqual(bs['pointer'], 0); 13 | assert.strictEqual(bs['data'], ''); 14 | assert.strictEqual(bs.getData(), ''); 15 | }); 16 | }); 17 | 18 | describe('write', () => { 19 | it('should add an item to the buffer', () => { 20 | let bs = new BinaryString(); 21 | 22 | bs.write(1); 23 | assert.strictEqual(bs['buffer'], 1); 24 | assert.strictEqual(bs['pointer'], 1); 25 | assert.strictEqual(bs['data'], ''); 26 | 27 | bs.write(0); 28 | assert.strictEqual(bs['buffer'], 2); 29 | assert.strictEqual(bs['pointer'], 2); 30 | assert.strictEqual(bs['data'], ''); 31 | 32 | bs.write(3); 33 | assert.strictEqual(bs['buffer'], 11); 34 | assert.strictEqual(bs['pointer'], 4); 35 | assert.strictEqual(bs['data'], ''); 36 | }); 37 | 38 | it('should write encoded data whenever buffer is sufficently full', () => { 39 | let bs = new BinaryString(); 40 | 41 | bs.write(1); 42 | bs.write(1); 43 | bs.write(1); 44 | bs.write(1); 45 | bs.write(1); 46 | assert.strictEqual(bs['buffer'], 31); 47 | assert.strictEqual(bs['pointer'], 5); 48 | assert.strictEqual(bs['data'], ''); 49 | bs.write(1); 50 | assert.strictEqual(bs['buffer'], 0); 51 | assert.strictEqual(bs['pointer'], 0); 52 | assert.strictEqual(bs['data'], '/'); 53 | 54 | bs.write(64); 55 | assert.strictEqual(bs['buffer'], 0); 56 | assert.strictEqual(bs['pointer'], 1); 57 | assert.strictEqual(bs['data'], '/g'); 58 | }); 59 | 60 | it('should write data into a specified width', () => { 61 | let bs = new BinaryString(); 62 | 63 | bs.write(0, 2); 64 | assert.strictEqual(bs['buffer'], 0); 65 | assert.strictEqual(bs['pointer'], 2); 66 | assert.strictEqual(bs['data'], ''); 67 | 68 | bs.write(1, 4); 69 | assert.strictEqual(bs['buffer'], 0); 70 | assert.strictEqual(bs['pointer'], 0); 71 | assert.strictEqual(bs['data'], 'B'); 72 | }); 73 | 74 | it('should throw an error if trying to write into too small a width', () => { 75 | let bs = new BinaryString(); 76 | 77 | assert.throws(() => bs.write(2, 1)); 78 | }); 79 | }); 80 | 81 | describe('flush', () => { 82 | it('should empty the buffer, padding remaining contents with 0', () => { 83 | let bs = new BinaryString(); 84 | 85 | bs.write(2); 86 | 87 | bs.flush(); 88 | assert.strictEqual(bs['buffer'], 0); 89 | assert.strictEqual(bs['pointer'], 0); 90 | assert.strictEqual(bs['data'], 'g'); 91 | assert.strictEqual(bs.getData(), 'g'); 92 | }); 93 | }); 94 | 95 | describe('getData', () => { 96 | it('should get the data as a base-64 encoded string', () => { 97 | let bs = new BinaryString(); 98 | 99 | bs.write(1, 6); 100 | assert.strictEqual(bs['buffer'], 0); 101 | assert.strictEqual(bs['pointer'], 0); 102 | assert.strictEqual(bs['data'], 'B'); 103 | assert.strictEqual(bs.getData(), 'B'); 104 | }); 105 | 106 | it('should flush the buffer when getting data', () => { 107 | let bs = new BinaryString(); 108 | 109 | bs.write(1, 2); 110 | assert.strictEqual(bs['buffer'], 1); 111 | assert.strictEqual(bs['pointer'], 2); 112 | assert.strictEqual(bs['data'], ''); 113 | assert.strictEqual(bs.getData(), 'Q'); 114 | assert.strictEqual(bs['data'], 'Q'); 115 | }); 116 | }); 117 | 118 | }); 119 | -------------------------------------------------------------------------------- /src/BinaryString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Provide an interface for writing binary data into a Base64-encoded 3 | * string. 4 | */ 5 | 6 | import {floor_log2} from './floor_log2'; 7 | import {BASE64_INT_TO_CHAR} from './base64'; 8 | 9 | /** 10 | * Interface for writing binary data into a Base64-encoded string 11 | * @class 12 | */ 13 | export class BinaryString { 14 | 15 | /** 16 | * Data buffer 17 | * @type {Number?} 18 | */ 19 | private buffer = 0; 20 | 21 | /** 22 | * Word pointer for buffer. With every entry into the buffer, the 23 | * pointer gets incremented by the entry's width. Every six characters 24 | * may be encoded, so when the pointer exceeds 6, the buffer can be 25 | * emptied until the pointer is back under 6. 26 | * @type {Number} 27 | */ 28 | private pointer = 0; 29 | 30 | /** 31 | * Encoded data as a string of base64 characters 32 | * @type {String} 33 | */ 34 | private data = ''; 35 | 36 | /** 37 | * Write a value to the binary string. This value should be thought of as 38 | * an integer representing the binary data to write. 39 | * @param {Integer} val - data to write 40 | * @param {Integer} [width] - optionally specify a width for this data. 41 | * if none is given, width will be inferred 42 | * automatically. An error will be thrown if 43 | * the width is too small to contain the data. 44 | */ 45 | write(val: number, width: number = null) { 46 | let buf = this.buffer; 47 | let len = width || floor_log2(val) + 1; 48 | 49 | if (width && val >= (0x1 << width)) { 50 | throw new Error(`Can't write ${val} in only ${width} bits`); 51 | } 52 | 53 | this.buffer = (buf << len) | val; 54 | this.pointer += len; 55 | 56 | this._digest(); 57 | } 58 | 59 | /** 60 | * Encode the remaining items in the buffer. Use this when the input stream 61 | * is finished to ensure that all data has been encoded. 62 | */ 63 | flush() { 64 | let buffer = this.buffer; 65 | let pointer = this.pointer; 66 | // NB if pointer is at 0, there's nothing to flush. 67 | while (pointer && pointer < 6) { 68 | buffer <<= 1; 69 | pointer += 1; 70 | } 71 | this.pointer = pointer; 72 | this.buffer = buffer; 73 | this._digest(); 74 | } 75 | 76 | /** 77 | * Get the binary data as base64. This output does not include padding 78 | * characters. This procedure flushes the buffer. 79 | * @return {String} 80 | */ 81 | getData() { 82 | this.flush(); 83 | return this.data; 84 | } 85 | 86 | /** 87 | * Write values from the buffer into the binary encoded string until the 88 | * pointer is below 6. Use @link BinaryString#flush to print out all values 89 | * regardless of whether they are complete and return the pointer to 0. 90 | * 91 | * This method is used internally during writes and does not need to be 92 | * called explicitly. 93 | * @private 94 | */ 95 | _digest() { 96 | let buffer = this.buffer; 97 | let pointer = this.pointer; 98 | let newData = ''; 99 | while (pointer >= 6) { 100 | let remainder = (pointer - 6); 101 | let code = buffer >> remainder; 102 | buffer = buffer ^ (code << remainder); 103 | pointer = remainder; 104 | newData += BASE64_INT_TO_CHAR[code]; 105 | } 106 | this.pointer = pointer; 107 | this.buffer = buffer; 108 | this.data += newData; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/PackedTrie.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | import {Trie} from './Trie'; 3 | import {PackedTrie} from './PackedTrie'; 4 | import {assert} from 'chai'; 5 | 6 | describe('PackedTrie', () => { 7 | 8 | describe('constructor', () => { 9 | it('should parse header fields on init', () => { 10 | const encoded = 'BAAAAABAwIfboarzKTbjds1FDB'; 11 | const trie = new PackedTrie(encoded); 12 | 13 | assert.strictEqual(trie['offset'], 1); 14 | assert.deepEqual(trie['table'], { 15 | '\0': 0, 16 | f: 1, 17 | b: 2, 18 | o: 3, 19 | a: 4, 20 | r: 5, 21 | z: 6 22 | }); 23 | assert.strictEqual(trie['wordWidth'], 6); 24 | assert.strictEqual(trie['lastMask'], parseInt('1', 2)); 25 | assert.strictEqual(trie['pointerMask'], parseInt('11', 2)); 26 | assert.strictEqual(trie['pointerShift'], 1); 27 | assert.strictEqual(trie['charMask'], parseInt('111', 2)); 28 | assert.strictEqual(trie['charShift'], 3); 29 | assert.strictEqual(trie['data'], encoded.substr(16)); 30 | }); 31 | 32 | it('should throw a version mismatch error if encoded string differs from reader version', () => { 33 | const encoded = 'BD/wAABAwIfboarzKTbjds1FDB'; 34 | assert.throws(() => new PackedTrie(encoded)); 35 | }); 36 | }); 37 | 38 | describe('test', () => { 39 | it('should determine whether an item is in the Trie', () => { 40 | const encoded = 'BAAAAABAwIfboarzKTbjds1FDB'; 41 | const trie = new PackedTrie(encoded); 42 | 43 | ['foo', 'bar', 'baz'].forEach(w => assert(trie.test(w))); 44 | ['fu', 'boer', 'batz'].forEach(w => assert(!trie.test(w))); 45 | }); 46 | 47 | it('should provide the same answers as a full Trie', () => { 48 | [ 49 | ['Africa', 'Asia', 'North America', 'South America', 'Europe', 'Antarctica'], 50 | ['red', 'yellow', 'green', 'aliceblue', 'pink', 'rose'], 51 | ['agricola', 'agricolae', 'agricolae', 'agricolam', 'agricolā'], 52 | ['любить', 'люблю', 'любишь', 'любит', 'любим', 'любите', 'любят'] 53 | ].forEach(words => { 54 | const sdrow = words.slice().map(w => w.split('').reverse().join('')); 55 | const trie = new Trie(); 56 | words.forEach(w => trie.insert(w)); 57 | words.forEach(w => assert(trie.test(w))); 58 | sdrow.forEach(s => assert(!trie.test(s))); 59 | const encoded = trie.freeze().encode(); 60 | const packed = new PackedTrie(encoded); 61 | words.forEach(w => assert(packed.test(w))); 62 | sdrow.forEach(s => assert(!packed.test(s))); 63 | }); 64 | }); 65 | 66 | it('returns true for fuzzy matches when wildcard is given', () => { 67 | const trie = new Trie(); 68 | trie.insert('foo'); 69 | trie.insert('bar'); 70 | trie.insert('bop'); 71 | trie.insert('baz'); 72 | const packed = new PackedTrie(trie.freeze().encode()); 73 | 74 | assert(packed.test('***', {wildcard: '*'})); 75 | assert(packed.test('**r', {wildcard: '*'})); 76 | assert(packed.test('*az', {wildcard: '*'})); 77 | assert(packed.test('f**', {wildcard: '*'})); 78 | assert(packed.test('f*o', {wildcard: '*'})); 79 | assert(!packed.test('**x', {wildcard: '*'})); 80 | }); 81 | 82 | it('returns true for partial matches when searching over prefixes', () => { 83 | const trie = new Trie(); 84 | trie.insert('foo'); 85 | trie.insert('food'); 86 | trie.insert('foodology'); 87 | const packed = new PackedTrie(trie.freeze().encode()); 88 | 89 | assert(packed.test('fo', {prefix: true})); 90 | assert(packed.test('foodolog', {prefix: true})); 91 | assert(!packed.test('fob', {prefix: true})); 92 | }); 93 | 94 | it('returns correct value for complex options cases', () => { 95 | const trie = new Trie(); 96 | trie.insert('foo'); 97 | trie.insert('bar'); 98 | trie.insert('foobar'); 99 | const packed = new PackedTrie(trie.freeze().encode()); 100 | 101 | assert(packed.test('foo', {wildcard: '*'})); 102 | assert(packed.test('bar', {wildcard: '*'})); 103 | assert(!packed.test('foob', {wildcard: '*', prefix: false})); 104 | assert(packed.test('foobar', {wildcard: '*', prefix: false})); 105 | assert(packed.test('foob*', {wildcard: '*', prefix: true})); 106 | assert(!packed.test('foob*', {wildcard: '*', prefix: false})); 107 | assert(packed.test('**ob*', {wildcard: '*', prefix: true})); 108 | }); 109 | }); 110 | 111 | describe('search', () => { 112 | const encoded = 'BMAAAAABAQfbgtoarleFBKNiPVzXZyxVzPV6vfbxWqzeazC0VCYQloNBYJg4BAIB'; 113 | const trie = new PackedTrie(encoded); 114 | 115 | it('returns all matching values with wildcard', () => { 116 | assert.deepEqual(trie.search('*oo', {wildcard: '*'}), ['foo', 'boo', 'goo']); 117 | assert.deepEqual(trie.search('*oo', {wildcard: '*', prefix: true}), [ 118 | 'foo', 'boo', 'goo', 'fool', 'tool']); 119 | assert.deepEqual(trie.search('f**', {wildcard: '*'}), ['foo', 'far']); 120 | assert.deepEqual(trie.search('*x*', {wildcard: '*'}), []); 121 | }); 122 | 123 | it('returns first match with wildcard', () => { 124 | assert(trie.search('f**', {wildcard: '*', first: true}) === 'foo'); 125 | assert(trie.search('**x', {wildcard: '*', first: true}) === null); 126 | assert.deepEqual(trie.search('*', {wildcard: '*', prefix: true}), [ 127 | 'foo', 'far', 'bar', 'boo', 'goo', 'gar', 'fool', 'bare', 'tool']); 128 | }); 129 | }); 130 | 131 | }); 132 | -------------------------------------------------------------------------------- /src/PackedTrie.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Small class for querying a binary-encoded Trie 3 | * 4 | * TODO - rewrite as a native class. Babel adds a lot of overhead. This class 5 | * should be tiny and transparent. 6 | */ 7 | 8 | import {ITrie, ISearchOpts, ITestOpts} from './BaseTrie'; 9 | import {BASE64_CHAR_TO_INT} from './base64'; 10 | import { 11 | TERMINAL, 12 | VERSION, 13 | HEADER_WIDTH_FIELD, 14 | VERSION_FIELD, 15 | OFFSET_SIGN_FIELD, 16 | OFFSET_VAL_FIELD, 17 | CHAR_WIDTH_FIELD, 18 | POINTER_WIDTH_FIELD 19 | } from './constants'; 20 | 21 | /** 22 | * Extract a window of bits from a Base64 encoded sequence 23 | * @param {String} binary - base64 encoded sequence 24 | * @param {Number} start - first bit to read 25 | * @param {Number} len - number of bits to read 26 | * @return {Number} - bits from string, as number 27 | */ 28 | function readBits(binary: string, start: number, len: number) { 29 | const startChar = ~~(start / 6); 30 | const startBitOffset = start % 6; 31 | const endBit = startBitOffset + len; 32 | const charLen = Math.ceil(endBit / 6); 33 | const mask = (0x1 << len) - 1; 34 | let chunk = 0; 35 | 36 | for (let i = 0; i < charLen; i++) { 37 | chunk <<= 6; 38 | chunk |= BASE64_CHAR_TO_INT[binary[startChar + i]]; 39 | } 40 | 41 | let rightPadding = endBit % 6; 42 | if (rightPadding) { 43 | chunk >>= (6 - rightPadding); 44 | } 45 | 46 | return chunk & mask; 47 | } 48 | 49 | /** 50 | * Class for interacting with an encoded trie. The class performs lookups 51 | * virtually just as fast as a regular trie. The binary data never actually 52 | * have to be processed as a whole, so instantiation time and memory usage are 53 | * phenomenally low. 54 | * @class 55 | */ 56 | export class PackedTrie implements ITrie { 57 | 58 | /** 59 | * Binary string encoded as Base64 representing Trie 60 | * @type {String} 61 | */ 62 | public data: string; 63 | 64 | /** 65 | * Pointer offset. Add this to every pointer read from every word in 66 | * the trie to obtain the true value of the pointer. This offset is 67 | * used to avoid signed integers in the word. 68 | * @type {Number} 69 | */ 70 | private offset: number; 71 | 72 | /** 73 | * Character table, mapping character to an integer ID 74 | * @type {Object} 75 | */ 76 | private table: {[key: string]: number}; 77 | 78 | /** 79 | * Inverse of character table, mapping integer ID to character. 80 | * @type {Array} 81 | */ 82 | private inverseTable: {[key: number]: string}; 83 | 84 | /** 85 | * Number of bits in one word 86 | * @type {Number} 87 | */ 88 | private wordWidth: number; 89 | 90 | /** 91 | * Mask for reading the "last block" flag in a word 92 | * @type {Number} 93 | */ 94 | private lastMask = 0x1; 95 | 96 | /** 97 | * Mask for reading the pointer value from a word 98 | * @type {Number} 99 | */ 100 | private pointerMask: number; 101 | 102 | /** 103 | * Offset of pointer field in a word 104 | * @type {Number} 105 | */ 106 | private pointerShift = 1; 107 | 108 | /** 109 | * Mask for reading the charTable index in a word 110 | * @type {Number} 111 | */ 112 | private charMask: number; 113 | 114 | /** 115 | * Offset of charTable index field in a word 116 | * @type {Number} 117 | */ 118 | private charShift: number; 119 | 120 | /** 121 | * Instantiate a packed binary trie, parsing its headers to configure the 122 | * instance for queries. 123 | * @constructor 124 | * @param {String} binary - binary string from {@link Trie#encode} 125 | * @return {PackedTrie} 126 | */ 127 | constructor(binary: string) { 128 | let ptr = 0; 129 | 130 | // Split binary into header and content by checking first field 131 | const headerCharCount = readBits(binary, ptr, HEADER_WIDTH_FIELD); 132 | ptr += HEADER_WIDTH_FIELD; 133 | const header = binary.substr(0, headerCharCount); 134 | 135 | const version = readBits(binary, ptr, VERSION_FIELD); 136 | ptr += VERSION_FIELD; 137 | 138 | if (version !== VERSION) { 139 | throw new Error(`Version mismatch! Binary: ${version}, Reader: ${VERSION}`); 140 | } 141 | 142 | // Main trie data 143 | this.data = binary.substr(headerCharCount); 144 | 145 | // compute pointer offset 146 | const offsetSign = readBits(header, ptr, OFFSET_SIGN_FIELD); 147 | ptr += OFFSET_SIGN_FIELD; 148 | let offset = readBits(header, ptr, OFFSET_VAL_FIELD); 149 | ptr += OFFSET_VAL_FIELD; 150 | 151 | if (offsetSign) { 152 | offset = -offset; 153 | } 154 | 155 | // Pointer offset 156 | this.offset = offset; 157 | 158 | // interpret the field width within each word 159 | let charWidth = readBits(header, ptr, CHAR_WIDTH_FIELD); 160 | ptr += CHAR_WIDTH_FIELD; 161 | 162 | let pointerWidth = readBits(header, ptr, POINTER_WIDTH_FIELD); 163 | ptr += POINTER_WIDTH_FIELD; 164 | 165 | // Interpret the rest of the header as the charTable 166 | let headerFieldChars = Math.ceil(ptr / 6); 167 | let charTable = header.substr(headerFieldChars); 168 | 169 | this.table = charTable.split('').reduce((agg, char, i) => { 170 | agg[char] = i + 1; 171 | return agg; 172 | }, { [TERMINAL]: 0 } as {[key: string]: number}); 173 | 174 | // Construct inverse table 175 | this.inverseTable = [TERMINAL].concat(charTable.split('')); 176 | 177 | // Number of bits in a word 178 | this.wordWidth = charWidth + pointerWidth + 1; 179 | 180 | // Mask for reading pointer 181 | this.pointerMask = (0x1 << pointerWidth) - 1; 182 | 183 | // Mask for reading characters 184 | this.charMask = (0x1 << charWidth) - 1; 185 | 186 | // Offset of charTable 187 | this.charShift = 1 + pointerWidth; 188 | } 189 | 190 | /** 191 | * Test membership in the trie. 192 | * @param {String} str - Search query 193 | * @param {String?} opts.wildcard - See PackedTrie#search wildcard doc 194 | * @param {Boolean?} opts.prefix - See PackedTrie#search prefix doc 195 | * @return {Boolean} 196 | */ 197 | test(str: string, {wildcard, prefix}: ITestOpts = {wildcard: null, prefix: false}) { 198 | // Delegate to #search with early exit. Could write an optimized path, 199 | // especially for the prefix search case. 200 | return this.search(str, {wildcard, prefix, first: true}) !== null; 201 | } 202 | 203 | /** 204 | * Query for matching words in the trie. 205 | * @param {String} str - Search query 206 | * @param {String?} opts.wildcard - Wildcard to use for fuzzy matching. 207 | * Default is no wildcard; only match 208 | * literal query. 209 | * @param {Boolean?} opts.prefix - Perform prefix search (returns true if 210 | * any word exists in the trie starts with 211 | * the search query). Default is false; 212 | * only match the full query. 213 | * @param {Boolean} opts.first - Return only first match that is found, 214 | * short-circuiting the search. Default is 215 | * false; return all matches. 216 | * @return {String?|String[]} - Return an optional string result when in 217 | * first-only mode; otherwise return a list 218 | * of strings that match the query. 219 | */ 220 | search(str: string, {wildcard, prefix, first}: ISearchOpts = {wildcard: null, prefix: false, first: false}) { 221 | if (wildcard && wildcard.length !== 1) { 222 | throw new Error(`Wilcard must be a single character; got ${wildcard}`); 223 | } 224 | 225 | const { 226 | data, 227 | offset, 228 | table, 229 | inverseTable, 230 | wordWidth, 231 | lastMask, 232 | pointerShift, 233 | pointerMask, 234 | charShift, 235 | charMask 236 | } = this; 237 | 238 | // List of matches found in the search. 239 | const matches = []; 240 | 241 | // Search queue. 242 | const queue = [{pointer: 0, memo: '', depth: 0}]; 243 | const lastDepth = str.length; 244 | 245 | // Do a BFS over nodes for the search query. 246 | while (queue.length) { 247 | const node = queue.shift(); 248 | const isLast = node.depth >= lastDepth; 249 | const token = isLast ? TERMINAL : str[node.depth]; 250 | // Flag for matching anything. Note that the overflow beyond the 251 | // length of the query in a prefix search behaves as a wildcard. 252 | const isWild = token === wildcard || (prefix && isLast); 253 | // We're committed to an O(N) scan over the entire node even in 254 | // the simple literal-search case, since our structure doesn't 255 | // currently guarantee any child ordering. 256 | // TODO(joen) ordering is a potential future format optimization. 257 | let wordPointer = node.pointer; 258 | while (true) { 259 | // Optimization: Exit immediately if the char was not found in 260 | // the table (meaning there can't be any children in the trie 261 | // with this character). Exception is wildcards. 262 | if (!isWild && !table.hasOwnProperty(token)) { 263 | break; 264 | } 265 | 266 | const bits = wordPointer * wordWidth; 267 | const chunk = readBits(data, bits, wordWidth); 268 | 269 | // Read the character index 270 | const charIdx = (chunk >> charShift) & charMask; 271 | 272 | // If this character is matched, jump to the pointer given in 273 | // this node. 274 | if (isWild || charIdx === table[token]) { 275 | const pointer = (chunk >> pointerShift) & pointerMask; 276 | // Find the next char with an inverse map, since we might 277 | // be using a wildcard search. 278 | const newChar = inverseTable[charIdx]; 279 | // Stopping condition: searching last block and we hit a terminal 280 | if (isLast && newChar === TERMINAL) { 281 | // Optimization: early exit if we only need first match. 282 | if (first) { 283 | return node.memo; 284 | } 285 | // Store this match. 286 | matches.push(node.memo); 287 | // If we're not matching everything, break out of the 288 | // inner loop. 289 | if (!isWild) { 290 | break; 291 | } 292 | } 293 | 294 | // Push next node for search, if it's non-terminal. 295 | if (newChar !== TERMINAL) { 296 | queue.push({ 297 | pointer: wordPointer + offset + pointer, 298 | depth: node.depth + 1, 299 | memo: node.memo + newChar, 300 | }); 301 | } 302 | } 303 | 304 | // If this wasn't a match, check if this was the last key in 305 | // the block. 306 | const last = chunk & lastMask; 307 | 308 | // If this was the last node, the word was not found. 309 | if (last) { 310 | break; 311 | } 312 | // Otherwise increment the pointer to the next sibling key 313 | else { 314 | wordPointer += 1; 315 | } 316 | } 317 | } 318 | 319 | // If first was requested it should have returned by now. Otherwise 320 | // return the matches list, which may be empty. 321 | return first ? null : matches; 322 | } 323 | 324 | } 325 | -------------------------------------------------------------------------------- /src/base64.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Lookup tables for Base64 conversions 3 | */ 4 | 5 | /** 6 | * Lookup table for transforming a 6-bit binary integer into a Base-64 ASCII 7 | * character. 8 | * @constant {String[]} 9 | */ 10 | export const BASE64_INT_TO_CHAR = `\ 11 | ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 12 | abcdefghijklmnopqrstuvwxyz\ 13 | 0123456789\ 14 | +/\ 15 | `.split(''); 16 | 17 | /** 18 | * Inverse lookup table for transformating a Base-64 ASCII character into the 19 | * corresponding integer value. 20 | * @constant {Object} 21 | */ 22 | export const BASE64_CHAR_TO_INT = BASE64_INT_TO_CHAR.reduce((agg, char, i) => { 23 | agg[char] = i; 24 | return agg; 25 | }, {} as {[key: string]: number}); 26 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Parameters used for encoding 3 | */ 4 | 5 | /** 6 | * String terminal character 7 | * @constant {String} 8 | */ 9 | export const TERMINAL = '\0'; 10 | 11 | /** 12 | * Terminal edge 13 | * @constant {Object} 14 | */ 15 | export const TERMINUS = Object.create(null); 16 | 17 | /** 18 | * Encoding version. Bump when breaking encoding changes are introduced. 19 | * @constant {Number} 20 | */ 21 | export const VERSION = 0; 22 | 23 | /** 24 | * Width of header field storing entire header width (including char table). 25 | * Value is given in Base64 characters (i.e., every six bits) 26 | * @constant {Number} 27 | */ 28 | export const HEADER_WIDTH_FIELD = 10; 29 | 30 | /** 31 | * Width of version field 32 | * @type {Number} 33 | */ 34 | export const VERSION_FIELD = 10; 35 | 36 | /** 37 | * Width of header field representing sign of offset 38 | * @constant {Number} 39 | */ 40 | export const OFFSET_SIGN_FIELD = 1; 41 | 42 | /** 43 | * Width of header field representing unsigned value of offset 44 | * @constant {Number} 45 | */ 46 | export const OFFSET_VAL_FIELD = 21; 47 | 48 | /** 49 | * Width of header field representing the width of the char index in a word 50 | * @constant {Number} 51 | */ 52 | export const CHAR_WIDTH_FIELD = 8; 53 | 54 | /** 55 | * Width of header field representing the width of the offset pointer in a word 56 | * @constant {Number} 57 | */ 58 | export const POINTER_WIDTH_FIELD = 8; 59 | -------------------------------------------------------------------------------- /src/floor_log2.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | import {floor_log2} from './floor_log2'; 3 | import {assert} from 'chai'; 4 | 5 | describe('floor_log2', () => { 6 | it('should compute the floored log base 2 of a number', () => { 7 | assert.strictEqual(floor_log2(0), 0); 8 | assert.strictEqual(floor_log2(1), 0); 9 | assert.strictEqual(floor_log2(2), 1); 10 | assert.strictEqual(floor_log2(3), 1); 11 | assert.strictEqual(floor_log2(4), 2); 12 | assert.strictEqual(floor_log2(5), 2); 13 | assert.strictEqual(floor_log2(6), 2); 14 | assert.strictEqual(floor_log2(7), 2); 15 | assert.strictEqual(floor_log2(8), 3); 16 | assert.strictEqual(floor_log2(15), 3); 17 | assert.strictEqual(floor_log2(16), 4); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/floor_log2.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Provides a fast floor_log2 function 3 | */ 4 | 5 | /** 6 | * Fast floor(log2(x)) operation 7 | * @param {Number} x 8 | * @return {Number} 9 | */ 10 | export function floor_log2(x: number) { 11 | let n = 0; 12 | while (x >>= 1) { 13 | n++; 14 | } 15 | return n; 16 | } 17 | -------------------------------------------------------------------------------- /src/index.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { 4 | createSync, 5 | createFrozenSync 6 | } from './index'; 7 | import {Trie} from './Trie'; 8 | import {assert} from 'chai'; 9 | 10 | describe('index', function() { 11 | 12 | describe('createSync', function() { 13 | it('creates a valid trie', function() { 14 | let trie = createSync(['foo', 'bar', 'zap']); 15 | assert(trie instanceof Trie); 16 | ['foo', 'bar', 'zap'].forEach(s => assert(trie.test(s))); 17 | }); 18 | }); 19 | 20 | describe('createFrozenSync', function() { 21 | it('creates a valid frozen trie', function() { 22 | let frozenTrie = createFrozenSync(['foo', 'bar', 'zap']); 23 | assert(frozenTrie instanceof Trie); 24 | assert(frozenTrie.frozen); 25 | assert.throws(() => frozenTrie.insert('bop')); 26 | }); 27 | }); 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Convenient functional tools for creating Tries from arrays 3 | */ 4 | 5 | import {Trie} from './Trie'; 6 | export {Trie} from './Trie'; 7 | 8 | /** 9 | * Synchronously construct a new Trie out of the given strings. 10 | * @param {String[]} words 11 | * @return {Trie} 12 | */ 13 | export function createSync(strings: string[]) { 14 | const trie = new Trie(); 15 | 16 | strings.forEach(s => trie.insert(s)); 17 | 18 | return trie; 19 | } 20 | 21 | /** 22 | * Create a frozen Trie out of given words 23 | * @param {String[]} words 24 | * @return {Trie} 25 | */ 26 | export function createFrozenSync(words: string[]) { 27 | return createSync(words).freeze(); 28 | } 29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "lib/", 4 | "target": "es6", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "noImplicitAny": true, 8 | "removeComments": true, 9 | "preserveConstEnums": true, 10 | "sourceMap": true 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["src/**/*.test.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": [ 4 | true, 5 | "parameters", 6 | "statements" 7 | ], 8 | "ban": false, 9 | "class-name": true, 10 | "comment-format": [ 11 | true, 12 | "check-space" 13 | ], 14 | "curly": true, 15 | "eofline": false, 16 | "forin": true, 17 | "indent": [ true, "spaces" ], 18 | "interface-name": [true, "always-prefix"], 19 | "jsdoc-format": true, 20 | "jsx-no-lambda": false, 21 | "jsx-no-multiline-js": false, 22 | "label-position": true, 23 | "max-line-length": [ true, 120 ], 24 | "member-ordering": [ 25 | true, 26 | "public-before-private", 27 | "static-before-instance", 28 | "variables-before-functions" 29 | ], 30 | "no-any": true, 31 | "no-arg": true, 32 | "no-bitwise": false, 33 | "no-console": [ 34 | true, 35 | "log", 36 | "error", 37 | "debug", 38 | "info", 39 | "time", 40 | "timeEnd", 41 | "trace" 42 | ], 43 | "no-consecutive-blank-lines": true, 44 | "no-construct": true, 45 | "no-debugger": true, 46 | "no-duplicate-variable": true, 47 | "no-empty": true, 48 | "no-eval": true, 49 | "no-shadowed-variable": true, 50 | "no-string-literal": false, 51 | "no-switch-case-fall-through": true, 52 | "no-trailing-whitespace": false, 53 | "no-unused-expression": true, 54 | "no-use-before-declare": true, 55 | "one-line": [ 56 | true, 57 | "check-catch", 58 | "check-open-brace", 59 | "check-whitespace" 60 | ], 61 | "quotemark": [true, "single", "jsx-double"], 62 | "radix": true, 63 | "semicolon": [true, "always"], 64 | "switch-default": true, 65 | 66 | "trailing-comma": false, 67 | 68 | "triple-equals": [ true, "allow-null-check" ], 69 | "typedef": [ 70 | true, 71 | "parameter", 72 | "property-declaration" 73 | ], 74 | "typedef-whitespace": [ 75 | true, 76 | { 77 | "call-signature": "nospace", 78 | "index-signature": "nospace", 79 | "parameter": "nospace", 80 | "property-declaration": "nospace", 81 | "variable-declaration": "nospace" 82 | } 83 | ], 84 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 85 | "whitespace": [ 86 | false, 87 | "check-branch", 88 | "check-decl", 89 | "check-module", 90 | "check-operator", 91 | "check-separator", 92 | "check-type", 93 | "check-typecast" 94 | ] 95 | } 96 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | var path = require('path'); 3 | 4 | var DEBUG = process.env.NODE_ENV !== 'production'; 5 | 6 | var bundleExt = (DEBUG ? '' : '.min') + '.js'; 7 | 8 | 9 | module.exports = { 10 | entry: { 11 | 'tiny-trie': './src/index.ts', 12 | 'packed-trie': './src/PackedTrie.ts' 13 | }, 14 | mode: DEBUG ? 'development' : 'production', 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.js$/, 19 | exclude: [/node_modules/], 20 | use: [{ 21 | loader: 'babel-loader', 22 | options: {cacheDirectory: true} 23 | }] 24 | }, 25 | { 26 | test: /\.ts$/, 27 | exclude: [/node_modules/], 28 | use: [{ 29 | loader: 'babel-loader', 30 | options: {cacheDirectory: true} 31 | }, { 32 | loader: 'ts-loader' 33 | }] 34 | }, 35 | ], 36 | }, 37 | devtool: DEBUG ? 'source-map' : false, 38 | output: { 39 | path: path.join(__dirname, 'dist'), 40 | filename: '[name]' + bundleExt, 41 | libraryTarget: 'umd', 42 | library: 'TinyTrie' 43 | }, 44 | resolve: { 45 | extensions: ['.js', '.ts'], 46 | modules: [path.join(__dirname, 'src'), 'node_modules'] 47 | } 48 | }; 49 | --------------------------------------------------------------------------------