* @brief A simple, fast 2D array of bits. */
| 26 | * @brief A simple, fast 2D array of bits. |
| 27 | */ |
| 28 | class BitMatrix |
| 29 | { |
| 30 | int _width = 0; |
| 31 | int _height = 0; |
| 32 | using data_t = uint8_t; |
| 33 | |
| 34 | std::vector<data_t> _bits; |
| 35 | // There is nothing wrong to support this but disable to make it explicit since we may copy something very big here. |
| 36 | // Use copy() below. |
| 37 | BitMatrix(const BitMatrix&) = default; |
| 38 | BitMatrix& operator=(const BitMatrix&) = delete; |
| 39 | |
| 40 | const data_t& get(int i) const |
| 41 | { |
| 42 | #if 1 |
| 43 | return _bits.at(i); |
| 44 | #else |
| 45 | return _bits[i]; |
| 46 | #endif |
| 47 | } |
| 48 | |
| 49 | data_t& get(int i) { return const_cast<data_t&>(static_cast<const BitMatrix*>(this)->get(i)); } |
| 50 | |
| 51 | bool getTopLeftOnBit(int &left, int& top) const; |
| 52 | bool getBottomRightOnBit(int &right, int& bottom) const; |
| 53 | |
| 54 | public: |
| 55 | static constexpr data_t SET_V = 0xff; // allows playing with SIMD binarization |
| 56 | static constexpr data_t UNSET_V = 0; |
| 57 | static_assert(bool(SET_V) && !bool(UNSET_V), "SET_V needs to evaluate to true, UNSET_V to false, see iterator usage"); |
| 58 | |
| 59 | BitMatrix() = default; |
| 60 | |
| 61 | #ifdef __GNUC__ |
| 62 | __attribute__((no_sanitize("signed-integer-overflow"))) |
| 63 | #endif |
| 64 | BitMatrix(int width, int height) : _width(width), _height(height), _bits(width * height, UNSET_V) |
| 65 | { |
| 66 | if (width != 0 && Size(_bits) / width != height) |
| 67 | throw std::invalid_argument("invalid size: width * height is too big"); |
| 68 | } |
| 69 | |
| 70 | explicit BitMatrix(int dimension) : BitMatrix(dimension, dimension) {} // Construct a square matrix. |
| 71 | |
| 72 | BitMatrix(BitMatrix&& other) noexcept = default; |
| 73 | BitMatrix& operator=(BitMatrix&& other) noexcept = default; |
| 74 | |
| 75 | BitMatrix copy() const { return *this; } |
| 76 | |
| 77 | Range<data_t*> row(int y) { return {_bits.data() + y * _width, _bits.data() + (y + 1) * _width}; } |
| 78 | Range<const data_t*> row(int y) const { return {_bits.data() + y * _width, _bits.data() + (y + 1) * _width}; } |
| 79 | |
| 80 | Range<StrideIter<const data_t*>> col(int x) const |
| 81 | { |
| 82 | return {{_bits.data() + x + (_height - 1) * _width, -_width}, {_bits.data() + x - _width, -_width}}; |
| 83 | } |
| 84 | |
| 85 | bool get(int x, int y) const { return get(y * _width + x); } |