1 /* 2 * ElementIterator.js - Iterate through a list of collation elements 3 * 4 * Copyright © 2013-2015, JEDLSoft 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 /** 21 * @class 22 * An iterator through a sequence of collation elements. This 23 * iterator takes a source of code points, converts them into 24 * collation elements, and allows the caller to get single 25 * elements at a time. 26 * 27 * @constructor 28 * @private 29 * @param {CodePointSource} source source of code points to 30 * convert to collation elements 31 * @param {Object} map mapping from sequences of code points to 32 * collation elements 33 * @param {number} keysize size in bits of the collation elements 34 */ 35 var ElementIterator = function (source, map, keysize) { 36 this.elements = []; 37 this.source = source; 38 this.map = map; 39 this.keysize = keysize; 40 }; 41 42 /** 43 * @private 44 */ 45 ElementIterator.prototype._fillBuffer = function () { 46 var str = undefined; 47 48 // peek ahead by up to 4 characters, which may combine 49 // into 1 or more collation elements 50 for (var i = 4; i > 0; i--) { 51 str = this.source.peek(i); 52 if (str && this.map[str]) { 53 this.elements = this.elements.concat(this.map[str]); 54 this.source.consume(i); 55 return; 56 } 57 } 58 59 if (str) { 60 // no mappings for the first code point, so just use its 61 // Unicode code point as a proxy for its sort order. Shift 62 // it by the key size so that everything unknown sorts 63 // after things that have mappings 64 this.elements.push(str.charCodeAt(0) << this.keysize); 65 this.source.consume(1); 66 } else { 67 // end of the string 68 return undefined; 69 } 70 }; 71 72 /** 73 * Return true if there are more collation elements left to 74 * iterate through. 75 * @returns {boolean} true if there are more elements left to 76 * iterate through, and false otherwise 77 */ 78 ElementIterator.prototype.hasNext = function () { 79 if (this.elements.length < 1) { 80 this._fillBuffer(); 81 } 82 return !!this.elements.length; 83 }; 84 85 /** 86 * Return the next collation element. If more than one collation 87 * element is generated from a sequence of code points 88 * (ie. an "expansion"), then this class will buffer the 89 * other elements and return them on subsequent calls to 90 * this method. 91 * 92 * @returns {number|undefined} the next collation element or 93 * undefined for no more collation elements 94 */ 95 ElementIterator.prototype.next = function () { 96 if (this.elements.length < 1) { 97 this._fillBuffer(); 98 } 99 var ret = this.elements[0]; 100 this.elements = this.elements.slice(1); 101 return ret; 102 }; 103 104 module.exports = ElementIterator; 105