bitary 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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