bitary 0.1.0 → 0.1.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/README.md +7 -9
- data/lib/bitary/handler/append.rb +20 -0
- data/lib/bitary/handler/get.rb +22 -0
- data/lib/bitary/handler/set.rb +22 -0
- data/lib/bitary/handler/unset.rb +22 -0
- data/lib/bitary/handler.rb +19 -0
- data/lib/bitary/size.rb +10 -0
- data/lib/bitary/version.rb +2 -2
- data/lib/bitary.rb +121 -128
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80cd57b662219349dc57edd47612599f95f5aeca086dbec30af067adb10fe587
|
4
|
+
data.tar.gz: dc630c61a13c74a20e3472a90f244dd995f4c7196fb6146ca15973efe02e310d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9adf435f35e798c71a3a81213f408da0c178b2d3137ecae3619c84e3c95d564e060a4985d24a4746b93a0fb8e2d73fc4a209a38908c7dad25d87dfd728e575da
|
7
|
+
data.tar.gz: a6f136e8e5f140ad9455c14b13d94232d40bfc37e09e62b6827857888d03dacbc53fb027a9da1901dfa2d2f966144680a3e2d0a5dd57c4af563d4bd09af99326
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
-
## [
|
1
|
+
## [0.1.1] - 2024-03-26
|
2
|
+
|
3
|
+
- Change root namespace to a class, instead of a module
|
2
4
|
|
3
5
|
## [0.1.0] - 2024-03-26
|
4
6
|
|
5
7
|
- Initial release
|
8
|
+
- Basic implementation to set/unset/get bits from the bit array
|
9
|
+
- Ability to traverse each byte of the structure
|
10
|
+
- Increase/decrease the number of bits used internally per element
|
data/README.md
CHANGED
@@ -24,10 +24,8 @@ Documentation still needs to be written, but here is a breakdown
|
|
24
24
|
of the main capabilities brought by the current bit array implementation:
|
25
25
|
|
26
26
|
```ruby
|
27
|
-
|
28
|
-
|
29
|
-
bit_array_sz = BitArray.new(128) # give an explicit size. Defaults to 64 bits used per item
|
30
|
-
bit_array_ar = BitArray.new(
|
27
|
+
bit_array_sz = Bitary.new(128) # give an explicit size. Defaults to 64 bits used per item
|
28
|
+
bit_array_ar = Bitary.new(
|
31
29
|
[255, 10, 20],
|
32
30
|
bits_per_item: 8
|
33
31
|
) # create based on some integer array
|
@@ -53,18 +51,18 @@ bit_array_sz.each_byte do |byte|
|
|
53
51
|
end
|
54
52
|
|
55
53
|
# convert
|
56
|
-
bit_array_ar.to_a # [
|
57
|
-
bit_array_ar.to_s # "
|
54
|
+
bit_array_ar.to_a # [127, 10, 20]
|
55
|
+
bit_array_ar.to_s # "01111111 00001010 00010100"
|
58
56
|
|
59
57
|
# increase/decrease bits used per item
|
60
58
|
bit_array_ar.bits_per_item = 64
|
61
|
-
bit_array_ar.to_a # [
|
62
|
-
bit_array_ar.to_s # "
|
59
|
+
bit_array_ar.to_a # [8_325_652]
|
60
|
+
bit_array_ar.to_s # "0000000000000000000000000000000000000000011111110000101000010100"
|
63
61
|
|
64
62
|
bit_array_sz.bits_per_item # 64
|
65
63
|
bit_array_sz.to_a # [1_099_511_627_776, 0]
|
66
64
|
bit_array_sz.bits_per_item = 32
|
67
|
-
bit_array_sz.to_a # [256, 0, 0,
|
65
|
+
bit_array_sz.to_a # [256, 0, 0, 0]
|
68
66
|
```
|
69
67
|
|
70
68
|
## Development
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Bitary
|
4
|
+
class Handler
|
5
|
+
class Append < Bitary::Handler
|
6
|
+
def execute(**kwargs)
|
7
|
+
raise ArgumentError unless kwargs.all? do |key, _value|
|
8
|
+
%i[offset value].include?(key)
|
9
|
+
end
|
10
|
+
|
11
|
+
offset = kwargs[:offset] or raise KeyError
|
12
|
+
value = kwargs[:value] or raise KeyError
|
13
|
+
raise ArgumentError unless offset.is_a?(Integer)
|
14
|
+
raise ArgumentError unless value.is_a?(Integer)
|
15
|
+
|
16
|
+
(@value << offset) | value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Bitary
|
4
|
+
class Handler
|
5
|
+
class Get < Bitary::Handler
|
6
|
+
def execute(**kwargs)
|
7
|
+
raise ArgumentError unless kwargs.all? do |key, _value|
|
8
|
+
%i[index size].include?(key)
|
9
|
+
end
|
10
|
+
|
11
|
+
index = kwargs[:index] or raise KeyError
|
12
|
+
size = kwargs[:size] or raise KeyError
|
13
|
+
raise ArgumentError unless index.is_a?(Integer)
|
14
|
+
raise ArgumentError unless size.is_a?(Integer)
|
15
|
+
|
16
|
+
raise IndexError if index.negative? || index >= size
|
17
|
+
|
18
|
+
(@value >> (size - index - 1)) & 0x1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Bitary
|
4
|
+
class Handler
|
5
|
+
class Set < Bitary::Handler
|
6
|
+
def execute(**kwargs)
|
7
|
+
raise ArgumentError unless kwargs.all? do |key, _value|
|
8
|
+
%i[index size].include?(key)
|
9
|
+
end
|
10
|
+
|
11
|
+
index = kwargs[:index] or raise KeyError
|
12
|
+
size = kwargs[:size] or raise KeyError
|
13
|
+
raise ArgumentError unless index.is_a?(Integer)
|
14
|
+
raise ArgumentError unless size.is_a?(Integer)
|
15
|
+
|
16
|
+
raise IndexError if index.negative? || index >= size
|
17
|
+
|
18
|
+
@value | (2**(size - index - 1))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Bitary
|
4
|
+
class Handler
|
5
|
+
class Unset < Bitary::Handler
|
6
|
+
def execute(**kwargs)
|
7
|
+
raise ArgumentError unless kwargs.all? do |key, _value|
|
8
|
+
%i[index size].include?(key)
|
9
|
+
end
|
10
|
+
|
11
|
+
index = kwargs[:index] or raise KeyError
|
12
|
+
size = kwargs[:size] or raise KeyError
|
13
|
+
raise ArgumentError unless index.is_a?(Integer)
|
14
|
+
raise ArgumentError unless size.is_a?(Integer)
|
15
|
+
|
16
|
+
raise IndexError if index.negative? || index >= size
|
17
|
+
|
18
|
+
@value & (((2**size) - 1) - (2**(size - index - 1)))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'handler/set'
|
4
|
+
|
5
|
+
class Bitary
|
6
|
+
class Handler
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
def initialize(value)
|
10
|
+
raise ArgumentError unless value.is_a?(Integer)
|
11
|
+
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(**kwargs)
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/bitary/size.rb
ADDED
data/lib/bitary/version.rb
CHANGED
data/lib/bitary.rb
CHANGED
@@ -1,171 +1,164 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'bitary/size'
|
3
4
|
require_relative 'bitary/version'
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
attr_reader :size, :bits_per_item
|
6
|
+
class Bitary
|
7
|
+
include Size
|
8
8
|
|
9
|
-
|
10
|
-
raise ArgumentError unless [8, 16, 32, 64].include?(bits_per_item)
|
9
|
+
attr_reader :size, :bits_per_item
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
@bits_per_item = bits_per_item
|
15
|
-
end
|
11
|
+
def initialize(initial_data, bits_per_item: LONG)
|
12
|
+
raise ArgumentError unless [BYTE, SHORT, INT, LONG].include?(bits_per_item)
|
16
13
|
|
17
|
-
|
18
|
-
|
14
|
+
@size = init_size(initial_data, bits_per_item)
|
15
|
+
@internal_array = init_internal_array(initial_data, @size, bits_per_item)
|
16
|
+
@bits_per_item = bits_per_item
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
offset = compute_relative_offset(index, item_bit_size)
|
19
|
+
def [](index)
|
20
|
+
raise IndexError if index.negative? || index >= @size
|
23
21
|
|
24
|
-
|
25
|
-
|
22
|
+
item_index = compute_item_index(index)
|
23
|
+
item_bit_size = compute_item_bit_size(item_index)
|
24
|
+
item = @internal_array[item_index]
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
item_bit_size = compute_item_bit_size(item_index)
|
33
|
-
offset = compute_relative_offset(index, item_bit_size)
|
34
|
-
|
35
|
-
@internal_array[item_index] =
|
36
|
-
if bit == 1
|
37
|
-
set_bit(@internal_array[item_index], offset)
|
38
|
-
else
|
39
|
-
unset_bit(
|
40
|
-
@internal_array[item_index],
|
41
|
-
offset,
|
42
|
-
item_bit_size
|
43
|
-
)
|
44
|
-
end
|
45
|
-
end
|
26
|
+
Handler::Get.new(item).execute(
|
27
|
+
index: index % @bits_per_item,
|
28
|
+
size: item_bit_size
|
29
|
+
)
|
30
|
+
end
|
46
31
|
|
47
|
-
|
48
|
-
|
49
|
-
proc ? res.each { |byte| proc.call(byte) } : res.each
|
50
|
-
end
|
32
|
+
def []=(index, value)
|
33
|
+
raise IndexError if index.negative? || index >= @size
|
51
34
|
|
52
|
-
|
53
|
-
|
54
|
-
|
35
|
+
bit = map_to_bit(value)
|
36
|
+
item_index = compute_item_index(index)
|
37
|
+
item_bit_size = compute_item_bit_size(item_index)
|
38
|
+
item = @internal_array[item_index]
|
55
39
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
40
|
+
@internal_array[item_index] =
|
41
|
+
if bit == 1
|
42
|
+
Handler::Set.new(item).execute(
|
43
|
+
index: index % @bits_per_item,
|
44
|
+
size: item_bit_size
|
45
|
+
)
|
46
|
+
else
|
47
|
+
Handler::Unset.new(item).execute(
|
48
|
+
index: index % @bits_per_item,
|
49
|
+
size: item_bit_size
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
61
53
|
|
62
|
-
|
63
|
-
|
54
|
+
def set(index)
|
55
|
+
self[index] = 1
|
56
|
+
end
|
64
57
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
else
|
69
|
-
decrease_items_size(@internal_array, value, @bits_per_item)
|
70
|
-
end
|
58
|
+
def unset(index)
|
59
|
+
self[index] = 0
|
60
|
+
end
|
71
61
|
|
72
|
-
|
73
|
-
|
62
|
+
def each_byte(&proc)
|
63
|
+
res = decrease_items_size(@internal_array, BYTE, @bits_per_item)
|
64
|
+
proc ? res.each { |byte| proc.call(byte) } : res.each
|
65
|
+
end
|
74
66
|
|
75
|
-
|
67
|
+
def to_a
|
68
|
+
@internal_array.clone
|
69
|
+
end
|
76
70
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
83
|
-
end
|
71
|
+
def to_s
|
72
|
+
@internal_array.map do |item|
|
73
|
+
format("%0#{@bits_per_item}d", item.to_s(2))
|
74
|
+
end.join(' ')
|
75
|
+
end
|
84
76
|
|
85
|
-
|
86
|
-
|
87
|
-
initial_data.is_a?(Array) ? initial_data.clone : res
|
88
|
-
end
|
77
|
+
def bits_per_item=(value)
|
78
|
+
raise ArgumentError unless [BYTE, SHORT, INT, LONG].include?(value)
|
89
79
|
|
90
|
-
|
91
|
-
if value
|
92
|
-
|
93
|
-
value.zero? ? 0 : 1
|
94
|
-
else
|
95
|
-
1
|
96
|
-
end
|
80
|
+
@internal_array =
|
81
|
+
if value > @bits_per_item
|
82
|
+
increase_items_size(@internal_array, value, @bits_per_item)
|
97
83
|
else
|
98
|
-
|
84
|
+
decrease_items_size(@internal_array, value, @bits_per_item)
|
99
85
|
end
|
100
|
-
end
|
101
86
|
|
102
|
-
|
103
|
-
|
104
|
-
size - ((@internal_array.length - 1) * @bits_per_item)
|
105
|
-
else
|
106
|
-
@bits_per_item
|
107
|
-
end
|
108
|
-
end
|
87
|
+
@bits_per_item = value
|
88
|
+
end
|
109
89
|
|
110
|
-
|
111
|
-
index / @bits_per_item
|
112
|
-
end
|
90
|
+
private
|
113
91
|
|
114
|
-
|
115
|
-
|
92
|
+
def init_size(initial_data, bits_per_item)
|
93
|
+
if initial_data.is_a?(Array)
|
94
|
+
bits_per_item * initial_data.length
|
95
|
+
else
|
96
|
+
initial_data
|
116
97
|
end
|
98
|
+
end
|
117
99
|
|
118
|
-
|
119
|
-
|
120
|
-
|
100
|
+
def init_internal_array(initial_data, size, bits_per_item)
|
101
|
+
res = [0] * (size / bits_per_item.to_f).ceil
|
102
|
+
initial_data.is_a?(Array) ? initial_data.clone : res
|
103
|
+
end
|
121
104
|
|
122
|
-
|
123
|
-
|
105
|
+
def map_to_bit(value)
|
106
|
+
if value
|
107
|
+
if value.is_a?(Integer)
|
108
|
+
value.zero? ? 0 : 1
|
109
|
+
else
|
110
|
+
1
|
111
|
+
end
|
112
|
+
else
|
113
|
+
0
|
124
114
|
end
|
115
|
+
end
|
125
116
|
|
126
|
-
|
127
|
-
|
117
|
+
def compute_item_bit_size(index)
|
118
|
+
if index == @internal_array.length - 1
|
119
|
+
size - ((@internal_array.length - 1) * @bits_per_item)
|
120
|
+
else
|
121
|
+
@bits_per_item
|
128
122
|
end
|
123
|
+
end
|
129
124
|
|
130
|
-
|
131
|
-
|
132
|
-
|
125
|
+
def compute_item_index(index)
|
126
|
+
index / @bits_per_item
|
127
|
+
end
|
133
128
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
143
|
-
|
144
|
-
acc[-1] = append_bits(acc[-1], offset, item)
|
145
|
-
processed_bits += bpi
|
129
|
+
def increase_items_size(array, new_size, bpi)
|
130
|
+
processed_bits = 0
|
131
|
+
array.each_with_object([0]) do |value, acc|
|
132
|
+
offset = bpi
|
133
|
+
if processed_bits >= new_size
|
134
|
+
offset = 0
|
135
|
+
acc << 0
|
136
|
+
processed_bits = 0
|
146
137
|
end
|
147
|
-
end
|
148
138
|
|
149
|
-
|
150
|
-
|
151
|
-
acc.concat(explode_item(item, new_size, bpi))
|
152
|
-
end
|
139
|
+
acc[-1] = Handler::Append.new(acc[-1]).execute(offset:, value:)
|
140
|
+
processed_bits += bpi
|
153
141
|
end
|
142
|
+
end
|
154
143
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
144
|
+
def decrease_items_size(array, new_size, bpi)
|
145
|
+
array.each_with_object([]) do |item, acc|
|
146
|
+
acc.concat(explode_item(item, new_size, bpi))
|
147
|
+
end
|
148
|
+
end
|
159
149
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
150
|
+
def explode_item(item, new_size, bpi)
|
151
|
+
res = []
|
152
|
+
offset = bpi
|
153
|
+
mask = (2**new_size) - 1
|
164
154
|
|
165
|
-
|
155
|
+
while offset.positive?
|
156
|
+
offset -= new_size
|
157
|
+
res << ((item >> offset) & mask)
|
166
158
|
end
|
167
159
|
|
168
|
-
|
169
|
-
alias set []=
|
160
|
+
res
|
170
161
|
end
|
162
|
+
|
163
|
+
alias at []
|
171
164
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maximilien Ballesteros
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Ruby-based implementation of the bit array data structure
|
14
14
|
email:
|
@@ -24,6 +24,12 @@ files:
|
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
26
|
- lib/bitary.rb
|
27
|
+
- lib/bitary/handler.rb
|
28
|
+
- lib/bitary/handler/append.rb
|
29
|
+
- lib/bitary/handler/get.rb
|
30
|
+
- lib/bitary/handler/set.rb
|
31
|
+
- lib/bitary/handler/unset.rb
|
32
|
+
- lib/bitary/size.rb
|
27
33
|
- lib/bitary/version.rb
|
28
34
|
- sig/bitary.rbs
|
29
35
|
homepage: https://github.com/Patacode/bitary
|