Skip to content

Commit

Permalink
Add logical operator andNot, and, or and xor
Browse files Browse the repository at this point in the history
Also add from constructor which creates a new BitVector instance
from the given BitVector.
  • Loading branch information
Kwang Yul Seo committed Oct 15, 2016
1 parent 95abb02 commit 091b38d
Show file tree
Hide file tree
Showing 2 changed files with 245 additions and 2 deletions.
79 changes: 77 additions & 2 deletions lib/src/bit_vector_base.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2016, Kwang Yul Seo. 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:math' show max;
import 'dart:math' show max, min;
import 'dart:typed_data';

import 'package:fixnum/fixnum.dart';
Expand Down Expand Up @@ -55,6 +55,11 @@ class BitVector {
_initWord(length);
}

/// Creates a new [BitVector] instance that is equal to [other].
BitVector.from(BitVector other)
: _words = new Int64List.fromList(other._words),
_wordsInUse = other._wordsInUse;

void _initWord(int length) {
_words = new Int64List(_wordIndex(length - 1) + 1);
}
Expand All @@ -67,7 +72,6 @@ class BitVector {
int wordIndex = _wordIndex(bitIndex);
return (wordIndex < _wordsInUse) &&
((_words[wordIndex] & (1 << (bitIndex & _bitMask)) != 0));

}

/// Sets the bit at the specified index to true.
Expand Down Expand Up @@ -114,6 +118,77 @@ class BitVector {
}
}

/// Performs a logical `and`.
void and(BitVector other) {
if (identical(this, other)) return;

while (_wordsInUse > other._wordsInUse) {
_words[--_wordsInUse] = 0;
}

for (var i = 0; i < _wordsInUse; i++) {
_words[i] &= other._words[i];
}

_recalculateWordsInUse();
}

/// Performs a logical `or`.
void or(BitVector other) {
if (identical(this, other)) return;

int wordsInCommon = min(_wordsInUse, other._wordsInUse);

if (_wordsInUse < other._wordsInUse) {
_ensureCapacity(other._wordsInUse);
_wordsInUse = other._wordsInUse;
}

for (var i = 0; i < wordsInCommon; i++) {
_words[i] |= other._words[i];
}

// Copy any remaining words
if (wordsInCommon < other._wordsInUse) {
_words.setRange(
wordsInCommon, other._wordsInUse, other._words, wordsInCommon);
}

// _recalculateWordsInUse() is not necessary
}

/// Performs a logical `xor`.
void xor(BitVector other) {
int wordsInCommon = min(_wordsInUse, other._wordsInUse);

if (_wordsInUse < other._wordsInUse) {
_ensureCapacity(other._wordsInUse);
_wordsInUse = other._wordsInUse;
}

for (var i = 0; i < wordsInCommon; i++) {
_words[i] ^= other._words[i];
}

// Copy any remaining words
if (wordsInCommon < other._wordsInUse) {
_words.setRange(
wordsInCommon, other._wordsInUse, other._words, wordsInCommon);
}

_recalculateWordsInUse();
}

/// Clears all of the bits set in this [BitVector] whose corresponding bit is
/// set in [other].
void andNot(BitVector other) {
for (var i = min(_wordsInUse, other._wordsInUse) - 1; i >= 0; i--) {
_words[i] &= ~other._words[i];
}

_recalculateWordsInUse();
}

/// Given a bit index, returns word index containing it.
int _wordIndex(int bitIndex) => bitIndex >> _addressBitsPerWord;

Expand Down
168 changes: 168 additions & 0 deletions test/bit_vector_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,21 @@ import 'package:test/test.dart';

Random generator = new Random();

BitVector makeVector(Iterable<int> elements) {
final BitVector b = new BitVector();
for (int element in elements) {
b.set(element);
}
return b;
}

void checkEquality(BitVector s, BitVector t) {
expect(s, equals(t));
expect(s.length, equals(t.length));
}

bool boolXor(bool x, bool y) => (x && !y) || (!x && y);

void main() {
group('BitVector', () {
test('test []/set/clear/toggle', () {
Expand Down Expand Up @@ -172,5 +182,163 @@ void main() {

expect(failCount, 0);
});

test('andNot', () {
int failCount = 0;

for (var i = 0; i < 100; i++) {
BitVector b1 = new BitVector(256);
BitVector b2 = new BitVector(256);

for (var x = 0; x < 10; x++) {
b1.set(generator.nextInt(255));
}

for (var x = 0; x < 10; x++) {
b2.set(generator.nextInt(255));
}

// andNot the sets together
BitVector b3 = new BitVector.from(b1);
b3.andNot(b2);

// Examine each bit of b3 for errors
for (var x = 0; x < 256; x++) {
bool bit1 = b1[x];
bool bit2 = b2[x];
bool bit3 = b3[x];
if (!(bit3 == (bit1 && (!bit2)))) {
failCount++;
}
}
}

expect(failCount, 0);
});

test('and', () {
int failCount = 0;

for (var i = 0; i < 100; i++) {
BitVector b1 = new BitVector(256);
BitVector b2 = new BitVector(256);

for (var x = 0; x < 10; x++) {
b1.set(generator.nextInt(255));
}

for (var x = 0; x < 10; x++) {
b2.set(generator.nextInt(255));
}

// And the sets together
BitVector b3 = new BitVector.from(b1);
b3.and(b2);

// Examine each bit of b3 for errors
for (var x = 0; x < 256; x++) {
bool bit1 = b1[x];
bool bit2 = b2[x];
bool bit3 = b3[x];
if (!(bit3 == (bit1 && bit2))) {
failCount++;
}
}
}

// `and' that happens to clear the last word
BitVector b4 = makeVector([2, 127]);
b4.and(makeVector([2, 64]));
if (!(b4 == makeVector([2]))) {
failCount++;
}

expect(failCount, 0);
});

test('or', () {
int failCount = 0;

for (var i = 0; i < 100; i++) {
BitVector b1 = new BitVector(256);
BitVector b2 = new BitVector(256);
List<int> history = new List<int>(20);

// Set some random bits in first set and remember them
int nextBitToSet = 0;
for (var x = 0; x < 10; x++) {
nextBitToSet = generator.nextInt(255);
history[x] = nextBitToSet;
b1.set(nextBitToSet);
}

// Set more random bits in second set and remember them
for (int x = 10; x < 20; x++) {
nextBitToSet = generator.nextInt(255);
history[x] = nextBitToSet;
b2.set(nextBitToSet);
}

// Or the sets together
BitVector b3 = new BitVector.from(b1);
b3.or(b2);

// Verify the set bits of b3 from the history
for (int x = 0; x < 20; x++) {
if (!b3[history[x]]) {
failCount++;
}
}

// Examine each bit of b3 for errors
for (var x = 0; x < 256; x++) {
bool bit1 = b1[x];
bool bit2 = b2[x];
bool bit3 = b3[x];
if (!(bit3 == (bit1 || bit2))) {
failCount++;
}
}
}

expect(failCount, 0);
});

test('xor', () {
int failCount = 0;

for (var i = 0; i < 100; i++) {
BitVector b1 = new BitVector(256);
BitVector b2 = new BitVector(256);

int nextBitToSet = 0;
for (var x = 0; x < 10; x++) {
nextBitToSet = generator.nextInt(255);
b1.set(nextBitToSet);
}

for (int x = 0; x < 10; x++) {
nextBitToSet = generator.nextInt(255);
b2.set(nextBitToSet);
}

// Xor the sets together
BitVector b3 = new BitVector.from(b1);
b3.xor(b2);

// Examine each bit of b3 for errors
for (var x = 0; x < 256; x++) {
bool bit1 = b1[x];
bool bit2 = b2[x];
bool bit3 = b3[x];
if (!(bit3 == (boolXor(bit1, bit2)))) {
failCount++;
}
}
}

expect(failCount, 0);
});
});
}

0 comments on commit 091b38d

Please sign in to comment.