ingramj-bitarray 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +3 -5
- data/VERSION +1 -1
- data/bitarray.gemspec +3 -5
- data/ext/bitarray.c +388 -338
- data/test/bm.rb +13 -37
- data/test/test.rb +15 -2
- metadata +2 -4
- data/test/bitfield.rb +0 -67
data/README
CHANGED
@@ -15,8 +15,7 @@ Example usage:
|
|
15
15
|
bm.clear_bit 0
|
16
16
|
|
17
17
|
|
18
|
-
The test/ directory has a unit test file
|
19
|
-
comparison with Peter Cooper's pure Ruby BitField class.
|
18
|
+
The test/ directory has a unit test file, and benchmarking utility.
|
20
19
|
|
21
20
|
The examples/ directory has bloom filter dictionary-lookup demonstration.
|
22
21
|
|
@@ -43,9 +42,8 @@ See the LICENSE file for copyright and license information.
|
|
43
42
|
|
44
43
|
Some inspiration was taken from Peter Cooper's BitField class, and various Open
|
45
44
|
Source bitarray implementations found online, but this implementation contains
|
46
|
-
only original code, except for test
|
47
|
-
BitField
|
48
|
-
code.
|
45
|
+
only original code, except for some parts for test.rb, which were modified from
|
46
|
+
BitField's unit test file.
|
49
47
|
|
50
48
|
BitField: http://snippets.dzone.com/posts/show/4234
|
51
49
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.1
|
data/bitarray.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{bitarray}
|
5
|
-
s.version = "0.5.
|
5
|
+
s.version = "0.5.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["James E. Ingram"]
|
9
|
-
s.date = %q{2009-06-
|
9
|
+
s.date = %q{2009-06-02}
|
10
10
|
s.description = %q{A bit array class for Ruby, implemented as a C extension. Includes methods for setting and clearing individual bits, and all bits at once. Also has the standard array access methods, [] and []=, and it mixes in Enumerable.}
|
11
11
|
s.email = %q{ingramj@gmail.com}
|
12
12
|
s.extensions = ["ext/extconf.rb"]
|
@@ -26,7 +26,6 @@ Gem::Specification.new do |s|
|
|
26
26
|
"examples/boolnet.rb",
|
27
27
|
"ext/bitarray.c",
|
28
28
|
"ext/extconf.rb",
|
29
|
-
"test/bitfield.rb",
|
30
29
|
"test/bm.rb",
|
31
30
|
"test/test.rb"
|
32
31
|
]
|
@@ -38,8 +37,7 @@ Gem::Specification.new do |s|
|
|
38
37
|
s.rubygems_version = %q{1.3.1}
|
39
38
|
s.summary = %q{A bitarray class for Ruby, implemented as a C extension.}
|
40
39
|
s.test_files = [
|
41
|
-
"test/
|
42
|
-
"test/test.rb",
|
40
|
+
"test/test.rb",
|
43
41
|
"test/bm.rb",
|
44
42
|
"examples/bloomfilter.rb",
|
45
43
|
"examples/boolnet.rb"
|
data/ext/bitarray.c
CHANGED
@@ -2,122 +2,135 @@
|
|
2
2
|
#include <limits.h>
|
3
3
|
#include <string.h>
|
4
4
|
|
5
|
-
/* Bits are stored in an array of unsigned ints. We'll use a couple of defines
|
6
|
-
* for getting the size of unsigned ints in bytes and bits.
|
7
|
-
*/
|
8
5
|
#define UINT_BYTES (sizeof(unsigned int))
|
9
6
|
#define UINT_BITS (UINT_BYTES * CHAR_BIT)
|
10
7
|
|
11
|
-
/*
|
12
|
-
#define bitmask(bit) (1 << (bit % UINT_BITS))
|
8
|
+
/* Accessing a particular bit within a word. */
|
9
|
+
#define bitmask(bit) (1 << ((bit) % UINT_BITS))
|
10
|
+
|
11
|
+
/* Determining how many unsigned ints we need to store a given number of bits.
|
12
|
+
* We check if (bits - 1) is negative because the C standard helpfully
|
13
|
+
* specifies that in an arithmetic expression "... if either operand is
|
14
|
+
* unsigned long int, the other is converted to unsigned long int", causing
|
15
|
+
* large amounts of hilarity when one of the operands is negative.
|
16
|
+
*/
|
17
|
+
#define uint_array_size(bits) (bits <= 0 ? 0 : (((bits) - 1) / UINT_BITS + 1))
|
18
|
+
|
19
|
+
/* Get the number of bits stored in a bitarray. */
|
20
|
+
#define bitarray_size(ba) (ba->bits)
|
13
21
|
|
14
|
-
|
15
|
-
|
16
|
-
long
|
17
|
-
long array_size; /* Size of the storage array. */
|
22
|
+
struct bitarray {
|
23
|
+
long bits; /* Number of bits. */
|
24
|
+
long array_size; /* Size of the storage array. */
|
18
25
|
unsigned int *array; /* Array of unsigned ints, used for bit storage. */
|
19
26
|
};
|
20
27
|
|
21
28
|
|
22
|
-
/*
|
29
|
+
/* Low-level bit-manipulation functions.
|
30
|
+
*
|
31
|
+
* These function are used by the Ruby interface functions to modify
|
32
|
+
* bitarray structures.
|
33
|
+
*
|
34
|
+
* Functions that take an index will raise an IndexError if it is out of range.
|
35
|
+
* Negative indices count from the end of the array.
|
36
|
+
*/
|
23
37
|
|
24
|
-
|
25
|
-
|
26
|
-
|
38
|
+
|
39
|
+
/* This function is used by all of the bit-manipulation functions to check
|
40
|
+
* indices. It handles negative-index conversion and bounds checking.
|
41
|
+
*/
|
42
|
+
static inline long
|
43
|
+
check_index(struct bitarray *ba, long index)
|
27
44
|
{
|
28
|
-
if (
|
29
|
-
if (
|
30
|
-
|
45
|
+
if (index < 0) index += ba->bits;
|
46
|
+
if (index >= ba->bits) {
|
47
|
+
rb_raise(rb_eIndexError, "index %ld out of bit array", index);
|
31
48
|
}
|
32
49
|
|
33
|
-
|
34
|
-
|
50
|
+
return index;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
/* Set the specified bit to 1. */
|
55
|
+
static inline void
|
56
|
+
set_bit(struct bitarray *ba, long index)
|
57
|
+
{
|
58
|
+
index = check_index(ba, index);
|
59
|
+
ba->array[index / UINT_BITS] |= bitmask(index);
|
35
60
|
}
|
36
61
|
|
37
62
|
|
38
63
|
/* Set all bits to 1. */
|
39
|
-
static inline
|
40
|
-
set_all_bits(struct
|
64
|
+
static inline void
|
65
|
+
set_all_bits(struct bitarray *ba)
|
41
66
|
{
|
42
67
|
memset(ba->array, 0xff, (ba->array_size * UINT_BYTES));
|
43
|
-
return 1;
|
44
68
|
}
|
45
69
|
|
46
70
|
|
47
|
-
/* Clear the specified bit to 0.
|
48
|
-
static inline
|
49
|
-
clear_bit(struct
|
71
|
+
/* Clear the specified bit to 0. */
|
72
|
+
static inline void
|
73
|
+
clear_bit(struct bitarray *ba, long index)
|
50
74
|
{
|
51
|
-
|
52
|
-
|
53
|
-
return 0;
|
54
|
-
}
|
55
|
-
|
56
|
-
ba->array[bit / UINT_BITS] &= ~bitmask(bit);
|
57
|
-
return 1;
|
75
|
+
index = check_index(ba, index);
|
76
|
+
ba->array[index / UINT_BITS] &= ~bitmask(index);
|
58
77
|
}
|
59
78
|
|
60
79
|
|
61
80
|
/* Clear all bits to 0. */
|
62
|
-
static inline
|
63
|
-
clear_all_bits(struct
|
81
|
+
static inline void
|
82
|
+
clear_all_bits(struct bitarray *ba)
|
64
83
|
{
|
65
84
|
memset(ba->array, 0x00, (ba->array_size * UINT_BYTES));
|
66
|
-
return 1;
|
67
85
|
}
|
68
86
|
|
69
87
|
|
70
|
-
/* Toggle the state of the specified bit.
|
71
|
-
static inline
|
72
|
-
toggle_bit(struct
|
88
|
+
/* Toggle the state of the specified bit. */
|
89
|
+
static inline void
|
90
|
+
toggle_bit(struct bitarray *ba, long index)
|
73
91
|
{
|
74
|
-
|
75
|
-
|
76
|
-
return 0;
|
77
|
-
}
|
78
|
-
|
79
|
-
ba->array[bit / UINT_BITS] ^= bitmask(bit);
|
80
|
-
return 1;
|
92
|
+
index = check_index(ba, index);
|
93
|
+
ba->array[index / UINT_BITS] ^= bitmask(index);
|
81
94
|
}
|
82
95
|
|
83
96
|
|
84
97
|
/* Toggle the state of all bits. */
|
85
|
-
static inline
|
86
|
-
toggle_all_bits(struct
|
98
|
+
static inline void
|
99
|
+
toggle_all_bits(struct bitarray *ba)
|
87
100
|
{
|
88
101
|
long i;
|
89
102
|
for(i = 0; i < ba->array_size; i++) {
|
90
103
|
ba->array[i] ^= ~0ul; /* ~0 = all bits set. */
|
91
104
|
}
|
92
|
-
return 1;
|
93
105
|
}
|
94
106
|
|
95
107
|
|
96
|
-
/* Assign the specified value to a bit.
|
97
|
-
*
|
98
|
-
|
99
|
-
|
108
|
+
/* Assign the specified value to a bit. If the specified value is invalid,
|
109
|
+
* raises an ArgumentError.
|
110
|
+
*/
|
111
|
+
static inline void
|
112
|
+
assign_bit(struct bitarray *ba, long index, int value)
|
100
113
|
{
|
101
114
|
if (value == 0) {
|
102
|
-
|
115
|
+
clear_bit(ba, index);
|
103
116
|
} else if (value == 1) {
|
104
|
-
|
117
|
+
set_bit(ba, index);
|
105
118
|
} else {
|
106
|
-
|
119
|
+
rb_raise(rb_eArgError, "bit value %d out of range", value);
|
107
120
|
}
|
108
121
|
}
|
109
122
|
|
110
123
|
|
111
|
-
/* Get the state of the specified bit.
|
124
|
+
/* Get the state of the specified bit. */
|
112
125
|
static inline int
|
113
|
-
get_bit(struct
|
126
|
+
get_bit(struct bitarray *ba, long index)
|
114
127
|
{
|
115
|
-
|
116
|
-
if (bit >= ba->bits) {
|
117
|
-
return -1;
|
118
|
-
}
|
128
|
+
index = check_index(ba, index);
|
119
129
|
|
120
|
-
|
130
|
+
/* We could shift the bit down, but this is easier. We need an unsigned int
|
131
|
+
* to prevent overflow.
|
132
|
+
*/
|
133
|
+
unsigned int b = (ba->array[index / UINT_BITS] & bitmask(index));
|
121
134
|
if (b > 0) {
|
122
135
|
return 1;
|
123
136
|
} else {
|
@@ -128,7 +141,7 @@ get_bit(struct bit_array *ba, long bit)
|
|
128
141
|
|
129
142
|
/* Return the number of set bits in the array. */
|
130
143
|
static inline long
|
131
|
-
total_set(struct
|
144
|
+
total_set(struct bitarray *ba)
|
132
145
|
{
|
133
146
|
/* This is basically the algorithm from K&R, with a running total for all
|
134
147
|
* array elements. There are faster algorithms, but this one is simpler to
|
@@ -148,13 +161,110 @@ total_set(struct bit_array *ba)
|
|
148
161
|
}
|
149
162
|
|
150
163
|
|
151
|
-
/*
|
164
|
+
/* Initialize an already-allocated bitarray structure. The array is initialized
|
165
|
+
* to all zeros.
|
166
|
+
*/
|
167
|
+
static inline void
|
168
|
+
initialize_bitarray(struct bitarray *ba, long size)
|
169
|
+
{
|
170
|
+
if (size <= 0) {
|
171
|
+
ba->bits = 0;
|
172
|
+
ba->array_size = 0;
|
173
|
+
ba->array = NULL;
|
174
|
+
return;
|
175
|
+
}
|
176
|
+
|
177
|
+
ba->bits = size;
|
178
|
+
ba->array_size = uint_array_size(size);
|
179
|
+
ba->array = ruby_xcalloc(ba->array_size, UINT_BYTES);
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
/* Initialize an already-allocated bitarray structure as a copy of another
|
184
|
+
* bitarray structure.
|
185
|
+
*/
|
186
|
+
static inline void
|
187
|
+
initialize_bitarray_copy(struct bitarray *new_ba, struct bitarray *orig_ba)
|
188
|
+
{
|
189
|
+
new_ba->bits = orig_ba->bits;
|
190
|
+
new_ba->array_size = orig_ba->array_size;
|
191
|
+
new_ba->array = ruby_xmalloc2(new_ba->array_size, UINT_BYTES);
|
152
192
|
|
193
|
+
memcpy(new_ba->array, orig_ba->array, new_ba->array_size * UINT_BYTES);
|
194
|
+
}
|
195
|
+
|
196
|
+
|
197
|
+
/* Initialize an already-allocated bitarray structure as the concatenation of
|
198
|
+
* two other bitarrays structures.
|
199
|
+
*/
|
200
|
+
static void
|
201
|
+
initialize_bitarray_concat(struct bitarray *new_ba, struct bitarray *x_ba,
|
202
|
+
struct bitarray *y_ba)
|
203
|
+
{
|
204
|
+
new_ba->bits = x_ba->bits + y_ba->bits;
|
205
|
+
new_ba->array_size = uint_array_size(new_ba->bits);
|
206
|
+
new_ba->array = ruby_xmalloc2(new_ba->array_size, UINT_BYTES);
|
207
|
+
|
208
|
+
|
209
|
+
/* For each bit set in x_ba and y_ba, set the corresponding bit in new_ba.
|
210
|
+
*
|
211
|
+
* First, copy x_ba->array to the beginning of new_ba->array.
|
212
|
+
*/
|
213
|
+
memcpy(new_ba->array, x_ba->array, x_ba->array_size * UINT_BYTES);
|
214
|
+
|
215
|
+
/* Then, if x_ba->bits is a multiple of UINT_BITS, we can just copy
|
216
|
+
* y_ba->array onto the end of new_ba->array.
|
217
|
+
*
|
218
|
+
* Otherwise, we need to go through y_ba->array bit-by-bit and set the
|
219
|
+
* appropriate bits in new_ba->array.
|
220
|
+
*/
|
221
|
+
if ((x_ba->bits % UINT_BITS) == 0) {
|
222
|
+
unsigned int *start = new_ba->array + x_ba->array_size;
|
223
|
+
memcpy(start, y_ba->array, y_ba->array_size * UINT_BYTES);
|
224
|
+
} else {
|
225
|
+
long y_index, new_index;
|
226
|
+
for (y_index = 0, new_index = x_ba->bits;
|
227
|
+
y_index < y_ba->bits;
|
228
|
+
y_index++, new_index++)
|
229
|
+
{
|
230
|
+
if (get_bit(y_ba, y_index) == 1) {
|
231
|
+
set_bit(new_ba, new_index);
|
232
|
+
} else {
|
233
|
+
clear_bit(new_ba, new_index);
|
234
|
+
}
|
235
|
+
}
|
236
|
+
}
|
237
|
+
|
238
|
+
}
|
239
|
+
|
240
|
+
|
241
|
+
|
242
|
+
/* Ruby Interface Functions.
|
243
|
+
*
|
244
|
+
* These functions put a Ruby face on top of the lower-level functions. With
|
245
|
+
* very few exceptions, they should not access the bitarray structs' members
|
246
|
+
* directly.
|
247
|
+
*
|
248
|
+
* "bitarray" refers to the C structure. "BitArray" refers to the Ruby class.
|
249
|
+
*
|
250
|
+
* All publicly-accessible functions (those with an rb_define_method call in
|
251
|
+
* Init_bitarray) should have RDoc comment headers.
|
252
|
+
*
|
253
|
+
* When in doubt, see how array.c does things.
|
254
|
+
*/
|
255
|
+
|
256
|
+
|
257
|
+
/* Our BitArray class. This is initialized in Init_bitarray, but we declare it
|
258
|
+
* here because a few functions need it.
|
259
|
+
*/
|
153
260
|
static VALUE rb_bitarray_class;
|
154
261
|
|
155
262
|
|
263
|
+
/* This gets called when a BitArray is garbage collected. It frees the memory
|
264
|
+
* used by the bitarray struct.
|
265
|
+
*/
|
156
266
|
static void
|
157
|
-
rb_bitarray_free(struct
|
267
|
+
rb_bitarray_free(struct bitarray *ba)
|
158
268
|
{
|
159
269
|
if (ba && ba->array) {
|
160
270
|
ruby_xfree(ba->array);
|
@@ -163,33 +273,96 @@ rb_bitarray_free(struct bit_array *ba)
|
|
163
273
|
}
|
164
274
|
|
165
275
|
|
276
|
+
/* This function is called by BitArray.new to allocate a new BitArray.
|
277
|
+
* Initialization is done in a seperate function.
|
278
|
+
*
|
279
|
+
* This function can be called directly with BitArray.allocate, but that is not
|
280
|
+
* very useful.
|
281
|
+
*/
|
166
282
|
static VALUE
|
167
283
|
rb_bitarray_alloc(VALUE klass)
|
168
284
|
{
|
169
|
-
struct
|
170
|
-
return Data_Make_Struct(rb_bitarray_class, struct
|
285
|
+
struct bitarray *ba;
|
286
|
+
return Data_Make_Struct(rb_bitarray_class, struct bitarray, NULL,
|
171
287
|
rb_bitarray_free, ba);
|
172
288
|
}
|
173
289
|
|
174
290
|
|
291
|
+
/* Initialization helper-function prototypes. These functions are defined after
|
292
|
+
* rb_bitarray_initialize.
|
293
|
+
*/
|
294
|
+
static VALUE rb_bitarray_from_string(VALUE self, VALUE string);
|
295
|
+
static VALUE rb_bitarray_from_array(VALUE self, VALUE array);
|
296
|
+
|
297
|
+
|
298
|
+
/* call-seq:
|
299
|
+
* BitArray.new(size)
|
300
|
+
* BitArray.new(string)
|
301
|
+
* BitArray.new(array)
|
302
|
+
*
|
303
|
+
* When called with a size, creates a new BitArray of the specified size, with
|
304
|
+
* all bits cleared. When called with a string or an array, creates a new
|
305
|
+
* BitArray from the argument.
|
306
|
+
*
|
307
|
+
* If a string is given, it should consist of ones and zeroes. If there are
|
308
|
+
* any other characters in the string, the first invalid character and all
|
309
|
+
* following characters will be ignored.
|
310
|
+
*
|
311
|
+
* b = BitArray.new("10101010") => 10101010
|
312
|
+
* b = BitArray.new("1010abcd") => 1010
|
313
|
+
* b = BitArray.new("abcd") =>
|
314
|
+
*
|
315
|
+
* If an array is given, the BitArray is initialized from its elements using
|
316
|
+
* the following rules:
|
317
|
+
*
|
318
|
+
* 1. 0, false, or nil => 0
|
319
|
+
* 2. anything else => 1
|
320
|
+
*
|
321
|
+
* Note that the 0 is a number, not a string. "Anything else" means strings,
|
322
|
+
* symbols, non-zero numbers, subarrays, etc.
|
323
|
+
*
|
324
|
+
* b = BitArray.new([0,0,0,1,1,0]) => 000110
|
325
|
+
* b = BitArray.new([false, true, false]) => 010
|
326
|
+
* b = BitArray.new([:a, :b, :c, [:d, :e]]) => 1111
|
327
|
+
*/
|
328
|
+
static VALUE
|
329
|
+
rb_bitarray_initialize(VALUE self, VALUE arg)
|
330
|
+
{
|
331
|
+
if (TYPE(arg) == T_FIXNUM || TYPE(arg) == T_BIGNUM) {
|
332
|
+
struct bitarray *ba;
|
333
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
334
|
+
|
335
|
+
initialize_bitarray(ba, NUM2LONG(arg));
|
336
|
+
|
337
|
+
return self;
|
338
|
+
|
339
|
+
} else if (TYPE(arg) == T_STRING) {
|
340
|
+
return rb_bitarray_from_string(self, arg);
|
341
|
+
} else if (TYPE(arg) == T_ARRAY) {
|
342
|
+
return rb_bitarray_from_array(self, arg);
|
343
|
+
} else {
|
344
|
+
rb_raise(rb_eArgError, "must be size, string, or array");
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
|
175
349
|
/* Create a new BitArray from a string. Called by rb_bitarray_initialize. */
|
176
350
|
static VALUE
|
177
|
-
rb_bitarray_from_string(VALUE self, VALUE
|
351
|
+
rb_bitarray_from_string(VALUE self, VALUE string)
|
178
352
|
{
|
179
|
-
struct
|
180
|
-
Data_Get_Struct(self, struct
|
353
|
+
struct bitarray *ba;
|
354
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
181
355
|
|
182
356
|
/* Extract a C-string from arg. */
|
183
|
-
long str_len = RSTRING_LEN(
|
357
|
+
long str_len = RSTRING_LEN(string) + 1;
|
184
358
|
char cstr[str_len];
|
185
|
-
strncpy(cstr, StringValueCStr(
|
359
|
+
strncpy(cstr, StringValueCStr(string), str_len);
|
186
360
|
|
187
361
|
/* If the string doesn't begin with a '1' or '0', return an empty
|
188
362
|
* BitArray.
|
189
363
|
*/
|
190
364
|
if (cstr[0] != '0' && cstr[0] != '1') {
|
191
|
-
ba
|
192
|
-
ba->array_size = 0;
|
365
|
+
initialize_bitarray(ba, 0);
|
193
366
|
return self;
|
194
367
|
}
|
195
368
|
|
@@ -205,9 +378,7 @@ rb_bitarray_from_string(VALUE self, VALUE arg)
|
|
205
378
|
}
|
206
379
|
|
207
380
|
/* Setup the BitArray structure. */
|
208
|
-
ba
|
209
|
-
ba->array_size = ((ba->bits - 1) / UINT_BITS) + 1;
|
210
|
-
ba->array = ruby_xmalloc(ba->array_size * UINT_BYTES);
|
381
|
+
initialize_bitarray(ba, strlen(cstr));
|
211
382
|
|
212
383
|
/* Initialize the bit array with the string. */
|
213
384
|
for (i = 0; i < ba->bits; i++) {
|
@@ -224,19 +395,18 @@ rb_bitarray_from_string(VALUE self, VALUE arg)
|
|
224
395
|
|
225
396
|
/* Create a new BitArray from an Array. Called by rb_bitarray_initialize */
|
226
397
|
static VALUE
|
227
|
-
rb_bitarray_from_array(VALUE self, VALUE
|
398
|
+
rb_bitarray_from_array(VALUE self, VALUE array)
|
228
399
|
{
|
229
|
-
struct
|
230
|
-
Data_Get_Struct(self, struct
|
400
|
+
struct bitarray *ba;
|
401
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
231
402
|
|
232
|
-
|
233
|
-
|
234
|
-
ba->array = ruby_xmalloc(ba->array_size * UINT_BYTES);
|
403
|
+
long size = RARRAY_LEN(array);
|
404
|
+
initialize_bitarray(ba, size);
|
235
405
|
|
236
406
|
VALUE e;
|
237
407
|
long i;
|
238
|
-
for (i = 0; i <
|
239
|
-
e = rb_ary_entry(
|
408
|
+
for (i = 0; i < size; i++) {
|
409
|
+
e = rb_ary_entry(array, i);
|
240
410
|
|
241
411
|
switch (TYPE(e)) {
|
242
412
|
case T_FIXNUM: /* fixnums and bignums treated the same. */
|
@@ -256,66 +426,6 @@ rb_bitarray_from_array(VALUE self, VALUE arg)
|
|
256
426
|
}
|
257
427
|
|
258
428
|
|
259
|
-
/* call-seq:
|
260
|
-
* BitArray.new(size)
|
261
|
-
* BitArray.new(string)
|
262
|
-
* BitArray.new(array)
|
263
|
-
*
|
264
|
-
* When called with a size, creates a new BitArray of the specified size, with
|
265
|
-
* all bits cleared. When called with a string or an array, creates a new
|
266
|
-
* BitArray from the argument.
|
267
|
-
*
|
268
|
-
* If a string is given, it should consist of ones and zeroes. If there are
|
269
|
-
* any other characters in the string, the first invalid character and all
|
270
|
-
* following characters will be ignored.
|
271
|
-
*
|
272
|
-
* b = BitArray.new("10101010") => 10101010
|
273
|
-
* b = BitArray.new("1010abcd") => 1010
|
274
|
-
* b = BitArray.new("abcd") =>
|
275
|
-
*
|
276
|
-
* If an array is given, the BitArray is initialized from its elements using
|
277
|
-
* the following rules:
|
278
|
-
*
|
279
|
-
* 1. 0, false, or nil => 0
|
280
|
-
* 2. anything else => 1
|
281
|
-
*
|
282
|
-
* Note that the 0 is a number, not a string. "Anything else" means strings,
|
283
|
-
* symbols, non-zero numbers, subarrays, etc.
|
284
|
-
*
|
285
|
-
* b = BitArray.new([0,0,0,1,1,0]) => 000110
|
286
|
-
* b = BitArray.new([false, true, false]) => 010
|
287
|
-
* b = BitArray.new([:a, :b, :c, [:d, :e]]) => 1111
|
288
|
-
*/
|
289
|
-
static VALUE
|
290
|
-
rb_bitarray_initialize(VALUE self, VALUE arg)
|
291
|
-
{
|
292
|
-
if (TYPE(arg) == T_FIXNUM || TYPE(arg) == T_BIGNUM) {
|
293
|
-
struct bit_array *ba;
|
294
|
-
Data_Get_Struct(self, struct bit_array, ba);
|
295
|
-
|
296
|
-
long bits = NUM2LONG(arg);
|
297
|
-
if (bits <= 0) {
|
298
|
-
ba->bits = 0;
|
299
|
-
ba->array_size = 0;
|
300
|
-
return self;
|
301
|
-
}
|
302
|
-
|
303
|
-
ba->bits = bits;
|
304
|
-
ba->array_size = ((bits - 1) / UINT_BITS) + 1;
|
305
|
-
ba->array = ruby_xcalloc(ba->array_size, UINT_BYTES);
|
306
|
-
|
307
|
-
return self;
|
308
|
-
|
309
|
-
} else if (TYPE(arg) == T_STRING) {
|
310
|
-
return rb_bitarray_from_string(self, arg);
|
311
|
-
} else if (TYPE(arg) == T_ARRAY) {
|
312
|
-
return rb_bitarray_from_array(self, arg);
|
313
|
-
} else {
|
314
|
-
rb_raise(rb_eArgError, "must be size, string, or array");
|
315
|
-
}
|
316
|
-
}
|
317
|
-
|
318
|
-
|
319
429
|
/* call-seq:
|
320
430
|
* bitarray.clone -> a_bitarray
|
321
431
|
* bitarray.dup -> a_bitarray
|
@@ -325,15 +435,11 @@ rb_bitarray_initialize(VALUE self, VALUE arg)
|
|
325
435
|
static VALUE
|
326
436
|
rb_bitarray_initialize_copy(VALUE self, VALUE orig)
|
327
437
|
{
|
328
|
-
struct
|
329
|
-
Data_Get_Struct(self, struct
|
330
|
-
Data_Get_Struct(orig, struct
|
438
|
+
struct bitarray *new_ba, *orig_ba;
|
439
|
+
Data_Get_Struct(self, struct bitarray, new_ba);
|
440
|
+
Data_Get_Struct(orig, struct bitarray, orig_ba);
|
331
441
|
|
332
|
-
new_ba
|
333
|
-
new_ba->array_size = orig_ba->array_size;
|
334
|
-
new_ba->array = ruby_xcalloc(new_ba->array_size, UINT_BYTES);
|
335
|
-
|
336
|
-
memcpy(new_ba->array, orig_ba->array, (new_ba->array_size * UINT_BYTES));
|
442
|
+
initialize_bitarray_copy(new_ba, orig_ba);
|
337
443
|
|
338
444
|
return self;
|
339
445
|
}
|
@@ -348,40 +454,18 @@ rb_bitarray_initialize_copy(VALUE self, VALUE orig)
|
|
348
454
|
static VALUE
|
349
455
|
rb_bitarray_concat(VALUE x, VALUE y)
|
350
456
|
{
|
351
|
-
/* Get the
|
352
|
-
struct
|
353
|
-
Data_Get_Struct(x, struct
|
354
|
-
Data_Get_Struct(y, struct
|
355
|
-
|
356
|
-
/* Create a new BitArray, and its
|
357
|
-
VALUE z;
|
358
|
-
struct
|
359
|
-
z
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
/* For each bit set in x and y, set the corresponding bit in z. First, copy
|
364
|
-
* x to the beginning of z. Then, if x->bits is a multiple of UINT_BITS, we
|
365
|
-
* can just copy y onto the end of z. Otherwise, we need to go through y
|
366
|
-
* bit-by-bit and set the appropriate bits in z.
|
367
|
-
*/
|
368
|
-
memcpy(z_ba->array, x_ba->array, (x_ba->array_size * UINT_BYTES));
|
369
|
-
if ((x_ba->bits % UINT_BITS) == 0) {
|
370
|
-
unsigned int *start = z_ba->array + x_ba->array_size;
|
371
|
-
memcpy(start, y_ba->array, (y_ba->array_size * UINT_BYTES));
|
372
|
-
} else {
|
373
|
-
long y_index, z_index;
|
374
|
-
for (y_index = 0, z_index = x_ba->bits;
|
375
|
-
y_index < y_ba->bits;
|
376
|
-
y_index++, z_index++)
|
377
|
-
{
|
378
|
-
if (get_bit(y_ba, y_index) == 1) {
|
379
|
-
set_bit(z_ba, z_index);
|
380
|
-
} else {
|
381
|
-
clear_bit(z_ba, z_index);
|
382
|
-
}
|
383
|
-
}
|
384
|
-
}
|
457
|
+
/* Get the bitarrays from x and y */
|
458
|
+
struct bitarray *x_ba, *y_ba;
|
459
|
+
Data_Get_Struct(x, struct bitarray, x_ba);
|
460
|
+
Data_Get_Struct(y, struct bitarray, y_ba);
|
461
|
+
|
462
|
+
/* Create a new BitArray, and its bitarray structure*/
|
463
|
+
VALUE z = rb_bitarray_alloc(rb_bitarray_class);
|
464
|
+
struct bitarray *z_ba;
|
465
|
+
Data_Get_Struct(z, struct bitarray, z_ba);
|
466
|
+
|
467
|
+
initialize_bitarray_concat(z_ba, x_ba, y_ba);
|
468
|
+
|
385
469
|
return z;
|
386
470
|
}
|
387
471
|
|
@@ -395,10 +479,10 @@ rb_bitarray_concat(VALUE x, VALUE y)
|
|
395
479
|
static VALUE
|
396
480
|
rb_bitarray_size(VALUE self)
|
397
481
|
{
|
398
|
-
struct
|
399
|
-
Data_Get_Struct(self, struct
|
482
|
+
struct bitarray *ba;
|
483
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
400
484
|
|
401
|
-
return LONG2NUM(ba
|
485
|
+
return LONG2NUM(bitarray_size(ba));
|
402
486
|
}
|
403
487
|
|
404
488
|
|
@@ -410,11 +494,10 @@ rb_bitarray_size(VALUE self)
|
|
410
494
|
static VALUE
|
411
495
|
rb_bitarray_total_set(VALUE self)
|
412
496
|
{
|
413
|
-
struct
|
414
|
-
Data_Get_Struct(self, struct
|
497
|
+
struct bitarray *ba;
|
498
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
415
499
|
|
416
|
-
|
417
|
-
return LONG2NUM(count);
|
500
|
+
return LONG2NUM(total_set(ba));
|
418
501
|
}
|
419
502
|
|
420
503
|
|
@@ -426,18 +509,13 @@ rb_bitarray_total_set(VALUE self)
|
|
426
509
|
* +IndexError+ is raised.
|
427
510
|
*/
|
428
511
|
static VALUE
|
429
|
-
rb_bitarray_set_bit(VALUE self, VALUE
|
512
|
+
rb_bitarray_set_bit(VALUE self, VALUE index)
|
430
513
|
{
|
431
|
-
struct
|
432
|
-
Data_Get_Struct(self, struct
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
if (set_bit(ba, index)) {
|
437
|
-
return self;
|
438
|
-
} else {
|
439
|
-
rb_raise(rb_eIndexError, "index %ld out of bit array", index);
|
440
|
-
}
|
514
|
+
struct bitarray *ba;
|
515
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
516
|
+
|
517
|
+
set_bit(ba, NUM2LONG(index));
|
518
|
+
return self;
|
441
519
|
}
|
442
520
|
|
443
521
|
|
@@ -449,14 +527,11 @@ rb_bitarray_set_bit(VALUE self, VALUE bit)
|
|
449
527
|
static VALUE
|
450
528
|
rb_bitarray_set_all_bits(VALUE self)
|
451
529
|
{
|
452
|
-
struct
|
453
|
-
Data_Get_Struct(self, struct
|
530
|
+
struct bitarray *ba;
|
531
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
454
532
|
|
455
|
-
|
456
|
-
|
457
|
-
} else {
|
458
|
-
rb_bug("BitArray#set_all_bits failed. This should not occur.");
|
459
|
-
}
|
533
|
+
set_all_bits(ba);
|
534
|
+
return self;
|
460
535
|
}
|
461
536
|
|
462
537
|
|
@@ -468,18 +543,13 @@ rb_bitarray_set_all_bits(VALUE self)
|
|
468
543
|
* +IndexError+ is raised.
|
469
544
|
*/
|
470
545
|
static VALUE
|
471
|
-
rb_bitarray_clear_bit(VALUE self, VALUE
|
546
|
+
rb_bitarray_clear_bit(VALUE self, VALUE index)
|
472
547
|
{
|
473
|
-
struct
|
474
|
-
Data_Get_Struct(self, struct
|
548
|
+
struct bitarray *ba;
|
549
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
475
550
|
|
476
|
-
|
477
|
-
|
478
|
-
if (clear_bit(ba, index)) {
|
479
|
-
return self;
|
480
|
-
} else {
|
481
|
-
rb_raise(rb_eIndexError, "index %ld out of bit array", index);
|
482
|
-
}
|
551
|
+
clear_bit(ba, NUM2LONG(index));
|
552
|
+
return self;
|
483
553
|
}
|
484
554
|
|
485
555
|
|
@@ -491,14 +561,11 @@ rb_bitarray_clear_bit(VALUE self, VALUE bit)
|
|
491
561
|
static VALUE
|
492
562
|
rb_bitarray_clear_all_bits(VALUE self)
|
493
563
|
{
|
494
|
-
struct
|
495
|
-
Data_Get_Struct(self, struct
|
564
|
+
struct bitarray *ba;
|
565
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
496
566
|
|
497
|
-
|
498
|
-
|
499
|
-
} else {
|
500
|
-
rb_bug("BitArray#clear_all_bits failed. This should not occur.");
|
501
|
-
}
|
567
|
+
clear_all_bits(ba);
|
568
|
+
return self;
|
502
569
|
}
|
503
570
|
|
504
571
|
|
@@ -510,18 +577,13 @@ rb_bitarray_clear_all_bits(VALUE self)
|
|
510
577
|
* +IndexError+ is raised.
|
511
578
|
*/
|
512
579
|
static VALUE
|
513
|
-
rb_bitarray_toggle_bit(VALUE self, VALUE
|
580
|
+
rb_bitarray_toggle_bit(VALUE self, VALUE index)
|
514
581
|
{
|
515
|
-
struct
|
516
|
-
Data_Get_Struct(self, struct
|
517
|
-
|
518
|
-
long index = NUM2LONG(bit);
|
582
|
+
struct bitarray *ba;
|
583
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
519
584
|
|
520
|
-
|
521
|
-
|
522
|
-
} else {
|
523
|
-
rb_raise(rb_eIndexError, "index %ld out of bit array", index);
|
524
|
-
}
|
585
|
+
toggle_bit(ba, NUM2LONG(index));
|
586
|
+
return self;
|
525
587
|
}
|
526
588
|
|
527
589
|
|
@@ -533,82 +595,19 @@ rb_bitarray_toggle_bit(VALUE self, VALUE bit)
|
|
533
595
|
static VALUE
|
534
596
|
rb_bitarray_toggle_all_bits(VALUE self)
|
535
597
|
{
|
536
|
-
struct
|
537
|
-
Data_Get_Struct(self, struct
|
538
|
-
|
539
|
-
if(toggle_all_bits(ba)) {
|
540
|
-
return self;
|
541
|
-
} else {
|
542
|
-
rb_bug("BitArray#clear_all_bits failed. This should not occur.");
|
543
|
-
}
|
544
|
-
}
|
598
|
+
struct bitarray *ba;
|
599
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
545
600
|
|
546
|
-
|
547
|
-
|
548
|
-
rb_bitarray_get_bit(VALUE self, long index)
|
549
|
-
{
|
550
|
-
struct bit_array *ba;
|
551
|
-
Data_Get_Struct(self, struct bit_array, ba);
|
552
|
-
|
553
|
-
int bit_value = get_bit(ba, index);
|
554
|
-
|
555
|
-
if (bit_value >= 0) {
|
556
|
-
return INT2NUM(bit_value);
|
557
|
-
} else {
|
558
|
-
rb_raise(rb_eIndexError, "index %ld out of bit array", index);
|
559
|
-
}
|
601
|
+
toggle_all_bits(ba);
|
602
|
+
return self;
|
560
603
|
}
|
561
604
|
|
562
605
|
|
563
|
-
/*
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
struct bit_array *x_ba;
|
569
|
-
Data_Get_Struct(x, struct bit_array, x_ba);
|
570
|
-
|
571
|
-
/* Quick exit - a negative length, or a beginning past the end of the
|
572
|
-
* array returns nil.
|
573
|
-
*/
|
574
|
-
if (beg < 0) {
|
575
|
-
beg += x_ba->bits;
|
576
|
-
}
|
577
|
-
if (len < 0 || beg > x_ba->bits) {
|
578
|
-
return Qnil;
|
579
|
-
}
|
580
|
-
|
581
|
-
/* Make sure that we don't try getting more bits than x has. We handle this
|
582
|
-
* the same way as Array; if beg+len is past the end of x, shorten len.
|
583
|
-
*/
|
584
|
-
if (x_ba->bits < len || x_ba->bits < (beg + len)) {
|
585
|
-
len = x_ba->bits - beg;
|
586
|
-
}
|
587
|
-
|
588
|
-
/* Create a new BitArray of the appropriate size. */
|
589
|
-
VALUE y;
|
590
|
-
y = rb_bitarray_alloc(rb_bitarray_class);
|
591
|
-
rb_bitarray_initialize(y, LONG2NUM(len));
|
592
|
-
/* If our length is 0, we can just return now. */
|
593
|
-
if (len == 0) {
|
594
|
-
return y;
|
595
|
-
}
|
596
|
-
struct bit_array *y_ba;
|
597
|
-
Data_Get_Struct(y, struct bit_array, y_ba);
|
598
|
-
|
599
|
-
/* For each set bit in x[beg..len], set the corresponding bit in y. */
|
600
|
-
long x_index, y_index;
|
601
|
-
for (x_index = beg, y_index = 0;
|
602
|
-
x_index < beg + len;
|
603
|
-
x_index++, y_index++)
|
604
|
-
{
|
605
|
-
if (get_bit(x_ba, x_index) == 1) {
|
606
|
-
set_bit(y_ba, y_index);
|
607
|
-
}
|
608
|
-
}
|
609
|
-
|
610
|
-
return y;
|
611
|
-
}
|
606
|
+
/* Bit-reference helper-function prototypes. These are defined after
|
607
|
+
* rb_bitarray_bitref.
|
608
|
+
*/
|
609
|
+
static inline VALUE rb_bitarray_get_bit(VALUE self, long index);
|
610
|
+
static VALUE rb_bitarray_subseq(VALUE self, long beg, long len);
|
612
611
|
|
613
612
|
|
614
613
|
/* call-seq:
|
@@ -622,7 +621,6 @@ rb_bitarray_subseq(VALUE x, long beg, long len)
|
|
622
621
|
* _index_ is greater than the capacity of _bitarray_, an +IndexError+ is
|
623
622
|
* raised.
|
624
623
|
*/
|
625
|
-
|
626
624
|
static VALUE
|
627
625
|
rb_bitarray_bitref(int argc, VALUE *argv, VALUE self)
|
628
626
|
{
|
@@ -650,8 +648,8 @@ rb_bitarray_bitref(int argc, VALUE *argv, VALUE self)
|
|
650
648
|
return rb_bitarray_get_bit(self, FIX2LONG(arg));
|
651
649
|
}
|
652
650
|
|
653
|
-
struct
|
654
|
-
Data_Get_Struct(self, struct
|
651
|
+
struct bitarray *ba;
|
652
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
655
653
|
/* Next we see if arg is a range. rb_range_beg_len is defined in range.c
|
656
654
|
* If arg is not a range, it returns Qfalse. If arg is a range, but it
|
657
655
|
* refers to invalid indices, it returns Qnil. Otherwise, it sets beg and
|
@@ -671,6 +669,67 @@ rb_bitarray_bitref(int argc, VALUE *argv, VALUE self)
|
|
671
669
|
}
|
672
670
|
|
673
671
|
|
672
|
+
/* Return an individual bit. */
|
673
|
+
static inline VALUE
|
674
|
+
rb_bitarray_get_bit(VALUE self, long index)
|
675
|
+
{
|
676
|
+
struct bitarray *ba;
|
677
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
678
|
+
|
679
|
+
return INT2NUM(get_bit(ba, index));
|
680
|
+
}
|
681
|
+
|
682
|
+
|
683
|
+
/* Create a new BitArray from a subsequence of x. */
|
684
|
+
static VALUE
|
685
|
+
rb_bitarray_subseq(VALUE x, long beg, long len)
|
686
|
+
{
|
687
|
+
|
688
|
+
struct bitarray *x_ba;
|
689
|
+
Data_Get_Struct(x, struct bitarray, x_ba);
|
690
|
+
|
691
|
+
/* Quick exit - a negative length, or a beginning past the end of the
|
692
|
+
* array returns nil.
|
693
|
+
*/
|
694
|
+
if (beg < 0) {
|
695
|
+
beg += bitarray_size(x_ba);
|
696
|
+
}
|
697
|
+
if (len < 0 || beg > bitarray_size(x_ba)) {
|
698
|
+
return Qnil;
|
699
|
+
}
|
700
|
+
|
701
|
+
/* Make sure that we don't try getting more bits than x has. We handle this
|
702
|
+
* the same way as Array; if beg+len is past the end of x, shorten len.
|
703
|
+
*/
|
704
|
+
if (bitarray_size(x_ba) < len || bitarray_size(x_ba) < (beg + len)) {
|
705
|
+
len = bitarray_size(x_ba) - beg;
|
706
|
+
}
|
707
|
+
|
708
|
+
/* Create a new BitArray of the appropriate size. */
|
709
|
+
VALUE y = rb_bitarray_alloc(rb_bitarray_class);
|
710
|
+
rb_bitarray_initialize(y, LONG2NUM(len));
|
711
|
+
/* If our length is 0, we can just return now. */
|
712
|
+
if (len == 0) {
|
713
|
+
return y;
|
714
|
+
}
|
715
|
+
struct bitarray *y_ba;
|
716
|
+
Data_Get_Struct(y, struct bitarray, y_ba);
|
717
|
+
|
718
|
+
/* For each set bit in x[beg..len], set the corresponding bit in y. */
|
719
|
+
long x_index, y_index;
|
720
|
+
for (x_index = beg, y_index = 0;
|
721
|
+
x_index < beg + len;
|
722
|
+
x_index++, y_index++)
|
723
|
+
{
|
724
|
+
if (get_bit(x_ba, x_index) == 1) {
|
725
|
+
set_bit(y_ba, y_index);
|
726
|
+
}
|
727
|
+
}
|
728
|
+
|
729
|
+
return y;
|
730
|
+
}
|
731
|
+
|
732
|
+
|
674
733
|
/* call-seq:
|
675
734
|
* bitarray[index] = value -> value
|
676
735
|
*
|
@@ -682,22 +741,13 @@ rb_bitarray_bitref(int argc, VALUE *argv, VALUE self)
|
|
682
741
|
* raised.
|
683
742
|
*/
|
684
743
|
static VALUE
|
685
|
-
rb_bitarray_assign_bit(VALUE self, VALUE
|
744
|
+
rb_bitarray_assign_bit(VALUE self, VALUE index, VALUE value)
|
686
745
|
{
|
687
|
-
struct
|
688
|
-
Data_Get_Struct(self, struct
|
689
|
-
|
690
|
-
long index = NUM2LONG(bit);
|
691
|
-
int bit_value = NUM2INT(value);
|
746
|
+
struct bitarray *ba;
|
747
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
692
748
|
|
693
|
-
|
694
|
-
|
695
|
-
return value;
|
696
|
-
} else if (result == 0) {
|
697
|
-
rb_raise(rb_eIndexError, "index %ld out of bit array", index);
|
698
|
-
} else {
|
699
|
-
rb_raise(rb_eRuntimeError, "bit value %d out of range", bit_value);
|
700
|
-
}
|
749
|
+
assign_bit(ba, NUM2LONG(index), NUM2INT(value));
|
750
|
+
return value;
|
701
751
|
}
|
702
752
|
|
703
753
|
|
@@ -710,17 +760,17 @@ rb_bitarray_assign_bit(VALUE self, VALUE bit, VALUE value)
|
|
710
760
|
static VALUE
|
711
761
|
rb_bitarray_inspect(VALUE self)
|
712
762
|
{
|
713
|
-
struct
|
714
|
-
Data_Get_Struct(self, struct
|
763
|
+
struct bitarray *ba;
|
764
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
715
765
|
|
716
|
-
long cstr_size = ba
|
766
|
+
long cstr_size = bitarray_size(ba) + 1;
|
717
767
|
char cstr[cstr_size];
|
718
768
|
|
719
769
|
long i;
|
720
|
-
for (i = 0; i < ba
|
770
|
+
for (i = 0; i < bitarray_size(ba); i++) {
|
721
771
|
cstr[i] = get_bit(ba, i) + '0';
|
722
772
|
}
|
723
|
-
cstr[
|
773
|
+
cstr[cstr_size - 1] = '\0';
|
724
774
|
|
725
775
|
VALUE str = rb_str_new2(cstr);
|
726
776
|
return str;
|
@@ -735,10 +785,10 @@ rb_bitarray_inspect(VALUE self)
|
|
735
785
|
static VALUE
|
736
786
|
rb_bitarray_to_a(VALUE self)
|
737
787
|
{
|
738
|
-
struct
|
739
|
-
Data_Get_Struct(self, struct
|
788
|
+
struct bitarray *ba;
|
789
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
740
790
|
|
741
|
-
long array_size = ba
|
791
|
+
long array_size = bitarray_size(ba);
|
742
792
|
VALUE c_array[array_size];
|
743
793
|
|
744
794
|
int i;
|
@@ -766,13 +816,13 @@ rb_bitarray_to_a(VALUE self)
|
|
766
816
|
static VALUE
|
767
817
|
rb_bitarray_each(VALUE self)
|
768
818
|
{
|
769
|
-
struct
|
770
|
-
Data_Get_Struct(self, struct
|
819
|
+
struct bitarray *ba;
|
820
|
+
Data_Get_Struct(self, struct bitarray, ba);
|
771
821
|
|
772
822
|
long i;
|
773
823
|
|
774
824
|
RETURN_ENUMERATOR(self, 0, 0);
|
775
|
-
for (i = 0; i < ba
|
825
|
+
for (i = 0; i < bitarray_size(ba); i++) {
|
776
826
|
int bit_value = get_bit(ba, i);
|
777
827
|
rb_yield(INT2NUM(bit_value));
|
778
828
|
}
|
data/test/bm.rb
CHANGED
@@ -1,61 +1,37 @@
|
|
1
|
-
require 'bitfield'
|
2
1
|
require 'bitarray'
|
3
2
|
require 'benchmark'
|
4
3
|
|
5
4
|
Benchmark.bm(28) { |bm|
|
6
|
-
puts "---------------------------- Object instantiation (10,000 iterations)"
|
7
|
-
bm.report("BitField initialize") { 10000.times { BitField.new(256) } }
|
8
5
|
bm.report("BitArray initialize") { 10000.times { BitArray.new(256) } }
|
9
6
|
s = "0"*256
|
10
7
|
bm.report("BitArray init from string") { 10000.times { BitArray.new(s) } }
|
11
8
|
a = [0]*256
|
12
9
|
bm.report("BitArray init from array") { 10000.times { BitArray.new(a) } }
|
13
10
|
|
14
|
-
bf = BitField.new(256)
|
15
11
|
ba = BitArray.new(256)
|
16
12
|
|
17
|
-
puts "---------------------------- Element Reading (10,000 iterations)"
|
18
|
-
bm.report("BitField []") { 10000.times { bf[rand(256)] } }
|
19
13
|
bm.report("BitArray []") { 10000.times { ba[rand(256)] } }
|
20
|
-
|
21
|
-
puts "---------------------------- Element Writing (10,000 iterations)"
|
22
|
-
bm.report("BitField []=") { 10000.times { bf[rand(256)] = [0,1][rand(2)] } }
|
23
14
|
bm.report("BitArray []=") { 10000.times { ba[rand(256)] = [0,1][rand(2)] } }
|
24
|
-
|
25
|
-
puts "---------------------------- Element Enumeration (10,000 iterations)"
|
26
|
-
bm.report("BitField each") { 10000.times { bf.each {|b| b } } }
|
27
15
|
bm.report("BitArray each") { 10000.times { ba.each {|b| b } } }
|
28
|
-
|
29
|
-
puts "---------------------------- To String (10,000 iterations)"
|
30
|
-
bm.report("BitField to_s") { 10000.times { bf.to_s } }
|
31
16
|
bm.report("BitArray to_s") { 10000.times { ba.to_s } }
|
32
|
-
|
33
|
-
puts "---------------------------- To Array (10,000 iterations)"
|
34
|
-
bm.report("BitField to_a") { 10000.times { bf.to_a } }
|
35
17
|
bm.report("BitArray to_a") { 10000.times { ba.to_a } }
|
36
|
-
|
37
|
-
puts "---------------------------- Total Set (100,000 iterations)"
|
38
|
-
bf = BitField.new(256)
|
18
|
+
|
39
19
|
ba = BitArray.new(256)
|
40
|
-
bm.report("
|
41
|
-
bm.report("BitArray total_set (none)") { 100000.times { ba.total_set } }
|
42
|
-
bf.each {|b| b = 1}
|
20
|
+
bm.report("BitArray total_set (none)") { 10000.times { ba.total_set } }
|
43
21
|
ba.set_all_bits
|
44
|
-
bm.report("
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
bm.report("BitArray
|
49
|
-
bm.report("BitArray
|
50
|
-
bm.report("BitArray
|
51
|
-
bm.report("BitArray
|
52
|
-
bm.report("BitArray
|
53
|
-
bm.report("BitArray slice (beg,len)") { 100000.times { ba[17, 230] } }
|
54
|
-
bm.report("BitArray slice (range)") { 100000.times { ba[17..247] } }
|
22
|
+
bm.report("BitArray total_set (all)") { 10000.times { ba.total_set } }
|
23
|
+
|
24
|
+
bm.report("BitArray set_all_bits") { 10000.times { ba.set_all_bits} }
|
25
|
+
bm.report("BitArray clear_all_bits") { 10000.times { ba.clear_all_bits } }
|
26
|
+
bm.report("BitArray toggle_bit") { 10000.times { ba.toggle_bit(1) } }
|
27
|
+
bm.report("BitArray toggle_all_bits") { 10000.times { ba.toggle_all_bits } }
|
28
|
+
bm.report("BitArray clone") { 10000.times { ba.clone } }
|
29
|
+
bm.report("BitArray slice (beg,len)") { 10000.times { ba[17, 230] } }
|
30
|
+
bm.report("BitArray slice (range)") { 10000.times { ba[17..247] } }
|
55
31
|
ba.set_all_bits
|
56
|
-
bm.report("BitArray + (256, all set)") {
|
32
|
+
bm.report("BitArray + (256, all set)") { 10000.times { ba + ba } }
|
57
33
|
ba2 = BitArray.new(240)
|
58
34
|
ba2.set_all_bits
|
59
|
-
bm.report("BitArray + (240, all set)") {
|
35
|
+
bm.report("BitArray + (240, all set)") { 10000.times { ba2 + ba2 } }
|
60
36
|
}
|
61
37
|
|
data/test/test.rb
CHANGED
@@ -33,14 +33,16 @@ class TestLibraryFileName < Test::Unit::TestCase
|
|
33
33
|
|
34
34
|
def test_multiple_setting
|
35
35
|
1.upto(999) do |pos|
|
36
|
-
|
36
|
+
@public_ba[pos] = 1
|
37
|
+
@public_ba[pos] = 1
|
37
38
|
assert_equal 1, @public_ba[pos]
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
41
42
|
def test_multiple_unsetting
|
42
43
|
1.upto(999) do |pos|
|
43
|
-
|
44
|
+
@public_ba[pos] = 0
|
45
|
+
@public_ba[pos] = 0
|
44
46
|
assert_equal 0, @public_ba[pos]
|
45
47
|
end
|
46
48
|
end
|
@@ -135,6 +137,13 @@ class TestLibraryFileName < Test::Unit::TestCase
|
|
135
137
|
assert_equal "111111100000000000000000000000000000000", ba3.to_s
|
136
138
|
end
|
137
139
|
|
140
|
+
def test_concatenation3
|
141
|
+
ba1 = BitArray.new(0)
|
142
|
+
ba2 = BitArray.new(0)
|
143
|
+
ba3 = ba1 + ba2
|
144
|
+
assert_equal "", ba3.to_s
|
145
|
+
end
|
146
|
+
|
138
147
|
def test_to_a
|
139
148
|
ba = BitArray.new(16)
|
140
149
|
ba[1] = 1
|
@@ -149,6 +158,8 @@ class TestLibraryFileName < Test::Unit::TestCase
|
|
149
158
|
assert_equal "00011", ba.to_s
|
150
159
|
ba = BitArray.new("abcd0101")
|
151
160
|
assert_equal "", ba.to_s
|
161
|
+
ba = BitArray.new("")
|
162
|
+
assert_equal "", ba.to_s
|
152
163
|
end
|
153
164
|
|
154
165
|
|
@@ -159,6 +170,8 @@ class TestLibraryFileName < Test::Unit::TestCase
|
|
159
170
|
assert_equal "11001", ba.to_s
|
160
171
|
ba = BitArray.new([nil, nil, :a, nil, [:b, :c]])
|
161
172
|
assert_equal "00101", ba.to_s
|
173
|
+
ba = BitArray.new([])
|
174
|
+
assert_equal "", ba.to_s
|
162
175
|
end
|
163
176
|
end
|
164
177
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ingramj-bitarray
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James E. Ingram
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-02 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -34,7 +34,6 @@ files:
|
|
34
34
|
- examples/boolnet.rb
|
35
35
|
- ext/bitarray.c
|
36
36
|
- ext/extconf.rb
|
37
|
-
- test/bitfield.rb
|
38
37
|
- test/bm.rb
|
39
38
|
- test/test.rb
|
40
39
|
has_rdoc: true
|
@@ -68,7 +67,6 @@ signing_key:
|
|
68
67
|
specification_version: 2
|
69
68
|
summary: A bitarray class for Ruby, implemented as a C extension.
|
70
69
|
test_files:
|
71
|
-
- test/bitfield.rb
|
72
70
|
- test/test.rb
|
73
71
|
- test/bm.rb
|
74
72
|
- examples/bloomfilter.rb
|
data/test/bitfield.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
# NAME: BitField
|
2
|
-
# AUTHOR: Peter Cooper
|
3
|
-
# LICENSE: MIT ( http://www.opensource.org/licenses/mit-license.php )
|
4
|
-
# COPYRIGHT: (c) 2007 Peter Cooper (http://www.petercooper.co.uk/)
|
5
|
-
# VERSION: v4
|
6
|
-
# HISTORY: v4 (fixed bug where setting 0 bits to 0 caused a set to 1)
|
7
|
-
# v3 (supports dynamic bitwidths for array elements.. now doing 32 bit widths default)
|
8
|
-
# v2 (now uses 1 << y, rather than 2 ** y .. it's 21.8 times faster!)
|
9
|
-
# v1 (first release)
|
10
|
-
#
|
11
|
-
# DESCRIPTION: Basic, pure Ruby bit field. Pretty fast (for what it is) and memory efficient.
|
12
|
-
# I've written a pretty intensive test suite for it and it passes great.
|
13
|
-
# Works well for Bloom filters (the reason I wrote it).
|
14
|
-
#
|
15
|
-
# Create a bit field 1000 bits wide
|
16
|
-
# bf = BitField.new(1000)
|
17
|
-
#
|
18
|
-
# Setting and reading bits
|
19
|
-
# bf[100] = 1
|
20
|
-
# bf[100] .. => 1
|
21
|
-
# bf[100] = 0
|
22
|
-
#
|
23
|
-
# More
|
24
|
-
# bf.to_s = "10101000101010101" (example)
|
25
|
-
# bf.total_set .. => 10 (example - 10 bits are set to "1")
|
26
|
-
|
27
|
-
class BitField
|
28
|
-
attr_reader :size
|
29
|
-
include Enumerable
|
30
|
-
|
31
|
-
ELEMENT_WIDTH = 32
|
32
|
-
|
33
|
-
def initialize(size)
|
34
|
-
@size = size
|
35
|
-
@field = Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Set a bit (1/0)
|
39
|
-
def []=(position, value)
|
40
|
-
if value == 1
|
41
|
-
@field[position / ELEMENT_WIDTH] |= 1 << (position % ELEMENT_WIDTH)
|
42
|
-
elsif (@field[position / ELEMENT_WIDTH]) & (1 << (position % ELEMENT_WIDTH)) != 0
|
43
|
-
@field[position / ELEMENT_WIDTH] ^= 1 << (position % ELEMENT_WIDTH)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Read a bit (1/0)
|
48
|
-
def [](position)
|
49
|
-
@field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
|
50
|
-
end
|
51
|
-
|
52
|
-
# Iterate over each bit
|
53
|
-
def each(&block)
|
54
|
-
@size.times { |position| yield self[position] }
|
55
|
-
end
|
56
|
-
|
57
|
-
# Returns the field as a string like "0101010100111100," etc.
|
58
|
-
def to_s
|
59
|
-
inject("") { |a, b| a + b.to_s }
|
60
|
-
end
|
61
|
-
|
62
|
-
# Returns the total number of bits that are set
|
63
|
-
# (The technique used here is about 6 times faster than using each or inject direct on the bitfield)
|
64
|
-
def total_set
|
65
|
-
@field.inject(0) { |a, byte| a += byte & 1 and byte >>= 1 until byte == 0; a }
|
66
|
-
end
|
67
|
-
end
|