/* * Copyright 2012 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. */ #import "ZXBitArray.h" #import "ZXByteArray.h" #import "ZXIntArray.h" @interface ZXBitArray () @property (nonatomic, assign) int32_t *bits; @property (nonatomic, assign) int bitsLength; @property (nonatomic, assign) int size; @end @implementation ZXBitArray - (id)init { if (self = [super init]) { _size = 0; _bits = (int32_t *)calloc(1, sizeof(int32_t)); _bitsLength = 1; } return self; } // For testing only - (id)initWithBits:(ZXIntArray *)bits size:(int)size { if (self = [self initWithSize:size]) { _bits = bits.array; _bits = (int32_t *)malloc(bits.length * sizeof(int32_t)); memcpy(_bits, bits.array, bits.length * sizeof(int32_t)); _bitsLength = bits.length; } return self; } - (id)initWithSize:(int)size { if (self = [super init]) { _size = size; _bitsLength = (size + 31) / 32; _bits = (int32_t *)calloc(_bitsLength, sizeof(int32_t)); } return self; } - (void)dealloc { if (_bits != NULL) { free(_bits); _bits = NULL; } } - (int)sizeInBytes { return (self.size + 7) / 8; } - (void)ensureCapacity:(int)size { if (size > self.bitsLength * 32) { int newBitsLength = (size + 31) / 32; self.bits = realloc(self.bits, newBitsLength * sizeof(int32_t)); memset(self.bits + self.bitsLength, 0, (newBitsLength - self.bitsLength) * sizeof(int32_t)); self.bitsLength = newBitsLength; } } - (BOOL)get:(int)i { return (_bits[i / 32] & (1 << (i & 0x1F))) != 0; } - (void)set:(int)i { _bits[i / 32] |= 1 << (i & 0x1F); } - (void)flip:(int)i { _bits[i / 32] ^= 1 << (i & 0x1F); } - (int)nextSet:(int)from { if (from >= self.size) { return self.size; } int bitsOffset = from / 32; int32_t currentBits = self.bits[bitsOffset]; // mask off lesser bits first currentBits &= ~((1 << (from & 0x1F)) - 1); while (currentBits == 0) { if (++bitsOffset == self.bitsLength) { return self.size; } currentBits = self.bits[bitsOffset]; } int result = (bitsOffset * 32) + [self numberOfTrailingZeros:currentBits]; return result > self.size ? self.size : result; } - (int)nextUnset:(int)from { if (from >= self.size) { return self.size; } int bitsOffset = from / 32; int32_t currentBits = ~self.bits[bitsOffset]; // mask off lesser bits first currentBits &= ~((1 << (from & 0x1F)) - 1); while (currentBits == 0) { if (++bitsOffset == self.bitsLength) { return self.size; } currentBits = ~self.bits[bitsOffset]; } int result = (bitsOffset * 32) + [self numberOfTrailingZeros:currentBits]; return result > self.size ? self.size : result; } - (void)setBulk:(int)i newBits:(int32_t)newBits { _bits[i / 32] = newBits; } - (void)setRange:(int)start end:(int)end { if (end < start) { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Start greater than end" userInfo:nil]; } 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; int32_t mask; if (lastBit > 31) { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Bit-shift operand does not support more than 31 bits" userInfo:nil]; } if (firstBit == 0 && lastBit == 31) { mask = -1; } else { mask = 0; for (int j = firstBit; j <= lastBit; j++) { mask |= 1 << j; } } _bits[i] |= mask; } } - (void)clear { memset(self.bits, 0, self.bitsLength * sizeof(int32_t)); } - (BOOL)isRange:(int)start end:(int)end value:(BOOL)value { if (end < start) { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Start greater than end" userInfo:nil]; } if (end == start) { return YES; // 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; int32_t mask; if (lastBit > 31) { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Bit-shift operand does not support more than 31 bits" userInfo:nil]; } if (firstBit == 0 && lastBit == 31) { mask = -1; } else { mask = 0; for (int j = firstBit; j <= lastBit; j++) { mask |= 1 << j; } } // 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 NO; } } return YES; } - (void)appendBit:(BOOL)bit { [self ensureCapacity:self.size + 1]; if (bit) { self.bits[self.size / 32] |= 1 << (self.size & 0x1F); } self.size++; } - (void)appendBits:(int32_t)value numBits:(int)numBits { if (numBits < 0 || numBits > 32) { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Num bits must be between 0 and 32" userInfo:nil]; } [self ensureCapacity:self.size + numBits]; for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) { [self appendBit:((value >> (numBitsLeft - 1)) & 0x01) == 1]; } } - (void)appendBitArray:(ZXBitArray *)other { int otherSize = [other size]; [self ensureCapacity:self.size + otherSize]; for (int i = 0; i < otherSize; i++) { [self appendBit:[other get:i]]; } } - (void)xor:(ZXBitArray *)other { if (self.bitsLength != other.bitsLength) { @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Sizes don't match" userInfo:nil]; } for (int i = 0; i < self.bitsLength; i++) { // The last byte could be incomplete (i.e. not have 8 bits in // it) but there is no problem since 0 XOR 0 == 0. self.bits[i] ^= other.bits[i]; } } - (void)toBytes:(int)bitOffset array:(ZXByteArray *)array offset:(int)offset numBytes:(int)numBytes { for (int i = 0; i < numBytes; i++) { int32_t theByte = 0; for (int j = 0; j < 8; j++) { if ([self get:bitOffset]) { theByte |= 1 << (7 - j); } bitOffset++; } array.array[offset + i] = (int8_t) theByte; } } - (ZXIntArray *)bitArray { ZXIntArray *array = [[ZXIntArray alloc] initWithLength:self.bitsLength]; memcpy(array.array, self.bits, array.length * sizeof(int32_t)); return array; } - (BOOL)isEqual:(id)o { if (![o isKindOfClass:[ZXBitArray class]]) { return NO; } ZXBitArray *other = (ZXBitArray *)o; return self.size == other.size && memcmp(self.bits, other.bits, self.bitsLength) != 0; } - (NSUInteger)hash { return 31 * self.size; } - (void)reverse { int32_t *newBits = (int32_t *)calloc(self.bitsLength, sizeof(int32_t)); int size = self.size; // reverse all int's first int len = ((size-1) / 32); int oldBitsLen = len + 1; for (int i = 0; i < oldBitsLen; i++) { long x = (long) self.bits[i]; x = ((x >> 1) & 0x55555555L) | ((x & 0x55555555L) << 1); x = ((x >> 2) & 0x33333333L) | ((x & 0x33333333L) << 2); x = ((x >> 4) & 0x0f0f0f0fL) | ((x & 0x0f0f0f0fL) << 4); x = ((x >> 8) & 0x00ff00ffL) | ((x & 0x00ff00ffL) << 8); x = ((x >> 16) & 0x0000ffffL) | ((x & 0x0000ffffL) << 16); newBits[len - i] = (int32_t) x; } // 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 mask = 1; for (int i = 0; i < 31 - leftOffset; i++) { mask = (mask << 1) | 1; } int32_t currentInt = (newBits[0] >> leftOffset) & mask; for (int i = 1; i < oldBitsLen; i++) { int32_t nextInt = newBits[i]; currentInt |= nextInt << (32 - leftOffset); newBits[i - 1] = currentInt; currentInt = (nextInt >> leftOffset) & mask; } newBits[oldBitsLen - 1] = currentInt; } if (self.bits != NULL) { free(self.bits); } self.bits = newBits; } - (NSString *)description { NSMutableString *result = [NSMutableString string]; for (int i = 0; i < self.size; i++) { if ((i & 0x07) == 0) { [result appendString:@" "]; } [result appendString:[self get:i] ? @"X" : @"."]; } return result; } // Ported from OpenJDK Integer.numberOfTrailingZeros implementation - (int32_t)numberOfTrailingZeros:(int32_t)i { int32_t y; if (i == 0) return 32; int32_t n = 31; y = i <<16; if (y != 0) { n = n -16; i = y; } y = i << 8; if (y != 0) { n = n - 8; i = y; } y = i << 4; if (y != 0) { n = n - 4; i = y; } y = i << 2; if (y != 0) { n = n - 2; i = y; } return n - (int32_t)((uint32_t)(i << 1) >> 31); } - (id)copyWithZone:(NSZone *)zone { ZXBitArray *copy = [[ZXBitArray allocWithZone:zone] initWithSize:self.size]; memcpy(copy.bits, self.bits, self.size * sizeof(int32_t)); return copy; } @end