From 353a092f572c8d08be6ebcfaf911e7a30e4af745 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 24 Aug 2022 16:49:38 -0500 Subject: [PATCH] BitArray --- src/common/BitArray.java | 359 ----------------------------------- src/common/mod.rs | 401 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 400 insertions(+), 360 deletions(-) delete mode 100644 src/common/BitArray.java diff --git a/src/common/BitArray.java b/src/common/BitArray.java deleted file mode 100644 index b07785b..0000000 --- a/src/common/BitArray.java +++ /dev/null @@ -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; - -/** - *

A simple, fast array of bits, represented compactly by an array of ints internally.

- * - * @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); - } - -} diff --git a/src/common/mod.rs b/src/common/mod.rs index 11a9695..7633bf8 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,8 +1,11 @@ pub mod detector; pub mod reedsolomon; +use std::cmp; +use std::fmt; use std::{any::Any, collections::HashMap}; +use crate::exceptions::IllegalArgumentException; use crate::DecodeHintType; use encoding::Encoding; @@ -48,7 +51,7 @@ pub struct StringUtils { // 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 GB2312_CHARSET: Encoding = encoding::label::encoding_from_whatwg_label("GB2312"); const EUC_JP: Encoding = encoding::label::encoding_from_whatwg_label("EUC_JP"); @@ -264,3 +267,399 @@ impl StringUtils { 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; + +/** + *

A simple, fast array of bits, represented compactly by an array of ints internally.

+ * + * @author Sean Owen + */ +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub struct BitArray { + bits: Vec, + 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, 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 { + 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 { + 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 { + 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) + } +}