| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <!-- | 2 <!-- |
| 3 Copyright (c) 2014 The Chromium Authors. All rights reserved. | 3 Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
| 5 found in the LICENSE file. | 5 found in the LICENSE file. |
| 6 --> | 6 --> |
| 7 <link rel="import" href="/tracing/base/base.html"> | 7 <link rel="import" href="/tracing/base/base.html"> |
| 8 <script> | 8 <script> |
| 9 'use strict'; | 9 'use strict'; |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 * | 23 * |
| 24 * @param {Array} ary An array of arbitrary objects. | 24 * @param {Array} ary An array of arbitrary objects. |
| 25 * @param {function():*} mapFn Callback that produces a key value | 25 * @param {function():*} mapFn Callback that produces a key value |
| 26 * from an element in ary. | 26 * from an element in ary. |
| 27 * @param {number} loVal Value for which to search. | 27 * @param {number} loVal Value for which to search. |
| 28 * @return {Number} Offset o into ary where all ary[i] for i <= o | 28 * @return {Number} Offset o into ary where all ary[i] for i <= o |
| 29 * are < loVal, or ary.length if loVal is greater than all elements in | 29 * are < loVal, or ary.length if loVal is greater than all elements in |
| 30 * the array. | 30 * the array. |
| 31 */ | 31 */ |
| 32 function findLowIndexInSortedArray(ary, mapFn, loVal) { | 32 function findLowIndexInSortedArray(ary, mapFn, loVal) { |
| 33 if (ary.length === 0) | 33 if (ary.length === 0) return 1; |
| 34 return 1; | |
| 35 | 34 |
| 36 var low = 0; | 35 var low = 0; |
| 37 var high = ary.length - 1; | 36 var high = ary.length - 1; |
| 38 var i; | 37 var i; |
| 39 var comparison; | 38 var comparison; |
| 40 var hitPos = -1; | 39 var hitPos = -1; |
| 41 while (low <= high) { | 40 while (low <= high) { |
| 42 i = Math.floor((low + high) / 2); | 41 i = Math.floor((low + high) / 2); |
| 43 comparison = mapFn(ary[i]) - loVal; | 42 comparison = mapFn(ary[i]) - loVal; |
| 44 if (comparison < 0) { | 43 if (comparison < 0) { |
| 45 low = i + 1; continue; | 44 low = i + 1; continue; |
| 46 } else if (comparison > 0) { | 45 } else if (comparison > 0) { |
| 47 high = i - 1; continue; | 46 high = i - 1; continue; |
| 48 } else { | 47 } else { |
| 49 hitPos = i; | 48 hitPos = i; |
| 50 high = i - 1; | 49 high = i - 1; |
| 51 } | 50 } |
| 52 } | 51 } |
| 53 // return where we hit, or failing that the low pos | 52 // return where we hit, or failing that the low pos |
| 54 return hitPos !== -1 ? hitPos : low; | 53 return hitPos !== -1 ? hitPos : low; |
| 55 } | 54 } |
| 56 | 55 |
| 57 // From devtools/front_end/platform/utilities.js upperBound | 56 // From devtools/front_end/platform/utilities.js upperBound |
| 58 function findHighIndexInSortedArray(ary, mapFn, loVal, hiVal) { | 57 function findHighIndexInSortedArray(ary, mapFn, loVal, hiVal) { |
| 59 var lo = loVal || 0; | 58 var lo = loVal || 0; |
| 60 var hi = hiVal !== undefined ? hiVal : ary.length; | 59 var hi = hiVal !== undefined ? hiVal : ary.length; |
| 61 while (lo < hi) { | 60 while (lo < hi) { |
| 62 var mid = (lo + hi) >> 1; | 61 var mid = (lo + hi) >> 1; |
| 63 if (mapFn(ary[mid]) >= 0) | 62 if (mapFn(ary[mid]) >= 0) { |
| 64 lo = mid + 1; | 63 lo = mid + 1; |
| 65 else | 64 } else { |
| 66 hi = mid; | 65 hi = mid; |
| 66 } |
| 67 } | 67 } |
| 68 return hi; | 68 return hi; |
| 69 } | 69 } |
| 70 | 70 |
| 71 /** | 71 /** |
| 72 * Finds an index in an array of intervals that either intersects | 72 * Finds an index in an array of intervals that either intersects |
| 73 * the provided loVal, or if no intersection is found, -1 or ary.length. | 73 * the provided loVal, or if no intersection is found, -1 or ary.length. |
| 74 * | 74 * |
| 75 * The array of intervals is defined implicitly via two mapping functions | 75 * The array of intervals is defined implicitly via two mapping functions |
| 76 * over the provided ary. mapLoFn determines the lower value of the interval, | 76 * over the provided ary. mapLoFn determines the lower value of the interval, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 87 * interval represented by an element in the array. | 87 * interval represented by an element in the array. |
| 88 * @param {number} loVal The low value for the search. | 88 * @param {number} loVal The low value for the search. |
| 89 * @return {Number} An index in the array that intersects or is first-above | 89 * @return {Number} An index in the array that intersects or is first-above |
| 90 * loVal, -1 if none found and loVal is below than all the intervals, | 90 * loVal, -1 if none found and loVal is below than all the intervals, |
| 91 * ary.length if loVal is greater than all the intervals. | 91 * ary.length if loVal is greater than all the intervals. |
| 92 */ | 92 */ |
| 93 function findIndexInSortedIntervals(ary, mapLoFn, mapWidthFn, loVal) { | 93 function findIndexInSortedIntervals(ary, mapLoFn, mapWidthFn, loVal) { |
| 94 var first = findLowIndexInSortedArray(ary, mapLoFn, loVal); | 94 var first = findLowIndexInSortedArray(ary, mapLoFn, loVal); |
| 95 if (first === 0) { | 95 if (first === 0) { |
| 96 if (loVal >= mapLoFn(ary[0]) && | 96 if (loVal >= mapLoFn(ary[0]) && |
| 97 loVal < mapLoFn(ary[0]) + mapWidthFn(ary[0], 0)) | 97 loVal < mapLoFn(ary[0]) + mapWidthFn(ary[0], 0)) { |
| 98 return 0; | 98 return 0; |
| 99 } |
| 99 return -1; | 100 return -1; |
| 100 } | 101 } |
| 101 | 102 |
| 102 if (first < ary.length) { | 103 if (first < ary.length) { |
| 103 if (loVal >= mapLoFn(ary[first]) && | 104 if (loVal >= mapLoFn(ary[first]) && |
| 104 loVal < mapLoFn(ary[first]) + mapWidthFn(ary[first], first)) | 105 loVal < mapLoFn(ary[first]) + mapWidthFn(ary[first], first)) { |
| 105 return first; | 106 return first; |
| 107 } |
| 106 if (loVal >= mapLoFn(ary[first - 1]) && | 108 if (loVal >= mapLoFn(ary[first - 1]) && |
| 107 loVal < mapLoFn(ary[first - 1]) + | 109 loVal < mapLoFn(ary[first - 1]) + |
| 108 mapWidthFn(ary[first - 1], first - 1)) | 110 mapWidthFn(ary[first - 1], first - 1)) { |
| 109 return first - 1; | 111 return first - 1; |
| 112 } |
| 110 return ary.length; | 113 return ary.length; |
| 111 } | 114 } |
| 112 | 115 |
| 113 if (first === ary.length) { | 116 if (first === ary.length) { |
| 114 if (loVal >= mapLoFn(ary[first - 1]) && | 117 if (loVal >= mapLoFn(ary[first - 1]) && |
| 115 loVal < mapLoFn(ary[first - 1]) + | 118 loVal < mapLoFn(ary[first - 1]) + |
| 116 mapWidthFn(ary[first - 1], first - 1)) | 119 mapWidthFn(ary[first - 1], first - 1)) { |
| 117 return first - 1; | 120 return first - 1; |
| 121 } |
| 118 return ary.length; | 122 return ary.length; |
| 119 } | 123 } |
| 120 | 124 |
| 121 return ary.length; | 125 return ary.length; |
| 122 } | 126 } |
| 123 | 127 |
| 124 /** | 128 /** |
| 125 * Finds an index in an array of sorted closed intervals that either | 129 * Finds an index in an array of sorted closed intervals that either |
| 126 * intersects the provided val, or if no intersection is found, -1 or | 130 * intersects the provided val, or if no intersection is found, -1 or |
| 127 * ary.length. | 131 * ary.length. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 142 * interval represented by an element in the array. | 146 * interval represented by an element in the array. |
| 143 * @param {number} val The value for the search. | 147 * @param {number} val The value for the search. |
| 144 * @return {Number} An index in the array that intersects or is first-above | 148 * @return {Number} An index in the array that intersects or is first-above |
| 145 * val, -1 if none found and val is below than all the intervals, | 149 * val, -1 if none found and val is below than all the intervals, |
| 146 * ary.length if val is greater than all the intervals. | 150 * ary.length if val is greater than all the intervals. |
| 147 */ | 151 */ |
| 148 function findIndexInSortedClosedIntervals(ary, mapLoFn, mapHiFn, val) { | 152 function findIndexInSortedClosedIntervals(ary, mapLoFn, mapHiFn, val) { |
| 149 var i = findLowIndexInSortedArray(ary, mapLoFn, val); | 153 var i = findLowIndexInSortedArray(ary, mapLoFn, val); |
| 150 if (i === 0) { | 154 if (i === 0) { |
| 151 if (val >= mapLoFn(ary[0], 0) && | 155 if (val >= mapLoFn(ary[0], 0) && |
| 152 val <= mapHiFn(ary[0], 0)) | 156 val <= mapHiFn(ary[0], 0)) { |
| 153 return 0; | 157 return 0; |
| 158 } |
| 154 return -1; | 159 return -1; |
| 155 } | 160 } |
| 156 | 161 |
| 157 if (i < ary.length) { | 162 if (i < ary.length) { |
| 158 if (val >= mapLoFn(ary[i - 1], i - 1) && | 163 if (val >= mapLoFn(ary[i - 1], i - 1) && |
| 159 val <= mapHiFn(ary[i - 1], i - 1)) | 164 val <= mapHiFn(ary[i - 1], i - 1)) { |
| 160 return i - 1; | 165 return i - 1; |
| 166 } |
| 161 if (val >= mapLoFn(ary[i], i) && | 167 if (val >= mapLoFn(ary[i], i) && |
| 162 val <= mapHiFn(ary[i], i)) | 168 val <= mapHiFn(ary[i], i)) { |
| 163 return i; | 169 return i; |
| 170 } |
| 164 return ary.length; | 171 return ary.length; |
| 165 } | 172 } |
| 166 | 173 |
| 167 if (i === ary.length) { | 174 if (i === ary.length) { |
| 168 if (val >= mapLoFn(ary[i - 1], i - 1) && | 175 if (val >= mapLoFn(ary[i - 1], i - 1) && |
| 169 val <= mapHiFn(ary[i - 1], i - 1)) | 176 val <= mapHiFn(ary[i - 1], i - 1)) { |
| 170 return i - 1; | 177 return i - 1; |
| 178 } |
| 171 return ary.length; | 179 return ary.length; |
| 172 } | 180 } |
| 173 | 181 |
| 174 return ary.length; | 182 return ary.length; |
| 175 } | 183 } |
| 176 | 184 |
| 177 /** | 185 /** |
| 178 * Calls cb for all intervals in the implicit array of intervals | 186 * Calls cb for all intervals in the implicit array of intervals |
| 179 * defnied by ary, mapLoFn and mapHiFn that intersect the range | 187 * defnied by ary, mapLoFn and mapHiFn that intersect the range |
| 180 * [loVal,hiVal) | 188 * [loVal,hiVal) |
| 181 * | 189 * |
| 182 * This function uses the same scheme as findLowIndexInSortedArray | 190 * This function uses the same scheme as findLowIndexInSortedArray |
| 183 * to define the intervals. The same restrictions on sortedness and | 191 * to define the intervals. The same restrictions on sortedness and |
| 184 * non-overlappingness apply. | 192 * non-overlappingness apply. |
| 185 * | 193 * |
| 186 * @param {Array} ary An array of objects that can be converted into sorted | 194 * @param {Array} ary An array of objects that can be converted into sorted |
| 187 * nonoverlapping ranges [x,y) using the mapLoFn and mapWidth. | 195 * nonoverlapping ranges [x,y) using the mapLoFn and mapWidth. |
| 188 * @param {function():*} mapLoFn Callback that produces the low value for the | 196 * @param {function():*} mapLoFn Callback that produces the low value for the |
| 189 * interval represented by an element in the array. | 197 * interval represented by an element in the array. |
| 190 * @param {function():*} mapWidthFn Callback that produces the width for the | 198 * @param {function():*} mapWidthFn Callback that produces the width for the |
| 191 * interval represented by an element in the array. | 199 * interval represented by an element in the array. |
| 192 * @param {number} loVal The low value for the search, inclusive. | 200 * @param {number} loVal The low value for the search, inclusive. |
| 193 * @param {number} hiVal The high value for the search, non inclusive. | 201 * @param {number} hiVal The high value for the search, non inclusive. |
| 194 * @param {function():*} cb The function to run for intersecting intervals. | 202 * @param {function():*} cb The function to run for intersecting intervals. |
| 195 */ | 203 */ |
| 196 function iterateOverIntersectingIntervals(ary, mapLoFn, mapWidthFn, loVal, | 204 function iterateOverIntersectingIntervals(ary, mapLoFn, mapWidthFn, loVal, |
| 197 hiVal, cb) { | 205 hiVal, cb) { |
| 198 if (ary.length === 0) | 206 if (ary.length === 0) return; |
| 199 return; | |
| 200 | 207 |
| 201 if (loVal > hiVal) return; | 208 if (loVal > hiVal) return; |
| 202 | 209 |
| 203 var i = findLowIndexInSortedArray(ary, mapLoFn, loVal); | 210 var i = findLowIndexInSortedArray(ary, mapLoFn, loVal); |
| 204 if (i === -1) { | 211 if (i === -1) { |
| 205 return; | 212 return; |
| 206 } | 213 } |
| 207 if (i > 0) { | 214 if (i > 0) { |
| 208 var hi = mapLoFn(ary[i - 1]) + mapWidthFn(ary[i - 1], i - 1); | 215 var hi = mapLoFn(ary[i - 1]) + mapWidthFn(ary[i - 1], i - 1); |
| 209 if (hi >= loVal) { | 216 if (hi >= loVal) { |
| 210 cb(ary[i - 1], i - 1); | 217 cb(ary[i - 1], i - 1); |
| 211 } | 218 } |
| 212 } | 219 } |
| 213 if (i === ary.length) { | 220 if (i === ary.length) { |
| 214 return; | 221 return; |
| 215 } | 222 } |
| 216 | 223 |
| 217 for (var n = ary.length; i < n; i++) { | 224 for (var n = ary.length; i < n; i++) { |
| 218 var lo = mapLoFn(ary[i]); | 225 var lo = mapLoFn(ary[i]); |
| 219 if (lo >= hiVal) | 226 if (lo >= hiVal) break; |
| 220 break; | |
| 221 cb(ary[i], i); | 227 cb(ary[i], i); |
| 222 } | 228 } |
| 223 } | 229 } |
| 224 | 230 |
| 225 /** | 231 /** |
| 226 * Non iterative version of iterateOverIntersectingIntervals. | 232 * Non iterative version of iterateOverIntersectingIntervals. |
| 227 * | 233 * |
| 228 * @return {Array} Array of elements in ary that intersect loVal, hiVal. | 234 * @return {Array} Array of elements in ary that intersect loVal, hiVal. |
| 229 */ | 235 */ |
| 230 function getIntersectingIntervals(ary, mapLoFn, mapWidthFn, loVal, hiVal) { | 236 function getIntersectingIntervals(ary, mapLoFn, mapWidthFn, loVal, hiVal) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 244 * @param {Array} ary An array of arbitrary objects. | 250 * @param {Array} ary An array of arbitrary objects. |
| 245 * @param {function():*} mapFn Callback that produces a key value | 251 * @param {function():*} mapFn Callback that produces a key value |
| 246 * from an element in ary. | 252 * from an element in ary. |
| 247 * @param {number} val Value for which to search. | 253 * @param {number} val Value for which to search. |
| 248 * @param {number} maxDiff Maximum allowed difference in value between |val| | 254 * @param {number} maxDiff Maximum allowed difference in value between |val| |
| 249 * and an element's value. | 255 * and an element's value. |
| 250 * @return {object} Object in the array whose value is closest to |val|, or | 256 * @return {object} Object in the array whose value is closest to |val|, or |
| 251 * null if no object is within range. | 257 * null if no object is within range. |
| 252 */ | 258 */ |
| 253 function findClosestElementInSortedArray(ary, mapFn, val, maxDiff) { | 259 function findClosestElementInSortedArray(ary, mapFn, val, maxDiff) { |
| 254 if (ary.length === 0) | 260 if (ary.length === 0) return null; |
| 255 return null; | |
| 256 | 261 |
| 257 var aftIdx = findLowIndexInSortedArray(ary, mapFn, val); | 262 var aftIdx = findLowIndexInSortedArray(ary, mapFn, val); |
| 258 var befIdx = aftIdx > 0 ? aftIdx - 1 : 0; | 263 var befIdx = aftIdx > 0 ? aftIdx - 1 : 0; |
| 259 | 264 |
| 260 if (aftIdx === ary.length) | 265 if (aftIdx === ary.length) aftIdx -= 1; |
| 261 aftIdx -= 1; | |
| 262 | 266 |
| 263 var befDiff = Math.abs(val - mapFn(ary[befIdx])); | 267 var befDiff = Math.abs(val - mapFn(ary[befIdx])); |
| 264 var aftDiff = Math.abs(val - mapFn(ary[aftIdx])); | 268 var aftDiff = Math.abs(val - mapFn(ary[aftIdx])); |
| 265 | 269 |
| 266 if (befDiff > maxDiff && aftDiff > maxDiff) | 270 if (befDiff > maxDiff && aftDiff > maxDiff) return null; |
| 267 return null; | |
| 268 | 271 |
| 269 var idx = befDiff < aftDiff ? befIdx : aftIdx; | 272 var idx = befDiff < aftDiff ? befIdx : aftIdx; |
| 270 return ary[idx]; | 273 return ary[idx]; |
| 271 } | 274 } |
| 272 | 275 |
| 273 /** | 276 /** |
| 274 * Finds the closest interval in the implicit array of intervals | 277 * Finds the closest interval in the implicit array of intervals |
| 275 * defined by ary, mapLoFn and mapHiFn. | 278 * defined by ary, mapLoFn and mapHiFn. |
| 276 * | 279 * |
| 277 * This function uses the same scheme as findLowIndexInSortedArray | 280 * This function uses the same scheme as findLowIndexInSortedArray |
| 278 * to define the intervals. The same restrictions on sortedness and | 281 * to define the intervals. The same restrictions on sortedness and |
| 279 * non-overlappingness apply. | 282 * non-overlappingness apply. |
| 280 * | 283 * |
| 281 * @param {Array} ary An array of objects that can be converted into sorted | 284 * @param {Array} ary An array of objects that can be converted into sorted |
| 282 * nonoverlapping ranges [x,y) using the mapLoFn and mapHiFn. | 285 * nonoverlapping ranges [x,y) using the mapLoFn and mapHiFn. |
| 283 * @param {function():*} mapLoFn Callback that produces the low value for the | 286 * @param {function():*} mapLoFn Callback that produces the low value for the |
| 284 * interval represented by an element in the array. | 287 * interval represented by an element in the array. |
| 285 * @param {function():*} mapHiFn Callback that produces the high for the | 288 * @param {function():*} mapHiFn Callback that produces the high for the |
| 286 * interval represented by an element in the array. | 289 * interval represented by an element in the array. |
| 287 * @param {number} val The value for the search. | 290 * @param {number} val The value for the search. |
| 288 * @param {number} maxDiff Maximum allowed difference in value between |val| | 291 * @param {number} maxDiff Maximum allowed difference in value between |val| |
| 289 * and an interval's low or high value. | 292 * and an interval's low or high value. |
| 290 * @return {interval} Interval in the array whose high or low value is closest | 293 * @return {interval} Interval in the array whose high or low value is closest |
| 291 * to |val|, or null if no interval is within range. | 294 * to |val|, or null if no interval is within range. |
| 292 */ | 295 */ |
| 293 function findClosestIntervalInSortedIntervals(ary, mapLoFn, mapHiFn, val, | 296 function findClosestIntervalInSortedIntervals(ary, mapLoFn, mapHiFn, val, |
| 294 maxDiff) { | 297 maxDiff) { |
| 295 if (ary.length === 0) | 298 if (ary.length === 0) return null; |
| 296 return null; | |
| 297 | 299 |
| 298 var idx = findLowIndexInSortedArray(ary, mapLoFn, val); | 300 var idx = findLowIndexInSortedArray(ary, mapLoFn, val); |
| 299 if (idx > 0) | 301 if (idx > 0) idx -= 1; |
| 300 idx -= 1; | |
| 301 | 302 |
| 302 var hiInt = ary[idx]; | 303 var hiInt = ary[idx]; |
| 303 var loInt = hiInt; | 304 var loInt = hiInt; |
| 304 | 305 |
| 305 if (val > mapHiFn(hiInt) && idx + 1 < ary.length) | 306 if (val > mapHiFn(hiInt) && idx + 1 < ary.length) { |
| 306 loInt = ary[idx + 1]; | 307 loInt = ary[idx + 1]; |
| 308 } |
| 307 | 309 |
| 308 var loDiff = Math.abs(val - mapLoFn(loInt)); | 310 var loDiff = Math.abs(val - mapLoFn(loInt)); |
| 309 var hiDiff = Math.abs(val - mapHiFn(hiInt)); | 311 var hiDiff = Math.abs(val - mapHiFn(hiInt)); |
| 310 | 312 |
| 311 if (loDiff > maxDiff && hiDiff > maxDiff) | 313 if (loDiff > maxDiff && hiDiff > maxDiff) return null; |
| 312 return null; | |
| 313 | 314 |
| 314 if (loDiff < hiDiff) | 315 if (loDiff < hiDiff) return loInt; |
| 315 return loInt; | |
| 316 | 316 |
| 317 return hiInt; | 317 return hiInt; |
| 318 } | 318 } |
| 319 | 319 |
| 320 return { | 320 return { |
| 321 findLowIndexInSortedArray, | 321 findLowIndexInSortedArray, |
| 322 findHighIndexInSortedArray, | 322 findHighIndexInSortedArray, |
| 323 findIndexInSortedIntervals, | 323 findIndexInSortedIntervals, |
| 324 findIndexInSortedClosedIntervals, | 324 findIndexInSortedClosedIntervals, |
| 325 iterateOverIntersectingIntervals, | 325 iterateOverIntersectingIntervals, |
| 326 getIntersectingIntervals, | 326 getIntersectingIntervals, |
| 327 findClosestElementInSortedArray, | 327 findClosestElementInSortedArray, |
| 328 findClosestIntervalInSortedIntervals, | 328 findClosestIntervalInSortedIntervals, |
| 329 }; | 329 }; |
| 330 }); | 330 }); |
| 331 </script> | 331 </script> |
| OLD | NEW |