Coverage Report

Created: 2026-10-28 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tesseract/src/ccutil/bitvector.cpp
Line
Count
Source
1
// Copyright 2011 Google Inc. All Rights Reserved.
2
// Author: rays@google.com (Ray Smith)
3
///////////////////////////////////////////////////////////////////////
4
// File:        bitvector.cpp
5
// Description: Class replacement for BITVECTOR.
6
// Author:      Ray Smith
7
//
8
// (C) Copyright 2011, Google Inc.
9
// Licensed under the Apache License, Version 2.0 (the "License");
10
// you may not use this file except in compliance with the License.
11
// You may obtain a copy of the License at
12
// http://www.apache.org/licenses/LICENSE-2.0
13
// Unless required by applicable law or agreed to in writing, software
14
// distributed under the License is distributed on an "AS IS" BASIS,
15
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
// See the License for the specific language governing permissions and
17
// limitations under the License.
18
//
19
///////////////////////////////////////////////////////////////////////
20
21
#include "bitvector.h"
22
#include <algorithm>
23
#include <cstring>
24
#include "helpers.h"
25
#include "serialis.h" // for tesseract::Serialize
26
27
namespace tesseract {
28
29
// Fast lookup table to get the first least significant set bit in a byte.
30
// For zero, the table has 255, but since it is a special case, most code
31
// that uses this table will check for zero before looking up lsb_index_.
32
const uint8_t BitVector::lsb_index_[256] = {
33
    255, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,
34
    0,   1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0,
35
    1,   0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1,
36
    0,   3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0,
37
    2,   0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
38
    0,   1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0,
39
    1,   0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1,
40
    0,   2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0,
41
    3,   0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
42
43
// Fast lookup table to get the residual bits after zeroing the first (lowest)
44
// set bit in a byte.
45
const uint8_t BitVector::lsb_eroded_[256] = {
46
    0,    0,    0,    0x2,  0,    0x4,  0x4,  0x6,  0,    0x8,  0x8,  0x0a, 0x08, 0x0c, 0x0c, 0x0e,
47
    0,    0x10, 0x10, 0x12, 0x10, 0x14, 0x14, 0x16, 0x10, 0x18, 0x18, 0x1a, 0x18, 0x1c, 0x1c, 0x1e,
48
    0,    0x20, 0x20, 0x22, 0x20, 0x24, 0x24, 0x26, 0x20, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x2c, 0x2e,
49
    0x20, 0x30, 0x30, 0x32, 0x30, 0x34, 0x34, 0x36, 0x30, 0x38, 0x38, 0x3a, 0x38, 0x3c, 0x3c, 0x3e,
50
    0,    0x40, 0x40, 0x42, 0x40, 0x44, 0x44, 0x46, 0x40, 0x48, 0x48, 0x4a, 0x48, 0x4c, 0x4c, 0x4e,
51
    0x40, 0x50, 0x50, 0x52, 0x50, 0x54, 0x54, 0x56, 0x50, 0x58, 0x58, 0x5a, 0x58, 0x5c, 0x5c, 0x5e,
52
    0x40, 0x60, 0x60, 0x62, 0x60, 0x64, 0x64, 0x66, 0x60, 0x68, 0x68, 0x6a, 0x68, 0x6c, 0x6c, 0x6e,
53
    0x60, 0x70, 0x70, 0x72, 0x70, 0x74, 0x74, 0x76, 0x70, 0x78, 0x78, 0x7a, 0x78, 0x7c, 0x7c, 0x7e,
54
    0,    0x80, 0x80, 0x82, 0x80, 0x84, 0x84, 0x86, 0x80, 0x88, 0x88, 0x8a, 0x88, 0x8c, 0x8c, 0x8e,
55
    0x80, 0x90, 0x90, 0x92, 0x90, 0x94, 0x94, 0x96, 0x90, 0x98, 0x98, 0x9a, 0x98, 0x9c, 0x9c, 0x9e,
56
    0x80, 0xa0, 0xa0, 0xa2, 0xa0, 0xa4, 0xa4, 0xa6, 0xa0, 0xa8, 0xa8, 0xaa, 0xa8, 0xac, 0xac, 0xae,
57
    0xa0, 0xb0, 0xb0, 0xb2, 0xb0, 0xb4, 0xb4, 0xb6, 0xb0, 0xb8, 0xb8, 0xba, 0xb8, 0xbc, 0xbc, 0xbe,
58
    0x80, 0xc0, 0xc0, 0xc2, 0xc0, 0xc4, 0xc4, 0xc6, 0xc0, 0xc8, 0xc8, 0xca, 0xc8, 0xcc, 0xcc, 0xce,
59
    0xc0, 0xd0, 0xd0, 0xd2, 0xd0, 0xd4, 0xd4, 0xd6, 0xd0, 0xd8, 0xd8, 0xda, 0xd8, 0xdc, 0xdc, 0xde,
60
    0xc0, 0xe0, 0xe0, 0xe2, 0xe0, 0xe4, 0xe4, 0xe6, 0xe0, 0xe8, 0xe8, 0xea, 0xe8, 0xec, 0xec, 0xee,
61
    0xe0, 0xf0, 0xf0, 0xf2, 0xf0, 0xf4, 0xf4, 0xf6, 0xf0, 0xf8, 0xf8, 0xfa, 0xf8, 0xfc, 0xfc, 0xfe};
62
63
// Fast lookup table to give the number of set bits in a byte.
64
const int BitVector::hamming_table_[256] = {
65
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
66
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
67
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
68
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
69
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
70
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
71
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
72
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
73
74
0
BitVector &BitVector::operator=(const BitVector &src) {
75
0
  array_ = src.array_;
76
0
  bit_size_ = src.bit_size_;
77
0
  return *this;
78
0
}
79
80
// Initializes the array to length * false.
81
0
void BitVector::Init(int length) {
82
0
  Alloc(length);
83
0
  SetAllFalse();
84
0
}
85
86
// Writes to the given file. Returns false in case of error.
87
0
bool BitVector::Serialize(FILE *fp) const {
88
0
  if (!tesseract::Serialize(fp, &bit_size_)) {
89
0
    return false;
90
0
  }
91
0
  int wordlen = WordLength();
92
0
  return tesseract::Serialize(fp, &array_[0], wordlen);
93
0
}
94
95
// Reads from the given file. Returns false in case of error.
96
// If swap is true, assumes a big/little-endian swap is needed.
97
0
bool BitVector::DeSerialize(bool swap, FILE *fp) {
98
0
  uint32_t new_bit_size;
99
0
  if (!tesseract::DeSerialize(fp, &new_bit_size)) {
100
0
    return false;
101
0
  }
102
0
  if (swap) {
103
0
    ReverseN(&new_bit_size, sizeof(new_bit_size));
104
0
  }
105
  // Reject unreasonably large bit vectors.
106
0
  if (new_bit_size > 500000000) {
107
0
    return false;
108
0
  }
109
0
  Alloc(new_bit_size);
110
0
  int wordlen = WordLength();
111
0
  if (!tesseract::DeSerialize(fp, &array_[0], wordlen)) {
112
0
    return false;
113
0
  }
114
0
  if (swap) {
115
0
    for (int i = 0; i < wordlen; ++i) {
116
0
      ReverseN(&array_[i], sizeof(array_[i]));
117
0
    }
118
0
  }
119
0
  return true;
120
0
}
121
122
0
void BitVector::SetAllFalse() {
123
0
  memset(&array_[0], 0, ByteLength());
124
0
}
125
0
void BitVector::SetAllTrue() {
126
0
  memset(&array_[0], ~0, ByteLength());
127
0
}
128
129
// Returns the index of the next set bit after the given index.
130
// Useful for quickly iterating through the set bits in a sparse vector.
131
0
int BitVector::NextSetBit(int prev_bit) const {
132
  // Move on to the next bit.
133
0
  int next_bit = prev_bit + 1;
134
0
  if (next_bit >= bit_size_) {
135
0
    return -1;
136
0
  }
137
  // Check the remains of the word containing the next_bit first.
138
0
  int next_word = WordIndex(next_bit);
139
0
  int bit_index = next_word * kBitFactor;
140
0
  int word_end = bit_index + kBitFactor;
141
0
  uint32_t word = array_[next_word];
142
0
  uint8_t byte = word & 0xff;
143
0
  while (bit_index < word_end) {
144
0
    if (bit_index + 8 > next_bit && byte != 0) {
145
0
      while (bit_index + lsb_index_[byte] < next_bit && byte != 0) {
146
0
        byte = lsb_eroded_[byte];
147
0
      }
148
0
      if (byte != 0) {
149
0
        return bit_index + lsb_index_[byte];
150
0
      }
151
0
    }
152
0
    word >>= 8;
153
0
    bit_index += 8;
154
0
    byte = word & 0xff;
155
0
  }
156
  // next_word didn't contain a 1, so find the next word with set bit.
157
0
  ++next_word;
158
0
  int wordlen = WordLength();
159
0
  while (next_word < wordlen && (word = array_[next_word]) == 0) {
160
0
    ++next_word;
161
0
    bit_index += kBitFactor;
162
0
  }
163
0
  if (bit_index >= bit_size_) {
164
0
    return -1;
165
0
  }
166
  // Find the first non-zero byte within the word.
167
0
  while ((word & 0xff) == 0) {
168
0
    word >>= 8;
169
0
    bit_index += 8;
170
0
  }
171
0
  return bit_index + lsb_index_[word & 0xff];
172
0
}
173
174
// Returns the number of set bits in the vector.
175
0
int BitVector::NumSetBits() const {
176
0
  int wordlen = WordLength();
177
0
  int total_bits = 0;
178
0
  for (int w = 0; w < wordlen; ++w) {
179
0
    uint32_t word = array_[w];
180
0
    for (int i = 0; i < 4; ++i) {
181
0
      total_bits += hamming_table_[word & 0xff];
182
0
      word >>= 8;
183
0
    }
184
0
  }
185
0
  return total_bits;
186
0
}
187
188
// Logical in-place operations on whole bit vectors. Tries to do something
189
// sensible if they aren't the same size, but they should be really.
190
0
void BitVector::operator|=(const BitVector &other) {
191
0
  int length = std::min(WordLength(), other.WordLength());
192
0
  for (int w = 0; w < length; ++w) {
193
0
    array_[w] |= other.array_[w];
194
0
  }
195
0
}
196
0
void BitVector::operator&=(const BitVector &other) {
197
0
  int length = std::min(WordLength(), other.WordLength());
198
0
  for (int w = 0; w < length; ++w) {
199
0
    array_[w] &= other.array_[w];
200
0
  }
201
0
  for (int w = WordLength() - 1; w >= length; --w) {
202
0
    array_[w] = 0;
203
0
  }
204
0
}
205
0
void BitVector::operator^=(const BitVector &other) {
206
0
  int length = std::min(WordLength(), other.WordLength());
207
0
  for (int w = 0; w < length; ++w) {
208
0
    array_[w] ^= other.array_[w];
209
0
  }
210
0
}
211
// Set subtraction *this = v1 - v2.
212
0
void BitVector::SetSubtract(const BitVector &v1, const BitVector &v2) {
213
0
  Alloc(v1.size());
214
0
  int length = std::min(v1.WordLength(), v2.WordLength());
215
0
  for (int w = 0; w < length; ++w) {
216
0
    array_[w] = v1.array_[w] ^ (v1.array_[w] & v2.array_[w]);
217
0
  }
218
0
  for (int w = WordLength() - 1; w >= length; --w) {
219
0
    array_[w] = v1.array_[w];
220
0
  }
221
0
}
222
223
// Allocates memory for a vector of the given length.
224
// Reallocates if the array is a different size, larger or smaller.
225
0
void BitVector::Alloc(int length) {
226
0
  int initial_wordlength = WordLength();
227
0
  bit_size_ = length;
228
0
  int new_wordlength = WordLength();
229
0
  if (new_wordlength != initial_wordlength) {
230
0
    array_.resize(new_wordlength);
231
0
  }
232
0
}
233
234
} // namespace tesseract.