bitary 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ac785e04cdffcc47ba24323144ee8a7c28337fe337e5d21e3e915409e261eea9
4
+ data.tar.gz: 764c93d304bc84137e3e1e2af4db62411503e65a14a397330b04d4eaa3b209d8
5
+ SHA512:
6
+ metadata.gz: de516b045c571f67e33cc9d377c6602837edfc70fd0191c18edd0ff7777e37acafce24fb5e104c54f0ab4ea6f21dd20e40b3693cd560c658089b401f9323b635
7
+ data.tar.gz: b826149418b68db29efe5a9a87ccfbe287ccfc3e8632da8abd8e834ea622561dddb3250fdf69de5b9519daee02fb67e4f246ce8bca348d8b19fdb6261468ff94
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,23 @@
1
+ AllCops:
2
+ NewCops: enable
3
+
4
+ Style/Documentation:
5
+ Enabled: false
6
+
7
+ Metrics/BlockLength:
8
+ Exclude:
9
+ - 'spec/**/*.rb'
10
+
11
+ Metrics/MethodLength:
12
+ Max: 15
13
+
14
+ Style/CaseEquality:
15
+ Exclude:
16
+ - 'spec/**/*.rb'
17
+
18
+ Layout/LineLength:
19
+ Max: 80
20
+
21
+ Style/MixinUsage:
22
+ Exclude:
23
+ - 'spec/**/*.rb'
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-03-26
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Maximilien Ballesteros
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # Bitary
2
+
3
+ Ruby-based implementation of the bit array data structure.
4
+
5
+ It's still under development, but as of now, it implements simple and well-optimized logic allowing you to set, unset and retrieve bits.
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ ```bash
12
+ $ bundle add bitary
13
+ ```
14
+
15
+ If bundler is not being used to manage dependencies, install the gem by executing:
16
+
17
+ ```bash
18
+ $ gem install bitary
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Documentation still needs to be written, but here is a breakdown
24
+ of the main capabilities brought by the current bit array implementation:
25
+
26
+ ```ruby
27
+ include Bitary
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(
31
+ [255, 10, 20],
32
+ bits_per_item: 8
33
+ ) # create based on some integer array
34
+
35
+ bit_array_sz.bits_per_item # 64
36
+ bit_array_ar.bits_per_item # 8
37
+
38
+ bit_array_ar.size # 128
39
+ bit_array_ar.size # 24
40
+
41
+ # set/unset/get
42
+ bit_array_sz[23] = 1 # set bit at position 23 (0-indexed)
43
+ bit_array_sz[23] # 1
44
+ bit_array_sz[32] # 0
45
+
46
+ bit_array_ar[0] # 1
47
+ bit_array_ar[0] = 0 # unset bit at position 0 (0-indexed)
48
+ bit_array_ar[0] # 0
49
+
50
+ # traverse
51
+ bit_array_sz.each_byte do |byte|
52
+ # do something with each byte
53
+ end
54
+
55
+ # convert
56
+ bit_array_ar.to_a # [255, 10, 20]
57
+ bit_array_ar.to_s # "11111111 00001010 00010100"
58
+
59
+ # increase/decrease bits used per item
60
+ bit_array_ar.bits_per_item = 64
61
+ bit_array_ar.to_a # [16_714_260]
62
+ bit_array_ar.to_s # "0000000000000000000000000000000000000000111111110000101000010100"
63
+
64
+ bit_array_sz.bits_per_item # 64
65
+ bit_array_sz.to_a # [1_099_511_627_776, 0]
66
+ bit_array_sz.bits_per_item = 32
67
+ bit_array_sz.to_a # [256, 0, 0, 1]
68
+ ```
69
+
70
+ ## Development
71
+
72
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests and `rake rubocop` to lint your code. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
73
+
74
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
75
+
76
+ ## Contributing
77
+
78
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Patacode/bitary.
79
+
80
+ ## License
81
+
82
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: %i[spec rubocop]
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bitary
4
+ VERSION = '0.1.0'
5
+ end
data/lib/bitary.rb ADDED
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'bitary/version'
4
+
5
+ module Bitary
6
+ class BitArray
7
+ attr_reader :size, :bits_per_item
8
+
9
+ def initialize(initial_data, bits_per_item: 64)
10
+ raise ArgumentError unless [8, 16, 32, 64].include?(bits_per_item)
11
+
12
+ @size = init_size(initial_data, bits_per_item)
13
+ @internal_array = init_internal_array(initial_data, @size, bits_per_item)
14
+ @bits_per_item = bits_per_item
15
+ end
16
+
17
+ def [](index)
18
+ raise IndexError if index.negative? || index >= @size
19
+
20
+ item_index = compute_item_index(index)
21
+ item_bit_size = compute_item_bit_size(item_index)
22
+ offset = compute_relative_offset(index, item_bit_size)
23
+
24
+ get_bit(@internal_array[item_index], offset)
25
+ end
26
+
27
+ def []=(index, value)
28
+ raise IndexError if index.negative? || index >= @size
29
+
30
+ bit = map_to_bit(value)
31
+ item_index = compute_item_index(index)
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
46
+
47
+ def each_byte(&proc)
48
+ res = decrease_items_size(@internal_array, 8, @bits_per_item)
49
+ proc ? res.each { |byte| proc.call(byte) } : res.each
50
+ end
51
+
52
+ def to_a
53
+ @internal_array.clone
54
+ end
55
+
56
+ def to_s
57
+ @internal_array.map do |item|
58
+ format("%0#{@bits_per_item}d", item.to_s(2))
59
+ end.join(' ')
60
+ end
61
+
62
+ def bits_per_item=(value)
63
+ raise ArgumentError unless [8, 16, 32, 64].include?(value)
64
+
65
+ @internal_array =
66
+ if value > @bits_per_item
67
+ increase_items_size(@internal_array, value, @bits_per_item)
68
+ else
69
+ decrease_items_size(@internal_array, value, @bits_per_item)
70
+ end
71
+
72
+ @bits_per_item = value
73
+ end
74
+
75
+ private
76
+
77
+ def init_size(initial_data, bits_per_item)
78
+ if initial_data.is_a?(Array)
79
+ bits_per_item * initial_data.length
80
+ else
81
+ initial_data
82
+ end
83
+ end
84
+
85
+ def init_internal_array(initial_data, size, bits_per_item)
86
+ res = [0] * (size / bits_per_item.to_f).ceil
87
+ initial_data.is_a?(Array) ? initial_data.clone : res
88
+ end
89
+
90
+ def map_to_bit(value)
91
+ if value
92
+ if value.is_a?(Integer)
93
+ value.zero? ? 0 : 1
94
+ else
95
+ 1
96
+ end
97
+ else
98
+ 0
99
+ end
100
+ end
101
+
102
+ def compute_item_bit_size(index)
103
+ if index == @internal_array.length - 1
104
+ size - ((@internal_array.length - 1) * @bits_per_item)
105
+ else
106
+ @bits_per_item
107
+ end
108
+ end
109
+
110
+ def compute_item_index(index)
111
+ index / @bits_per_item
112
+ end
113
+
114
+ def compute_relative_offset(index, size)
115
+ size - (index % @bits_per_item) - 1
116
+ end
117
+
118
+ def set_bit(value, offset)
119
+ value | (2**offset)
120
+ end
121
+
122
+ def unset_bit(value, offset, size)
123
+ value & (((2**size) - 1) - (2**offset))
124
+ end
125
+
126
+ def get_bit(value, offset)
127
+ (value >> offset) & 0x1
128
+ end
129
+
130
+ def append_bits(value, offset, bits)
131
+ (value << offset) | bits
132
+ end
133
+
134
+ def increase_items_size(array, new_size, bpi)
135
+ processed_bits = 0
136
+ array.each_with_object([0]) do |item, acc|
137
+ offset = bpi
138
+ if processed_bits >= new_size
139
+ offset = 0
140
+ acc << 0
141
+ processed_bits = 0
142
+ end
143
+
144
+ acc[-1] = append_bits(acc[-1], offset, item)
145
+ processed_bits += bpi
146
+ end
147
+ end
148
+
149
+ def decrease_items_size(array, new_size, bpi)
150
+ array.each_with_object([]) do |item, acc|
151
+ acc.concat(explode_item(item, new_size, bpi))
152
+ end
153
+ end
154
+
155
+ def explode_item(item, new_size, bpi)
156
+ res = []
157
+ offset = bpi
158
+ mask = (2**new_size) - 1
159
+
160
+ while offset.positive?
161
+ offset -= new_size
162
+ res << ((item >> offset) & mask)
163
+ end
164
+
165
+ res
166
+ end
167
+
168
+ alias at []
169
+ alias set []=
170
+ end
171
+ end
data/sig/bitary.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Bitary
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bitary
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Maximilien Ballesteros
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-03-26 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby-based implementation of the bit array data structure
14
+ email:
15
+ - maxou.info@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rspec"
21
+ - ".rubocop.yml"
22
+ - CHANGELOG.md
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - lib/bitary.rb
27
+ - lib/bitary/version.rb
28
+ - sig/bitary.rbs
29
+ homepage: https://github.com/Patacode/bitary
30
+ licenses:
31
+ - MIT
32
+ metadata:
33
+ allowed_push_host: https://rubygems.org
34
+ homepage_uri: https://github.com/Patacode/bitary
35
+ source_code_uri: https://github.com/Patacode/bitary
36
+ changelog_uri: https://github.com/Patacode/bitary/blob/main/CHANGELOG.md
37
+ rubygems_mfa_required: 'true'
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 3.3.0
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubygems_version: 3.5.3
54
+ signing_key:
55
+ specification_version: 4
56
+ summary: Bit array data structure
57
+ test_files: []