blob: 3ff3f1de546ee0a07988499bc9bd2af8f6222904 [file] [log] [blame]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:typed_data';
// Based on (as in mostly a copy from) the _IntervalListBuilder in
// package:kernel/class_hierarchy.dart.
class IntervalListBuilder {
final List<int> _events = <int>[];
void addIntervalIncludingEnd(int start, int end) {
// Add an event point for each interval end point, using the low bit to
// distinguish opening from closing end points. Closing end points should
// have the high bit to ensure they occur after an opening end point.
_events.add(start << 1);
// Add 1 to include the end.
_events.add(((end + 1) << 1) + 1);
}
void addIntervalExcludingEnd(int start, int end) {
// Add an event point for each interval end point, using the low bit to
// distinguish opening from closing end points. Closing end points should
// have the high bit to ensure they occur after an opening end point.
_events.add(start << 1);
_events.add((end << 1) + 1);
}
void addSingleton(int x) {
addIntervalExcludingEnd(x, x + 1);
}
IntervalList buildIntervalList() {
// Sort the event points and sweep left to right while tracking how many
// intervals we are currently inside. Record an interval end point when the
// number of intervals drop to zero or increase from zero to one.
// Event points are encoded so that an opening end point occur before a
// closing end point at the same value.
_events.sort();
int insideCount = 0; // The number of intervals we are currently inside.
int storeIndex = 0;
for (int i = 0; i < _events.length; ++i) {
int event = _events[i];
if (event & 1 == 0) {
// Start point
++insideCount;
if (insideCount == 1) {
// Store the results temporarily back in the event array.
_events[storeIndex++] = event >> 1;
}
} else {
// End point
--insideCount;
if (insideCount == 0) {
_events[storeIndex++] = event >> 1;
}
}
}
// Copy the results over to a typed array of the correct length.
Uint32List result = new Uint32List(storeIndex);
for (int i = 0; i < storeIndex; ++i) {
result[i] = _events[i];
}
return new IntervalList._(result);
}
}
class IntervalList {
final Uint32List _intervalList;
IntervalList._(this._intervalList);
bool get isEmpty => _intervalList.isEmpty;
bool contains(int x) {
int low = 0, high = _intervalList.length - 1;
if (high == -1 || x < _intervalList[0] || _intervalList[high] <= x) {
return false;
}
// Find the lower bound of x in the list.
// If the lower bound is at an even index, the lower bound is an opening
// point of an interval that contains x, otherwise it is a closing point of
// an interval below x and there is no interval containing x.
while (low < high) {
int mid = high - ((high - low) >> 1); // Get middle, rounding up.
int pivot = _intervalList[mid];
if (pivot <= x) {
low = mid;
} else {
high = mid - 1;
}
}
return low == high && (low & 1) == 0;
}
}