/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. |