main.js (4424B)
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 from right to left over each element in a sparse array-like object. 33 * 34 * ## Notes 35 * 36 * - For dynamic array resizing, the only behavior made intentionally consistent with iterating from left to right is when elements are pushed onto the beginning (end) of an array. In other words, iterating from left to right combined with `[].push()` is consistent with iterating from right to left combined with `[].unshift()`. 37 * 38 * @param {Collection} src - input value 39 * @param {Function} [mapFcn] - function to invoke for each iterated value 40 * @param {*} [thisArg] - execution context 41 * @throws {TypeError} first argument must be an array-like object 42 * @throws {TypeError} second argument must be a function 43 * @returns {Iterator} iterator 44 * 45 * @example 46 * var iter = sparsearray2iteratorRight( [ 1, , 3, 4 ] ); 47 * 48 * var v = iter.next().value; 49 * // returns 4 50 * 51 * v = iter.next().value; 52 * // returns 3 53 * 54 * v = iter.next().value; 55 * // returns 1 56 */ 57 function sparsearray2iteratorRight( src ) { 58 var thisArg; 59 var iter; 60 var FLG; 61 var fcn; 62 var len; 63 var i; 64 if ( !isCollection( src ) ) { 65 throw new TypeError( 'invalid argument. First argument must be an array-like object. Value: `' + src + '`.' ); 66 } 67 if ( arguments.length > 1 ) { 68 fcn = arguments[ 1 ]; 69 if ( !isFunction( fcn ) ) { 70 throw new TypeError( 'invalid argument. Second argument must be a function. Value: `' + fcn + '`.' ); 71 } 72 thisArg = arguments[ 2 ]; 73 } 74 len = src.length; 75 i = len; 76 77 // Create an iterator protocol-compliant object: 78 iter = {}; 79 if ( fcn ) { 80 setReadOnly( iter, 'next', next1 ); 81 } else { 82 setReadOnly( iter, 'next', next2 ); 83 } 84 setReadOnly( iter, 'return', end ); 85 86 // If an environment supports `Symbol.iterator`, make the iterator iterable: 87 if ( iteratorSymbol ) { 88 setReadOnly( iter, iteratorSymbol, factory ); 89 } 90 return iter; 91 92 /** 93 * Returns an iterator protocol-compliant object containing the next iterated value. 94 * 95 * @private 96 * @returns {Object} iterator protocol-compliant object 97 */ 98 function next1() { 99 if ( FLG ) { 100 return { 101 'done': true 102 }; 103 } 104 i += src.length - len - 1; // accounts for a dynamic array 105 len = src.length; 106 while ( i >= 0 && src[ i ] === void 0 ) { 107 i -= 1; 108 } 109 if ( i < 0 ) { 110 FLG = true; 111 return { 112 'done': true 113 }; 114 } 115 return { 116 'value': fcn.call( thisArg, src[ i ], i, src ), 117 'done': false 118 }; 119 } 120 121 /** 122 * Returns an iterator protocol-compliant object containing the next iterated value. 123 * 124 * @private 125 * @returns {Object} iterator protocol-compliant object 126 */ 127 function next2() { 128 if ( FLG ) { 129 return { 130 'done': true 131 }; 132 } 133 i += src.length - len - 1; // accounts for a dynamic array 134 len = src.length; 135 while ( i >= 0 && src[ i ] === void 0 ) { 136 i -= 1; 137 } 138 if ( i < 0 ) { 139 FLG = true; 140 return { 141 'done': true 142 }; 143 } 144 return { 145 'value': src[ i ], 146 'done': false 147 }; 148 } 149 150 /** 151 * Finishes an iterator. 152 * 153 * @private 154 * @param {*} [value] - value to return 155 * @returns {Object} iterator protocol-compliant object 156 */ 157 function end( value ) { 158 FLG = true; 159 if ( arguments.length ) { 160 return { 161 'value': value, 162 'done': true 163 }; 164 } 165 return { 166 'done': true 167 }; 168 } 169 170 /** 171 * Returns a new iterator. 172 * 173 * @private 174 * @returns {Iterator} iterator 175 */ 176 function factory() { 177 if ( fcn ) { 178 return sparsearray2iteratorRight( src, fcn, thisArg ); 179 } 180 return sparsearray2iteratorRight( src ); 181 } 182 } 183 184 185 // EXPORTS // 186 187 module.exports = sparsearray2iteratorRight;