roaringbitmap 0.1__tar.gz → 0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {roaringbitmap-0.1 → roaringbitmap-0.3}/PKG-INFO +3 -2
- {roaringbitmap-0.1 → roaringbitmap-0.3}/README.rst +2 -0
- {roaringbitmap-0.1 → roaringbitmap-0.3}/setup.py +34 -24
- {roaringbitmap-0.1 → roaringbitmap-0.3}/src/arrayops.pxi +2 -2
- {roaringbitmap-0.1 → roaringbitmap-0.3}/src/bitcount.h +7 -7
- {roaringbitmap-0.1 → roaringbitmap-0.3}/src/bitops.pxi +3 -3
- {roaringbitmap-0.1 → roaringbitmap-0.3}/src/block.pxi +113 -89
- {roaringbitmap-0.1 → roaringbitmap-0.3}/src/macros.h +1 -1
- roaringbitmap-0.3/src/roaringbitmap.c +27240 -0
- {roaringbitmap-0.1 → roaringbitmap-0.3}/src/roaringbitmap.pxd +3 -1
- {roaringbitmap-0.1 → roaringbitmap-0.3}/src/roaringbitmap.pyx +141 -83
- {roaringbitmap-0.1 → roaringbitmap-0.3}/tests/unittests.py +12 -3
- {roaringbitmap-0.1 → roaringbitmap-0.3}/LICENSE +0 -0
- {roaringbitmap-0.1 → roaringbitmap-0.3}/tests/benchmarks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 1.1
|
|
2
2
|
Name: roaringbitmap
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3
|
|
4
4
|
Summary: Roaring Bitmap
|
|
5
5
|
Home-page: https://github.com/andreasvc/roaringbitmap/
|
|
6
6
|
Author: Andreas van Cranenburgh
|
|
@@ -47,6 +47,8 @@ Description: Roaring Bitmap in Cython
|
|
|
47
47
|
>>> RoaringBitmap(range(10)) & RoaringBitmap(range(5, 15))
|
|
48
48
|
RoaringBitmap({5, 6, 7, 8, 9})
|
|
49
49
|
|
|
50
|
+
For API documentation cf. https://pythonhosted.org/roaringbitmap/
|
|
51
|
+
|
|
50
52
|
Benchmarks
|
|
51
53
|
----------
|
|
52
54
|
Output of ``$ python benchmarks.py``::
|
|
@@ -102,4 +104,3 @@ Classifier: Operating System :: POSIX
|
|
|
102
104
|
Classifier: Programming Language :: Python :: 2.7
|
|
103
105
|
Classifier: Programming Language :: Python :: 3.3
|
|
104
106
|
Classifier: Programming Language :: Cython
|
|
105
|
-
Requires: cython (>=0.20)
|
|
@@ -39,6 +39,8 @@ Python set containing (unsigned) 32-bit integers::
|
|
|
39
39
|
>>> RoaringBitmap(range(10)) & RoaringBitmap(range(5, 15))
|
|
40
40
|
RoaringBitmap({5, 6, 7, 8, 9})
|
|
41
41
|
|
|
42
|
+
For API documentation cf. https://pythonhosted.org/roaringbitmap/
|
|
43
|
+
|
|
42
44
|
Benchmarks
|
|
43
45
|
----------
|
|
44
46
|
Output of ``$ python benchmarks.py``::
|
|
@@ -3,15 +3,20 @@ import os
|
|
|
3
3
|
import sys
|
|
4
4
|
from distutils.core import setup
|
|
5
5
|
from distutils.extension import Extension
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
USE_CYTHON = '--with-cython' in sys.argv
|
|
7
|
+
if USE_CYTHON:
|
|
8
|
+
sys.argv.remove('--with-cython')
|
|
9
|
+
try:
|
|
10
|
+
from Cython.Build import cythonize
|
|
11
|
+
from Cython.Distutils import build_ext
|
|
12
|
+
except ImportError:
|
|
13
|
+
raise ValueError('could not import Cython.')
|
|
14
|
+
cmdclass = dict(build_ext=build_ext)
|
|
15
|
+
else:
|
|
16
|
+
cmdclass = dict()
|
|
12
17
|
|
|
13
18
|
metadata = dict(name='roaringbitmap',
|
|
14
|
-
version='0.
|
|
19
|
+
version='0.3',
|
|
15
20
|
description='Roaring Bitmap',
|
|
16
21
|
long_description=open('README.rst').read(),
|
|
17
22
|
author='Andreas van Cranenburgh',
|
|
@@ -26,9 +31,6 @@ metadata = dict(name='roaringbitmap',
|
|
|
26
31
|
'Programming Language :: Python :: 3.3',
|
|
27
32
|
'Programming Language :: Cython',
|
|
28
33
|
],
|
|
29
|
-
requires=[
|
|
30
|
-
'cython (>=0.20)',
|
|
31
|
-
],
|
|
32
34
|
)
|
|
33
35
|
|
|
34
36
|
# some of these directives increase performance,
|
|
@@ -51,19 +53,27 @@ directives = {
|
|
|
51
53
|
|
|
52
54
|
if __name__ == '__main__':
|
|
53
55
|
os.environ['GCC_COLORS'] = 'auto'
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
if USE_CYTHON:
|
|
57
|
+
extensions = [Extension(
|
|
58
|
+
'*',
|
|
59
|
+
sources=['src/*.pyx'],
|
|
60
|
+
extra_compile_args=['-O3', '-DNDEBUG', '-march=native'],
|
|
61
|
+
# extra_compile_args=['-O0', '-g'],
|
|
62
|
+
# extra_link_args=['-g'],
|
|
63
|
+
)]
|
|
64
|
+
ext_modules = cythonize(
|
|
65
|
+
extensions,
|
|
66
|
+
annotate=True,
|
|
67
|
+
compiler_directives=directives,
|
|
68
|
+
language_level=3,
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
ext_modules = [Extension(
|
|
72
|
+
'roaringbitmap',
|
|
73
|
+
sources=['src/roaringbitmap.c'],
|
|
74
|
+
extra_compile_args=['-O3', '-DNDEBUG', '-march=native'],
|
|
75
|
+
)]
|
|
61
76
|
setup(
|
|
62
|
-
cmdclass=
|
|
63
|
-
ext_modules=
|
|
64
|
-
extensions,
|
|
65
|
-
annotate=True,
|
|
66
|
-
compiler_directives=directives,
|
|
67
|
-
language_level=3,
|
|
68
|
-
),
|
|
77
|
+
cmdclass=cmdclass,
|
|
78
|
+
ext_modules=ext_modules,
|
|
69
79
|
**metadata)
|
|
@@ -100,9 +100,9 @@ cdef int advance(uint16_t *data, int pos, int length, uint16_t minitem):
|
|
|
100
100
|
return upper
|
|
101
101
|
if data[upper] < minitem:
|
|
102
102
|
return length
|
|
103
|
-
lower += spansize
|
|
103
|
+
lower += spansize >> 1
|
|
104
104
|
while lower + 1 != upper:
|
|
105
|
-
mid = (lower + upper)
|
|
105
|
+
mid = (<unsigned int>lower + <unsigned int>upper) >> 1
|
|
106
106
|
if data[mid] == minitem:
|
|
107
107
|
return mid
|
|
108
108
|
elif data[mid] < minitem:
|
|
@@ -27,7 +27,7 @@ extern "C" {
|
|
|
27
27
|
|
|
28
28
|
#ifdef BITCOUNT_VS_X86
|
|
29
29
|
#include <intrin.h>
|
|
30
|
-
#pragma intrinsic(
|
|
30
|
+
#pragma intrinsic(_BitScanForward64,_BitScanReverse64,__popcnt64)
|
|
31
31
|
#endif
|
|
32
32
|
|
|
33
33
|
#include <limits.h>
|
|
@@ -43,10 +43,10 @@ unsigned int bit_popcount_general(uint64_t);
|
|
|
43
43
|
bit position. If v is 0, the result is undefined. */
|
|
44
44
|
BITCOUNT_INLINE unsigned int bit_clz(uint64_t v) {
|
|
45
45
|
#if defined(BITCOUNT_GCC)
|
|
46
|
-
return
|
|
46
|
+
return __builtin_clzll(v);
|
|
47
47
|
#elif defined(BITCOUNT_VS_X86)
|
|
48
48
|
uint64_t result;
|
|
49
|
-
|
|
49
|
+
_BitScanReverse64(&result, v);
|
|
50
50
|
return BITCOUNT_BITS - 1 - result;
|
|
51
51
|
#else
|
|
52
52
|
return bit_clz_general(v);
|
|
@@ -57,10 +57,10 @@ BITCOUNT_INLINE unsigned int bit_clz(uint64_t v) {
|
|
|
57
57
|
bit position. If v is 0, the result is undefined. */
|
|
58
58
|
BITCOUNT_INLINE unsigned int bit_ctz(uint64_t v) {
|
|
59
59
|
#if defined(BITCOUNT_GCC)
|
|
60
|
-
return
|
|
60
|
+
return __builtin_ctzll(v);
|
|
61
61
|
#elif defined(BITCOUNT_VS_X86)
|
|
62
62
|
uint64_t result;
|
|
63
|
-
|
|
63
|
+
_BitScanForward64(&result, v);
|
|
64
64
|
return result;
|
|
65
65
|
#else
|
|
66
66
|
return bit_ctz_general(v);
|
|
@@ -70,9 +70,9 @@ BITCOUNT_INLINE unsigned int bit_ctz(uint64_t v) {
|
|
|
70
70
|
/* Returns the number of 1-bits in v. */
|
|
71
71
|
BITCOUNT_INLINE unsigned int bit_popcount(uint64_t v) {
|
|
72
72
|
#if defined(BITCOUNT_GCC)
|
|
73
|
-
return
|
|
73
|
+
return __builtin_popcountll(v);
|
|
74
74
|
#elif defined(BITCOUNT_VS_X86)
|
|
75
|
-
return
|
|
75
|
+
return __popcnt64(v);
|
|
76
76
|
#else
|
|
77
77
|
return bit_popcount_general(v);
|
|
78
78
|
#endif
|
|
@@ -44,7 +44,7 @@ cdef inline int iteratesetbits(uint64_t *vec, int slots,
|
|
|
44
44
|
return -1
|
|
45
45
|
cur[0] = vec[idx[0]]
|
|
46
46
|
tmp = bit_ctz(cur[0]) # index of right-most 1-bit in current slot
|
|
47
|
-
cur[0] ^=
|
|
47
|
+
cur[0] ^= 1ULL << tmp # TOGGLEBIT(cur, tmp)
|
|
48
48
|
return idx[0] * BITSIZE + tmp
|
|
49
49
|
|
|
50
50
|
|
|
@@ -60,7 +60,7 @@ cdef inline int iterateunsetbits(uint64_t *vec, int slots,
|
|
|
60
60
|
return -1
|
|
61
61
|
cur[0] = ~vec[idx[0]]
|
|
62
62
|
tmp = bit_ctz(cur[0]) # index of right-most 0-bit in current slot
|
|
63
|
-
cur[0] ^=
|
|
63
|
+
cur[0] ^= 1ULL << tmp # TOGGLEBIT(cur, tmp)
|
|
64
64
|
return idx[0] * BITSIZE + tmp
|
|
65
65
|
|
|
66
66
|
|
|
@@ -90,7 +90,7 @@ cdef inline int reviteratesetbits(uint64_t *vec, uint64_t *cur, int *idx):
|
|
|
90
90
|
return -1
|
|
91
91
|
cur[0] = vec[idx[0]]
|
|
92
92
|
tmp = BITSIZE - bit_clz(cur[0]) - 1 # index of left-most 1-bit in cur
|
|
93
|
-
cur[0] &= ~(
|
|
93
|
+
cur[0] &= ~(1ULL << tmp) # CLEARBIT(cur, tmp)
|
|
94
94
|
return idx[0] * BITSIZE + tmp
|
|
95
95
|
|
|
96
96
|
|
|
@@ -3,7 +3,6 @@ cdef inline Block new_Block(uint16_t key):
|
|
|
3
3
|
block.key = key
|
|
4
4
|
block.state = POSITIVE
|
|
5
5
|
block.cardinality = 0
|
|
6
|
-
block.buf = array.clone(ushortarray, 0, False)
|
|
7
6
|
return block
|
|
8
7
|
|
|
9
8
|
|
|
@@ -17,7 +16,7 @@ cdef class Block(object):
|
|
|
17
16
|
cdef uint8_t state # either DENSE, INVERTED, or POSITIVE
|
|
18
17
|
cdef uint16_t key # the high bits of elements in this block
|
|
19
18
|
cdef uint32_t cardinality # the number of elements
|
|
20
|
-
cdef array.array buf #
|
|
19
|
+
cdef array.array buf # data: sparse array or fixed-size bitvector
|
|
21
20
|
|
|
22
21
|
def __cinit__(self):
|
|
23
22
|
pass
|
|
@@ -86,6 +85,27 @@ cdef class Block(object):
|
|
|
86
85
|
del self.buf[i]
|
|
87
86
|
self.cardinality -= 1
|
|
88
87
|
|
|
88
|
+
cdef _and(self, Block other):
|
|
89
|
+
cdef Block result
|
|
90
|
+
cdef int n
|
|
91
|
+
if self.state == DENSE:
|
|
92
|
+
if other.state == POSITIVE:
|
|
93
|
+
result = new_Block(self.key)
|
|
94
|
+
result.buf = array.clone(ushortarray, other.cardinality, False)
|
|
95
|
+
result.state = POSITIVE
|
|
96
|
+
result.cardinality = 0
|
|
97
|
+
for n in range(other.cardinality):
|
|
98
|
+
if TESTBIT(self.buf.data.as_ulongs,
|
|
99
|
+
other.buf.data.as_ushorts[n]):
|
|
100
|
+
result.buf.data.as_ushorts[self.cardinality
|
|
101
|
+
] = other.buf.data.as_ushorts[n]
|
|
102
|
+
result.cardinality += 1
|
|
103
|
+
array.resize(result.buf, result.cardinality)
|
|
104
|
+
return result
|
|
105
|
+
result = self.copy()
|
|
106
|
+
result &= other
|
|
107
|
+
return result
|
|
108
|
+
|
|
89
109
|
cdef iand(self, Block other):
|
|
90
110
|
cdef array.array tmp
|
|
91
111
|
cdef int length, n
|
|
@@ -99,9 +119,9 @@ cdef class Block(object):
|
|
|
99
119
|
tmp.data.as_ushorts[self.cardinality
|
|
100
120
|
] = other.buf.data.as_ushorts[n]
|
|
101
121
|
self.cardinality += 1
|
|
102
|
-
array.resize(tmp, self.cardinality)
|
|
103
|
-
self.state = POSITIVE
|
|
104
122
|
self.buf = tmp
|
|
123
|
+
array.resize(self.buf, self.cardinality)
|
|
124
|
+
self.state = POSITIVE
|
|
105
125
|
elif other.state == DENSE:
|
|
106
126
|
self.cardinality = bitsetintersectinplace(
|
|
107
127
|
self.buf.data.as_ulongs,
|
|
@@ -114,22 +134,19 @@ cdef class Block(object):
|
|
|
114
134
|
other.buf.data.as_ushorts[n])
|
|
115
135
|
self.cardinality -= 1
|
|
116
136
|
elif other.state == DENSE:
|
|
137
|
+
tmp = array.clone(ushortarray, BITMAPSIZE // sizeof(short), False)
|
|
117
138
|
if self.state == INVERTED:
|
|
118
|
-
tmp
|
|
119
|
-
memset(tmp.data.as_uchars, 255, BLOCKSIZE // sizeof(char))
|
|
139
|
+
memset(tmp.data.as_chars, 255, BITMAPSIZE)
|
|
120
140
|
for n in range(BLOCKSIZE - self.cardinality):
|
|
121
|
-
CLEARBIT(tmp.data.as_ulongs,
|
|
122
|
-
self.buf.data.as_ushorts[n])
|
|
141
|
+
CLEARBIT(tmp.data.as_ulongs, self.buf.data.as_ushorts[n])
|
|
123
142
|
else: # self.state == POSITIVE:
|
|
124
|
-
tmp
|
|
143
|
+
memset(tmp.data.as_chars, 0, BITMAPSIZE)
|
|
125
144
|
for n in range(self.cardinality):
|
|
126
|
-
SETBIT(tmp.data.as_ulongs,
|
|
127
|
-
|
|
145
|
+
SETBIT(tmp.data.as_ulongs, self.buf.data.as_ushorts[n])
|
|
146
|
+
self.buf = tmp
|
|
128
147
|
self.cardinality = bitsetintersectinplace(
|
|
129
|
-
|
|
130
|
-
other.buf.data.as_ulongs)
|
|
148
|
+
self.buf.data.as_ulongs, other.buf.data.as_ulongs)
|
|
131
149
|
self.state = DENSE
|
|
132
|
-
self.buf = tmp
|
|
133
150
|
elif self.state == POSITIVE and other.state == POSITIVE:
|
|
134
151
|
length = intersect2by2(
|
|
135
152
|
self.buf.data.as_ushorts,
|
|
@@ -148,9 +165,9 @@ cdef class Block(object):
|
|
|
148
165
|
BLOCKSIZE - self.cardinality,
|
|
149
166
|
BLOCKSIZE - other.cardinality,
|
|
150
167
|
tmp.data.as_ushorts)
|
|
151
|
-
array.resize(tmp, length)
|
|
152
|
-
self.cardinality = BLOCKSIZE - length
|
|
153
168
|
self.buf = tmp
|
|
169
|
+
array.resize(self.buf, length)
|
|
170
|
+
self.cardinality = BLOCKSIZE - length
|
|
154
171
|
elif self.state == INVERTED and other.state == POSITIVE:
|
|
155
172
|
tmp = array.clone(ushortarray,
|
|
156
173
|
max(BLOCKSIZE - self.cardinality, other.cardinality),
|
|
@@ -161,10 +178,10 @@ cdef class Block(object):
|
|
|
161
178
|
other.cardinality,
|
|
162
179
|
BLOCKSIZE - self.cardinality,
|
|
163
180
|
tmp.data.as_ushorts)
|
|
164
|
-
|
|
181
|
+
self.buf = tmp
|
|
182
|
+
array.resize(self.buf, length)
|
|
165
183
|
self.state = POSITIVE
|
|
166
184
|
self.cardinality = length
|
|
167
|
-
self.buf = tmp
|
|
168
185
|
elif self.state == POSITIVE and other.state == INVERTED:
|
|
169
186
|
length = difference(
|
|
170
187
|
self.buf.data.as_ushorts,
|
|
@@ -187,20 +204,22 @@ cdef class Block(object):
|
|
|
187
204
|
other.buf.data.as_ushorts,
|
|
188
205
|
self.cardinality, other.cardinality,
|
|
189
206
|
tmp.data.as_ushorts)
|
|
190
|
-
array.resize(tmp, self.cardinality)
|
|
191
207
|
self.buf = tmp
|
|
208
|
+
array.resize(self.buf, self.cardinality)
|
|
192
209
|
elif other.state == DENSE:
|
|
193
|
-
tmp = array.
|
|
210
|
+
tmp = array.clone(ushortarray, BITMAPSIZE // sizeof(short),
|
|
211
|
+
False)
|
|
212
|
+
memcpy(tmp.data.as_chars, other.buf.data.as_chars,
|
|
213
|
+
BITMAPSIZE)
|
|
194
214
|
length = other.cardinality
|
|
195
|
-
array.resize(tmp, length + self.cardinality)
|
|
196
215
|
for n in range(self.cardinality):
|
|
197
216
|
if not TESTBIT(tmp.data.as_ulongs,
|
|
198
217
|
self.buf.data.as_ushorts[n]):
|
|
218
|
+
SETBIT(tmp.data.as_ulongs, self.buf.data.as_ushorts[n])
|
|
199
219
|
length += 1
|
|
200
|
-
|
|
220
|
+
self.buf = tmp
|
|
201
221
|
self.state = DENSE
|
|
202
222
|
self.cardinality = length
|
|
203
|
-
self.buf = tmp
|
|
204
223
|
elif other.state == INVERTED:
|
|
205
224
|
tmp = array.clone(ushortarray, BLOCKSIZE - self.cardinality,
|
|
206
225
|
False)
|
|
@@ -210,10 +229,10 @@ cdef class Block(object):
|
|
|
210
229
|
BLOCKSIZE - other.cardinality,
|
|
211
230
|
self.cardinality,
|
|
212
231
|
tmp.data.as_ushorts)
|
|
213
|
-
|
|
232
|
+
self.buf = tmp
|
|
233
|
+
array.resize(self.buf, length)
|
|
214
234
|
self.state = INVERTED
|
|
215
235
|
self.cardinality = BLOCKSIZE - length
|
|
216
|
-
self.buf = tmp
|
|
217
236
|
elif self.state == DENSE:
|
|
218
237
|
if other.state == POSITIVE:
|
|
219
238
|
for n in range(other.cardinality):
|
|
@@ -235,10 +254,10 @@ cdef class Block(object):
|
|
|
235
254
|
tmp.data.as_ushorts[length] = (
|
|
236
255
|
other.buf.data.as_ushorts[n])
|
|
237
256
|
length += 1
|
|
238
|
-
|
|
257
|
+
self.buf = tmp
|
|
258
|
+
array.resize(self.buf, length)
|
|
239
259
|
self.cardinality = BLOCKSIZE - length
|
|
240
260
|
self.state = INVERTED
|
|
241
|
-
self.buf = tmp
|
|
242
261
|
elif self.state == INVERTED:
|
|
243
262
|
if other.state == POSITIVE:
|
|
244
263
|
length = difference(
|
|
@@ -258,9 +277,9 @@ cdef class Block(object):
|
|
|
258
277
|
tmp.data.as_ushorts[length] = (
|
|
259
278
|
self.buf.data.as_ushorts[n])
|
|
260
279
|
length += 1
|
|
261
|
-
array.resize(tmp, length)
|
|
262
|
-
self.cardinality = BLOCKSIZE - length
|
|
263
280
|
self.buf = tmp
|
|
281
|
+
array.resize(self.buf, length)
|
|
282
|
+
self.cardinality = BLOCKSIZE - length
|
|
264
283
|
elif other.state == INVERTED:
|
|
265
284
|
length = intersect2by2(self.buf.data.as_ushorts,
|
|
266
285
|
other.buf.data.as_ushorts,
|
|
@@ -322,9 +341,9 @@ cdef class Block(object):
|
|
|
322
341
|
BLOCKSIZE - self.cardinality,
|
|
323
342
|
BLOCKSIZE - other.cardinality,
|
|
324
343
|
tmp.data.as_ushorts)
|
|
325
|
-
array.resize(tmp, length)
|
|
326
|
-
self.cardinality = BLOCKSIZE - length
|
|
327
344
|
self.buf = tmp
|
|
345
|
+
array.resize(self.buf, length)
|
|
346
|
+
self.cardinality = BLOCKSIZE - length
|
|
328
347
|
elif self.state == INVERTED and other.state == POSITIVE:
|
|
329
348
|
length = intersect2by2(
|
|
330
349
|
self.buf.data.as_ushorts,
|
|
@@ -361,7 +380,7 @@ cdef class Block(object):
|
|
|
361
380
|
if TESTBIT(self.buf.data.as_ulongs,
|
|
362
381
|
other.buf.data.as_ushorts[n]):
|
|
363
382
|
CLEARBIT(self.buf.data.as_ulongs,
|
|
364
|
-
|
|
383
|
+
other.buf.data.as_ushorts[n])
|
|
365
384
|
self.cardinality -= 1
|
|
366
385
|
elif self.state == INVERTED and other.state == DENSE:
|
|
367
386
|
self.todense()
|
|
@@ -381,9 +400,9 @@ cdef class Block(object):
|
|
|
381
400
|
self.cardinality,
|
|
382
401
|
other.cardinality,
|
|
383
402
|
tmp.data.as_ushorts)
|
|
384
|
-
array.resize(tmp, length)
|
|
385
|
-
self.cardinality = length
|
|
386
403
|
self.buf = tmp
|
|
404
|
+
array.resize(self.buf, length)
|
|
405
|
+
self.cardinality = length
|
|
387
406
|
elif self.state == INVERTED and other.state == INVERTED:
|
|
388
407
|
tmp = array.clone(ushortarray,
|
|
389
408
|
BLOCKSIZE - (self.cardinality + other.cardinality),
|
|
@@ -394,9 +413,9 @@ cdef class Block(object):
|
|
|
394
413
|
BLOCKSIZE - self.cardinality,
|
|
395
414
|
BLOCKSIZE - other.cardinality,
|
|
396
415
|
tmp.data.as_ushorts)
|
|
397
|
-
array.resize(tmp, length)
|
|
398
|
-
self.cardinality = BLOCKSIZE - length
|
|
399
416
|
self.buf = tmp
|
|
417
|
+
array.resize(self.buf, length)
|
|
418
|
+
self.cardinality = BLOCKSIZE - length
|
|
400
419
|
elif self.state == INVERTED and other.state == POSITIVE:
|
|
401
420
|
self.todense()
|
|
402
421
|
self.ixor(other)
|
|
@@ -407,44 +426,6 @@ cdef class Block(object):
|
|
|
407
426
|
return
|
|
408
427
|
self.resize()
|
|
409
428
|
|
|
410
|
-
cdef flip(self):
|
|
411
|
-
"""In-place complement of this block."""
|
|
412
|
-
if self.state == DENSE:
|
|
413
|
-
for n in range(BITNSLOTS(BLOCKSIZE)):
|
|
414
|
-
self.buf.data.as_ulongs[n] = ~self.buf.data.as_ulongs[n]
|
|
415
|
-
elif self.state == POSITIVE:
|
|
416
|
-
self.state = INVERTED
|
|
417
|
-
elif self.state == INVERTED:
|
|
418
|
-
self.state = POSITIVE
|
|
419
|
-
# FIXME: need notion of maximium element
|
|
420
|
-
self.cardinality = BLOCKSIZE - self.cardinality
|
|
421
|
-
|
|
422
|
-
cdef resize(self):
|
|
423
|
-
"""Convert between dense, sparse, inverted sparse as needed."""
|
|
424
|
-
if self.state == DENSE:
|
|
425
|
-
if self.cardinality < MAXARRAYLENGTH:
|
|
426
|
-
self.toposarray()
|
|
427
|
-
elif self.cardinality > BLOCKSIZE - MAXARRAYLENGTH:
|
|
428
|
-
self.toinvarray()
|
|
429
|
-
elif self.state == INVERTED:
|
|
430
|
-
if (MAXARRAYLENGTH < self.cardinality
|
|
431
|
-
< BLOCKSIZE - MAXARRAYLENGTH):
|
|
432
|
-
self.todense()
|
|
433
|
-
elif self.cardinality < MAXARRAYLENGTH:
|
|
434
|
-
# shouldn't happen?
|
|
435
|
-
raise ValueError
|
|
436
|
-
elif self.state == POSITIVE:
|
|
437
|
-
if MAXARRAYLENGTH < self.cardinality < BLOCKSIZE - MAXARRAYLENGTH:
|
|
438
|
-
# To dense bitvector
|
|
439
|
-
self.todense()
|
|
440
|
-
elif self.cardinality > BLOCKSIZE - MAXARRAYLENGTH:
|
|
441
|
-
# shouldn't happen?
|
|
442
|
-
raise ValueError
|
|
443
|
-
|
|
444
|
-
def size(self):
|
|
445
|
-
"""Return memory usage."""
|
|
446
|
-
return 2 * len(self.buf)
|
|
447
|
-
|
|
448
429
|
cdef issubset(self, Block other):
|
|
449
430
|
cdef int n, m = 0
|
|
450
431
|
if self.key != other.key or self.cardinality > other.cardinality:
|
|
@@ -594,7 +575,7 @@ cdef class Block(object):
|
|
|
594
575
|
elif self.state == POSITIVE:
|
|
595
576
|
return self.buf.data.as_ushorts[i]
|
|
596
577
|
elif self.state == DENSE:
|
|
597
|
-
for n in range(
|
|
578
|
+
for n in range(BITNSLOTS(BLOCKSIZE)):
|
|
598
579
|
w = bit_popcount(self.buf.data.as_ulongs[n])
|
|
599
580
|
if w > i:
|
|
600
581
|
return BITSIZE * n + select64(
|
|
@@ -608,18 +589,55 @@ cdef class Block(object):
|
|
|
608
589
|
return self.buf.data.as_ushorts[len(self.buf) - 1] + (
|
|
609
590
|
i - len(self.buf))
|
|
610
591
|
|
|
592
|
+
cdef flip(self):
|
|
593
|
+
"""In-place complement of this block."""
|
|
594
|
+
if self.state == DENSE:
|
|
595
|
+
for n in range(BITNSLOTS(BLOCKSIZE)):
|
|
596
|
+
self.buf.data.as_ulongs[n] = ~self.buf.data.as_ulongs[n]
|
|
597
|
+
elif self.state == POSITIVE:
|
|
598
|
+
self.state = INVERTED
|
|
599
|
+
elif self.state == INVERTED:
|
|
600
|
+
self.state = POSITIVE
|
|
601
|
+
# FIXME: need notion of maximium element
|
|
602
|
+
self.cardinality = BLOCKSIZE - self.cardinality
|
|
603
|
+
|
|
604
|
+
cdef resize(self):
|
|
605
|
+
"""Convert between dense, sparse, inverted sparse as needed."""
|
|
606
|
+
if self.state == DENSE:
|
|
607
|
+
if self.cardinality < MAXARRAYLENGTH:
|
|
608
|
+
self.toposarray()
|
|
609
|
+
elif self.cardinality > BLOCKSIZE - MAXARRAYLENGTH:
|
|
610
|
+
self.toinvarray()
|
|
611
|
+
elif self.state == INVERTED:
|
|
612
|
+
if (MAXARRAYLENGTH < self.cardinality
|
|
613
|
+
< BLOCKSIZE - MAXARRAYLENGTH):
|
|
614
|
+
self.todense()
|
|
615
|
+
elif self.cardinality < MAXARRAYLENGTH:
|
|
616
|
+
# shouldn't happen?
|
|
617
|
+
raise ValueError
|
|
618
|
+
elif self.state == POSITIVE:
|
|
619
|
+
if MAXARRAYLENGTH < self.cardinality < BLOCKSIZE - MAXARRAYLENGTH:
|
|
620
|
+
# To dense bitvector
|
|
621
|
+
self.todense()
|
|
622
|
+
elif self.cardinality > BLOCKSIZE - MAXARRAYLENGTH:
|
|
623
|
+
# shouldn't happen?
|
|
624
|
+
raise ValueError
|
|
625
|
+
|
|
626
|
+
def __sizeof__(self):
|
|
627
|
+
"""Return memory usage in bytes."""
|
|
628
|
+
return (sizeof(self.state) + sizeof(self.key)
|
|
629
|
+
+ sizeof(self.cardinality) + sys.getsizeof(self.buf))
|
|
630
|
+
|
|
611
631
|
cdef todense(self):
|
|
612
632
|
# To dense bitvector
|
|
613
|
-
cdef array.array tmp
|
|
614
633
|
cdef int n
|
|
634
|
+
tmp = array.clone(ushortarray, BITMAPSIZE // sizeof(short), False)
|
|
615
635
|
if self.state == INVERTED:
|
|
616
|
-
tmp
|
|
617
|
-
memset(tmp.data.as_uchars, 255, BLOCKSIZE // sizeof(char))
|
|
636
|
+
memset(tmp.data.as_chars, 255, BITMAPSIZE)
|
|
618
637
|
for n in range(BLOCKSIZE - self.cardinality):
|
|
619
|
-
CLEARBIT(tmp.data.as_ulongs,
|
|
620
|
-
self.buf.data.as_ushorts[n])
|
|
638
|
+
CLEARBIT(tmp.data.as_ulongs, self.buf.data.as_ushorts[n])
|
|
621
639
|
else: # self.state == POSITIVE:
|
|
622
|
-
tmp
|
|
640
|
+
memset(tmp.data.as_chars, 0, BITMAPSIZE)
|
|
623
641
|
for n in range(self.cardinality):
|
|
624
642
|
SETBIT(tmp.data.as_ulongs, self.buf.data.as_ushorts[n])
|
|
625
643
|
self.state = DENSE
|
|
@@ -755,15 +773,21 @@ cdef class Block(object):
|
|
|
755
773
|
elif self.state == POSITIVE:
|
|
756
774
|
return 'array(%r)' % self.buf
|
|
757
775
|
|
|
776
|
+
cdef allocarray(self):
|
|
777
|
+
self.buf = array.clone(ushortarray, 0, False)
|
|
778
|
+
|
|
758
779
|
def __reduce__(self):
|
|
759
|
-
return (Block,
|
|
760
|
-
self.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
self.
|
|
780
|
+
return (Block, (), dict(
|
|
781
|
+
key=self.key,
|
|
782
|
+
state=self.state,
|
|
783
|
+
cardinality=self.cardinality,
|
|
784
|
+
buf=self.buf))
|
|
785
|
+
|
|
786
|
+
def __setstate__(self, state):
|
|
787
|
+
self.key = state['key']
|
|
788
|
+
self.state = state['state']
|
|
789
|
+
self.cardinality = state['cardinality']
|
|
790
|
+
self.buf = state['buf']
|
|
767
791
|
|
|
768
792
|
|
|
769
793
|
cdef inline int min(int a, int b):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/* http://c-faq.com/misc/bitsets.html */
|
|
3
3
|
#define BITSIZE (8 * sizeof(uint64_t))
|
|
4
|
-
#define BITMASK(b) (
|
|
4
|
+
#define BITMASK(b) (1ULL << ((b) % BITSIZE))
|
|
5
5
|
#define BITSLOT(b) ((b) / BITSIZE)
|
|
6
6
|
#define SETBIT(a, b) ((a)[BITSLOT(b)] |= BITMASK(b))
|
|
7
7
|
#define TOGGLEBIT(a, b) ((a)[BITSLOT(b)] ^= BITMASK(b))
|