blob: 4cc567b88f4b48794175816bc05fc1c5251e2879 [file] [log] [blame]
// Copyright (c) 2020, 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:collection' show SetBase;
import 'dart:typed_data';
/// Creates an empty set of non-negative integers.
///
/// The [maxElements] it must be no larger than [maxSupportedElements].
/// Then the resulting set can only contain integers which
/// are non-negative and *less than* [maxElements].
///
/// The set is backed directly by as many bits as necessary.
/// A verly large value for [maxElements] may not be supported by the
/// underlying system.
Set<int> bitSet(int maxElements) {
RangeError.checkNotNegative(maxElements, "maxElements");
return _DenseBitSet(maxElements);
}
class _DenseBitSet extends SetBase<int> {
final int _maxElements;
final Uint8List _bits;
int _elementCount = 0;
_DenseBitSet(this._maxElements) : _bits = Uint8List((_maxElements + 7) ~/ 8);
// Used by [toSet].
_DenseBitSet._(this._maxElements, this._elementCount, this._bits);
bool add(int value) {
RangeError.checkValidIndex(value, this, "value", _maxElements);
var mask = 1 << (value & 7);
int index = value ~/ 8;
int byte = _bits[index];
if (byte & mask == 0) {
_bits[index] = byte + mask;
_elementCount++;
return true;
}
return false;
}
bool contains(Object element) {
if (element is int) {
if (element < 0 || element >= _maxElements) return false;
return _contains(element);
}
return false;
}
bool _contains(int element) =>
_bits[element ~/ 8] & (1 << (element & 7)) != 0;
Iterable<int> get _elements sync* {
int index = 0;
for (int i = 0; i < _bits.length; i++) {
int byte = _bits[i];
if (byte != 0) {
for (int j = 0, bit = 1; j < 8; bit += bit, j++) {
if (byte & bit != 0) yield index;
index++;
}
} else {
index += 8;
}
}
}
Iterator<int> get iterator => _elements.iterator;
int get length => _elementCount;
@override
int/*?*/ lookup(Object element) {
if (element is int) {
if (element < 0 || element >= _maxElements) return null;
if (_contains(element)) return element;
}
return null;
}
@override
bool remove(Object value) {
if (value is int) {
if (value < 0 || value >= _maxElements) return false;
var mask = 1 << (value & 7);
int index = value ~/ 8;
int byte = _bits[index];
if (byte & mask == 1) {
_bits[index] = byte - mask;
_elementCount--;
return true;
}
}
return false;
}
Set<int> toSet() =>
_DenseBitSet._(_maxElements, _elementCount, Uint8List.fromList(_bits));
}