Skip to content

Commit

Permalink
When growing a BitList make sure all newly exposed values are properl…
Browse files Browse the repository at this point in the history
…y initialized.
  • Loading branch information
renggli committed Sep 3, 2023
1 parent 5a8f72d commit 71a4f80
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 20 deletions.
48 changes: 28 additions & 20 deletions lib/src/collection/bitlist.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,26 +107,7 @@ abstract class BitList extends ListBase<bool> {
@override
void fillRange(int start, int end, [bool? fill]) {
RangeError.checkValidRange(start, end, length);
if (start == end) return;
final startIndex = start >> bitShift, startBit = start & bitOffset;
final endIndex = (end - 1) >> bitShift, endBit = (end - 1) & bitOffset;
if (startIndex == endIndex) {
if (fill == true) {
buffer[startIndex] |= ((1 << (endBit - startBit + 1)) - 1) << startBit;
} else {
buffer[startIndex] &= ((1 << startBit) - 1) | (bitMask << (endBit + 1));
}
} else {
if (fill == true) {
buffer[startIndex] |= bitMask << startBit;
buffer.fillRange(startIndex + 1, endIndex, bitMask);
buffer[endIndex] |= (1 << (endBit + 1)) - 1;
} else {
buffer[startIndex] &= (1 << startBit) - 1;
buffer.fillRange(startIndex + 1, endIndex, 0);
buffer[endIndex] &= bitMask << (endBit + 1);
}
}
_fillRange(buffer, start, end, fill ?? false);
}

/// Sets the bit at the specified [index] to the complement of its current
Expand Down Expand Up @@ -332,6 +313,10 @@ class GrowableBitList extends BitList {
newBuffer.setRange(0, newBuffer.length, buffer);
buffer = newBuffer;
}
if (_length < length) {
// When growing, make sure we always have predictable state.
_fillRange(buffer, _length, length, false);
}
_length = length;
}
}
Expand Down Expand Up @@ -425,3 +410,26 @@ const List<int> bitClearMask = [
-1073741825,
-2147483649
];

void _fillRange(Uint32List buffer, int start, int end, bool? fill) {
if (start == end) return;
final startIndex = start >> bitShift, startBit = start & bitOffset;
final endIndex = (end - 1) >> bitShift, endBit = (end - 1) & bitOffset;
if (startIndex == endIndex) {
if (fill == true) {
buffer[startIndex] |= ((1 << (endBit - startBit + 1)) - 1) << startBit;
} else {
buffer[startIndex] &= ((1 << startBit) - 1) | (bitMask << (endBit + 1));
}
} else {
if (fill == true) {
buffer[startIndex] |= bitMask << startBit;
buffer.fillRange(startIndex + 1, endIndex, bitMask);
buffer[endIndex] |= (1 << (endBit + 1)) - 1;
} else {
buffer[startIndex] &= (1 << startBit) - 1;
buffer.fillRange(startIndex + 1, endIndex, 0);
buffer[endIndex] &= bitMask << (endBit + 1);
}
}
}
17 changes: 17 additions & 0 deletions test/collection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,23 @@ void main() {
target.length -= 2;
expect(target.buffer, same(buffer));
});
test('length (cleared)', () {
final generator = Random(584);
for (var i = 0; i < 0xff; i++) {
final original = 1 + generator.nextInt(0xff);
final smaller = generator.nextInt(original);
final larger = original + generator.nextInt(0xff);
final target = BitList.filled(original, true, growable: growable);
target.length = smaller;
target.length = larger;
for (var i = 0; i < smaller; i++) {
expect(target[i], isTrue);
}
for (var i = smaller; i < larger; i++) {
expect(target[i], isFalse);
}
}
});
test('removeLast', () {
final source = randomBooleans(453, 500);
final target = BitList.of(source, growable: growable);
Expand Down

0 comments on commit 71a4f80

Please sign in to comment.