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.
5 cr
.define('media', function() {
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.
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.
19 function DisjointRangeSet() {
23 DisjointRangeSet
.prototype = {
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.
33 clearRange: function(start
, end
, sloppiness
) {
34 var ranges
= this.ranges_
;
35 var result
= {start
: start
, end
: end
};
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
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
);
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.
58 add: function(start
, end
) {
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
);
69 * Combines a DisjointRangeSet with this one.
70 * @param {DisjointRangeSet} ranges A DisjointRangeSet to be squished into
73 merge: function(other
) {
75 other
.forEach(function(start
, end
) { ranges
.add(start
, end
); });
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.
84 remove: function(start
, end
) {
88 // Remove instersecting ranges.
89 result
= this.clearRange(start
, end
, 0);
91 // Add back non-overlapping ranges.
92 if (result
.start
< start
)
93 this.ranges_
[result
.start
] = start
- 1;
95 this.ranges_
[end
+ 1] = result
.end
;
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.
103 forEach: function(iterator
) {
104 for (var start
in this.ranges_
)
105 iterator(start
, this.ranges_
[start
]);
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).
114 map: function(mapper
) {
116 for (var start
in this.ranges_
)
117 starts
.push(parseInt(start
));
118 starts
.sort(function(a
, b
) {
122 var ranges
= this.ranges_
;
123 var results
= starts
.map(function(s
) {
124 return mapper(s
, ranges
[s
]);
131 * Finds the maximum value present in any of the contained ranges.
132 * @return {int} The maximum value contained by this DisjointRangeSet.
136 for (var start
in this.ranges_
)
137 max
= Math
.max(max
, this.ranges_
[start
]);
143 DisjointRangeSet
: DisjointRangeSet