main.js (3932B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2019 The Stdlib Authors. 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 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); 24 var isFunction = require( '@stdlib/assert/is-function' ); 25 var isCollection = require( '@stdlib/assert/is-collection' ); 26 var iteratorSymbol = require( '@stdlib/symbol/iterator' ); 27 28 29 // MAIN // 30 31 /** 32 * Returns an iterator which iterates over each element in a sparse array-like object. 33 * 34 * @param {Collection} src - input value 35 * @param {Function} [mapFcn] - function to invoke for each iterated value 36 * @param {*} [thisArg] - execution context 37 * @throws {TypeError} first argument must be an array-like object 38 * @throws {TypeError} second argument must be a function 39 * @returns {Iterator} iterator 40 * 41 * @example 42 * var iter = sparsearray2iterator( [ 1, , 3, 4 ] ); 43 * 44 * var v = iter.next().value; 45 * // returns 1 46 * 47 * v = iter.next().value; 48 * // returns 3 49 * 50 * v = iter.next().value; 51 * // returns 4 52 */ 53 function sparsearray2iterator( src ) { 54 var thisArg; 55 var iter; 56 var FLG; 57 var fcn; 58 var i; 59 if ( !isCollection( src ) ) { 60 throw new TypeError( 'invalid argument. First argument must be an array-like object. Value: `' + src + '`.' ); 61 } 62 if ( arguments.length > 1 ) { 63 fcn = arguments[ 1 ]; 64 if ( !isFunction( fcn ) ) { 65 throw new TypeError( 'invalid argument. Second argument must be a function. Value: `' + fcn + '`.' ); 66 } 67 thisArg = arguments[ 2 ]; 68 } 69 i = -1; 70 71 // Create an iterator protocol-compliant object: 72 iter = {}; 73 if ( fcn ) { 74 setReadOnly( iter, 'next', next1 ); 75 } else { 76 setReadOnly( iter, 'next', next2 ); 77 } 78 setReadOnly( iter, 'return', end ); 79 80 // If an environment supports `Symbol.iterator`, make the iterator iterable: 81 if ( iteratorSymbol ) { 82 setReadOnly( iter, iteratorSymbol, factory ); 83 } 84 return iter; 85 86 /** 87 * Returns an iterator protocol-compliant object containing the next iterated value. 88 * 89 * @private 90 * @returns {Object} iterator protocol-compliant object 91 */ 92 function next1() { 93 var len; 94 if ( FLG ) { 95 return { 96 'done': true 97 }; 98 } 99 len = src.length; 100 i += 1; 101 while ( i < len && src[ i ] === void 0 ) { 102 i += 1; 103 } 104 if ( i >= len ) { 105 FLG = true; 106 return { 107 'done': true 108 }; 109 } 110 return { 111 'value': fcn.call( thisArg, src[ i ], i, src ), 112 'done': false 113 }; 114 } 115 116 /** 117 * Returns an iterator protocol-compliant object containing the next iterated value. 118 * 119 * @private 120 * @returns {Object} iterator protocol-compliant object 121 */ 122 function next2() { 123 var len; 124 if ( FLG ) { 125 return { 126 'done': true 127 }; 128 } 129 len = src.length; 130 i += 1; 131 while ( i < len && src[ i ] === void 0 ) { 132 i += 1; 133 } 134 if ( i >= len ) { 135 FLG = true; 136 return { 137 'done': true 138 }; 139 } 140 return { 141 'value': src[ i ], 142 'done': false 143 }; 144 } 145 146 /** 147 * Finishes an iterator. 148 * 149 * @private 150 * @param {*} [value] - value to return 151 * @returns {Object} iterator protocol-compliant object 152 */ 153 function end( value ) { 154 FLG = true; 155 if ( arguments.length ) { 156 return { 157 'value': value, 158 'done': true 159 }; 160 } 161 return { 162 'done': true 163 }; 164 } 165 166 /** 167 * Returns a new iterator. 168 * 169 * @private 170 * @returns {Iterator} iterator 171 */ 172 function factory() { 173 if ( fcn ) { 174 return sparsearray2iterator( src, fcn, thisArg ); 175 } 176 return sparsearray2iterator( src ); 177 } 178 } 179 180 181 // EXPORTS // 182 183 module.exports = sparsearray2iterator;