| 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 |