main.js (3616B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 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 an 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 = array2iterator( [ 1, 2, 3, 4 ] ); 43 * 44 * var v = iter.next().value; 45 * // returns 1 46 * 47 * v = iter.next().value; 48 * // returns 2 49 * 50 * v = iter.next().value; 51 * // returns 3 52 * 53 * // ... 54 */ 55 function array2iterator( src ) { 56 var thisArg; 57 var iter; 58 var FLG; 59 var fcn; 60 var i; 61 if ( !isCollection( src ) ) { 62 throw new TypeError( 'invalid argument. First argument must be an array-like object. Value: `' + src + '`.' ); 63 } 64 if ( arguments.length > 1 ) { 65 fcn = arguments[ 1 ]; 66 if ( !isFunction( fcn ) ) { 67 throw new TypeError( 'invalid argument. Second argument must be a function. Value: `' + fcn + '`.' ); 68 } 69 thisArg = arguments[ 2 ]; 70 } 71 i = -1; 72 73 // Create an iterator protocol-compliant object: 74 iter = {}; 75 if ( fcn ) { 76 setReadOnly( iter, 'next', next1 ); 77 } else { 78 setReadOnly( iter, 'next', next2 ); 79 } 80 setReadOnly( iter, 'return', end ); 81 82 // If an environment supports `Symbol.iterator`, make the iterator iterable: 83 if ( iteratorSymbol ) { 84 setReadOnly( iter, iteratorSymbol, factory ); 85 } 86 return iter; 87 88 /** 89 * Returns an iterator protocol-compliant object containing the next iterated value. 90 * 91 * @private 92 * @returns {Object} iterator protocol-compliant object 93 */ 94 function next1() { 95 i += 1; 96 if ( FLG || i >= src.length ) { 97 return { 98 'done': true 99 }; 100 } 101 return { 102 'value': fcn.call( thisArg, src[ i ], i, src ), 103 'done': false 104 }; 105 } 106 107 /** 108 * Returns an iterator protocol-compliant object containing the next iterated value. 109 * 110 * @private 111 * @returns {Object} iterator protocol-compliant object 112 */ 113 function next2() { 114 i += 1; 115 if ( FLG || i >= src.length ) { 116 return { 117 'done': true 118 }; 119 } 120 return { 121 'value': src[ i ], 122 'done': false 123 }; 124 } 125 126 /** 127 * Finishes an iterator. 128 * 129 * @private 130 * @param {*} [value] - value to return 131 * @returns {Object} iterator protocol-compliant object 132 */ 133 function end( value ) { 134 FLG = true; 135 if ( arguments.length ) { 136 return { 137 'value': value, 138 'done': true 139 }; 140 } 141 return { 142 'done': true 143 }; 144 } 145 146 /** 147 * Returns a new iterator. 148 * 149 * @private 150 * @returns {Iterator} iterator 151 */ 152 function factory() { 153 if ( fcn ) { 154 return array2iterator( src, fcn, thisArg ); 155 } 156 return array2iterator( src ); 157 } 158 } 159 160 161 // EXPORTS // 162 163 module.exports = array2iterator;