time-to-botec

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

main.js (5632B)


      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 subtraction 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, 5.0 ] );
     53 * var it2 = array2iterator( [ 3.0, 4.0 ] );
     54 *
     55 * var iter = iterSubtract( it1, it2 );
     56 *
     57 * var v = iter.next().value;
     58 * // returns -2.0
     59 *
     60 * v = iter.next().value;
     61 * // returns 1.0
     62 *
     63 * var bool = iter.next().done;
     64 * // returns true
     65 */
     66 function iterSubtract() {
     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 		if ( types[ 0 ] ) {
    128 			v = iterators[ 0 ].next();
    129 			if ( v.done ) {
    130 				FLG += 1;
    131 				if ( hasOwnProp( v, 'value' ) ) {
    132 					if ( typeof v.value === 'number' ) {
    133 						s = v.value;
    134 					} else {
    135 						s = NaN;
    136 					}
    137 				} else {
    138 					return {
    139 						'done': true
    140 					};
    141 				}
    142 			} else if ( typeof v.value === 'number' ) {
    143 				s = v.value;
    144 			} else {
    145 				s = NaN;
    146 			}
    147 		} else {
    148 			s = iterators[ 0 ];
    149 		}
    150 		for ( i = 1; i < niter; i++ ) {
    151 			if ( types[ i ] ) {
    152 				v = iterators[ i ].next();
    153 				if ( v.done ) {
    154 					FLG += 1;
    155 					if ( hasOwnProp( v, 'value' ) ) {
    156 						if ( typeof v.value === 'number' ) {
    157 							s -= v.value;
    158 						} else {
    159 							s = NaN;
    160 						}
    161 						continue;
    162 					}
    163 					return {
    164 						'done': true
    165 					};
    166 				}
    167 				if ( typeof v.value === 'number' ) {
    168 					s -= v.value;
    169 				} else {
    170 					s = NaN;
    171 				}
    172 			} else {
    173 				s -= iterators[ i ];
    174 			}
    175 		}
    176 		return {
    177 			'value': s,
    178 			'done': false
    179 		};
    180 	}
    181 
    182 	/**
    183 	* Finishes an iterator.
    184 	*
    185 	* @private
    186 	* @param {*} [value] - value to return
    187 	* @returns {Object} iterator protocol-compliant object
    188 	*/
    189 	function end( value ) {
    190 		FLG = 1;
    191 		if ( arguments.length ) {
    192 			return {
    193 				'value': value,
    194 				'done': true
    195 			};
    196 		}
    197 		return {
    198 			'done': true
    199 		};
    200 	}
    201 
    202 	/**
    203 	* Returns a new iterator.
    204 	*
    205 	* @private
    206 	* @returns {Iterator} iterator
    207 	*/
    208 	function factory() {
    209 		var args;
    210 		var i;
    211 
    212 		args = [];
    213 		for ( i = 0; i < niter; i++ ) {
    214 			if ( types[ i ] ) {
    215 				args.push( iterators[ i ][ iteratorSymbol ]() );
    216 			} else {
    217 				args.push( iterators[ i ] );
    218 			}
    219 		}
    220 		return iterSubtract.apply( null, args );
    221 	}
    222 }
    223 
    224 
    225 // EXPORTS //
    226 
    227 module.exports = iterSubtract;