ewah: compressed bitmap implementation

EWAH is a word-aligned compressed variant of a bitset (i.e. a data structure that acts as a 0-indexed boolean array for many entries). It uses a 64-bit run-length encoding (RLE) compression scheme, trading some compression for better processing speed. The goal of this word-aligned implementation is not to achieve the best compression, but rather to improve query processing time. As it stands right now, this EWAH implementation will always be more efficient storage-wise than its uncompressed alternative. EWAH arrays will be used as the on-disk format to store reachability bitmaps for all objects in a repository while keeping reasonable sizes, in the same way that JGit does. This EWAH implementation is a mostly straightforward port of the original `javaewah` library that JGit currently uses. The library is self-contained and has been embedded whole (4 files) inside the `ewah` folder to ease redistribution. The library is re-licensed under the GPLv2 with the permission of Daniel Lemire, the original author. The source code for the C version can be found on GitHub: https://github.com/vmg/libewok The original Java implementation can also be found on GitHub: https://github.com/lemire/javaewah [jc: stripped debug-only code per Peff's $gmane/239768] Signed-off-by: Vicent Marti <tanoku@gmail.com> Signed-off-by: Jeff King <peff@peff.net> Helped-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Vicent Marti committed Nov 14, 2013 at 07:43 UTC e1273106f62927e3efdb1cfa107cb1a9f913274c
7 files changed +1599 -2
Makefile
+9 -2
@@ -667,6 +667,8 @@ LIB_H += diff.h
667 LIB_H += diffcore.h
668 LIB_H += dir.h
669 LIB_H += exec_cmd.h
670 +LIB_H += ewah/ewok.h
671 +LIB_H += ewah/ewok_rlw.h
672 LIB_H += fetch-pack.h
673 LIB_H += fmt-merge-msg.h
674 LIB_H += fsck.h
@@ -800,6 +802,10 @@ LIB_OBJS += dir.o
802 LIB_OBJS += editor.o
803 LIB_OBJS += entry.o
804 LIB_OBJS += environment.o
805 +LIB_OBJS += ewah/bitmap.o
806 +LIB_OBJS += ewah/ewah_bitmap.o
807 +LIB_OBJS += ewah/ewah_io.o
808 +LIB_OBJS += ewah/ewah_rlw.o
809 LIB_OBJS += exec_cmd.o
810 LIB_OBJS += fetch-pack.o
811 LIB_OBJS += fsck.o
@@ -2474,8 +2480,9 @@ profile-clean:
2480 $(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
2481
2482 clean: profile-clean coverage-clean
2477 - $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
2478 - builtin/*.o $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
2483 + $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o
2484 + $(RM) xdiff/*.o vcs-svn/*.o ewah/*.o builtin/*.o
2485 + $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
2486 $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
2487 $(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
2488 $(RM) -r bin-wrappers $(dep_dirs)
ewah/bitmap.c new
+221
@@ -0,0 +1,221 @@
1 +/**
2 + * Copyright 2013, GitHub, Inc
3 + * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
4 + * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
5 + *
6 + * This program is free software; you can redistribute it and/or
7 + * modify it under the terms of the GNU General Public License
8 + * as published by the Free Software Foundation; either version 2
9 + * of the License, or (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program; if not, write to the Free Software
18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 + */
20 +#include "git-compat-util.h"
21 +#include "ewok.h"
22 +
23 +#define MASK(x) ((eword_t)1 << (x % BITS_IN_WORD))
24 +#define BLOCK(x) (x / BITS_IN_WORD)
25 +
26 +struct bitmap *bitmap_new(void)
27 +{
28 + struct bitmap *bitmap = ewah_malloc(sizeof(struct bitmap));
29 + bitmap->words = ewah_calloc(32, sizeof(eword_t));
30 + bitmap->word_alloc = 32;
31 + return bitmap;
32 +}
33 +
34 +void bitmap_set(struct bitmap *self, size_t pos)
35 +{
36 + size_t block = BLOCK(pos);
37 +
38 + if (block >= self->word_alloc) {
39 + size_t old_size = self->word_alloc;
40 + self->word_alloc = block * 2;
41 + self->words = ewah_realloc(self->words,
42 + self->word_alloc * sizeof(eword_t));
43 +
44 + memset(self->words + old_size, 0x0,
45 + (self->word_alloc - old_size) * sizeof(eword_t));
46 + }
47 +
48 + self->words[block] |= MASK(pos);
49 +}
50 +
51 +void bitmap_clear(struct bitmap *self, size_t pos)
52 +{
53 + size_t block = BLOCK(pos);
54 +
55 + if (block < self->word_alloc)
56 + self->words[block] &= ~MASK(pos);
57 +}
58 +
59 +int bitmap_get(struct bitmap *self, size_t pos)
60 +{
61 + size_t block = BLOCK(pos);
62 + return block < self->word_alloc &&
63 + (self->words[block] & MASK(pos)) != 0;
64 +}
65 +
66 +struct ewah_bitmap *bitmap_to_ewah(struct bitmap *bitmap)
67 +{
68 + struct ewah_bitmap *ewah = ewah_new();
69 + size_t i, running_empty_words = 0;
70 + eword_t last_word = 0;
71 +
72 + for (i = 0; i < bitmap->word_alloc; ++i) {
73 + if (bitmap->words[i] == 0) {
74 + running_empty_words++;
75 + continue;
76 + }
77 +
78 + if (last_word != 0)
79 + ewah_add(ewah, last_word);
80 +
81 + if (running_empty_words > 0) {
82 + ewah_add_empty_words(ewah, 0, running_empty_words);
83 + running_empty_words = 0;
84 + }
85 +
86 + last_word = bitmap->words[i];
87 + }
88 +
89 + ewah_add(ewah, last_word);
90 + return ewah;
91 +}
92 +
93 +struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)
94 +{
95 + struct bitmap *bitmap = bitmap_new();
96 + struct ewah_iterator it;
97 + eword_t blowup;
98 + size_t i = 0;
99 +
100 + ewah_iterator_init(&it, ewah);
101 +
102 + while (ewah_iterator_next(&blowup, &it)) {
103 + if (i >= bitmap->word_alloc) {
104 + bitmap->word_alloc *= 1.5;
105 + bitmap->words = ewah_realloc(
106 + bitmap->words, bitmap->word_alloc * sizeof(eword_t));
107 + }
108 +
109 + bitmap->words[i++] = blowup;
110 + }
111 +
112 + bitmap->word_alloc = i;
113 + return bitmap;
114 +}
115 +
116 +void bitmap_and_not(struct bitmap *self, struct bitmap *other)
117 +{
118 + const size_t count = (self->word_alloc < other->word_alloc) ?
119 + self->word_alloc : other->word_alloc;
120 +
121 + size_t i;
122 +
123 + for (i = 0; i < count; ++i)
124 + self->words[i] &= ~other->words[i];
125 +}
126 +
127 +void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)
128 +{
129 + size_t original_size = self->word_alloc;
130 + size_t other_final = (other->bit_size / BITS_IN_WORD) + 1;
131 + size_t i = 0;
132 + struct ewah_iterator it;
133 + eword_t word;
134 +
135 + if (self->word_alloc < other_final) {
136 + self->word_alloc = other_final;
137 + self->words = ewah_realloc(self->words,
138 + self->word_alloc * sizeof(eword_t));
139 + memset(self->words + original_size, 0x0,
140 + (self->word_alloc - original_size) * sizeof(eword_t));
141 + }
142 +
143 + ewah_iterator_init(&it, other);
144 +
145 + while (ewah_iterator_next(&word, &it))
146 + self->words[i++] |= word;
147 +}
148 +
149 +void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data)
150 +{
151 + size_t pos = 0, i;
152 +
153 + for (i = 0; i < self->word_alloc; ++i) {
154 + eword_t word = self->words[i];
155 + uint32_t offset;
156 +
157 + if (word == (eword_t)~0) {
158 + for (offset = 0; offset < BITS_IN_WORD; ++offset)
159 + callback(pos++, data);
160 + } else {
161 + for (offset = 0; offset < BITS_IN_WORD; ++offset) {
162 + if ((word >> offset) == 0)
163 + break;
164 +
165 + offset += ewah_bit_ctz64(word >> offset);
166 + callback(pos + offset, data);
167 + }
168 + pos += BITS_IN_WORD;
169 + }
170 + }
171 +}
172 +
173 +size_t bitmap_popcount(struct bitmap *self)
174 +{
175 + size_t i, count = 0;
176 +
177 + for (i = 0; i < self->word_alloc; ++i)
178 + count += ewah_bit_popcount64(self->words[i]);
179 +
180 + return count;
181 +}
182 +
183 +int bitmap_equals(struct bitmap *self, struct bitmap *other)
184 +{
185 + struct bitmap *big, *small;
186 + size_t i;
187 +
188 + if (self->word_alloc < other->word_alloc) {
189 + small = self;
190 + big = other;
191 + } else {
192 + small = other;
193 + big = self;
194 + }
195 +
196 + for (i = 0; i < small->word_alloc; ++i) {
197 + if (small->words[i] != big->words[i])
198 + return 0;
199 + }
200 +
201 + for (; i < big->word_alloc; ++i) {
202 + if (big->words[i] != 0)
203 + return 0;
204 + }
205 +
206 + return 1;
207 +}
208 +
209 +void bitmap_reset(struct bitmap *bitmap)
210 +{
211 + memset(bitmap->words, 0x0, bitmap->word_alloc * sizeof(eword_t));
212 +}
213 +
214 +void bitmap_free(struct bitmap *bitmap)
215 +{
216 + if (bitmap == NULL)
217 + return;
218 +
219 + free(bitmap->words);
220 + free(bitmap);
221 +}
ewah/ewah_bitmap.c new
+714
@@ -0,0 +1,714 @@
1 +/**
2 + * Copyright 2013, GitHub, Inc
3 + * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
4 + * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
5 + *
6 + * This program is free software; you can redistribute it and/or
7 + * modify it under the terms of the GNU General Public License
8 + * as published by the Free Software Foundation; either version 2
9 + * of the License, or (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program; if not, write to the Free Software
18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 + */
20 +#include "git-compat-util.h"
21 +#include "ewok.h"
22 +#include "ewok_rlw.h"
23 +
24 +static inline size_t min_size(size_t a, size_t b)
25 +{
26 + return a < b ? a : b;
27 +}
28 +
29 +static inline size_t max_size(size_t a, size_t b)
30 +{
31 + return a > b ? a : b;
32 +}
33 +
34 +static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)
35 +{
36 + size_t rlw_offset = (uint8_t *)self->rlw - (uint8_t *)self->buffer;
37 +
38 + if (self->alloc_size >= new_size)
39 + return;
40 +
41 + self->alloc_size = new_size;
42 + self->buffer = ewah_realloc(self->buffer,
43 + self->alloc_size * sizeof(eword_t));
44 + self->rlw = self->buffer + (rlw_offset / sizeof(size_t));
45 +}
46 +
47 +static inline void buffer_push(struct ewah_bitmap *self, eword_t value)
48 +{
49 + if (self->buffer_size + 1 >= self->alloc_size)
50 + buffer_grow(self, self->buffer_size * 3 / 2);
51 +
52 + self->buffer[self->buffer_size++] = value;
53 +}
54 +
55 +static void buffer_push_rlw(struct ewah_bitmap *self, eword_t value)
56 +{
57 + buffer_push(self, value);
58 + self->rlw = self->buffer + self->buffer_size - 1;
59 +}
60 +
61 +static size_t add_empty_words(struct ewah_bitmap *self, int v, size_t number)
62 +{
63 + size_t added = 0;
64 + eword_t runlen, can_add;
65 +
66 + if (rlw_get_run_bit(self->rlw) != v && rlw_size(self->rlw) == 0) {
67 + rlw_set_run_bit(self->rlw, v);
68 + } else if (rlw_get_literal_words(self->rlw) != 0 ||
69 + rlw_get_run_bit(self->rlw) != v) {
70 + buffer_push_rlw(self, 0);
71 + if (v) rlw_set_run_bit(self->rlw, v);
72 + added++;
73 + }
74 +
75 + runlen = rlw_get_running_len(self->rlw);
76 + can_add = min_size(number, RLW_LARGEST_RUNNING_COUNT - runlen);
77 +
78 + rlw_set_running_len(self->rlw, runlen + can_add);
79 + number -= can_add;
80 +
81 + while (number >= RLW_LARGEST_RUNNING_COUNT) {
82 + buffer_push_rlw(self, 0);
83 + added++;
84 + if (v) rlw_set_run_bit(self->rlw, v);
85 + rlw_set_running_len(self->rlw, RLW_LARGEST_RUNNING_COUNT);
86 + number -= RLW_LARGEST_RUNNING_COUNT;
87 + }
88 +
89 + if (number > 0) {
90 + buffer_push_rlw(self, 0);
91 + added++;
92 +
93 + if (v) rlw_set_run_bit(self->rlw, v);
94 + rlw_set_running_len(self->rlw, number);
95 + }
96 +
97 + return added;
98 +}
99 +
100 +size_t ewah_add_empty_words(struct ewah_bitmap *self, int v, size_t number)
101 +{
102 + if (number == 0)
103 + return 0;
104 +
105 + self->bit_size += number * BITS_IN_WORD;
106 + return add_empty_words(self, v, number);
107 +}
108 +
109 +static size_t add_literal(struct ewah_bitmap *self, eword_t new_data)
110 +{
111 + eword_t current_num = rlw_get_literal_words(self->rlw);
112 +
113 + if (current_num >= RLW_LARGEST_LITERAL_COUNT) {
114 + buffer_push_rlw(self, 0);
115 +
116 + rlw_set_literal_words(self->rlw, 1);
117 + buffer_push(self, new_data);
118 + return 2;
119 + }
120 +
121 + rlw_set_literal_words(self->rlw, current_num + 1);
122 +
123 + /* sanity check */
124 + assert(rlw_get_literal_words(self->rlw) == current_num + 1);
125 +
126 + buffer_push(self, new_data);
127 + return 1;
128 +}
129 +
130 +void ewah_add_dirty_words(
131 + struct ewah_bitmap *self, const eword_t *buffer,
132 + size_t number, int negate)
133 +{
134 + size_t literals, can_add;
135 +
136 + while (1) {
137 + literals = rlw_get_literal_words(self->rlw);
138 + can_add = min_size(number, RLW_LARGEST_LITERAL_COUNT - literals);
139 +
140 + rlw_set_literal_words(self->rlw, literals + can_add);
141 +
142 + if (self->buffer_size + can_add >= self->alloc_size)
143 + buffer_grow(self, (self->buffer_size + can_add) * 3 / 2);
144 +
145 + if (negate) {
146 + size_t i;
147 + for (i = 0; i < can_add; ++i)
148 + self->buffer[self->buffer_size++] = ~buffer[i];
149 + } else {
150 + memcpy(self->buffer + self->buffer_size,
151 + buffer, can_add * sizeof(eword_t));
152 + self->buffer_size += can_add;
153 + }
154 +
155 + self->bit_size += can_add * BITS_IN_WORD;
156 +
157 + if (number - can_add == 0)
158 + break;
159 +
160 + buffer_push_rlw(self, 0);
161 + buffer += can_add;
162 + number -= can_add;
163 + }
164 +}
165 +
166 +static size_t add_empty_word(struct ewah_bitmap *self, int v)
167 +{
168 + int no_literal = (rlw_get_literal_words(self->rlw) == 0);
169 + eword_t run_len = rlw_get_running_len(self->rlw);
170 +
171 + if (no_literal && run_len == 0) {
172 + rlw_set_run_bit(self->rlw, v);
173 + assert(rlw_get_run_bit(self->rlw) == v);
174 + }
175 +
176 + if (no_literal && rlw_get_run_bit(self->rlw) == v &&
177 + run_len < RLW_LARGEST_RUNNING_COUNT) {
178 + rlw_set_running_len(self->rlw, run_len + 1);
179 + assert(rlw_get_running_len(self->rlw) == run_len + 1);
180 + return 0;
181 + } else {
182 + buffer_push_rlw(self, 0);
183 +
184 + assert(rlw_get_running_len(self->rlw) == 0);
185 + assert(rlw_get_run_bit(self->rlw) == 0);
186 + assert(rlw_get_literal_words(self->rlw) == 0);
187 +
188 + rlw_set_run_bit(self->rlw, v);
189 + assert(rlw_get_run_bit(self->rlw) == v);
190 +
191 + rlw_set_running_len(self->rlw, 1);
192 + assert(rlw_get_running_len(self->rlw) == 1);
193 + assert(rlw_get_literal_words(self->rlw) == 0);
194 + return 1;
195 + }
196 +}
197 +
198 +size_t ewah_add(struct ewah_bitmap *self, eword_t word)
199 +{
200 + self->bit_size += BITS_IN_WORD;
201 +
202 + if (word == 0)
203 + return add_empty_word(self, 0);
204 +
205 + if (word == (eword_t)(~0))
206 + return add_empty_word(self, 1);
207 +
208 + return add_literal(self, word);
209 +}
210 +
211 +void ewah_set(struct ewah_bitmap *self, size_t i)
212 +{
213 + const size_t dist =
214 + (i + BITS_IN_WORD) / BITS_IN_WORD -
215 + (self->bit_size + BITS_IN_WORD - 1) / BITS_IN_WORD;
216 +
217 + assert(i >= self->bit_size);
218 +
219 + self->bit_size = i + 1;
220 +
221 + if (dist > 0) {
222 + if (dist > 1)
223 + add_empty_words(self, 0, dist - 1);
224 +
225 + add_literal(self, (eword_t)1 << (i % BITS_IN_WORD));
226 + return;
227 + }
228 +
229 + if (rlw_get_literal_words(self->rlw) == 0) {
230 + rlw_set_running_len(self->rlw,
231 + rlw_get_running_len(self->rlw) - 1);
232 + add_literal(self, (eword_t)1 << (i % BITS_IN_WORD));
233 + return;
234 + }
235 +
236 + self->buffer[self->buffer_size - 1] |=
237 + ((eword_t)1 << (i % BITS_IN_WORD));
238 +
239 + /* check if we just completed a stream of 1s */
240 + if (self->buffer[self->buffer_size - 1] == (eword_t)(~0)) {
241 + self->buffer[--self->buffer_size] = 0;
242 + rlw_set_literal_words(self->rlw,
243 + rlw_get_literal_words(self->rlw) - 1);
244 + add_empty_word(self, 1);
245 + }
246 +}
247 +
248 +void ewah_each_bit(struct ewah_bitmap *self, void (*callback)(size_t, void*), void *payload)
249 +{
250 + size_t pos = 0;
251 + size_t pointer = 0;
252 + size_t k;
253 +
254 + while (pointer < self->buffer_size) {
255 + eword_t *word = &self->buffer[pointer];
256 +
257 + if (rlw_get_run_bit(word)) {
258 + size_t len = rlw_get_running_len(word) * BITS_IN_WORD;
259 + for (k = 0; k < len; ++k, ++pos)
260 + callback(pos, payload);
261 + } else {
262 + pos += rlw_get_running_len(word) * BITS_IN_WORD;
263 + }
264 +
265 + ++pointer;
266 +
267 + for (k = 0; k < rlw_get_literal_words(word); ++k) {
268 + int c;
269 +
270 + /* todo: zero count optimization */
271 + for (c = 0; c < BITS_IN_WORD; ++c, ++pos) {
272 + if ((self->buffer[pointer] & ((eword_t)1 << c)) != 0)
273 + callback(pos, payload);
274 + }
275 +
276 + ++pointer;
277 + }
278 + }
279 +}
280 +
281 +struct ewah_bitmap *ewah_new(void)
282 +{
283 + struct ewah_bitmap *self;
284 +
285 + self = ewah_malloc(sizeof(struct ewah_bitmap));
286 + if (self == NULL)
287 + return NULL;
288 +
289 + self->buffer = ewah_malloc(32 * sizeof(eword_t));
290 + self->alloc_size = 32;
291 +
292 + ewah_clear(self);
293 + return self;
294 +}
295 +
296 +void ewah_clear(struct ewah_bitmap *self)
297 +{
298 + self->buffer_size = 1;
299 + self->buffer[0] = 0;
300 + self->bit_size = 0;
301 + self->rlw = self->buffer;
302 +}
303 +
304 +void ewah_free(struct ewah_bitmap *self)
305 +{
306 + if (!self)
307 + return;
308 +
309 + if (self->alloc_size)
310 + free(self->buffer);
311 +
312 + free(self);
313 +}
314 +
315 +static void read_new_rlw(struct ewah_iterator *it)
316 +{
317 + const eword_t *word = NULL;
318 +
319 + it->literals = 0;
320 + it->compressed = 0;
321 +
322 + while (1) {
323 + word = &it->buffer[it->pointer];
324 +
325 + it->rl = rlw_get_running_len(word);
326 + it->lw = rlw_get_literal_words(word);
327 + it->b = rlw_get_run_bit(word);
328 +
329 + if (it->rl || it->lw)
330 + return;
331 +
332 + if (it->pointer < it->buffer_size - 1) {
333 + it->pointer++;
334 + } else {
335 + it->pointer = it->buffer_size;
336 + return;
337 + }
338 + }
339 +}
340 +
341 +int ewah_iterator_next(eword_t *next, struct ewah_iterator *it)
342 +{
343 + if (it->pointer >= it->buffer_size)
344 + return 0;
345 +
346 + if (it->compressed < it->rl) {
347 + it->compressed++;
348 + *next = it->b ? (eword_t)(~0) : 0;
349 + } else {
350 + assert(it->literals < it->lw);
351 +
352 + it->literals++;
353 + it->pointer++;
354 +
355 + assert(it->pointer < it->buffer_size);
356 +
357 + *next = it->buffer[it->pointer];
358 + }
359 +
360 + if (it->compressed == it->rl && it->literals == it->lw) {
361 + if (++it->pointer < it->buffer_size)
362 + read_new_rlw(it);
363 + }
364 +
365 + return 1;
366 +}
367 +
368 +void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent)
369 +{
370 + it->buffer = parent->buffer;
371 + it->buffer_size = parent->buffer_size;
372 + it->pointer = 0;
373 +
374 + it->lw = 0;
375 + it->rl = 0;
376 + it->compressed = 0;
377 + it->literals = 0;
378 + it->b = 0;
379 +
380 + if (it->pointer < it->buffer_size)
381 + read_new_rlw(it);
382 +}
383 +
384 +void ewah_not(struct ewah_bitmap *self)
385 +{
386 + size_t pointer = 0;
387 +
388 + while (pointer < self->buffer_size) {
389 + eword_t *word = &self->buffer[pointer];
390 + size_t literals, k;
391 +
392 + rlw_xor_run_bit(word);
393 + ++pointer;
394 +
395 + literals = rlw_get_literal_words(word);
396 + for (k = 0; k < literals; ++k) {
397 + self->buffer[pointer] = ~self->buffer[pointer];
398 + ++pointer;
399 + }
400 + }
401 +}
402 +
403 +void ewah_xor(
404 + struct ewah_bitmap *ewah_i,
405 + struct ewah_bitmap *ewah_j,
406 + struct ewah_bitmap *out)
407 +{
408 + struct rlw_iterator rlw_i;
409 + struct rlw_iterator rlw_j;
410 + size_t literals;
411 +
412 + rlwit_init(&rlw_i, ewah_i);
413 + rlwit_init(&rlw_j, ewah_j);
414 +
415 + while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
416 + while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
417 + struct rlw_iterator *prey, *predator;
418 + size_t index;
419 + int negate_words;
420 +
421 + if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
422 + prey = &rlw_i;
423 + predator = &rlw_j;
424 + } else {
425 + prey = &rlw_j;
426 + predator = &rlw_i;
427 + }
428 +
429 + negate_words = !!predator->rlw.running_bit;
430 + index = rlwit_discharge(prey, out,
431 + predator->rlw.running_len, negate_words);
432 +
433 + ewah_add_empty_words(out, negate_words,
434 + predator->rlw.running_len - index);
435 +
436 + rlwit_discard_first_words(predator,
437 + predator->rlw.running_len);
438 + }
439 +
440 + literals = min_size(
441 + rlw_i.rlw.literal_words,
442 + rlw_j.rlw.literal_words);
443 +
444 + if (literals) {
445 + size_t k;
446 +
447 + for (k = 0; k < literals; ++k) {
448 + ewah_add(out,
449 + rlw_i.buffer[rlw_i.literal_word_start + k] ^
450 + rlw_j.buffer[rlw_j.literal_word_start + k]
451 + );
452 + }
453 +
454 + rlwit_discard_first_words(&rlw_i, literals);
455 + rlwit_discard_first_words(&rlw_j, literals);
456 + }
457 + }
458 +
459 + if (rlwit_word_size(&rlw_i) > 0)
460 + rlwit_discharge(&rlw_i, out, ~0, 0);
461 + else
462 + rlwit_discharge(&rlw_j, out, ~0, 0);
463 +
464 + out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
465 +}
466 +
467 +void ewah_and(
468 + struct ewah_bitmap *ewah_i,
469 + struct ewah_bitmap *ewah_j,
470 + struct ewah_bitmap *out)
471 +{
472 + struct rlw_iterator rlw_i;
473 + struct rlw_iterator rlw_j;
474 + size_t literals;
475 +
476 + rlwit_init(&rlw_i, ewah_i);
477 + rlwit_init(&rlw_j, ewah_j);
478 +
479 + while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
480 + while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
481 + struct rlw_iterator *prey, *predator;
482 +
483 + if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
484 + prey = &rlw_i;
485 + predator = &rlw_j;
486 + } else {
487 + prey = &rlw_j;
488 + predator = &rlw_i;
489 + }
490 +
491 + if (predator->rlw.running_bit == 0) {
492 + ewah_add_empty_words(out, 0,
493 + predator->rlw.running_len);
494 + rlwit_discard_first_words(prey,
495 + predator->rlw.running_len);
496 + rlwit_discard_first_words(predator,
497 + predator->rlw.running_len);
498 + } else {
499 + size_t index = rlwit_discharge(prey, out,
500 + predator->rlw.running_len, 0);
501 + ewah_add_empty_words(out, 0,
502 + predator->rlw.running_len - index);
503 + rlwit_discard_first_words(predator,
504 + predator->rlw.running_len);
505 + }
506 + }
507 +
508 + literals = min_size(
509 + rlw_i.rlw.literal_words,
510 + rlw_j.rlw.literal_words);
511 +
512 + if (literals) {
513 + size_t k;
514 +
515 + for (k = 0; k < literals; ++k) {
516 + ewah_add(out,
517 + rlw_i.buffer[rlw_i.literal_word_start + k] &
518 + rlw_j.buffer[rlw_j.literal_word_start + k]
519 + );
520 + }
521 +
522 + rlwit_discard_first_words(&rlw_i, literals);
523 + rlwit_discard_first_words(&rlw_j, literals);
524 + }
525 + }
526 +
527 + if (rlwit_word_size(&rlw_i) > 0)
528 + rlwit_discharge_empty(&rlw_i, out);
529 + else
530 + rlwit_discharge_empty(&rlw_j, out);
531 +
532 + out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
533 +}
534 +
535 +void ewah_and_not(
536 + struct ewah_bitmap *ewah_i,
537 + struct ewah_bitmap *ewah_j,
538 + struct ewah_bitmap *out)
539 +{
540 + struct rlw_iterator rlw_i;
541 + struct rlw_iterator rlw_j;
542 + size_t literals;
543 +
544 + rlwit_init(&rlw_i, ewah_i);
545 + rlwit_init(&rlw_j, ewah_j);
546 +
547 + while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
548 + while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
549 + struct rlw_iterator *prey, *predator;
550 +
551 + if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
552 + prey = &rlw_i;
553 + predator = &rlw_j;
554 + } else {
555 + prey = &rlw_j;
556 + predator = &rlw_i;
557 + }
558 +
559 + if ((predator->rlw.running_bit && prey == &rlw_i) ||
560 + (!predator->rlw.running_bit && prey != &rlw_i)) {
561 + ewah_add_empty_words(out, 0,
562 + predator->rlw.running_len);
563 + rlwit_discard_first_words(prey,
564 + predator->rlw.running_len);
565 + rlwit_discard_first_words(predator,
566 + predator->rlw.running_len);
567 + } else {
568 + size_t index;
569 + int negate_words;
570 +
571 + negate_words = (&rlw_i != prey);
572 + index = rlwit_discharge(prey, out,
573 + predator->rlw.running_len, negate_words);
574 + ewah_add_empty_words(out, negate_words,
575 + predator->rlw.running_len - index);
576 + rlwit_discard_first_words(predator,
577 + predator->rlw.running_len);
578 + }
579 + }
580 +
581 + literals = min_size(
582 + rlw_i.rlw.literal_words,
583 + rlw_j.rlw.literal_words);
584 +
585 + if (literals) {
586 + size_t k;
587 +
588 + for (k = 0; k < literals; ++k) {
589 + ewah_add(out,
590 + rlw_i.buffer[rlw_i.literal_word_start + k] &
591 + ~(rlw_j.buffer[rlw_j.literal_word_start + k])
592 + );
593 + }
594 +
595 + rlwit_discard_first_words(&rlw_i, literals);
596 + rlwit_discard_first_words(&rlw_j, literals);
597 + }
598 + }
599 +
600 + if (rlwit_word_size(&rlw_i) > 0)
601 + rlwit_discharge(&rlw_i, out, ~0, 0);
602 + else
603 + rlwit_discharge_empty(&rlw_j, out);
604 +
605 + out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
606 +}
607 +
608 +void ewah_or(
609 + struct ewah_bitmap *ewah_i,
610 + struct ewah_bitmap *ewah_j,
611 + struct ewah_bitmap *out)
612 +{
613 + struct rlw_iterator rlw_i;
614 + struct rlw_iterator rlw_j;
615 + size_t literals;
616 +
617 + rlwit_init(&rlw_i, ewah_i);
618 + rlwit_init(&rlw_j, ewah_j);
619 +
620 + while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
621 + while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
622 + struct rlw_iterator *prey, *predator;
623 +
624 + if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
625 + prey = &rlw_i;
626 + predator = &rlw_j;
627 + } else {
628 + prey = &rlw_j;
629 + predator = &rlw_i;
630 + }
631 +
632 + if (predator->rlw.running_bit) {
633 + ewah_add_empty_words(out, 0,
634 + predator->rlw.running_len);
635 + rlwit_discard_first_words(prey,
636 + predator->rlw.running_len);
637 + rlwit_discard_first_words(predator,
638 + predator->rlw.running_len);
639 + } else {
640 + size_t index = rlwit_discharge(prey, out,
641 + predator->rlw.running_len, 0);
642 + ewah_add_empty_words(out, 0,
643 + predator->rlw.running_len - index);
644 + rlwit_discard_first_words(predator,
645 + predator->rlw.running_len);
646 + }
647 + }
648 +
649 + literals = min_size(
650 + rlw_i.rlw.literal_words,
651 + rlw_j.rlw.literal_words);
652 +
653 + if (literals) {
654 + size_t k;
655 +
656 + for (k = 0; k < literals; ++k) {
657 + ewah_add(out,
658 + rlw_i.buffer[rlw_i.literal_word_start + k] |
659 + rlw_j.buffer[rlw_j.literal_word_start + k]
660 + );
661 + }
662 +
663 + rlwit_discard_first_words(&rlw_i, literals);
664 + rlwit_discard_first_words(&rlw_j, literals);
665 + }
666 + }
667 +
668 + if (rlwit_word_size(&rlw_i) > 0)
669 + rlwit_discharge(&rlw_i, out, ~0, 0);
670 + else
671 + rlwit_discharge(&rlw_j, out, ~0, 0);
672 +
673 + out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
674 +}
675 +
676 +
677 +#define BITMAP_POOL_MAX 16
678 +static struct ewah_bitmap *bitmap_pool[BITMAP_POOL_MAX];
679 +static size_t bitmap_pool_size;
680 +
681 +struct ewah_bitmap *ewah_pool_new(void)
682 +{
683 + if (bitmap_pool_size)
684 + return bitmap_pool[--bitmap_pool_size];
685 +
686 + return ewah_new();
687 +}
688 +
689 +void ewah_pool_free(struct ewah_bitmap *self)
690 +{
691 + if (self == NULL)
692 + return;
693 +
694 + if (bitmap_pool_size == BITMAP_POOL_MAX ||
695 + self->alloc_size == 0) {
696 + ewah_free(self);
697 + return;
698 + }
699 +
700 + ewah_clear(self);
701 + bitmap_pool[bitmap_pool_size++] = self;
702 +}
703 +
704 +uint32_t ewah_checksum(struct ewah_bitmap *self)
705 +{
706 + const uint8_t *p = (uint8_t *)self->buffer;
707 + uint32_t crc = (uint32_t)self->bit_size;
708 + size_t size = self->buffer_size * sizeof(eword_t);
709 +
710 + while (size--)
711 + crc = (crc << 5) - crc + (uint32_t)*p++;
712 +
713 + return crc;
714 +}
ewah/ewah_io.c new
+193
@@ -0,0 +1,193 @@
1 +/**
2 + * Copyright 2013, GitHub, Inc
3 + * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
4 + * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
5 + *
6 + * This program is free software; you can redistribute it and/or
7 + * modify it under the terms of the GNU General Public License
8 + * as published by the Free Software Foundation; either version 2
9 + * of the License, or (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program; if not, write to the Free Software
18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 + */
20 +#include "git-compat-util.h"
21 +#include "ewok.h"
22 +
23 +int ewah_serialize_native(struct ewah_bitmap *self, int fd)
24 +{
25 + uint32_t write32;
26 + size_t to_write = self->buffer_size * 8;
27 +
28 + /* 32 bit -- bit size for the map */
29 + write32 = (uint32_t)self->bit_size;
30 + if (write(fd, &write32, 4) != 4)
31 + return -1;
32 +
33 + /** 32 bit -- number of compressed 64-bit words */
34 + write32 = (uint32_t)self->buffer_size;
35 + if (write(fd, &write32, 4) != 4)
36 + return -1;
37 +
38 + if (write(fd, self->buffer, to_write) != to_write)
39 + return -1;
40 +
41 + /** 32 bit -- position for the RLW */
42 + write32 = self->rlw - self->buffer;
43 + if (write(fd, &write32, 4) != 4)
44 + return -1;
45 +
46 + return (3 * 4) + to_write;
47 +}
48 +
49 +int ewah_serialize_to(struct ewah_bitmap *self,
50 + int (*write_fun)(void *, const void *, size_t),
51 + void *data)
52 +{
53 + size_t i;
54 + eword_t dump[2048];
55 + const size_t words_per_dump = sizeof(dump) / sizeof(eword_t);
56 + uint32_t bitsize, word_count, rlw_pos;
57 +
58 + const eword_t *buffer;
59 + size_t words_left;
60 +
61 + /* 32 bit -- bit size for the map */
62 + bitsize = htonl((uint32_t)self->bit_size);
63 + if (write_fun(data, &bitsize, 4) != 4)
64 + return -1;
65 +
66 + /** 32 bit -- number of compressed 64-bit words */
67 + word_count = htonl((uint32_t)self->buffer_size);
68 + if (write_fun(data, &word_count, 4) != 4)
69 + return -1;
70 +
71 + /** 64 bit x N -- compressed words */
72 + buffer = self->buffer;
73 + words_left = self->buffer_size;
74 +
75 + while (words_left >= words_per_dump) {
76 + for (i = 0; i < words_per_dump; ++i, ++buffer)
77 + dump[i] = htonll(*buffer);
78 +
79 + if (write_fun(data, dump, sizeof(dump)) != sizeof(dump))
80 + return -1;
81 +
82 + words_left -= words_per_dump;
83 + }
84 +
85 + if (words_left) {
86 + for (i = 0; i < words_left; ++i, ++buffer)
87 + dump[i] = htonll(*buffer);
88 +
89 + if (write_fun(data, dump, words_left * 8) != words_left * 8)
90 + return -1;
91 + }
92 +
93 + /** 32 bit -- position for the RLW */
94 + rlw_pos = (uint8_t*)self->rlw - (uint8_t *)self->buffer;
95 + rlw_pos = htonl(rlw_pos / sizeof(eword_t));
96 +
97 + if (write_fun(data, &rlw_pos, 4) != 4)
98 + return -1;
99 +
100 + return (3 * 4) + (self->buffer_size * 8);
101 +}
102 +
103 +static int write_helper(void *fd, const void *buf, size_t len)
104 +{
105 + return write((intptr_t)fd, buf, len);
106 +}
107 +
108 +int ewah_serialize(struct ewah_bitmap *self, int fd)
109 +{
110 + return ewah_serialize_to(self, write_helper, (void *)(intptr_t)fd);
111 +}
112 +
113 +int ewah_read_mmap(struct ewah_bitmap *self, void *map, size_t len)
114 +{
115 + uint32_t *read32 = map;
116 + eword_t *read64;
117 + size_t i;
118 +
119 + self->bit_size = ntohl(*read32++);
120 + self->buffer_size = self->alloc_size = ntohl(*read32++);
121 + self->buffer = ewah_realloc(self->buffer,
122 + self->alloc_size * sizeof(eword_t));
123 +
124 + if (!self->buffer)
125 + return -1;
126 +
127 + for (i = 0, read64 = (void *)read32; i < self->buffer_size; ++i)
128 + self->buffer[i] = ntohll(*read64++);
129 +
130 + read32 = (void *)read64;
131 + self->rlw = self->buffer + ntohl(*read32++);
132 +
133 + return (3 * 4) + (self->buffer_size * 8);
134 +}
135 +
136 +int ewah_deserialize(struct ewah_bitmap *self, int fd)
137 +{
138 + size_t i;
139 + eword_t dump[2048];
140 + const size_t words_per_dump = sizeof(dump) / sizeof(eword_t);
141 + uint32_t bitsize, word_count, rlw_pos;
142 +
143 + eword_t *buffer = NULL;
144 + size_t words_left;
145 +
146 + ewah_clear(self);
147 +
148 + /* 32 bit -- bit size for the map */
149 + if (read(fd, &bitsize, 4) != 4)
150 + return -1;
151 +
152 + self->bit_size = (size_t)ntohl(bitsize);
153 +
154 + /** 32 bit -- number of compressed 64-bit words */
155 + if (read(fd, &word_count, 4) != 4)
156 + return -1;
157 +
158 + self->buffer_size = self->alloc_size = (size_t)ntohl(word_count);
159 + self->buffer = ewah_realloc(self->buffer,
160 + self->alloc_size * sizeof(eword_t));
161 +
162 + if (!self->buffer)
163 + return -1;
164 +
165 + /** 64 bit x N -- compressed words */
166 + buffer = self->buffer;
167 + words_left = self->buffer_size;
168 +
169 + while (words_left >= words_per_dump) {
170 + if (read(fd, dump, sizeof(dump)) != sizeof(dump))
171 + return -1;
172 +
173 + for (i = 0; i < words_per_dump; ++i, ++buffer)
174 + *buffer = ntohll(dump[i]);
175 +
176 + words_left -= words_per_dump;
177 + }
178 +
179 + if (words_left) {
180 + if (read(fd, dump, words_left * 8) != words_left * 8)
181 + return -1;
182 +
183 + for (i = 0; i < words_left; ++i, ++buffer)
184 + *buffer = ntohll(dump[i]);
185 + }
186 +
187 + /** 32 bit -- position for the RLW */
188 + if (read(fd, &rlw_pos, 4) != 4)
189 + return -1;
190 +
191 + self->rlw = self->buffer + ntohl(rlw_pos);
192 + return 0;
193 +}
ewah/ewah_rlw.c new
+115
@@ -0,0 +1,115 @@
1 +/**
2 + * Copyright 2013, GitHub, Inc
3 + * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
4 + * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
5 + *
6 + * This program is free software; you can redistribute it and/or
7 + * modify it under the terms of the GNU General Public License
8 + * as published by the Free Software Foundation; either version 2
9 + * of the License, or (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program; if not, write to the Free Software
18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 + */
20 +#include "git-compat-util.h"
21 +#include "ewok.h"
22 +#include "ewok_rlw.h"
23 +
24 +static inline int next_word(struct rlw_iterator *it)
25 +{
26 + if (it->pointer >= it->size)
27 + return 0;
28 +
29 + it->rlw.word = &it->buffer[it->pointer];
30 + it->pointer += rlw_get_literal_words(it->rlw.word) + 1;
31 +
32 + it->rlw.literal_words = rlw_get_literal_words(it->rlw.word);
33 + it->rlw.running_len = rlw_get_running_len(it->rlw.word);
34 + it->rlw.running_bit = rlw_get_run_bit(it->rlw.word);
35 + it->rlw.literal_word_offset = 0;
36 +
37 + return 1;
38 +}
39 +
40 +void rlwit_init(struct rlw_iterator *it, struct ewah_bitmap *from_ewah)
41 +{
42 + it->buffer = from_ewah->buffer;
43 + it->size = from_ewah->buffer_size;
44 + it->pointer = 0;
45 +
46 + next_word(it);
47 +
48 + it->literal_word_start = rlwit_literal_words(it) +
49 + it->rlw.literal_word_offset;
50 +}
51 +
52 +void rlwit_discard_first_words(struct rlw_iterator *it, size_t x)
53 +{
54 + while (x > 0) {
55 + size_t discard;
56 +
57 + if (it->rlw.running_len > x) {
58 + it->rlw.running_len -= x;
59 + return;
60 + }
61 +
62 + x -= it->rlw.running_len;
63 + it->rlw.running_len = 0;
64 +
65 + discard = (x > it->rlw.literal_words) ? it->rlw.literal_words : x;
66 +
67 + it->literal_word_start += discard;
68 + it->rlw.literal_words -= discard;
69 + x -= discard;
70 +
71 + if (x > 0 || rlwit_word_size(it) == 0) {
72 + if (!next_word(it))
73 + break;
74 +
75 + it->literal_word_start =
76 + rlwit_literal_words(it) + it->rlw.literal_word_offset;
77 + }
78 + }
79 +}
80 +
81 +size_t rlwit_discharge(
82 + struct rlw_iterator *it, struct ewah_bitmap *out, size_t max, int negate)
83 +{
84 + size_t index = 0;
85 +
86 + while (index < max && rlwit_word_size(it) > 0) {
87 + size_t pd, pl = it->rlw.running_len;
88 +
89 + if (index + pl > max)
90 + pl = max - index;
91 +
92 + ewah_add_empty_words(out, it->rlw.running_bit ^ negate, pl);
93 + index += pl;
94 +
95 + pd = it->rlw.literal_words;
96 + if (pd + index > max)
97 + pd = max - index;
98 +
99 + ewah_add_dirty_words(out,
100 + it->buffer + it->literal_word_start, pd, negate);
101 +
102 + rlwit_discard_first_words(it, pd + pl);
103 + index += pd;
104 + }
105 +
106 + return index;
107 +}
108 +
109 +void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out)
110 +{
111 + while (rlwit_word_size(it) > 0) {
112 + ewah_add_empty_words(out, 0, rlwit_word_size(it));
113 + rlwit_discard_first_words(it, rlwit_word_size(it));
114 + }
115 +}
ewah/ewok.h new
+233
@@ -0,0 +1,233 @@
1 +/**
2 + * Copyright 2013, GitHub, Inc
3 + * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
4 + * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
5 + *
6 + * This program is free software; you can redistribute it and/or
7 + * modify it under the terms of the GNU General Public License
8 + * as published by the Free Software Foundation; either version 2
9 + * of the License, or (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program; if not, write to the Free Software
18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 + */
20 +#ifndef __EWOK_BITMAP_H__
21 +#define __EWOK_BITMAP_H__
22 +
23 +#ifndef ewah_malloc
24 +# define ewah_malloc xmalloc
25 +#endif
26 +#ifndef ewah_realloc
27 +# define ewah_realloc xrealloc
28 +#endif
29 +#ifndef ewah_calloc
30 +# define ewah_calloc xcalloc
31 +#endif
32 +
33 +typedef uint64_t eword_t;
34 +#define BITS_IN_WORD (sizeof(eword_t) * 8)
35 +
36 +/**
37 + * Do not use __builtin_popcountll. The GCC implementation
38 + * is notoriously slow on all platforms.
39 + *
40 + * See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36041
41 + */
42 +static inline uint32_t ewah_bit_popcount64(uint64_t x)
43 +{
44 + x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL);
45 + x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
46 + x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL);
47 + return (x * 0x0101010101010101ULL) >> 56;
48 +}
49 +
50 +#ifdef __GNUC__
51 +#define ewah_bit_ctz64(x) __builtin_ctzll(x)
52 +#else
53 +static inline int ewah_bit_ctz64(uint64_t x)
54 +{
55 + int n = 0;
56 + if ((x & 0xffffffff) == 0) { x >>= 32; n += 32; }
57 + if ((x & 0xffff) == 0) { x >>= 16; n += 16; }
58 + if ((x & 0xff) == 0) { x >>= 8; n += 8; }
59 + if ((x & 0xf) == 0) { x >>= 4; n += 4; }
60 + if ((x & 0x3) == 0) { x >>= 2; n += 2; }
61 + if ((x & 0x1) == 0) { x >>= 1; n += 1; }
62 + return n + !x;
63 +}
64 +#endif
65 +
66 +struct ewah_bitmap {
67 + eword_t *buffer;
68 + size_t buffer_size;
69 + size_t alloc_size;
70 + size_t bit_size;
71 + eword_t *rlw;
72 +};
73 +
74 +typedef void (*ewah_callback)(size_t pos, void *);
75 +
76 +struct ewah_bitmap *ewah_pool_new(void);
77 +void ewah_pool_free(struct ewah_bitmap *self);
78 +
79 +/**
80 + * Allocate a new EWAH Compressed bitmap
81 + */
82 +struct ewah_bitmap *ewah_new(void);
83 +
84 +/**
85 + * Clear all the bits in the bitmap. Does not free or resize
86 + * memory.
87 + */
88 +void ewah_clear(struct ewah_bitmap *self);
89 +
90 +/**
91 + * Free all the memory of the bitmap
92 + */
93 +void ewah_free(struct ewah_bitmap *self);
94 +
95 +int ewah_serialize_to(struct ewah_bitmap *self,
96 + int (*write_fun)(void *out, const void *buf, size_t len),
97 + void *out);
98 +int ewah_serialize(struct ewah_bitmap *self, int fd);
99 +int ewah_serialize_native(struct ewah_bitmap *self, int fd);
100 +
101 +int ewah_deserialize(struct ewah_bitmap *self, int fd);
102 +int ewah_read_mmap(struct ewah_bitmap *self, void *map, size_t len);
103 +int ewah_read_mmap_native(struct ewah_bitmap *self, void *map, size_t len);
104 +
105 +uint32_t ewah_checksum(struct ewah_bitmap *self);
106 +
107 +/**
108 + * Logical not (bitwise negation) in-place on the bitmap
109 + *
110 + * This operation is linear time based on the size of the bitmap.
111 + */
112 +void ewah_not(struct ewah_bitmap *self);
113 +
114 +/**
115 + * Call the given callback with the position of every single bit
116 + * that has been set on the bitmap.
117 + *
118 + * This is an efficient operation that does not fully decompress
119 + * the bitmap.
120 + */
121 +void ewah_each_bit(struct ewah_bitmap *self, ewah_callback callback, void *payload);
122 +
123 +/**
124 + * Set a given bit on the bitmap.
125 + *
126 + * The bit at position `pos` will be set to true. Because of the
127 + * way that the bitmap is compressed, a set bit cannot be unset
128 + * later on.
129 + *
130 + * Furthermore, since the bitmap uses streaming compression, bits
131 + * can only set incrementally.
132 + *
133 + * E.g.
134 + * ewah_set(bitmap, 1); // ok
135 + * ewah_set(bitmap, 76); // ok
136 + * ewah_set(bitmap, 77); // ok
137 + * ewah_set(bitmap, 8712800127); // ok
138 + * ewah_set(bitmap, 25); // failed, assert raised
139 + */
140 +void ewah_set(struct ewah_bitmap *self, size_t i);
141 +
142 +struct ewah_iterator {
143 + const eword_t *buffer;
144 + size_t buffer_size;
145 +
146 + size_t pointer;
147 + eword_t compressed, literals;
148 + eword_t rl, lw;
149 + int b;
150 +};
151 +
152 +/**
153 + * Initialize a new iterator to run through the bitmap in uncompressed form.
154 + *
155 + * The iterator can be stack allocated. The underlying bitmap must not be freed
156 + * before the iteration is over.
157 + *
158 + * E.g.
159 + *
160 + * struct ewah_bitmap *bitmap = ewah_new();
161 + * struct ewah_iterator it;
162 + *
163 + * ewah_iterator_init(&it, bitmap);
164 + */
165 +void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent);
166 +
167 +/**
168 + * Yield every single word in the bitmap in uncompressed form. This is:
169 + * yield single words (32-64 bits) where each bit represents an actual
170 + * bit from the bitmap.
171 + *
172 + * Return: true if a word was yield, false if there are no words left
173 + */
174 +int ewah_iterator_next(eword_t *next, struct ewah_iterator *it);
175 +
176 +void ewah_or(
177 + struct ewah_bitmap *ewah_i,
178 + struct ewah_bitmap *ewah_j,
179 + struct ewah_bitmap *out);
180 +
181 +void ewah_and_not(
182 + struct ewah_bitmap *ewah_i,
183 + struct ewah_bitmap *ewah_j,
184 + struct ewah_bitmap *out);
185 +
186 +void ewah_xor(
187 + struct ewah_bitmap *ewah_i,
188 + struct ewah_bitmap *ewah_j,
189 + struct ewah_bitmap *out);
190 +
191 +void ewah_and(
192 + struct ewah_bitmap *ewah_i,
193 + struct ewah_bitmap *ewah_j,
194 + struct ewah_bitmap *out);
195 +
196 +/**
197 + * Direct word access
198 + */
199 +size_t ewah_add_empty_words(struct ewah_bitmap *self, int v, size_t number);
200 +void ewah_add_dirty_words(
201 + struct ewah_bitmap *self, const eword_t *buffer, size_t number, int negate);
202 +size_t ewah_add(struct ewah_bitmap *self, eword_t word);
203 +
204 +
205 +/**
206 + * Uncompressed, old-school bitmap that can be efficiently compressed
207 + * into an `ewah_bitmap`.
208 + */
209 +struct bitmap {
210 + eword_t *words;
211 + size_t word_alloc;
212 +};
213 +
214 +struct bitmap *bitmap_new(void);
215 +void bitmap_set(struct bitmap *self, size_t pos);
216 +void bitmap_clear(struct bitmap *self, size_t pos);
217 +int bitmap_get(struct bitmap *self, size_t pos);
218 +void bitmap_reset(struct bitmap *self);
219 +void bitmap_free(struct bitmap *self);
220 +int bitmap_equals(struct bitmap *self, struct bitmap *other);
221 +int bitmap_is_subset(struct bitmap *self, struct bitmap *super);
222 +
223 +struct ewah_bitmap * bitmap_to_ewah(struct bitmap *bitmap);
224 +struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah);
225 +
226 +void bitmap_and_not(struct bitmap *self, struct bitmap *other);
227 +void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other);
228 +void bitmap_or(struct bitmap *self, const struct bitmap *other);
229 +
230 +void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data);
231 +size_t bitmap_popcount(struct bitmap *self);
232 +
233 +#endif
ewah/ewok_rlw.h new
+114
@@ -0,0 +1,114 @@
1 +/**
2 + * Copyright 2013, GitHub, Inc
3 + * Copyright 2009-2013, Daniel Lemire, Cliff Moon,
4 + * David McIntosh, Robert Becho, Google Inc. and Veronika Zenz
5 + *
6 + * This program is free software; you can redistribute it and/or
7 + * modify it under the terms of the GNU General Public License
8 + * as published by the Free Software Foundation; either version 2
9 + * of the License, or (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program; if not, write to the Free Software
18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 + */
20 +#ifndef __EWOK_RLW_H__
21 +#define __EWOK_RLW_H__
22 +
23 +#define RLW_RUNNING_BITS (sizeof(eword_t) * 4)
24 +#define RLW_LITERAL_BITS (sizeof(eword_t) * 8 - 1 - RLW_RUNNING_BITS)
25 +
26 +#define RLW_LARGEST_RUNNING_COUNT (((eword_t)1 << RLW_RUNNING_BITS) - 1)
27 +#define RLW_LARGEST_LITERAL_COUNT (((eword_t)1 << RLW_LITERAL_BITS) - 1)
28 +
29 +#define RLW_LARGEST_RUNNING_COUNT_SHIFT (RLW_LARGEST_RUNNING_COUNT << 1)
30 +
31 +#define RLW_RUNNING_LEN_PLUS_BIT (((eword_t)1 << (RLW_RUNNING_BITS + 1)) - 1)
32 +
33 +static int rlw_get_run_bit(const eword_t *word)
34 +{
35 + return *word & (eword_t)1;
36 +}
37 +
38 +static inline void rlw_set_run_bit(eword_t *word, int b)
39 +{
40 + if (b) {
41 + *word |= (eword_t)1;
42 + } else {
43 + *word &= (eword_t)(~1);
44 + }
45 +}
46 +
47 +static inline void rlw_xor_run_bit(eword_t *word)
48 +{
49 + if (*word & 1) {
50 + *word &= (eword_t)(~1);
51 + } else {
52 + *word |= (eword_t)1;
53 + }
54 +}
55 +
56 +static inline void rlw_set_running_len(eword_t *word, eword_t l)
57 +{
58 + *word |= RLW_LARGEST_RUNNING_COUNT_SHIFT;
59 + *word &= (l << 1) | (~RLW_LARGEST_RUNNING_COUNT_SHIFT);
60 +}
61 +
62 +static inline eword_t rlw_get_running_len(const eword_t *word)
63 +{
64 + return (*word >> 1) & RLW_LARGEST_RUNNING_COUNT;
65 +}
66 +
67 +static inline eword_t rlw_get_literal_words(const eword_t *word)
68 +{
69 + return *word >> (1 + RLW_RUNNING_BITS);
70 +}
71 +
72 +static inline void rlw_set_literal_words(eword_t *word, eword_t l)
73 +{
74 + *word |= ~RLW_RUNNING_LEN_PLUS_BIT;
75 + *word &= (l << (RLW_RUNNING_BITS + 1)) | RLW_RUNNING_LEN_PLUS_BIT;
76 +}
77 +
78 +static inline eword_t rlw_size(const eword_t *self)
79 +{
80 + return rlw_get_running_len(self) + rlw_get_literal_words(self);
81 +}
82 +
83 +struct rlw_iterator {
84 + const eword_t *buffer;
85 + size_t size;
86 + size_t pointer;
87 + size_t literal_word_start;
88 +
89 + struct {
90 + const eword_t *word;
91 + int literal_words;
92 + int running_len;
93 + int literal_word_offset;
94 + int running_bit;
95 + } rlw;
96 +};
97 +
98 +void rlwit_init(struct rlw_iterator *it, struct ewah_bitmap *bitmap);
99 +void rlwit_discard_first_words(struct rlw_iterator *it, size_t x);
100 +size_t rlwit_discharge(
101 + struct rlw_iterator *it, struct ewah_bitmap *out, size_t max, int negate);
102 +void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out);
103 +
104 +static inline size_t rlwit_word_size(struct rlw_iterator *it)
105 +{
106 + return it->rlw.running_len + it->rlw.literal_words;
107 +}
108 +
109 +static inline size_t rlwit_literal_words(struct rlw_iterator *it)
110 +{
111 + return it->pointer - it->rlw.literal_words;
112 +}
113 +
114 +#endif