ingramj-bitarray 0.5.0 → 0.5.1
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.
- 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
|