bitarray 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -2
- data/Rakefile +6 -0
- data/lib/bitarray-array.rb +1 -1
- data/lib/bitarray.rb +15 -6
- data/test/test_bitarray.rb +41 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6fcf6acdc1a14446a50e3cca4c8f96da1f36ab10
|
4
|
+
data.tar.gz: dc2cc9af844024134c930ab9678be08731458a7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ed10001a59707f9837e62727cf3fbd338c7d5c14af834862d04338800a69639a178a824d0ab629883451f89cdda006d27d9c8116b5751fc351dd17c33878d6a
|
7
|
+
data.tar.gz: 446232b243b040be2e7627b042ff5dc03db7c8ebd13ce4060ac2400299954d940c9aa97349a906a73170f5a1f401e3f7b5505d0d1f680c71781f114f1fa5d94e
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# BitArray: A simple bit-array/bitfield library in pure Ruby
|
2
2
|
|
3
|
-
|
3
|
+
A simple, pure-Ruby 'bit field' object. Works well for Bloom filters (the use case for which I originally wrote it).
|
4
4
|
|
5
5
|
Originally written in 2007 and left without significant update until 2017, it has now been updated to work within a typical, modern Ruby environment while maintaining the same API.
|
6
6
|
|
@@ -47,7 +47,23 @@ ba.total_set
|
|
47
47
|
#=> 7
|
48
48
|
```
|
49
49
|
|
50
|
+
Initializing `BitArray` with a custom field value:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
ba = BitArray.new(16, ["0000111111110000"].pack('B*'))
|
54
|
+
ba.to_s # "1111000000001111"
|
55
|
+
```
|
56
|
+
|
57
|
+
`BitArray` by default stores the bits in reverse order for each byte. If for example, you are initializing `BitArray` with Redis raw value manipulated with `setbit` / `getbit` operations, you will need to tell `BitArray` to not reverse the bits in each byte using the `reverse_byte: false` option:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
ba = BitArray.new(16, ["0000111111110000"].pack('B*'), reverse_byte: false)
|
61
|
+
ba.to_s # "0000111111110000"
|
62
|
+
```
|
63
|
+
|
64
|
+
|
50
65
|
## History
|
66
|
+
- 1.2 in 2018 (Added option to skip reverse the bits for each byte by @dalibor)
|
51
67
|
- 1.1 in 2018 (fixed a significant bug)
|
52
68
|
- 1.0 in 2017 (updated for modern Ruby, more efficient storage, and 10th birthday)
|
53
69
|
- 0.0.1 in 2012 (original v5 released on GitHub)
|
@@ -61,7 +77,7 @@ ba.total_set
|
|
61
77
|
|
62
78
|
Thanks to Michael Slade for encouraging me to update this library on its 10th birthday and for suggesting finally using String's getbyte and setbyte methods now that we're all on 1.9+ compatible implementations.
|
63
79
|
|
64
|
-
Further thanks to @tdeo, @JoshuaSP, and @m1lt0n for pull requests.
|
80
|
+
Further thanks to @tdeo, @JoshuaSP, @dalibor and @m1lt0n for pull requests.
|
65
81
|
|
66
82
|
## License
|
67
83
|
|
data/Rakefile
CHANGED
data/lib/bitarray-array.rb
CHANGED
data/lib/bitarray.rb
CHANGED
@@ -3,25 +3,26 @@ class BitArray
|
|
3
3
|
attr_reader :field
|
4
4
|
include Enumerable
|
5
5
|
|
6
|
-
VERSION = "1.
|
6
|
+
VERSION = "1.2.0"
|
7
7
|
|
8
|
-
def initialize(size, field = nil)
|
8
|
+
def initialize(size, field = nil, reverse_byte: true)
|
9
9
|
@size = size
|
10
10
|
@field = field || "\0" * (size / 8 + 1)
|
11
|
+
@reverse_byte = reverse_byte
|
11
12
|
end
|
12
13
|
|
13
14
|
# Set a bit (1/0)
|
14
15
|
def []=(position, value)
|
15
16
|
if value == 1
|
16
|
-
@field.setbyte(position >> 3, @field.getbyte(position >> 3) | (1 << (position % 8)))
|
17
|
+
@field.setbyte(position >> 3, @field.getbyte(position >> 3) | (1 << (byte_position(position) % 8)))
|
17
18
|
else
|
18
|
-
@field.setbyte(position >> 3, @field.getbyte(position >> 3) & ~(1 << (position % 8)))
|
19
|
+
@field.setbyte(position >> 3, @field.getbyte(position >> 3) & ~(1 << (byte_position(position) % 8)))
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
23
|
# Read a bit (1/0)
|
23
24
|
def [](position)
|
24
|
-
(@field.getbyte(position >> 3) & (1 << (position % 8))) > 0 ? 1 : 0
|
25
|
+
(@field.getbyte(position >> 3) & (1 << (byte_position(position) % 8))) > 0 ? 1 : 0
|
25
26
|
end
|
26
27
|
|
27
28
|
# Iterate over each bit
|
@@ -31,7 +32,11 @@ class BitArray
|
|
31
32
|
|
32
33
|
# Returns the field as a string like "0101010100111100," etc.
|
33
34
|
def to_s
|
34
|
-
|
35
|
+
if @reverse_byte
|
36
|
+
@field.bytes.collect { |ea| ("%08b" % ea).reverse }.join[0, @size]
|
37
|
+
else
|
38
|
+
@field.bytes.collect { |ea| ("%08b" % ea) }.join[0, @size]
|
39
|
+
end
|
35
40
|
end
|
36
41
|
|
37
42
|
# Returns the total number of bits that are set
|
@@ -39,4 +44,8 @@ class BitArray
|
|
39
44
|
def total_set
|
40
45
|
@field.bytes.inject(0) { |a, byte| a += byte & 1 and byte >>= 1 until byte == 0; a }
|
41
46
|
end
|
47
|
+
|
48
|
+
def byte_position(position)
|
49
|
+
@reverse_byte ? position : 7 - position
|
50
|
+
end
|
42
51
|
end
|
data/test/test_bitarray.rb
CHANGED
@@ -52,10 +52,26 @@ class TestBitArray < Minitest::Test
|
|
52
52
|
|
53
53
|
def test_to_s
|
54
54
|
ba = BitArray.new(35)
|
55
|
-
[1, 5, 6, 7, 10, 16, 33].each{|i|ba[i] = 1}
|
55
|
+
[1, 5, 6, 7, 10, 16, 33].each { |i| ba[i] = 1}
|
56
56
|
assert_equal "01000111001000001000000000000000010", ba.to_s
|
57
57
|
end
|
58
58
|
|
59
|
+
def test_field
|
60
|
+
ba = BitArray.new(35)
|
61
|
+
[1, 5, 6, 7, 10, 16, 33].each { |i| ba[i] = 1}
|
62
|
+
assert_equal "1110001000000100000000010000000000000010", ba.field.unpack('B*')[0]
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_initialize_with_field
|
66
|
+
ba = BitArray.new(15, ["0100011100100001"].pack('B*'))
|
67
|
+
|
68
|
+
assert_equal [0, 1, 2, 6, 8, 13], 0.upto(15).select { |i| ba[i] == 1 }
|
69
|
+
|
70
|
+
ba[2] = 1
|
71
|
+
ba[12] = 1
|
72
|
+
assert_equal [0, 1, 2, 6, 8, 12, 13], 0.upto(15).select { |i| ba[i] == 1 }
|
73
|
+
end
|
74
|
+
|
59
75
|
def test_total_set
|
60
76
|
ba = BitArray.new(10)
|
61
77
|
ba[1] = 1
|
@@ -64,3 +80,27 @@ class TestBitArray < Minitest::Test
|
|
64
80
|
assert_equal 3, ba.total_set
|
65
81
|
end
|
66
82
|
end
|
83
|
+
|
84
|
+
class TestBitArrayWhenNonReversedByte < Minitest::Test
|
85
|
+
def test_to_s
|
86
|
+
ba = BitArray.new(35, nil, reverse_byte: true)
|
87
|
+
[1, 5, 6, 7, 10, 16, 33].each { |i| ba[i] = 1}
|
88
|
+
assert_equal "01000111001000001000000000000000010", ba.to_s
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_field
|
92
|
+
ba = BitArray.new(35, nil, reverse_byte: false)
|
93
|
+
[1, 5, 6, 7, 10, 16, 33].each { |i| ba[i] = 1}
|
94
|
+
assert_equal "0100011100100000100000000000000001000000", ba.field.unpack('B*')[0]
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_initialize_with_field
|
98
|
+
ba = BitArray.new(15, ["0100011100100001"].pack('B*'), reverse_byte: false)
|
99
|
+
|
100
|
+
assert_equal [1, 5, 6, 7, 10, 15], 0.upto(15).select { |i| ba[i] == 1 }
|
101
|
+
|
102
|
+
ba[2] = 1
|
103
|
+
ba[12] = 1
|
104
|
+
assert_equal [1, 2, 5, 6, 7, 10, 12, 15], 0.upto(15).select { |i| ba[i] == 1 }
|
105
|
+
end
|
106
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitarray
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Cooper
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|