time-to-botec

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

main.js (2898B)


      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 objectKeys = require( '@stdlib/utils/keys' );
     24 
     25 
     26 // FUNCTIONS //
     27 
     28 /**
     29 * Tests if a value is an object.
     30 *
     31 * ## Notes
     32 *
     33 * -   The function excludes `null`.
     34 *
     35 * @private
     36 * @param {*} value - value to test
     37 * @returns {boolean} boolean indicating if a value is an object
     38 */
     39 function isObject( value ) {
     40 	var type = typeof value;
     41 	return ( value !== null && ( type === 'object' || type === 'function' ) );
     42 }
     43 
     44 /**
     45 * Tests if the seen array contains a search value.
     46 *
     47 * @private
     48 * @param {Array} seen - array of seen objects
     49 * @param {*} searchValue - search value
     50 * @returns {boolean} boolean indicating whether array contains search value
     51 */
     52 function contains( seen, searchValue ) {
     53 	var i;
     54 	for ( i = 0; i < seen.length; i++ ) {
     55 		if ( seen[ i ] === searchValue ) {
     56 			return true;
     57 		}
     58 	}
     59 	return false;
     60 }
     61 
     62 /**
     63 * Tests if an object contains a circular reference by recursively traversing object keys.
     64 *
     65 * @private
     66 * @param {Object} obj - object to test
     67 * @param {Array} seen - array of seen objects
     68 * @returns {boolean} boolean indicating whether object contains a circular reference
     69 */
     70 function isCircObj( obj, seen ) {
     71 	var keys;
     72 	var val;
     73 	var i;
     74 
     75 	seen.push( obj );
     76 	keys = objectKeys( obj );
     77 	if ( keys.length === 0 ) {
     78 		return false;
     79 	}
     80 	for ( i = 0; i < keys.length; i++ ) {
     81 		val = obj[ keys[ i ] ];
     82 		if ( isObject( val ) && ( contains( seen, val ) || isCircObj( val, seen ) ) ) { // eslint-disable-line max-len
     83 			return true;
     84 		}
     85 	}
     86 	seen.pop( obj );
     87 	return false;
     88 }
     89 
     90 
     91 // MAIN //
     92 
     93 /**
     94 * Tests if an object-like value contains a circular reference.
     95 *
     96 * @param {*} value - value to test
     97 * @returns {boolean} boolean indicating whether value is object-like and contains a circular reference
     98 *
     99 * @example
    100 * var obj = {
    101 *   'a': 'beep',
    102 *   'b': {
    103 *     'c': 'boop'
    104 *   }
    105 * };
    106 * obj.b.self = obj;
    107 * var bool = isCircular( obj );
    108 * // returns true
    109 *
    110 * @example
    111 * var arr = [ 1, 2, 3 ];
    112 * arr.push( arr );
    113 * var bool = isCircular( arr );
    114 * // returns true
    115 *
    116 * @example
    117 * var bool = isCircular( {} );
    118 * // returns false
    119 *
    120 * @example
    121 * var bool = isCircular( null );
    122 * // returns false
    123 */
    124 function isCircular( value ) {
    125 	if ( !isObject( value ) ) {
    126 		return false;
    127 	}
    128 	return isCircObj( value, [] );
    129 }
    130 
    131 
    132 // EXPORTS //
    133 
    134 module.exports = isCircular;