OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 cr.define('media', function() { | |
6 | |
7 /** | |
8 * This class represents a collection of non-intersecting ranges. Ranges | |
9 * specified by (start, end) can be added and removed at will. It is used to | |
10 * record which sections of a media file have been cached, e.g. the first and | |
11 * last few kB plus several MB in the middle. | |
12 * | |
13 * Example usage: | |
14 * someRange.add(0, 100); // Contains 0-100. | |
15 * someRange.add(150, 200); // Contains 0-100, 150-200. | |
16 * someRange.remove(25, 75); // Contains 0-24, 76-100, 150-200. | |
17 * someRange.add(25, 149); // Contains 0-200. | |
18 */ | |
19 function DisjointRangeSet() { | |
20 this.ranges_ = {}; | |
21 } | |
22 | |
23 DisjointRangeSet.prototype = { | |
24 /** | |
25 * Deletes all ranges intersecting with (start ... end) and returns the | |
26 * extents of the cleared area. | |
27 * @param {int} start The start of the range to remove. | |
28 * @param {int} end The end of the range to remove. | |
29 * @param {int} sloppiness 0 removes only strictly overlapping ranges, and | |
30 * 1 removes adjacent ones. | |
31 * @return {Object} The start and end of the newly cleared range. | |
32 */ | |
33 clearRange: function(start, end, sloppiness) { | |
34 var ranges = this.ranges_; | |
35 var result = {start: start, end: end}; | |
36 | |
37 for (var rangeStart in this.ranges_) { | |
38 rangeEnd = this.ranges_[rangeStart]; | |
39 // A range intersects another if its start lies within the other range | |
40 // or vice versa. | |
41 if ((rangeStart >= start && rangeStart <= (end + sloppiness)) || | |
42 (start >= rangeStart && start <= (rangeEnd + sloppiness))) { | |
43 delete ranges[rangeStart]; | |
44 result.start = Math.min(result.start, rangeStart); | |
45 result.end = Math.max(result.end, rangeEnd); | |
46 } | |
47 } | |
48 | |
49 return result; | |
50 }, | |
51 | |
52 /** | |
53 * Adds a range to this DisjointRangeSet. | |
54 * Joins adjacent and overlapping ranges together. | |
55 * @param {int} start The beginning of the range to add, inclusive. | |
56 * @param {int} end The end of the range to add, inclusive. | |
57 */ | |
58 add: function(start, end) { | |
59 if (end < start) | |
60 return; | |
61 | |
62 // Remove all touching ranges. | |
63 result = this.clearRange(start, end, 1); | |
64 // Add back a single contiguous range. | |
65 this.ranges_[Math.min(start, result.start)] = Math.max(end, result.end); | |
66 }, | |
67 | |
68 /** | |
69 * Combines a DisjointRangeSet with this one. | |
70 * @param {DisjointRangeSet} ranges A DisjointRangeSet to be squished into | |
71 * this one. | |
72 */ | |
73 merge: function(other) { | |
74 var ranges = this; | |
75 other.forEach(function(start, end) { ranges.add(start, end); }); | |
76 }, | |
77 | |
78 /** | |
79 * Removes a range from this DisjointRangeSet. | |
80 * Will split existing ranges if necessary. | |
81 * @param {int} start The beginning of the range to remove, inclusive. | |
82 * @param {int} end The end of the range to remove, inclusive. | |
83 */ | |
84 remove: function(start, end) { | |
85 if (end < start) | |
86 return; | |
87 | |
88 // Remove instersecting ranges. | |
89 result = this.clearRange(start, end, 0); | |
90 | |
91 // Add back non-overlapping ranges. | |
92 if (result.start < start) | |
93 this.ranges_[result.start] = start - 1; | |
94 if (result.end > end) | |
95 this.ranges_[end + 1] = result.end; | |
96 }, | |
97 | |
98 /** | |
99 * Iterates over every contiguous range in this DisjointRangeSet, calling a | |
100 * function for each (start, end). | |
101 * @param {function(int, int)} iterator The function to call on each range. | |
102 */ | |
103 forEach: function(iterator) { | |
104 for (var start in this.ranges_) | |
105 iterator(start, this.ranges_[start]); | |
106 }, | |
107 | |
108 /** | |
109 * Maps this DisjointRangeSet to an array by calling a given function on the | |
110 * start and end of each contiguous range, sorted by start. | |
111 * @param {function(int, int)} mapper Maps a range to an array element. | |
112 * @return {Array} An array of each mapper(range). | |
113 */ | |
114 map: function(mapper) { | |
115 var starts = []; | |
116 for (var start in this.ranges_) | |
117 starts.push(parseInt(start)); | |
118 starts.sort(function(a, b) { | |
119 return a - b; | |
120 }); | |
121 | |
122 var ranges = this.ranges_; | |
123 var results = starts.map(function(s) { | |
124 return mapper(s, ranges[s]); | |
125 }); | |
126 | |
127 return results; | |
128 }, | |
129 | |
130 /** | |
131 * Finds the maximum value present in any of the contained ranges. | |
132 * @return {int} The maximum value contained by this DisjointRangeSet. | |
133 */ | |
134 max: function() { | |
135 var max = -Infinity; | |
136 for (var start in this.ranges_) | |
137 max = Math.max(max, this.ranges_[start]); | |
138 return max; | |
139 }, | |
140 }; | |
141 | |
142 return { | |
143 DisjointRangeSet: DisjointRangeSet | |
144 }; | |
145 }); | |
OLD | NEW |