mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 12:52:34 +00:00
BitArray
This commit is contained in:
@@ -1,359 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.common;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public final class BitArray implements Cloneable {
|
|
||||||
|
|
||||||
private static final int[] EMPTY_BITS = {};
|
|
||||||
private static final float LOAD_FACTOR = 0.75f;
|
|
||||||
|
|
||||||
private int[] bits;
|
|
||||||
private int size;
|
|
||||||
|
|
||||||
public BitArray() {
|
|
||||||
this.size = 0;
|
|
||||||
this.bits = EMPTY_BITS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitArray(int size) {
|
|
||||||
this.size = size;
|
|
||||||
this.bits = makeArray(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For testing only
|
|
||||||
BitArray(int[] bits, int size) {
|
|
||||||
this.bits = bits;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSizeInBytes() {
|
|
||||||
return (size + 7) / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureCapacity(int newSize) {
|
|
||||||
if (newSize > bits.length * 32) {
|
|
||||||
int[] newBits = makeArray((int) Math.ceil(newSize / LOAD_FACTOR));
|
|
||||||
System.arraycopy(bits, 0, newBits, 0, bits.length);
|
|
||||||
this.bits = newBits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param i bit to get
|
|
||||||
* @return true iff bit i is set
|
|
||||||
*/
|
|
||||||
public boolean get(int i) {
|
|
||||||
return (bits[i / 32] & (1 << (i & 0x1F))) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets bit i.
|
|
||||||
*
|
|
||||||
* @param i bit to set
|
|
||||||
*/
|
|
||||||
public void set(int i) {
|
|
||||||
bits[i / 32] |= 1 << (i & 0x1F);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flips bit i.
|
|
||||||
*
|
|
||||||
* @param i bit to set
|
|
||||||
*/
|
|
||||||
public void flip(int i) {
|
|
||||||
bits[i / 32] ^= 1 << (i & 0x1F);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param from first bit to check
|
|
||||||
* @return index of first bit that is set, starting from the given index, or size if none are set
|
|
||||||
* at or beyond this given index
|
|
||||||
* @see #getNextUnset(int)
|
|
||||||
*/
|
|
||||||
public int getNextSet(int from) {
|
|
||||||
if (from >= size) {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
int bitsOffset = from / 32;
|
|
||||||
int currentBits = bits[bitsOffset];
|
|
||||||
// mask off lesser bits first
|
|
||||||
currentBits &= -(1 << (from & 0x1F));
|
|
||||||
while (currentBits == 0) {
|
|
||||||
if (++bitsOffset == bits.length) {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
currentBits = bits[bitsOffset];
|
|
||||||
}
|
|
||||||
int result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits);
|
|
||||||
return Math.min(result, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param from index to start looking for unset bit
|
|
||||||
* @return index of next unset bit, or {@code size} if none are unset until the end
|
|
||||||
* @see #getNextSet(int)
|
|
||||||
*/
|
|
||||||
public int getNextUnset(int from) {
|
|
||||||
if (from >= size) {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
int bitsOffset = from / 32;
|
|
||||||
int currentBits = ~bits[bitsOffset];
|
|
||||||
// mask off lesser bits first
|
|
||||||
currentBits &= -(1 << (from & 0x1F));
|
|
||||||
while (currentBits == 0) {
|
|
||||||
if (++bitsOffset == bits.length) {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
currentBits = ~bits[bitsOffset];
|
|
||||||
}
|
|
||||||
int result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits);
|
|
||||||
return Math.min(result, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a block of 32 bits, starting at bit i.
|
|
||||||
*
|
|
||||||
* @param i first bit to set
|
|
||||||
* @param newBits the new value of the next 32 bits. Note again that the least-significant bit
|
|
||||||
* corresponds to bit i, the next-least-significant to i+1, and so on.
|
|
||||||
*/
|
|
||||||
public void setBulk(int i, int newBits) {
|
|
||||||
bits[i / 32] = newBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a range of bits.
|
|
||||||
*
|
|
||||||
* @param start start of range, inclusive.
|
|
||||||
* @param end end of range, exclusive
|
|
||||||
*/
|
|
||||||
public void setRange(int start, int end) {
|
|
||||||
if (end < start || start < 0 || end > size) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
if (end == start) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
end--; // will be easier to treat this as the last actually set bit -- inclusive
|
|
||||||
int firstInt = start / 32;
|
|
||||||
int lastInt = end / 32;
|
|
||||||
for (int i = firstInt; i <= lastInt; i++) {
|
|
||||||
int firstBit = i > firstInt ? 0 : start & 0x1F;
|
|
||||||
int lastBit = i < lastInt ? 31 : end & 0x1F;
|
|
||||||
// Ones from firstBit to lastBit, inclusive
|
|
||||||
int mask = (2 << lastBit) - (1 << firstBit);
|
|
||||||
bits[i] |= mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all bits (sets to false).
|
|
||||||
*/
|
|
||||||
public void clear() {
|
|
||||||
int max = bits.length;
|
|
||||||
for (int i = 0; i < max; i++) {
|
|
||||||
bits[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Efficient method to check if a range of bits is set, or not set.
|
|
||||||
*
|
|
||||||
* @param start start of range, inclusive.
|
|
||||||
* @param end end of range, exclusive
|
|
||||||
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
|
|
||||||
* @return true iff all bits are set or not set in range, according to value argument
|
|
||||||
* @throws IllegalArgumentException if end is less than start or the range is not contained in the array
|
|
||||||
*/
|
|
||||||
public boolean isRange(int start, int end, boolean value) {
|
|
||||||
if (end < start || start < 0 || end > size) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
if (end == start) {
|
|
||||||
return true; // empty range matches
|
|
||||||
}
|
|
||||||
end--; // will be easier to treat this as the last actually set bit -- inclusive
|
|
||||||
int firstInt = start / 32;
|
|
||||||
int lastInt = end / 32;
|
|
||||||
for (int i = firstInt; i <= lastInt; i++) {
|
|
||||||
int firstBit = i > firstInt ? 0 : start & 0x1F;
|
|
||||||
int lastBit = i < lastInt ? 31 : end & 0x1F;
|
|
||||||
// Ones from firstBit to lastBit, inclusive
|
|
||||||
int mask = (2 << lastBit) - (1 << firstBit);
|
|
||||||
|
|
||||||
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,
|
|
||||||
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
|
|
||||||
if ((bits[i] & mask) != (value ? mask : 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void appendBit(boolean bit) {
|
|
||||||
ensureCapacity(size + 1);
|
|
||||||
if (bit) {
|
|
||||||
bits[size / 32] |= 1 << (size & 0x1F);
|
|
||||||
}
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends the least-significant bits, from value, in order from most-significant to
|
|
||||||
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
|
|
||||||
* 0, 1, 1, 1, 1, 0 in that order.
|
|
||||||
*
|
|
||||||
* @param value {@code int} containing bits to append
|
|
||||||
* @param numBits bits from value to append
|
|
||||||
*/
|
|
||||||
public void appendBits(int value, int numBits) {
|
|
||||||
if (numBits < 0 || numBits > 32) {
|
|
||||||
throw new IllegalArgumentException("Num bits must be between 0 and 32");
|
|
||||||
}
|
|
||||||
int nextSize = size;
|
|
||||||
ensureCapacity(nextSize + numBits);
|
|
||||||
for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) {
|
|
||||||
if ((value & (1 << numBitsLeft)) != 0) {
|
|
||||||
bits[nextSize / 32] |= 1 << (nextSize & 0x1F);
|
|
||||||
}
|
|
||||||
nextSize++;
|
|
||||||
}
|
|
||||||
size = nextSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void appendBitArray(BitArray other) {
|
|
||||||
int otherSize = other.size;
|
|
||||||
ensureCapacity(size + otherSize);
|
|
||||||
for (int i = 0; i < otherSize; i++) {
|
|
||||||
appendBit(other.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void xor(BitArray other) {
|
|
||||||
if (size != other.size) {
|
|
||||||
throw new IllegalArgumentException("Sizes don't match");
|
|
||||||
}
|
|
||||||
for (int i = 0; i < bits.length; i++) {
|
|
||||||
// The last int could be incomplete (i.e. not have 32 bits in
|
|
||||||
// it) but there is no problem since 0 XOR 0 == 0.
|
|
||||||
bits[i] ^= other.bits[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param bitOffset first bit to start writing
|
|
||||||
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
|
|
||||||
* of the internal representation, which is exposed by {@link #getBitArray()}
|
|
||||||
* @param offset position in array to start writing
|
|
||||||
* @param numBytes how many bytes to write
|
|
||||||
*/
|
|
||||||
public void toBytes(int bitOffset, byte[] array, int offset, int numBytes) {
|
|
||||||
for (int i = 0; i < numBytes; i++) {
|
|
||||||
int theByte = 0;
|
|
||||||
for (int j = 0; j < 8; j++) {
|
|
||||||
if (get(bitOffset)) {
|
|
||||||
theByte |= 1 << (7 - j);
|
|
||||||
}
|
|
||||||
bitOffset++;
|
|
||||||
}
|
|
||||||
array[offset + i] = (byte) theByte;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return underlying array of ints. The first element holds the first 32 bits, and the least
|
|
||||||
* significant bit is bit 0.
|
|
||||||
*/
|
|
||||||
public int[] getBitArray() {
|
|
||||||
return bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverses all bits in the array.
|
|
||||||
*/
|
|
||||||
public void reverse() {
|
|
||||||
int[] newBits = new int[bits.length];
|
|
||||||
// reverse all int's first
|
|
||||||
int len = (size - 1) / 32;
|
|
||||||
int oldBitsLen = len + 1;
|
|
||||||
for (int i = 0; i < oldBitsLen; i++) {
|
|
||||||
newBits[len - i] = Integer.reverse(bits[i]);
|
|
||||||
}
|
|
||||||
// now correct the int's if the bit size isn't a multiple of 32
|
|
||||||
if (size != oldBitsLen * 32) {
|
|
||||||
int leftOffset = oldBitsLen * 32 - size;
|
|
||||||
int currentInt = newBits[0] >>> leftOffset;
|
|
||||||
for (int i = 1; i < oldBitsLen; i++) {
|
|
||||||
int nextInt = newBits[i];
|
|
||||||
currentInt |= nextInt << (32 - leftOffset);
|
|
||||||
newBits[i - 1] = currentInt;
|
|
||||||
currentInt = nextInt >>> leftOffset;
|
|
||||||
}
|
|
||||||
newBits[oldBitsLen - 1] = currentInt;
|
|
||||||
}
|
|
||||||
bits = newBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[] makeArray(int size) {
|
|
||||||
return new int[(size + 31) / 32];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof BitArray)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
BitArray other = (BitArray) o;
|
|
||||||
return size == other.size && Arrays.equals(bits, other.bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return 31 * size + Arrays.hashCode(bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder result = new StringBuilder(size + (size / 8) + 1);
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
if ((i & 0x07) == 0) {
|
|
||||||
result.append(' ');
|
|
||||||
}
|
|
||||||
result.append(get(i) ? 'X' : '.');
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BitArray clone() {
|
|
||||||
return new BitArray(bits.clone(), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
pub mod detector;
|
pub mod detector;
|
||||||
pub mod reedsolomon;
|
pub mod reedsolomon;
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
|
use std::fmt;
|
||||||
use std::{any::Any, collections::HashMap};
|
use std::{any::Any, collections::HashMap};
|
||||||
|
|
||||||
|
use crate::exceptions::IllegalArgumentException;
|
||||||
use crate::DecodeHintType;
|
use crate::DecodeHintType;
|
||||||
use encoding::Encoding;
|
use encoding::Encoding;
|
||||||
|
|
||||||
@@ -48,7 +51,7 @@ pub struct StringUtils {
|
|||||||
// public static final String GB2312 = "GB2312";
|
// public static final String GB2312 = "GB2312";
|
||||||
}
|
}
|
||||||
|
|
||||||
const PLATFORM_DEFAULT_ENCODING: Encoding = encoding::all::UTF_8;
|
const PLATFORM_DEFAULT_ENCODING: dyn Encoding = encoding::all::UTF_8;
|
||||||
const SHIFT_JIS_CHARSET: Encoding = encoding::label::encoding_from_whatwg_label("SJIS");
|
const SHIFT_JIS_CHARSET: Encoding = encoding::label::encoding_from_whatwg_label("SJIS");
|
||||||
const GB2312_CHARSET: Encoding = encoding::label::encoding_from_whatwg_label("GB2312");
|
const GB2312_CHARSET: Encoding = encoding::label::encoding_from_whatwg_label("GB2312");
|
||||||
const EUC_JP: Encoding = encoding::label::encoding_from_whatwg_label("EUC_JP");
|
const EUC_JP: Encoding = encoding::label::encoding_from_whatwg_label("EUC_JP");
|
||||||
@@ -264,3 +267,399 @@ impl StringUtils {
|
|||||||
return PLATFORM_DEFAULT_ENCODING;
|
return PLATFORM_DEFAULT_ENCODING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package com.google.zxing.common;
|
||||||
|
|
||||||
|
// import java.util.Arrays;
|
||||||
|
|
||||||
|
static EMPTY_BITS: [u32; 0] = [0; 0];
|
||||||
|
static LOAD_FACTOR: f32 = 0.75f32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
|
pub struct BitArray {
|
||||||
|
bits: Vec<u32>,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitArray {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
bits: EMPTY_BITS,
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_size(size: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
bits: BitArray::makeArray(size),
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing only
|
||||||
|
pub fn with_initial_values(bits: Vec<u32>, size: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
bits: bits,
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getSize(&self) -> usize {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getSizeInBytes(&self) -> usize {
|
||||||
|
return (self.size + 7) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensureCapacity(&self, newSize: usize) {
|
||||||
|
if newSize > self.bits.len() * 32 {
|
||||||
|
let newBits = BitArray::makeArray((newSize as f32 / LOAD_FACTOR).ceil());
|
||||||
|
//System.arraycopy(bits, 0, newBits, 0, bits.length);
|
||||||
|
newBits[0..self.bits.len()].clone_from_slice(&self.bits[0..self.bits.len()]);
|
||||||
|
self.bits = newBits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param i bit to get
|
||||||
|
* @return true iff bit i is set
|
||||||
|
*/
|
||||||
|
pub fn get(&self, i: usize) -> bool {
|
||||||
|
return (self.bits[i / 32] & (1 << (i & 0x1F))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets bit i.
|
||||||
|
*
|
||||||
|
* @param i bit to set
|
||||||
|
*/
|
||||||
|
pub fn set(&self, i: usize) {
|
||||||
|
self.bits[i / 32] |= 1 << (i & 0x1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips bit i.
|
||||||
|
*
|
||||||
|
* @param i bit to set
|
||||||
|
*/
|
||||||
|
pub fn flip(&self, i: usize) {
|
||||||
|
self.bits[i / 32] ^= 1 << (i & 0x1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param from first bit to check
|
||||||
|
* @return index of first bit that is set, starting from the given index, or size if none are set
|
||||||
|
* at or beyond this given index
|
||||||
|
* @see #getNextUnset(int)
|
||||||
|
*/
|
||||||
|
pub fn getNextSet(&self, from: usize) -> usize {
|
||||||
|
if from >= self.size {
|
||||||
|
return self.size;
|
||||||
|
}
|
||||||
|
let bitsOffset = from / 32;
|
||||||
|
let currentBits = self.bits[bitsOffset];
|
||||||
|
// mask off lesser bits first
|
||||||
|
currentBits &= -(1 << (from & 0x1F));
|
||||||
|
while currentBits == 0 {
|
||||||
|
bitsOffset += 1;
|
||||||
|
if bitsOffset == self.bits.len() {
|
||||||
|
return self.size;
|
||||||
|
}
|
||||||
|
currentBits = self.bits[bitsOffset];
|
||||||
|
}
|
||||||
|
let result = (bitsOffset * 32) + currentBits.trailing_zeros();
|
||||||
|
cmp::min(result, self.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param from index to start looking for unset bit
|
||||||
|
* @return index of next unset bit, or {@code size} if none are unset until the end
|
||||||
|
* @see #getNextSet(int)
|
||||||
|
*/
|
||||||
|
pub fn getNextUnset(&self, from: usize) -> usize {
|
||||||
|
if from >= self.size {
|
||||||
|
return self.size;
|
||||||
|
}
|
||||||
|
let bitsOffset = from / 32;
|
||||||
|
let currentBits = !self.bits[bitsOffset];
|
||||||
|
// mask off lesser bits first
|
||||||
|
currentBits &= -(1 << (from & 0x1F));
|
||||||
|
while currentBits == 0 {
|
||||||
|
bitsOffset += 1;
|
||||||
|
if bitsOffset == self.bits.len() {
|
||||||
|
return self.size;
|
||||||
|
}
|
||||||
|
currentBits = !self.bits[bitsOffset];
|
||||||
|
}
|
||||||
|
let result = (bitsOffset * 32) + currentBits.trailing_zeros();
|
||||||
|
return cmp::min(result, self.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a block of 32 bits, starting at bit i.
|
||||||
|
*
|
||||||
|
* @param i first bit to set
|
||||||
|
* @param newBits the new value of the next 32 bits. Note again that the least-significant bit
|
||||||
|
* corresponds to bit i, the next-least-significant to i+1, and so on.
|
||||||
|
*/
|
||||||
|
pub fn setBulk(&self, i: usize, newBits: u32) {
|
||||||
|
self.bits[i / 32] = newBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a range of bits.
|
||||||
|
*
|
||||||
|
* @param start start of range, inclusive.
|
||||||
|
* @param end end of range, exclusive
|
||||||
|
*/
|
||||||
|
pub fn setRange(&self, start: usize, end: usize) -> Result<(), IllegalArgumentException> {
|
||||||
|
if end < start || start < 0 || end > self.size {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"end < start || start < 0 || end > self.size",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if end == start {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
end -= 1; // will be easier to treat this as the last actually set bit -- inclusive
|
||||||
|
let firstInt = start / 32;
|
||||||
|
let lastInt = end / 32;
|
||||||
|
for i in firstInt..=lastInt {
|
||||||
|
//for (int i = firstInt; i <= lastInt; i++) {
|
||||||
|
let firstBit = if i > firstInt { 0 } else { start & 0x1F };
|
||||||
|
let lastBit = if i < lastInt { 31 } else { end & 0x1F };
|
||||||
|
// Ones from firstBit to lastBit, inclusive
|
||||||
|
let mask = (2 << lastBit) - (1 << firstBit);
|
||||||
|
self.bits[i] |= mask;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all bits (sets to false).
|
||||||
|
*/
|
||||||
|
pub fn clear(&self) {
|
||||||
|
let max = self.bits.length;
|
||||||
|
for i in 0..max {
|
||||||
|
//for (int i = 0; i < max; i++) {
|
||||||
|
self.bits[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Efficient method to check if a range of bits is set, or not set.
|
||||||
|
*
|
||||||
|
* @param start start of range, inclusive.
|
||||||
|
* @param end end of range, exclusive
|
||||||
|
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
|
||||||
|
* @return true iff all bits are set or not set in range, according to value argument
|
||||||
|
* @throws IllegalArgumentException if end is less than start or the range is not contained in the array
|
||||||
|
*/
|
||||||
|
pub fn isRange(
|
||||||
|
&self,
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
|
value: bool,
|
||||||
|
) -> Result<bool, IllegalArgumentException> {
|
||||||
|
if end < start || start < 0 || end > self.size {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"end < start || start < 0 || end > self.size",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if end == start {
|
||||||
|
return Ok(true); // empty range matches
|
||||||
|
}
|
||||||
|
end -= 1; // will be easier to treat this as the last actually set bit -- inclusive
|
||||||
|
let firstInt = start / 32;
|
||||||
|
let lastInt = end / 32;
|
||||||
|
for i in firstInt..=lastInt {
|
||||||
|
//for (int i = firstInt; i <= lastInt; i++) {
|
||||||
|
let firstBit = if i > firstInt { 0 } else { start & 0x1F };
|
||||||
|
let lastBit = if i < lastInt { 31 } else { end & 0x1F };
|
||||||
|
// Ones from firstBit to lastBit, inclusive
|
||||||
|
let mask = (2 << lastBit) - (1 << firstBit);
|
||||||
|
|
||||||
|
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,
|
||||||
|
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
|
||||||
|
if (self.bits[i] & mask) != (if value { mask } else { 0 }) {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendBit(&self, bit: bool) {
|
||||||
|
self.ensureCapacity(self.size + 1);
|
||||||
|
if bit {
|
||||||
|
self.bits[self.size / 32] |= 1 << (self.size & 0x1F);
|
||||||
|
}
|
||||||
|
self.size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the least-significant bits, from value, in order from most-significant to
|
||||||
|
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
|
||||||
|
* 0, 1, 1, 1, 1, 0 in that order.
|
||||||
|
*
|
||||||
|
* @param value {@code int} containing bits to append
|
||||||
|
* @param numBits bits from value to append
|
||||||
|
*/
|
||||||
|
pub fn appendBits(&self, value: u32, numBits: usize) -> Result<(), IllegalArgumentException> {
|
||||||
|
if numBits < 0 || numBits > 32 {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"Num bits must be between 0 and 32",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let nextSize = self.size;
|
||||||
|
self.ensureCapacity(nextSize + numBits);
|
||||||
|
for numBitsLeft in (0..(numBits - 1)).rev() {
|
||||||
|
//for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) {
|
||||||
|
if (value & (1 << numBitsLeft)) != 0 {
|
||||||
|
self.bits[nextSize / 32] |= 1 << (nextSize & 0x1F);
|
||||||
|
}
|
||||||
|
nextSize += 1;
|
||||||
|
}
|
||||||
|
self.size = nextSize;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendBitArray(&self, other: BitArray) {
|
||||||
|
let otherSize = other.size;
|
||||||
|
self.ensureCapacity(self.size + otherSize);
|
||||||
|
for i in 0..otherSize {
|
||||||
|
//for (int i = 0; i < otherSize; i++) {
|
||||||
|
self.appendBit(other.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xor(&self, other: &BitArray) -> Result<(), IllegalArgumentException> {
|
||||||
|
if self.size != other.size {
|
||||||
|
return Err(IllegalArgumentException::new("Sizes don't match"));
|
||||||
|
}
|
||||||
|
for i in 0..self.bits.len() {
|
||||||
|
//for (int i = 0; i < bits.length; i++) {
|
||||||
|
// The last int could be incomplete (i.e. not have 32 bits in
|
||||||
|
// it) but there is no problem since 0 XOR 0 == 0.
|
||||||
|
self.bits[i] ^= other.bits[i];
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param bitOffset first bit to start writing
|
||||||
|
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
|
||||||
|
* of the internal representation, which is exposed by {@link #getBitArray()}
|
||||||
|
* @param offset position in array to start writing
|
||||||
|
* @param numBytes how many bytes to write
|
||||||
|
*/
|
||||||
|
pub fn toBytes(&self, bitOffset: usize, array: &mut [u8], offset: usize, numBytes: usize) {
|
||||||
|
for i in 0..numBytes {
|
||||||
|
//for (int i = 0; i < numBytes; i++) {
|
||||||
|
let theByte = 0;
|
||||||
|
for j in 0..8 {
|
||||||
|
//for (int j = 0; j < 8; j++) {
|
||||||
|
if self.get(bitOffset) {
|
||||||
|
theByte |= 1 << (7 - j);
|
||||||
|
}
|
||||||
|
bitOffset += 1;
|
||||||
|
}
|
||||||
|
array[offset + i] = theByte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return underlying array of ints. The first element holds the first 32 bits, and the least
|
||||||
|
* significant bit is bit 0.
|
||||||
|
*/
|
||||||
|
pub fn getBitArray(&self) -> Vec<u32> {
|
||||||
|
return self.bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverses all bits in the array.
|
||||||
|
*/
|
||||||
|
pub fn reverse(&self) {
|
||||||
|
let newBits = Vec::with_capacity(self.bits.len());
|
||||||
|
// reverse all int's first
|
||||||
|
let len = (self.size - 1) / 32;
|
||||||
|
let oldBitsLen = len + 1;
|
||||||
|
for i in 0..oldBitsLen {
|
||||||
|
//for (int i = 0; i < oldBitsLen; i++) {
|
||||||
|
newBits[len - i] = self.bits[i].reverse_bits();
|
||||||
|
}
|
||||||
|
// now correct the int's if the bit size isn't a multiple of 32
|
||||||
|
if self.size != oldBitsLen * 32 {
|
||||||
|
let leftOffset = oldBitsLen * 32 - self.size;
|
||||||
|
let currentInt = newBits[0] >> leftOffset;
|
||||||
|
for i in 1..oldBitsLen {
|
||||||
|
//for (int i = 1; i < oldBitsLen; i++) {
|
||||||
|
let nextInt = newBits[i];
|
||||||
|
currentInt |= nextInt << (32 - leftOffset);
|
||||||
|
newBits[i - 1] = currentInt;
|
||||||
|
currentInt = nextInt >> leftOffset;
|
||||||
|
}
|
||||||
|
newBits[oldBitsLen - 1] = currentInt;
|
||||||
|
}
|
||||||
|
self.bits = newBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn makeArray(size: usize) -> Vec<u32> {
|
||||||
|
return vec![0; (size + 31) / 32];
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean equals(Object o) {
|
||||||
|
// if (!(o instanceof BitArray)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// BitArray other = (BitArray) o;
|
||||||
|
// return size == other.size && Arrays.equals(bits, other.bits);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public int hashCode() {
|
||||||
|
// return 31 * size + Arrays.hashCode(bits);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public BitArray clone() {
|
||||||
|
// return new BitArray(bits.clone(), size);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BitArray {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let _str = String::with_capacity(self.size + (self.size / 8) + 1);
|
||||||
|
for i in 0..self.size {
|
||||||
|
//for (int i = 0; i < size; i++) {
|
||||||
|
if (i & 0x07) == 0 {
|
||||||
|
_str.push_str(" ");
|
||||||
|
}
|
||||||
|
_str.push_str(if self.get(i) { "X" } else { "." });
|
||||||
|
}
|
||||||
|
write!(f, "{}", _str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user