| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/tracing/base/base.html"> |
| <link rel="import" href="/tracing/base/iteration_helpers.html"> |
| <link rel="import" href="/tracing/base/math.html"> |
| |
| <script> |
| 'use strict'; |
| |
| /** |
| * @fileoverview Quick range computations. |
| */ |
| tr.exportTo('tr.b', function() { |
| |
| function Range() { |
| this.isEmpty_ = true; |
| this.min_ = undefined; |
| this.max_ = undefined; |
| } |
| |
| Range.prototype = { |
| __proto__: Object.prototype, |
| |
| reset: function() { |
| this.isEmpty_ = true; |
| this.min_ = undefined; |
| this.max_ = undefined; |
| }, |
| |
| get isEmpty() { |
| return this.isEmpty_; |
| }, |
| |
| addRange: function(range) { |
| if (range.isEmpty) |
| return; |
| this.addValue(range.min); |
| this.addValue(range.max); |
| }, |
| |
| addValue: function(value) { |
| if (this.isEmpty_) { |
| this.max_ = value; |
| this.min_ = value; |
| this.isEmpty_ = false; |
| return; |
| } |
| this.max_ = Math.max(this.max_, value); |
| this.min_ = Math.min(this.min_, value); |
| }, |
| |
| set min(min) { |
| this.isEmpty_ = false; |
| this.min_ = min; |
| }, |
| |
| get min() { |
| if (this.isEmpty_) |
| return undefined; |
| return this.min_; |
| }, |
| |
| get max() { |
| if (this.isEmpty_) |
| return undefined; |
| return this.max_; |
| }, |
| |
| set max(max) { |
| this.isEmpty_ = false; |
| this.max_ = max; |
| }, |
| |
| get range() { |
| if (this.isEmpty_) |
| return undefined; |
| return this.max_ - this.min_; |
| }, |
| |
| get center() { |
| return (this.min_ + this.max_) * 0.5; |
| }, |
| |
| get duration() { |
| if (this.isEmpty_) |
| return 0; |
| return this.max_ - this.min_; |
| }, |
| |
| normalize: function(x) { |
| return tr.b.normalize(x, this.min, this.max); |
| }, |
| |
| lerp: function(x) { |
| return tr.b.lerp(x, this.min, this.max); |
| }, |
| |
| equals: function(that) { |
| if (this.isEmpty && that.isEmpty) |
| return true; |
| if (this.isEmpty != that.isEmpty) |
| return false; |
| return (tr.b.approximately(this.min, that.min) && |
| tr.b.approximately(this.max, that.max)); |
| }, |
| |
| containsExplicitRangeInclusive: function(min, max) { |
| if (this.isEmpty) |
| return false; |
| return this.min_ <= min && max <= this.max_; |
| }, |
| |
| containsExplicitRangeExclusive: function(min, max) { |
| if (this.isEmpty) |
| return false; |
| return this.min_ < min && max < this.max_; |
| }, |
| |
| intersectsExplicitRangeInclusive: function(min, max) { |
| if (this.isEmpty) |
| return false; |
| return this.min_ <= max && min <= this.max_; |
| }, |
| |
| intersectsExplicitRangeExclusive: function(min, max) { |
| if (this.isEmpty) |
| return false; |
| return this.min_ < max && min < this.max_; |
| }, |
| |
| containsRangeInclusive: function(range) { |
| if (range.isEmpty) |
| return false; |
| return this.containsExplicitRangeInclusive(range.min_, range.max_); |
| }, |
| |
| containsRangeExclusive: function(range) { |
| if (range.isEmpty) |
| return false; |
| return this.containsExplicitRangeExclusive(range.min_, range.max_); |
| }, |
| |
| intersectsRangeInclusive: function(range) { |
| if (range.isEmpty) |
| return false; |
| return this.intersectsExplicitRangeInclusive(range.min_, range.max_); |
| }, |
| |
| intersectsRangeExclusive: function(range) { |
| if (range.isEmpty) |
| return false; |
| return this.intersectsExplicitRangeExclusive(range.min_, range.max_); |
| }, |
| |
| findExplicitIntersectionDuration: function(min, max) { |
| var min = Math.max(this.min, min); |
| var max = Math.min(this.max, max); |
| if (max < min) |
| return 0; |
| return max - min; |
| }, |
| |
| findIntersection: function(range) { |
| if (this.isEmpty || range.isEmpty) |
| return new Range(); |
| |
| var min = Math.max(this.min, range.min); |
| var max = Math.min(this.max, range.max); |
| |
| if (max < min) |
| return new Range(); |
| |
| return Range.fromExplicitRange(min, max); |
| }, |
| |
| toJSON: function() { |
| if (this.isEmpty_) |
| return {isEmpty: true}; |
| return { |
| isEmpty: false, |
| max: this.max, |
| min: this.min |
| }; |
| }, |
| |
| /** |
| * Returns a slice of the input array that intersects with this range |
| * inclusively. |
| * If the range does not have a min, it is treated as unbounded from below. |
| * Similarly, if max is undefined, the range is unbounded from above. |
| * |
| * @param {Array} array The array of elements to be filtered. |
| * @param {Funcation=} opt_keyFunc A function that extracts a numeric value, |
| * to be used in comparisons, from an element of the array. If not |
| * specified, array elements themselves will be used. |
| * @param {Object=} opt_this An optional this argument to be passed to |
| * opt_keyFunc. |
| */ |
| filterArray: function(array, opt_keyFunc, opt_this) { |
| if (this.isEmpty_) |
| return []; |
| // Binary search. |test| is a function that should return true when we |
| // need to explore the left branch and false to explore the right branch. |
| function binSearch(test) { |
| var i0 = 0; |
| var i1 = array.length; |
| while (i0 < i1) { |
| var i = Math.trunc((i0 + i1) / 2); |
| if (test(i)) |
| i1 = i; // Explore the left branch. |
| else |
| i0 = i + 1; // Explore the right branch. |
| } |
| return i1; |
| } |
| |
| var keyFunc = opt_keyFunc || tr.b.identity; |
| function getValue(index) { |
| return keyFunc.call(opt_this, array[index]); |
| } |
| |
| var first = binSearch(function(i) { |
| return this.min_ === undefined || this.min_ <= getValue(i); |
| }.bind(this)); |
| var last = binSearch(function(i) { |
| return this.max_ !== undefined && this.max_ < getValue(i); |
| }.bind(this)); |
| return array.slice(first, last); |
| } |
| }; |
| |
| Range.fromDict = function(d) { |
| if (d.isEmpty === true) { |
| return new Range(); |
| } else if (d.isEmpty === false) { |
| var range = new Range(); |
| range.min = d.min; |
| range.max = d.max; |
| return range; |
| } else { |
| throw new Error('Not a range'); |
| } |
| }; |
| |
| Range.fromExplicitRange = function(min, max) { |
| var range = new Range(); |
| range.min = min; |
| range.max = max; |
| return range; |
| }; |
| |
| Range.compareByMinTimes = function(a, b) { |
| if (!a.isEmpty && !b.isEmpty) |
| return a.min_ - b.min_; |
| |
| if (a.isEmpty && !b.isEmpty) |
| return -1; |
| |
| if (!a.isEmpty && b.isEmpty) |
| return 1; |
| |
| return 0; |
| }; |
| |
| Range.PERCENT_RANGE = Range.fromExplicitRange(0, 1); |
| Object.freeze(Range.PERCENT_RANGE); |
| |
| return { |
| Range: Range |
| }; |
| }); |
| </script> |