time-to-botec

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

main.js (5233B)


      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 isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
     26 var isIteratorLike = require( '@stdlib/assert/is-iterator-like' );
     27 var hasOwnProp = require( '@stdlib/assert/has-own-property' );
     28 var iteratorSymbol = require( '@stdlib/symbol/iterator' );
     29 
     30 
     31 // MAIN //
     32 
     33 /**
     34 * Returns an iterator which performs element-wise multiplication of two or more iterators.
     35 *
     36 * ## Notes
     37 *
     38 * -   If provided a numeric value as an iterator argument, the value is broadcast as an **infinite** iterator which **always** returns the provided value.
     39 * -   If an iterated value is non-numeric (including `NaN`), the returned iterator returns `NaN`. If non-numeric iterated values are possible, you are advised to provide an iterator which type checks and handles non-numeric values accordingly.
     40 * -   The length of the returned iterator is equal to the length of the shortest provided iterator. In other words, the returned iterator ends once **one** of the provided iterators ends.
     41 * -   If an environment supports `Symbol.iterator` and all provided iterators are iterable, the returned iterator is iterable.
     42 *
     43 * @param {Iterator} iter0 - first input iterator
     44 * @param {...(Iterator|number)} iterator - subsequent iterators
     45 * @throws {Error} must provide two or more iterators
     46 * @throws {TypeError} must provide iterator protocol-compliant objects
     47 * @returns {Iterator} iterator
     48 *
     49 * @example
     50 * var array2iterator = require( '@stdlib/array/to-iterator' );
     51 *
     52 * var it1 = array2iterator( [ 1.0, 2.0 ] );
     53 * var it2 = array2iterator( [ 3.0, 4.0 ] );
     54 *
     55 * var iter = iterMultiply( it1, it2 );
     56 *
     57 * var v = iter.next().value;
     58 * // returns 3.0
     59 *
     60 * v = iter.next().value;
     61 * // returns 8.0
     62 *
     63 * var bool = iter.next().done;
     64 * // returns true
     65 */
     66 function iterMultiply() {
     67 	var iterators;
     68 	var types;
     69 	var niter;
     70 	var iter;
     71 	var FLG;
     72 	var i;
     73 
     74 	niter = arguments.length;
     75 	if ( niter < 2 ) {
     76 		throw new Error( 'insufficient input arguments. Must provide two or more iterators.' );
     77 	}
     78 	iterators = [];
     79 	types = [];
     80 	for ( i = 0; i < niter; i++ ) {
     81 		iterators.push( arguments[ i ] );
     82 		if ( isIteratorLike( arguments[ i ] ) ) {
     83 			types.push( 1 );
     84 		} else if ( isNumber( arguments[ i ] ) ) {
     85 			types.push( 0 );
     86 		} else {
     87 			throw new TypeError( 'invalid argument. Must provide an iterator protocol-compliant object or a number. Argument: `' + i + '`. Value: `' + arguments[ i ] + '`.' );
     88 		}
     89 	}
     90 	// Create an iterator protocol-compliant object:
     91 	iter = {};
     92 	setReadOnly( iter, 'next', next );
     93 	setReadOnly( iter, 'return', end );
     94 
     95 	// If an environment supports `Symbol.iterator` and all provided iterators are iterable, make the iterator iterable:
     96 	if ( iteratorSymbol ) {
     97 		for ( i = 0; i < niter; i++ ) {
     98 			if ( types[ i ] && !isFunction( iterators[ i ][ iteratorSymbol ] ) ) { // eslint-disable-line max-len
     99 				FLG = true;
    100 				break;
    101 			}
    102 		}
    103 		if ( !FLG ) {
    104 			setReadOnly( iter, iteratorSymbol, factory );
    105 		}
    106 	}
    107 	FLG = 0;
    108 	i = 0;
    109 	return iter;
    110 
    111 	/**
    112 	* Returns an iterator protocol-compliant object containing the next iterated value.
    113 	*
    114 	* @private
    115 	* @returns {Object} iterator protocol-compliant object
    116 	*/
    117 	function next() {
    118 		var s;
    119 		var v;
    120 		var i;
    121 		if ( FLG ) {
    122 			return {
    123 				'done': true
    124 			};
    125 		}
    126 		FLG = 0;
    127 		s = 1.0;
    128 		for ( i = 0; i < niter; i++ ) {
    129 			if ( types[ i ] ) {
    130 				v = iterators[ i ].next();
    131 				if ( v.done ) {
    132 					FLG += 1;
    133 					if ( hasOwnProp( v, 'value' ) ) {
    134 						if ( typeof v.value === 'number' ) {
    135 							s *= v.value;
    136 						} else {
    137 							s = NaN;
    138 						}
    139 						continue;
    140 					}
    141 					return {
    142 						'done': true
    143 					};
    144 				}
    145 				if ( typeof v.value === 'number' ) {
    146 					s *= v.value;
    147 				} else {
    148 					s = NaN;
    149 				}
    150 			} else {
    151 				s *= iterators[ i ];
    152 			}
    153 		}
    154 		return {
    155 			'value': s,
    156 			'done': false
    157 		};
    158 	}
    159 
    160 	/**
    161 	* Finishes an iterator.
    162 	*
    163 	* @private
    164 	* @param {*} [value] - value to return
    165 	* @returns {Object} iterator protocol-compliant object
    166 	*/
    167 	function end( value ) {
    168 		FLG = 1;
    169 		if ( arguments.length ) {
    170 			return {
    171 				'value': value,
    172 				'done': true
    173 			};
    174 		}
    175 		return {
    176 			'done': true
    177 		};
    178 	}
    179 
    180 	/**
    181 	* Returns a new iterator.
    182 	*
    183 	* @private
    184 	* @returns {Iterator} iterator
    185 	*/
    186 	function factory() {
    187 		var args;
    188 		var i;
    189 
    190 		args = [];
    191 		for ( i = 0; i < niter; i++ ) {
    192 			if ( types[ i ] ) {
    193 				args.push( iterators[ i ][ iteratorSymbol ]() );
    194 			} else {
    195 				args.push( iterators[ i ] );
    196 			}
    197 		}
    198 		return iterMultiply.apply( null, args );
    199 	}
    200 }
    201 
    202 
    203 // EXPORTS //
    204 
    205 module.exports = iterMultiply;