time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

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;