You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.0 KiB
201 lines
5.0 KiB
/* |
|
* Copyright 2016 Nu-book Inc. |
|
* Copyright 2016 ZXing authors |
|
* Copyright 2017 Axel Waggershauser |
|
*/ |
|
// SPDX-License-Identifier: Apache-2.0 |
|
|
|
#pragma once |
|
|
|
#include "Range.h" |
|
#include "ZXAlgorithms.h" |
|
|
|
#include <algorithm> |
|
#include <cassert> |
|
#include <cstdint> |
|
#include <stdexcept> |
|
#include <type_traits> |
|
#include <vector> |
|
|
|
namespace ZXing { |
|
|
|
class ByteArray; |
|
|
|
/** |
|
* A simple, fast array of bits. |
|
*/ |
|
class BitArray |
|
{ |
|
std::vector<uint8_t> _bits; |
|
|
|
friend class BitMatrix; |
|
|
|
// Nothing wrong to support it, just to make it explicit, instead of by mistake. |
|
// Use copy() below. |
|
BitArray(const BitArray &) = default; |
|
|
|
public: |
|
|
|
using Iterator = std::vector<uint8_t>::const_iterator; |
|
|
|
BitArray() = default; |
|
|
|
explicit BitArray(int size) : _bits(size, 0) {} |
|
|
|
BitArray(BitArray&& other) noexcept = default; |
|
BitArray& operator=(BitArray&& other) noexcept = default; |
|
BitArray& operator=(const BitArray &) = delete; |
|
|
|
BitArray copy() const { return *this; } |
|
|
|
int size() const noexcept { return Size(_bits); } |
|
|
|
int sizeInBytes() const noexcept { return (size() + 7) / 8; } |
|
|
|
bool get(int i) const { return _bits.at(i) != 0; } |
|
void set(int i, bool val) { _bits.at(i) = val; } |
|
|
|
// If you know exactly how may bits you are going to iterate |
|
// and that you access bit in sequence, iterator is faster than get(). |
|
// However, be extremely careful since there is no check whatsoever. |
|
// (Performance is the reason for the iterator to exist in the first place.) |
|
Iterator iterAt(int i) const noexcept { return {_bits.cbegin() + i}; } |
|
Iterator begin() const noexcept { return _bits.cbegin(); } |
|
Iterator end() const noexcept { return _bits.cend(); } |
|
|
|
/** |
|
* 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 |
|
*/ |
|
void appendBits(int value, int numBits) |
|
{ |
|
assert(numBits >= 1 && numBits <= 32); |
|
|
|
for (; numBits; --numBits) |
|
_bits.push_back((value >> (numBits-1)) & 1); |
|
} |
|
|
|
void appendBits(uint32_t value, int numBits) |
|
{ |
|
appendBits(static_cast<int>(value), numBits); |
|
} |
|
|
|
void appendBit(bool bit) { _bits.push_back(bit); } |
|
|
|
void appendBitArray(const BitArray& other) { _bits.insert(_bits.end(), other.begin(), other.end()); } |
|
|
|
/** |
|
* Reverses all bits in the array. |
|
*/ |
|
void reverse() { std::reverse(_bits.begin(), _bits.end()); } |
|
|
|
void bitwiseXOR(const BitArray& other); |
|
|
|
/** |
|
* @param bitOffset first bit to extract |
|
* @param numBytes how many bytes to extract (-1 == until the end, padded with '0') |
|
* @return Bytes are written most-significant bit first. |
|
*/ |
|
ByteArray toBytes(int bitOffset = 0, int numBytes = -1) const; |
|
|
|
using Range = ZXing::Range<Iterator>; |
|
Range range() const { return {begin(), end()}; } |
|
|
|
friend bool operator==(const BitArray& a, const BitArray& b) { return a._bits == b._bits; } |
|
}; |
|
|
|
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>> |
|
constexpr T& AppendBit(T& val, bool bit) |
|
{ |
|
return (val <<= 1) |= static_cast<T>(bit); |
|
} |
|
|
|
template <typename ARRAY, typename = std::enable_if_t<std::is_integral_v<typename ARRAY::value_type>>> |
|
constexpr int ToInt(const ARRAY& a) |
|
{ |
|
assert(Reduce(a) <= 32); |
|
|
|
int pattern = 0; |
|
for (int i = 0; i < Size(a); i++) { |
|
if (a[i] < 0) // negative shift is undefined behavior |
|
return -1; |
|
pattern = (pattern << a[i]) | ~(0xffffffff << a[i]) * (~i & 1); |
|
} |
|
return pattern; |
|
} |
|
|
|
template <typename T = int, typename = std::enable_if_t<std::is_integral_v<T>>> |
|
T ToInt(const BitArray& bits, int pos = 0, int count = 8 * sizeof(T)) |
|
{ |
|
assert(0 <= count && count <= 8 * (int)sizeof(T)); |
|
assert(0 <= pos && pos + count <= bits.size()); |
|
|
|
count = std::min(count, bits.size()); |
|
int res = 0; |
|
auto it = bits.iterAt(pos); |
|
for (int i = 0; i < count; ++i, ++it) |
|
AppendBit(res, *it); |
|
|
|
return res; |
|
} |
|
|
|
template <typename T = int, typename = std::enable_if_t<std::is_integral_v<T>>> |
|
std::vector<T> ToInts(const BitArray& bits, int wordSize, int totalWords, int offset = 0) |
|
{ |
|
assert(totalWords >= bits.size() / wordSize); |
|
assert(wordSize <= 8 * (int)sizeof(T)); |
|
|
|
std::vector<T> res(totalWords, 0); |
|
for (int i = offset; i < bits.size(); i += wordSize) |
|
res[(i - offset) / wordSize] = ToInt(bits, i, wordSize); |
|
|
|
return res; |
|
} |
|
|
|
class BitArrayView |
|
{ |
|
const BitArray& bits; |
|
BitArray::Iterator cur; |
|
|
|
public: |
|
BitArrayView(const BitArray& bits) : bits(bits), cur(bits.begin()) {} |
|
|
|
BitArrayView& skipBits(int n) |
|
{ |
|
if (cur + n > bits.end()) |
|
throw std::out_of_range("BitArrayView::skipBits() out of range."); |
|
cur += n; |
|
return *this; |
|
} |
|
|
|
int peekBits(int n) const |
|
{ |
|
assert(n <= 32); |
|
if (cur + n > bits.end()) |
|
throw std::out_of_range("BitArrayView::peekBits() out of range."); |
|
int res = 0; |
|
for (auto i = cur; n > 0; --n, i++) |
|
AppendBit(res, *i); |
|
return res; |
|
} |
|
|
|
int readBits(int n) |
|
{ |
|
int res = peekBits(n); |
|
cur += n; |
|
return res; |
|
} |
|
|
|
int size() const |
|
{ |
|
return narrow_cast<int>(bits.end() - cur); |
|
} |
|
|
|
explicit operator bool() const { return size(); } |
|
}; |
|
|
|
} // ZXing
|
|
|