bitary 0.1.3 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc3397b948d902fe5cba56205955a01b7ad9f0d5d6eb7a1bf74984005f693114
4
- data.tar.gz: af6673d27575273094dc34a4c67c67fbaa603de8a4e04375b0719e247f8cbcd9
3
+ metadata.gz: 0a3a73becac006670efcdd4a87b36aee0c3c9bc48c50f5cf48d68e47e1e7cad3
4
+ data.tar.gz: e398cc62cdbfc33cf1f48146b59fe655f832b33d59caf8556a7898df1ef4e20d
5
5
  SHA512:
6
- metadata.gz: e44836498539b643e9b75ead2d63c9b91beda96008bc11d5e10a3b354d67ad4f604b1ceee4740665c60a7eeca7ca898e3f05b22aa48d2845f10fa71914a22998
7
- data.tar.gz: 2cc01a7ba3ab7463ab64283fb6e4f82ab8dab61865595f93bbea1efdbf966463008faf2d9dab42f8e304e1f9e6bfa57d597b7d1826ef8521e7f480d2749403f1
6
+ metadata.gz: 5f6d8328faf7a368daf44fc5dafedcfc4456369d2ae48b7a2e3736ad48bea686d76444b3fdd8c7c8d6b34774906e7544cf61cd78905350cfb60c94205916d832
7
+ data.tar.gz: 86f6f32038489a43a9dc18613c536110af4e7aed65e228f2d763f6c472037aba0518ba382566bbe6edeec3ff76491584971c6a0bad64f4efe5dc1d68e443bca4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [0.1.4] - 2024-03-31
2
+
3
+ - more refactoring of Bitary class
4
+ - fix issue in getting/setting bits when size is not % 8
5
+
6
+ ## [0.1.3] - 2024-03-29
7
+
8
+ - fix some missing require statements
9
+ - further refactoring of Bitary class
10
+
1
11
  ## [0.1.2] - 2024-03-29
2
12
 
3
13
  - internal refactoring of the Bitary class
data/README.md CHANGED
@@ -29,11 +29,11 @@ require 'bitary'
29
29
  bit_array_sz = Bitary.new(128) # give an explicit size. Defaults to 64 bits used per item
30
30
  bit_array_ar = Bitary.new(
31
31
  [255, 10, 20],
32
- bits_per_item: Bitary::Size::BYTE # 8 bits
32
+ bpi: Bitary::BYTE # 8 bits
33
33
  ) # create based on some integer array
34
34
 
35
- bit_array_sz.bits_per_item # 64
36
- bit_array_ar.bits_per_item # 8
35
+ bit_array_sz.bpi # 64
36
+ bit_array_ar.bpi # 8
37
37
 
38
38
  bit_array_ar.size # 128
39
39
  bit_array_ar.size # 24
@@ -57,13 +57,13 @@ bit_array_ar.to_a # [127, 10, 20]
57
57
  bit_array_ar.to_s # "01111111 00001010 00010100"
58
58
 
59
59
  # increase/decrease bits used per item
60
- bit_array_ar.bits_per_item = Bitary::Size::LONG # 64 bits
60
+ bit_array_ar.bpi = Bitary::LONG # 64 bits
61
61
  bit_array_ar.to_a # [8_325_652]
62
62
  bit_array_ar.to_s # "0000000000000000000000000000000000000000011111110000101000010100"
63
63
 
64
- bit_array_sz.bits_per_item # 64
64
+ bit_array_sz.bpi # 64
65
65
  bit_array_sz.to_a # [1_099_511_627_776, 0]
66
- bit_array_sz.bits_per_item = Bitary::Size::INT # 32 bits
66
+ bit_array_sz.bpi = Bitary::INT # 32 bits
67
67
  bit_array_sz.to_a # [256, 0, 0, 0]
68
68
  ```
69
69
 
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bitary
4
+ class Bitwarr
5
+ attr_reader :bpi
6
+
7
+ def initialize(initial_data, bpi: Bitary::LONG)
8
+ check_initial_data(initial_data)
9
+ check_bpi(bpi)
10
+
11
+ @bpi = bpi
12
+ @bitsize = init_bitsize(initial_data)
13
+ @array = init_array(initial_data)
14
+ end
15
+
16
+ def method_missing(method, *, &)
17
+ @array.respond_to?(method) ? @array.send(method, *, &) : super
18
+ end
19
+
20
+ def respond_to_missing?(method, include_all = false)
21
+ @array.respond_to?(method, include_all) || super
22
+ end
23
+
24
+ def bitsize(bit_index = nil)
25
+ if bit_index.nil?
26
+ @bitsize
27
+ else
28
+ check_bit_index(bit_index)
29
+
30
+ last_index = @array.length - 1
31
+ if item_index(bit_index) == last_index
32
+ @bitsize - (last_index * @bpi)
33
+ else
34
+ @bpi
35
+ end
36
+ end
37
+ end
38
+
39
+ def [](bit_index)
40
+ @array[item_index(bit_index)]
41
+ end
42
+
43
+ def []=(bit_index, value)
44
+ raise ArgumentError unless value.is_a?(Integer)
45
+
46
+ @array[item_index(bit_index)] = value
47
+ end
48
+
49
+ def relative_bit_index(bit_index)
50
+ check_bit_index(bit_index)
51
+
52
+ bit_index % @bpi
53
+ end
54
+
55
+ def item_index(bit_index)
56
+ check_bit_index(bit_index)
57
+
58
+ bit_index / @bpi
59
+ end
60
+
61
+ def bit_at(index)
62
+ operate_bit_at(:get, index)
63
+ end
64
+
65
+ def bit_at!(index)
66
+ operate_bit_at!(:set, index)
67
+ end
68
+
69
+ def unbit_at!(index)
70
+ operate_bit_at!(:unset, index)
71
+ end
72
+
73
+ def each_byte
74
+ @array.each do |item|
75
+ (@bpi / Bitary::BYTE).times do |i|
76
+ byte = (item >> (@bpi - (Bitary::BYTE * (i + 1))))
77
+ yield byte
78
+ end
79
+ end
80
+ end
81
+
82
+ def to_s
83
+ @array.map { |item| format("%0#{@bpi}d", item.to_s(2)) }.join(' ')
84
+ end
85
+
86
+ def bpi=(value)
87
+ check_bpi(value)
88
+
89
+ update_items_size!(value)
90
+
91
+ @bpi = value
92
+ end
93
+
94
+ private
95
+
96
+ def init_bitsize(initial_data)
97
+ initial_data.is_a?(Array) ? @bpi * initial_data.length : initial_data
98
+ end
99
+
100
+ def init_array(initial_data)
101
+ if initial_data.is_a?(Array)
102
+ initial_data.clone
103
+ else
104
+ [0] * (@bitsize / @bpi.to_f).ceil
105
+ end
106
+ end
107
+
108
+ def check_initial_data(initial_data)
109
+ raise ArgumentError unless [Array, Integer].include?(initial_data.class)
110
+ end
111
+
112
+ def check_bit_index(bit_index)
113
+ raise ArgumentError unless bit_index.is_a?(Integer)
114
+ raise IndexError if bit_index.negative? || bit_index >= @bitsize
115
+ end
116
+
117
+ def check_bpi(bpi)
118
+ raise ArgumentError unless [
119
+ Bitary::BYTE,
120
+ Bitary::SHORT,
121
+ Bitary::INT,
122
+ Bitary::LONG
123
+ ].include?(bpi)
124
+ end
125
+
126
+ def operate_bit_at(operation, index)
127
+ Factory
128
+ .make("Handler::#{operation.capitalize}", self[index])
129
+ .execute(
130
+ index: relative_bit_index(index),
131
+ size: @bpi
132
+ )
133
+ end
134
+
135
+ def operate_bit_at!(operation, index)
136
+ self[index] = operate_bit_at(operation, index)
137
+ end
138
+
139
+ def update_items_size!(value)
140
+ if value > @bpi
141
+ increase_items_size!(value)
142
+ else
143
+ decrease_items_size!(value)
144
+ end
145
+ end
146
+
147
+ def increase_items_size(array, new_size, bpi)
148
+ processed_bits = 0
149
+ array.each_with_object([0]) do |value, acc|
150
+ offset = bpi
151
+ if processed_bits >= new_size
152
+ offset = 0
153
+ acc << 0
154
+ processed_bits = 0
155
+ end
156
+
157
+ acc[-1] = Factory.make('Handler::Append', acc[-1]).execute(
158
+ offset:,
159
+ value:
160
+ )
161
+ processed_bits += bpi
162
+ end
163
+ end
164
+
165
+ def increase_items_size!(value)
166
+ @array = increase_items_size(@array, value, @bpi)
167
+ end
168
+
169
+ def decrease_items_size(array, new_size, bpi)
170
+ array.each_with_object([]) do |item, acc|
171
+ acc.concat(explode_item(item, new_size, bpi))
172
+ end
173
+ end
174
+
175
+ def decrease_items_size!(value)
176
+ @array = decrease_items_size(@array, value, @bpi)
177
+ end
178
+
179
+ def explode_item(item, new_size, bpi)
180
+ res = []
181
+ offset = bpi
182
+ mask = (2**new_size) - 1
183
+
184
+ while offset.positive?
185
+ offset -= new_size
186
+ res << ((item >> offset) & mask)
187
+ end
188
+
189
+ res
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bitary
4
+ class Decorator
5
+ class KwargsValidator < Bitary::Decorator
6
+ SPEC_KEYS = %i[required default type predicate].freeze
7
+
8
+ def initialize(wrappee, spec)
9
+ super(wrappee) { |method| spec.key?(method) }
10
+ @spec = check_spec(@wrappee, spec)
11
+ end
12
+
13
+ protected
14
+
15
+ def precall(method, *, **)
16
+ super(method, *, **check_kwargs(@spec, method, **))
17
+ end
18
+
19
+ private
20
+
21
+ def check_spec(wrappee, spec)
22
+ raise ArgumentError unless spec.is_a?(Hash)
23
+
24
+ spec.each do |method, method_spec|
25
+ check_spec_method(wrappee, method)
26
+ check_spec_method_value(method_spec)
27
+ end
28
+ end
29
+
30
+ def check_kwargs(spec, method, **kwargs)
31
+ check_unexpected_user_kwargs(kwargs, spec[method])
32
+ check_kwargs_against_spec(kwargs, spec[method])
33
+ end
34
+
35
+ def check_spec_method(wrappee, method)
36
+ raise ArgumentError unless wrappee.respond_to?(method)
37
+ end
38
+
39
+ def check_spec_method_value(method_spec)
40
+ raise ArgumentError unless method_spec.is_a?(Hash)
41
+
42
+ method_spec.each_value do |arg_spec|
43
+ raise ArgumentError unless arg_spec.is_a?(Hash)
44
+
45
+ check_arg_spec(arg_spec)
46
+ end
47
+ end
48
+
49
+ def check_arg_spec(arg_spec)
50
+ raise ArgumentError unless arg_spec.keys.all? do |spec_key|
51
+ SPEC_KEYS.include?(spec_key)
52
+ end
53
+
54
+ arg_spec.each do |spec_key, spec_value|
55
+ check_arg_spec_entry(spec_key, spec_value)
56
+ end
57
+
58
+ return unless arg_spec.key?(:required) && arg_spec[:required]
59
+ raise ArgumentError if arg_spec.key?(:default)
60
+ end
61
+
62
+ def check_arg_spec_entry(key, value)
63
+ case key
64
+ when :required then check_required(value)
65
+ when :default then check_default(value)
66
+ when :type then check_type(value)
67
+ when :predicate then check_predicate(value)
68
+ end
69
+ end
70
+
71
+ def check_required(value)
72
+ raise ArgumentError unless [true, false].include?(value)
73
+ end
74
+
75
+ def check_default(value)
76
+ # NOTHING TODO
77
+ end
78
+
79
+ def check_type(value)
80
+ raise ArgumentError unless value.is_a?(Class)
81
+ end
82
+
83
+ def check_predicate(value)
84
+ raise ArgumentError unless value.is_a?(Hash)
85
+
86
+ check_predicate_keys(value)
87
+ check_predicate_values(value)
88
+ end
89
+
90
+ def check_predicate_keys(value)
91
+ available_keys = %i[callback error]
92
+
93
+ raise ArgumentError unless value.keys.all? do |key|
94
+ available_keys.include?(key)
95
+ end
96
+
97
+ raise KeyError unless value.key?(:callback) && value.key?(:error)
98
+ end
99
+
100
+ def check_predicate_values(value)
101
+ raise ArgumentError unless value[:callback].is_a?(Proc)
102
+ raise ArgumentError unless value[:error].is_a?(Class)
103
+ raise ArgumentError unless value[:error] < Exception
104
+ end
105
+
106
+ def check_unexpected_user_kwargs(user_kwargs, method_spec)
107
+ raise ArgumentError unless user_kwargs.keys.all? do |key|
108
+ method_spec.include?(key)
109
+ end
110
+ end
111
+
112
+ def check_kwargs_against_spec(user_kwargs, method_spec)
113
+ predicates = []
114
+
115
+ parsed_kwargs = method_spec.reduce({}) do |acc, entry|
116
+ kwarg_name, kwarg_spec = entry
117
+ loaded_spec = load_spec(kwarg_spec)
118
+
119
+ validate_required(user_kwargs, loaded_spec, kwarg_name)
120
+ validate_type(user_kwargs, loaded_spec, kwarg_name)
121
+ predicates << loaded_spec[:predicate]
122
+
123
+ acc.merge(
124
+ kwarg_name => compute_value(user_kwargs, loaded_spec, kwarg_name)
125
+ )
126
+ end
127
+
128
+ predicates.each do |predicate|
129
+ validate_predicate(parsed_kwargs, predicate)
130
+ end
131
+
132
+ parsed_kwargs
133
+ end
134
+
135
+ def load_spec(kwarg_spec)
136
+ {
137
+ required: kwarg_spec[:required] || false,
138
+ default: kwarg_spec[:default],
139
+ type: kwarg_spec[:type] || Object,
140
+ predicate: kwarg_spec[:predicate] || {
141
+ callback: ->(_value) { true },
142
+ error: ArgumentError
143
+ }
144
+ }
145
+ end
146
+
147
+ def validate_required(user_kwargs, spec, expected_key)
148
+ return unless spec[:required]
149
+
150
+ raise KeyError unless user_kwargs.key?(expected_key)
151
+ end
152
+
153
+ def validate_type(user_kwargs, spec, expected_key)
154
+ return unless user_kwargs.key?(expected_key)
155
+
156
+ raise ArgumentError unless user_kwargs[expected_key].is_a?(spec[:type])
157
+ end
158
+
159
+ def validate_predicate(parsed_kwargs, predicate)
160
+ return if predicate[:callback].call(**parsed_kwargs)
161
+
162
+ raise predicate[:error]
163
+ end
164
+
165
+ def compute_value(user_kwargs, spec, expected_key)
166
+ if user_kwargs.key?(expected_key)
167
+ user_kwargs[expected_key]
168
+ else
169
+ spec[:default]
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bitary
4
+ class Decorator
5
+ class SingleMethod < Bitary::Decorator
6
+ class NonNilEnforcer < Bitary::Decorator::SingleMethod
7
+ protected
8
+
9
+ def postcall(resp)
10
+ (resp.nil? and raise TypeError) || resp
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bitary
4
+ class Decorator
5
+ class SingleMethod < Bitary::Decorator
6
+ class TruthyEnforcer < Bitary::Decorator::SingleMethod
7
+ protected
8
+
9
+ def postcall(resp)
10
+ resp or raise TypeError
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'single_method/non_nil_enforcer'
4
+ require_relative 'single_method/truthy_enforcer'
5
+
6
+ class Bitary
7
+ class Decorator
8
+ class SingleMethod < Bitary::Decorator
9
+ def initialize(wrappee, method)
10
+ super(wrappee) { |meth| meth == method }
11
+ check_method(wrappee, method)
12
+ end
13
+
14
+ private
15
+
16
+ def check_method(wrappee, method)
17
+ raise ArgumentError unless method.is_a?(Symbol)
18
+ raise NoMethodError unless wrappee.respond_to?(method)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'decorator/kwargs_validator'
4
+ require_relative 'decorator/single_method'
5
+
6
+ class Bitary
7
+ class Decorator
8
+ def initialize(wrappee, &proc)
9
+ @wrappee = wrappee
10
+ @predicate = proc || ->(_method) { true }
11
+ end
12
+
13
+ def method_missing(method, *, **, &)
14
+ if @wrappee.respond_to?(method)
15
+ if @predicate.call(method)
16
+ args, kwargs = precall(method, *, **)
17
+ resp = @wrappee.send(method, *args, **kwargs, &)
18
+ postcall(resp)
19
+ else
20
+ @wrappee.send(method, *, **, &)
21
+ end
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def respond_to_missing?(method, include_all = false)
28
+ @wrappee.respond_to?(method, include_all) || super
29
+ end
30
+
31
+ def wrappee
32
+ res = @wrappee
33
+ res = res.wrappee while res.respond_to?(:wrappee)
34
+ res
35
+ end
36
+
37
+ protected
38
+
39
+ def precall(_method, *args, **kwargs)
40
+ [args, kwargs]
41
+ end
42
+
43
+ def postcall(resp)
44
+ resp
45
+ end
46
+ end
47
+ end
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'deptainer'
4
-
5
3
  class Bitary
6
4
  class Factory
7
5
  private_class_method :new
8
- @container = Deptainer.new
6
+ @memo = {}
9
7
 
10
8
  def self.make(name, *, **)
11
9
  raise ArgumentError unless name.is_a?(String)
@@ -17,11 +15,11 @@ class Bitary
17
15
 
18
16
  def self.make_memo(name, *args, **kwargs)
19
17
  raise ArgumentError unless name.is_a?(String)
20
- if @container.has?(name.to_sym) && !args.empty? && !kwargs.empty?
18
+ if @memo.key?(name.to_sym) && !args.empty? && !kwargs.empty?
21
19
  raise ArgumentError
22
20
  end
23
21
 
24
- @container[name.to_sym] ||= make(name, *args, **kwargs)
22
+ @memo[name.to_sym] ||= make(name, *args, **kwargs)
25
23
  end
26
24
  end
27
25
  end
@@ -3,17 +3,19 @@
3
3
  class Bitary
4
4
  class Handler
5
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)
6
+ SPEC = {
7
+ offset: {
8
+ required: true,
9
+ type: Integer
10
+ },
11
+ value: {
12
+ required: true,
13
+ type: Integer
14
+ }
15
+ }.freeze
15
16
 
16
- (@value << offset) | value
17
+ def execute(**kwargs)
18
+ (@value << kwargs[:offset]) | kwargs[:value]
17
19
  end
18
20
  end
19
21
  end
@@ -3,19 +3,25 @@
3
3
  class Bitary
4
4
  class Handler
5
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)
6
+ SPEC = {
7
+ index: {
8
+ required: true,
9
+ type: Integer,
10
+ predicate: {
11
+ callback: lambda do |**kwargs|
12
+ kwargs[:index] >= 0 && kwargs[:index] < kwargs[:size]
13
+ end,
14
+ error: IndexError
15
+ }
16
+ },
17
+ size: {
18
+ required: true,
19
+ type: Integer
20
+ }
21
+ }.freeze
15
22
 
16
- raise IndexError if index.negative? || index >= size
17
-
18
- (@value >> (size - index - 1)) & 0x1
23
+ def execute(**kwargs)
24
+ (@value >> (kwargs[:size] - kwargs[:index] - 1)) & 0x1
19
25
  end
20
26
  end
21
27
  end
@@ -3,19 +3,25 @@
3
3
  class Bitary
4
4
  class Handler
5
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)
6
+ SPEC = {
7
+ index: {
8
+ required: true,
9
+ type: Integer,
10
+ predicate: {
11
+ callback: lambda do |**kwargs|
12
+ kwargs[:index] >= 0 && kwargs[:index] < kwargs[:size]
13
+ end,
14
+ error: IndexError
15
+ }
16
+ },
17
+ size: {
18
+ required: true,
19
+ type: Integer
20
+ }
21
+ }.freeze
15
22
 
16
- raise IndexError if index.negative? || index >= size
17
-
18
- @value | (2**(size - index - 1))
23
+ def execute(**kwargs)
24
+ @value | (2**(kwargs[:size] - kwargs[:index] - 1))
19
25
  end
20
26
  end
21
27
  end
@@ -3,19 +3,28 @@
3
3
  class Bitary
4
4
  class Handler
5
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)
6
+ SPEC = {
7
+ index: {
8
+ required: true,
9
+ type: Integer,
10
+ predicate: {
11
+ callback: lambda do |**kwargs|
12
+ kwargs[:index] >= 0 && kwargs[:index] < kwargs[:size]
13
+ end,
14
+ error: IndexError
15
+ }
16
+ },
17
+ size: {
18
+ required: true,
19
+ type: Integer
20
+ }
21
+ }.freeze
15
22
 
16
- raise IndexError if index.negative? || index >= size
23
+ def execute(**kwargs)
24
+ mask =
25
+ (2**kwargs[:size]) - 1 - (2**(kwargs[:size] - kwargs[:index] - 1))
17
26
 
18
- @value & (((2**size) - 1) - (2**(size - index - 1)))
27
+ @value & mask
19
28
  end
20
29
  end
21
30
  end
@@ -7,8 +7,17 @@ require_relative 'handler/append'
7
7
 
8
8
  class Bitary
9
9
  class Handler
10
+ SPEC = {}.freeze
11
+
10
12
  attr_reader :value
11
13
 
14
+ def self.new(*arg, **kwargs)
15
+ Decorator::SingleMethod::KwargsValidator.new(
16
+ super,
17
+ { execute: self::SPEC }
18
+ )
19
+ end
20
+
12
21
  def initialize(value)
13
22
  raise ArgumentError unless value.is_a?(Integer)
14
23
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bitary
4
+ class Mapper
5
+ class IntToBit < Bitary::Mapper
6
+ def map(value)
7
+ if value.is_a?(Integer)
8
+ value.zero? ? 0 : 1
9
+ else
10
+ 1
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bitary
4
+ class Mapper
5
+ class ObjToBit < Bitary::Mapper
6
+ def map(value)
7
+ case !!value
8
+ when true then IntToBit.new.map(value)
9
+ when false then 0
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mapper/int_to_bit'
4
+ require_relative 'mapper/obj_to_bit'
5
+
6
+ class Bitary
7
+ class Mapper
8
+ def self.new(*arg, **kwargs)
9
+ Decorator::SingleMethod::NonNilEnforcer.new(super, :map)
10
+ end
11
+
12
+ def map(value)
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Bitary
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.5'
5
5
  end
data/lib/bitary.rb CHANGED
@@ -4,54 +4,26 @@ require_relative 'bitary/size'
4
4
  require_relative 'bitary/version'
5
5
  require_relative 'bitary/handler'
6
6
  require_relative 'bitary/factory'
7
- require_relative 'bitary/deptainer'
7
+ require_relative 'bitary/bitwarr'
8
+ require_relative 'bitary/decorator'
9
+ require_relative 'bitary/mapper'
8
10
 
9
11
  class Bitary
10
12
  include Size
11
13
 
12
- attr_reader :size, :bits_per_item
13
-
14
- def initialize(initial_data, bits_per_item: LONG)
15
- raise ArgumentError unless [BYTE, SHORT, INT, LONG].include?(bits_per_item)
16
-
17
- @size = init_size(initial_data, bits_per_item)
18
- @internal_array = init_internal_array(initial_data, @size, bits_per_item)
19
- @bits_per_item = bits_per_item
14
+ def initialize(initial_data, bpi: LONG)
15
+ @internal_array = Bitwarr.new(initial_data, bpi:)
20
16
  end
21
17
 
22
18
  def [](index)
23
- raise IndexError if index.negative? || index >= @size
24
-
25
- item_index = compute_item_index(index)
26
- item_bit_size = compute_item_bit_size(item_index)
27
- item = @internal_array[item_index]
28
-
29
- Factory.make('Handler::Get', item).execute(
30
- index: index % @bits_per_item,
31
- size: item_bit_size
32
- )
19
+ @internal_array.bit_at(index)
33
20
  end
34
21
 
35
22
  def []=(index, value)
36
- raise IndexError if index.negative? || index >= @size
37
-
38
- bit = map_to_bit(value)
39
- item_index = compute_item_index(index)
40
- item_bit_size = compute_item_bit_size(item_index)
41
- item = @internal_array[item_index]
42
-
43
- @internal_array[item_index] =
44
- if bit == 1
45
- Factory.make('Handler::Set', item).execute(
46
- index: index % @bits_per_item,
47
- size: item_bit_size
48
- )
49
- else
50
- Factory.make('Handler::Unset', item).execute(
51
- index: index % @bits_per_item,
52
- size: item_bit_size
53
- )
54
- end
23
+ case Mapper::ObjToBit.new.map(value)
24
+ when 0 then @internal_array.unbit_at!(index)
25
+ else @internal_array.bit_at!(index)
26
+ end
55
27
  end
56
28
 
57
29
  def set(index)
@@ -62,108 +34,28 @@ class Bitary
62
34
  self[index] = 0
63
35
  end
64
36
 
65
- def each_byte(&proc)
66
- res = decrease_items_size(@internal_array, BYTE, @bits_per_item)
67
- proc ? res.each { |byte| proc.call(byte) } : res.each
37
+ def each_byte(&)
38
+ @internal_array.each_byte(&)
68
39
  end
69
40
 
70
41
  def to_a
71
- @internal_array.clone
42
+ @internal_array.to_a
72
43
  end
73
44
 
74
45
  def to_s
75
- @internal_array.map do |item|
76
- format("%0#{@bits_per_item}d", item.to_s(2))
77
- end.join(' ')
78
- end
79
-
80
- def bits_per_item=(value)
81
- raise ArgumentError unless [BYTE, SHORT, INT, LONG].include?(value)
82
-
83
- @internal_array =
84
- if value > @bits_per_item
85
- increase_items_size(@internal_array, value, @bits_per_item)
86
- else
87
- decrease_items_size(@internal_array, value, @bits_per_item)
88
- end
89
-
90
- @bits_per_item = value
91
- end
92
-
93
- private
94
-
95
- def init_size(initial_data, bits_per_item)
96
- if initial_data.is_a?(Array)
97
- bits_per_item * initial_data.length
98
- else
99
- initial_data
100
- end
46
+ @internal_array.to_s
101
47
  end
102
48
 
103
- def init_internal_array(initial_data, size, bits_per_item)
104
- res = [0] * (size / bits_per_item.to_f).ceil
105
- initial_data.is_a?(Array) ? initial_data.clone : res
49
+ def bpi=(value)
50
+ @internal_array.bpi = value
106
51
  end
107
52
 
108
- def map_to_bit(value)
109
- if value
110
- if value.is_a?(Integer)
111
- value.zero? ? 0 : 1
112
- else
113
- 1
114
- end
115
- else
116
- 0
117
- end
53
+ def size
54
+ @internal_array.bitsize
118
55
  end
119
56
 
120
- def compute_item_bit_size(index)
121
- if index == @internal_array.length - 1
122
- size - ((@internal_array.length - 1) * @bits_per_item)
123
- else
124
- @bits_per_item
125
- end
126
- end
127
-
128
- def compute_item_index(index)
129
- index / @bits_per_item
130
- end
131
-
132
- def increase_items_size(array, new_size, bpi)
133
- processed_bits = 0
134
- array.each_with_object([0]) do |value, acc|
135
- offset = bpi
136
- if processed_bits >= new_size
137
- offset = 0
138
- acc << 0
139
- processed_bits = 0
140
- end
141
-
142
- acc[-1] = Factory.make('Handler::Append', acc[-1]).execute(
143
- offset:,
144
- value:
145
- )
146
- processed_bits += bpi
147
- end
148
- end
149
-
150
- def decrease_items_size(array, new_size, bpi)
151
- array.each_with_object([]) do |item, acc|
152
- acc.concat(explode_item(item, new_size, bpi))
153
- end
154
- end
155
-
156
- def explode_item(item, new_size, bpi)
157
- res = []
158
- offset = bpi
159
- mask = (2**new_size) - 1
160
-
161
- while offset.positive?
162
- offset -= new_size
163
- res << ((item >> offset) & mask)
164
- end
165
-
166
- res
57
+ def bpi
58
+ @internal_array.bpi
167
59
  end
168
60
 
169
61
  alias at []
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.3
4
+ version: 0.1.5
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-29 00:00:00.000000000 Z
11
+ date: 2024-03-31 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby-based implementation of the bit array data structure
14
14
  email:
@@ -24,13 +24,21 @@ files:
24
24
  - README.md
25
25
  - Rakefile
26
26
  - lib/bitary.rb
27
- - lib/bitary/deptainer.rb
27
+ - lib/bitary/bitwarr.rb
28
+ - lib/bitary/decorator.rb
29
+ - lib/bitary/decorator/kwargs_validator.rb
30
+ - lib/bitary/decorator/single_method.rb
31
+ - lib/bitary/decorator/single_method/non_nil_enforcer.rb
32
+ - lib/bitary/decorator/single_method/truthy_enforcer.rb
28
33
  - lib/bitary/factory.rb
29
34
  - lib/bitary/handler.rb
30
35
  - lib/bitary/handler/append.rb
31
36
  - lib/bitary/handler/get.rb
32
37
  - lib/bitary/handler/set.rb
33
38
  - lib/bitary/handler/unset.rb
39
+ - lib/bitary/mapper.rb
40
+ - lib/bitary/mapper/int_to_bit.rb
41
+ - lib/bitary/mapper/obj_to_bit.rb
34
42
  - lib/bitary/size.rb
35
43
  - lib/bitary/version.rb
36
44
  - sig/bitary.rbs
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Bitary
4
- class Deptainer
5
- def initialize
6
- @store = {}
7
- end
8
-
9
- def [](key)
10
- raise ArgumentError unless key.is_a?(Symbol)
11
-
12
- @store[key]
13
- end
14
-
15
- def []=(key, value)
16
- raise ArgumentError unless key.is_a?(Symbol)
17
-
18
- @store[key] = value
19
- end
20
-
21
- def has?(key)
22
- raise ArgumentError unless key.is_a?(Symbol)
23
-
24
- @store.key?(key)
25
- end
26
- end
27
- end