OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple Inc. All rights reserved. |
3 * Copyright (C) 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2012 Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * | 8 * |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 1546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1557 * @param {T} defaultValue | 1557 * @param {T} defaultValue |
1558 * @return {!Promise.<T>} | 1558 * @return {!Promise.<T>} |
1559 * @template T | 1559 * @template T |
1560 */ | 1560 */ |
1561 Promise.prototype.catchException = function(defaultValue) { | 1561 Promise.prototype.catchException = function(defaultValue) { |
1562 return this.catch(function (error) { | 1562 return this.catch(function (error) { |
1563 console.error(error); | 1563 console.error(error); |
1564 return defaultValue; | 1564 return defaultValue; |
1565 }); | 1565 }); |
1566 } | 1566 } |
1567 | |
1568 /** | |
1569 * @constructor | |
1570 * @param {(function(!Segment, !Segment): ?Segment)=} mergeCallback | |
1571 */ | |
1572 function SegmentedRange(mergeCallback) | |
1573 { | |
1574 /** @type {!Array<!Segment>} */ | |
1575 this._segments = []; | |
1576 this._mergeCallback = mergeCallback; | |
1577 } | |
1578 | |
1579 /** | |
1580 * @constructor | |
1581 * @param {number} begin | |
1582 * @param {number} end | |
1583 * @param {*} data | |
1584 */ | |
1585 function Segment(begin, end, data) | |
1586 { | |
1587 if (begin > end) | |
1588 console.assert(false, "Invalid segment"); | |
1589 this.begin = begin; | |
1590 this.end = end; | |
1591 this.data = data; | |
1592 } | |
1593 | |
1594 Segment.prototype = { | |
1595 /** | |
1596 * @param {!Segment} that | |
1597 * @return {boolean} | |
1598 */ | |
1599 intersects: function(that) | |
1600 { | |
1601 return this.begin < that.end && that.begin < this.end; | |
1602 } | |
1603 }; | |
1604 | |
1605 SegmentedRange.prototype = { | |
1606 /** | |
1607 * @param {!Segment} newSegment | |
1608 */ | |
1609 append: function(newSegment) | |
1610 { | |
1611 // 1. Find the proper insertion point for new segment | |
1612 var startIndex = this._segments.lowerBound(newSegment, (a, b) => a.begin
- b.begin); | |
1613 var endIndex = startIndex; | |
1614 var merged = null; | |
1615 if (startIndex > 0) { | |
1616 // 2. Try mering the preceding segment | |
1617 var precedingSegment = this._segments[startIndex - 1]; | |
1618 merged = this._tryMerge(precedingSegment, newSegment); | |
1619 if (merged) { | |
1620 --startIndex; | |
1621 newSegment = merged; | |
1622 } else if (this._segments[startIndex - 1].end >= newSegment.begin) { | |
1623 // 2a. If merge failed and segments overlap, adjust preceding se
gment. | |
1624 // If an old segment entirely contains new one, split it in two. | |
1625 if (newSegment.end < precedingSegment.end) | |
1626 this._segments.splice(startIndex, 0, new Segment(newSegment.
end, precedingSegment.end, precedingSegment.data)); | |
1627 precedingSegment.end = newSegment.begin; | |
1628 } | |
1629 } | |
1630 // 3. Consume all segments that are entirely covered by the new one. | |
1631 while (endIndex < this._segments.length && this._segments[endIndex].end
<= newSegment.end) | |
1632 ++endIndex; | |
1633 // 4. Merge or adjust the succeeding segment if it overlaps. | |
1634 if (endIndex < this._segments.length) { | |
1635 merged = this._tryMerge(newSegment, this._segments[endIndex]); | |
1636 if (merged) { | |
1637 endIndex++; | |
1638 newSegment = merged; | |
1639 } else if (newSegment.intersects(this._segments[endIndex])) | |
1640 this._segments[endIndex].begin = newSegment.end; | |
1641 } | |
1642 this._segments.splice(startIndex, endIndex - startIndex, newSegment); | |
1643 }, | |
1644 | |
1645 /** | |
1646 * @param {!SegmentedRange} that | |
1647 */ | |
1648 appendRange: function(that) | |
1649 { | |
1650 that.segments().forEach(segment => this.append(segment)); | |
1651 }, | |
1652 | |
1653 /** | |
1654 * @return {!Array<!Segment>} | |
1655 */ | |
1656 segments: function() | |
1657 { | |
1658 return this._segments; | |
1659 }, | |
1660 | |
1661 /** | |
1662 * @param {!Segment} first | |
1663 * @param {!Segment} second | |
1664 * @return {?Segment} | |
1665 */ | |
1666 _tryMerge: function(first, second) | |
1667 { | |
1668 var merged = this._mergeCallback && this._mergeCallback(first, second); | |
1669 if (!merged) | |
1670 return null; | |
1671 merged.begin = first.begin; | |
1672 merged.end = Math.max(first.end, second.end); | |
1673 return merged; | |
1674 } | |
1675 } | |
OLD | NEW |