time-to-botec

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

main.js (6320B)


      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 hasOwnProp = require( '@stdlib/assert/has-own-property' );
     25 var isFunction = require( '@stdlib/assert/is-function' );
     26 var isCollection = require( '@stdlib/assert/is-collection' );
     27 var isObject = require( '@stdlib/assert/is-plain-object' );
     28 var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
     29 var iteratorSymbol = require( '@stdlib/symbol/iterator' );
     30 
     31 
     32 // MAIN //
     33 
     34 /**
     35 * Returns an iterator which repeatedly iterates over each element in an array-like object.
     36 *
     37 * @param {Collection} src - input value
     38 * @param {Options} [options] - function options
     39 * @param {NonNegativeInteger} [options.iter] - number of iterations
     40 * @param {integer} [options.dir=1] - iteration direction
     41 * @param {Function} [mapFcn] - function to invoke for each iterated value
     42 * @param {*} [thisArg] - execution context
     43 * @throws {TypeError} first argument must be an array-like object
     44 * @throws {TypeError} options argument must be an object
     45 * @throws {TypeError} must provide valid options
     46 * @throws {TypeError} callback argument must be a function
     47 * @returns {Iterator} iterator
     48 *
     49 * @example
     50 * var iter = circarray2iterator( [ 1, 2, 3, 4 ] );
     51 *
     52 * var v = iter.next().value;
     53 * // returns 1
     54 *
     55 * v = iter.next().value;
     56 * // returns 2
     57 *
     58 * v = iter.next().value;
     59 * // returns 3
     60 *
     61 * // ...
     62 */
     63 function circarray2iterator( src ) {
     64 	var thisArg;
     65 	var options;
     66 	var count;
     67 	var opts;
     68 	var iter;
     69 	var FLG;
     70 	var fcn;
     71 	var i;
     72 	if ( !isCollection( src ) ) {
     73 		throw new TypeError( 'invalid argument. First argument must be an array-like object. Value: `' + src + '`.' );
     74 	}
     75 	opts = {
     76 		'iter': 1e308, // ~infinity
     77 		'dir': 1       // left to right iteration
     78 	};
     79 	if ( arguments.length > 1 ) {
     80 		if ( isObject( arguments[ 1 ] ) ) {
     81 			options = arguments[ 1 ];
     82 			if ( arguments.length > 2 ) {
     83 				fcn = arguments[ 2 ];
     84 				if ( !isFunction( fcn ) ) {
     85 					throw new TypeError( 'invalid argument. Callback argument must be a function. Value: `' + fcn + '`.' );
     86 				}
     87 				thisArg = arguments[ 3 ];
     88 			}
     89 			if ( hasOwnProp( options, 'iter' ) ) {
     90 				opts.iter = options.iter;
     91 				if ( !isNonNegativeInteger( options.iter ) ) {
     92 					throw new TypeError( 'invalid option. `iter` option must be a nonnegative integer. Option: `' + options.iter + '`.' );
     93 				}
     94 			}
     95 			if ( hasOwnProp( options, 'dir' ) ) {
     96 				opts.dir = options.dir;
     97 				if ( options.dir !== 1 && options.dir !== -1 ) {
     98 					throw new TypeError( 'invalid option. `dir` option must be either `1` or `-1`. Option: `' + options.dir + '`.' );
     99 				}
    100 			}
    101 		} else {
    102 			fcn = arguments[ 1 ];
    103 			if ( !isFunction( fcn ) ) {
    104 				throw new TypeError( 'invalid argument. Second argument must be either a function or an options object. Value: `' + fcn + '`.' );
    105 			}
    106 			thisArg = arguments[ 2 ];
    107 		}
    108 	}
    109 	count = 0;
    110 
    111 	// Create an iterator protocol-compliant object:
    112 	iter = {};
    113 	if ( fcn ) {
    114 		if ( opts.dir === 1 ) {
    115 			i = -1;
    116 			setReadOnly( iter, 'next', next1a );
    117 		} else {
    118 			i = src.length;
    119 			setReadOnly( iter, 'next', next1b );
    120 		}
    121 	} else if ( opts.dir === 1 ) {
    122 		i = -1;
    123 		setReadOnly( iter, 'next', next2a );
    124 	} else {
    125 		i = src.length;
    126 		setReadOnly( iter, 'next', next2b );
    127 	}
    128 	setReadOnly( iter, 'return', end );
    129 
    130 	// If an environment supports `Symbol.iterator`, make the iterator iterable:
    131 	if ( iteratorSymbol ) {
    132 		setReadOnly( iter, iteratorSymbol, factory );
    133 	}
    134 	return iter;
    135 
    136 	/**
    137 	* Returns an iterator protocol-compliant object containing the next iterated value.
    138 	*
    139 	* @private
    140 	* @returns {Object} iterator protocol-compliant object
    141 	*/
    142 	function next1a() {
    143 		i = (i+1) % src.length;
    144 		count += 1;
    145 		if ( FLG || count > opts.iter || src.length === 0 ) {
    146 			return {
    147 				'done': true
    148 			};
    149 		}
    150 		return {
    151 			'value': fcn.call( thisArg, src[ i ], i, count, src ),
    152 			'done': false
    153 		};
    154 	}
    155 
    156 	/**
    157 	* Returns an iterator protocol-compliant object containing the next iterated value.
    158 	*
    159 	* @private
    160 	* @returns {Object} iterator protocol-compliant object
    161 	*/
    162 	function next1b() {
    163 		i -= 1;
    164 		if ( i < 0 ) {
    165 			i += src.length;
    166 		}
    167 		count += 1;
    168 		if ( FLG || count > opts.iter || src.length === 0 ) {
    169 			return {
    170 				'done': true
    171 			};
    172 		}
    173 		return {
    174 			'value': fcn.call( thisArg, src[ i ], i, count, src ),
    175 			'done': false
    176 		};
    177 	}
    178 
    179 	/**
    180 	* Returns an iterator protocol-compliant object containing the next iterated value.
    181 	*
    182 	* @private
    183 	* @returns {Object} iterator protocol-compliant object
    184 	*/
    185 	function next2a() {
    186 		i = (i+1) % src.length;
    187 		count += 1;
    188 		if ( FLG || count > opts.iter || src.length === 0 ) {
    189 			return {
    190 				'done': true
    191 			};
    192 		}
    193 		return {
    194 			'value': src[ i ],
    195 			'done': false
    196 		};
    197 	}
    198 
    199 	/**
    200 	* Returns an iterator protocol-compliant object containing the next iterated value.
    201 	*
    202 	* @private
    203 	* @returns {Object} iterator protocol-compliant object
    204 	*/
    205 	function next2b() {
    206 		i -= 1;
    207 		if ( i < 0 ) {
    208 			i += src.length;
    209 		}
    210 		count += 1;
    211 		if ( FLG || count > opts.iter || src.length === 0 ) {
    212 			return {
    213 				'done': true
    214 			};
    215 		}
    216 		return {
    217 			'value': src[ i ],
    218 			'done': false
    219 		};
    220 	}
    221 
    222 	/**
    223 	* Finishes an iterator.
    224 	*
    225 	* @private
    226 	* @param {*} [value] - value to return
    227 	* @returns {Object} iterator protocol-compliant object
    228 	*/
    229 	function end( value ) {
    230 		FLG = true;
    231 		if ( arguments.length ) {
    232 			return {
    233 				'value': value,
    234 				'done': true
    235 			};
    236 		}
    237 		return {
    238 			'done': true
    239 		};
    240 	}
    241 
    242 	/**
    243 	* Returns a new iterator.
    244 	*
    245 	* @private
    246 	* @returns {Iterator} iterator
    247 	*/
    248 	function factory() {
    249 		if ( fcn ) {
    250 			return circarray2iterator( src, opts, fcn, thisArg );
    251 		}
    252 		return circarray2iterator( src, opts );
    253 	}
    254 }
    255 
    256 
    257 // EXPORTS //
    258 
    259 module.exports = circarray2iterator;