bitint 0.5.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5b4702d20c7d5f3523dda0748265809d4d581ba33a217ac33ca116c82062fed5
4
+ data.tar.gz: c710ff424901df06d602dc2f29b5860664583320289ea19a10cdf752eaba5980
5
+ SHA512:
6
+ metadata.gz: 34c75a6b2b3ddfbdd910ffba7273a657a6d4486af4d7535325446fa430ac5acce4c9bf7e6475d2b53b31d4c194eabd46a58dfb6860b855cd6728d96ba32cace7
7
+ data.tar.gz: e396e8080ef6ebef611d5c300863b9771e97d1552f8d690e48569756090c7c865edcf86e8721dad0e6bbb3b0108933becbbe5b7300a834008eaa65c87148d582
data/.rdoc_options ADDED
@@ -0,0 +1 @@
1
+ markup: markdown
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in bitint.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "minitest", "~> 5.0"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Sam Westerman
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,41 @@
1
+ # BitInt
2
+
3
+ This gem lets you emulate 2's complement integers in ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'bitint'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install bitint
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ num = BitInt::U8.new(0xfe)
25
+ num += 2
26
+ puts num #=> 1
27
+ ```
28
+
29
+ ## Development
30
+
31
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
32
+
33
+ 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).
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sampersand/bitint.
38
+
39
+ ## License
40
+
41
+ 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,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/test_*.rb"]
10
+ end
11
+
12
+ task default: :test
data/Steepfile ADDED
@@ -0,0 +1,28 @@
1
+ D = Steep::Diagnostic
2
+
3
+ target :lib do
4
+ signature "sig"
5
+
6
+ # check "lib" # Directory name
7
+ check "lib/bitint/bitint.rb"
8
+ # check "Gemfile" # File name
9
+ check "app/models/**/*.rb" # Glob
10
+ # ignore "lib/templates/*.rb"
11
+
12
+ # library "pathname", "set" # Standard libraries
13
+ # library "strong_json" # Gems
14
+
15
+ # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
16
+ # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
17
+ configure_code_diagnostics do |hash| # You can setup everything yourself
18
+ hash[D::Ruby::UnknownConstant] = :hint
19
+ end
20
+ end
21
+
22
+ # target :test do
23
+ # signature "sig", "sig-private"
24
+ #
25
+ # check "test"
26
+ #
27
+ # # library "pathname", "set" # Standard libraries
28
+ # end
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "bitint"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,305 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BitInt < Numeric
4
+ # Indicates that +BitInt::new+ was called with an integer that was too large.
5
+ class OverflowError < RuntimeError
6
+ attr_reader :integer, :range
7
+
8
+ def initialize(integer, range)
9
+ super "#{integer} is out of bounds (range=#{range})"
10
+ @integer = integer
11
+ @range = range
12
+ end
13
+ end
14
+
15
+ @classes = {}
16
+
17
+ class << self
18
+ private :new
19
+
20
+ # Creates a new unsigned +BitInt+ class.
21
+ #
22
+ # === Example
23
+ # puts BitInt::U(16)::MAX #=> 65535
24
+ def U(bits) = self[bits, signed: false]
25
+ alias unsigned U
26
+
27
+ # Creates a new signed +BitInt+ class.
28
+ #
29
+ # === Example
30
+ # puts BitInt::I(16)::MAX #=> 32767
31
+ def I(bits) = self[bits, signed: true]
32
+ alias signed I
33
+ alias S I
34
+
35
+ # Creates a new +BitInt+. Raises an ArgumentError if bits is negative.
36
+ #
37
+ # === Example
38
+ # puts BitInt[8]::MAX #=> 255
39
+ # puts BitInt[8, signed: false]::MAX #=> 255
40
+ # puts BitInt[8, signed: true]::MAX #=> 127
41
+ def [](bits, signed: false) = create(bits: bits, signed: signed)
42
+
43
+ def create(bits: nil, bytes: nil, signed:)
44
+ if bits.nil? == bytes.nil?
45
+ raise ArgumentError, 'exactly one of `bits` or `bytes` must be supplied'
46
+ end
47
+
48
+ bits ||= bytes * 8
49
+
50
+ raise ArgumentError, 'bit count must be at least 1' unless bits.positive?
51
+
52
+ @classes[[bits, signed].freeze] ||= Class.new(self) do |cls|
53
+ cls.setup!(bits, signed)
54
+ end
55
+ end
56
+
57
+ # Returns whether this class represents a signed integer.
58
+ #
59
+ # === Example
60
+ # puts BitInt::U(8).signed? #=> false
61
+ # puts BitInt::I(8).signed? #=> true
62
+ def signed? = @signed
63
+
64
+ # Returns whether this class represents an unsigned integer.
65
+ #
66
+ # === Example
67
+ # puts BitInt::U(8).unsigned? #=> false
68
+ # puts BitInt::I(8).unsigned? #=> true
69
+ def unsigned? = !signed?
70
+
71
+ def inspect = name || "#{signed? ? 'I' : 'U'}#@bits"
72
+ alias to_s inspect
73
+
74
+ # :stopdoc:
75
+ protected def setup!(bits, signed)
76
+ @bits = bits
77
+ @signed = signed
78
+
79
+ create = ->(int) {
80
+ allocate.tap { |x| x.instance_variable_set :@int, int }
81
+ }
82
+
83
+ class << self
84
+ public :new
85
+ end
86
+
87
+ const_set :BITS, @bits
88
+ const_set :BYTES, (@bits / 8.0).ceil
89
+ const_set :MASK, (1 << @bits).pred
90
+ const_set :ZERO, create[0]
91
+ const_set :ONE, create[1]
92
+ const_set :MIN, create[signed? ? -(1 << @bits.pred) : 0]
93
+ const_set :MAX, create[signed? ? (1 << @bits.pred).pred : (1 << @bits).pred]
94
+ const_set :BOUNDS, self::MIN .. self::MAX
95
+ end
96
+
97
+ def pack_char
98
+
99
+ end
100
+ # :startdoc:
101
+ end
102
+
103
+ # Creates a new BitInt by masking +int+.
104
+ #
105
+ # If +int+ is not rdoc-ref:in_bounds? and +wrap+ is false, then an
106
+ # OverflowError is raised.
107
+ #
108
+ # === Example
109
+ # puts BitInt::U(8).new(27) #=> 27
110
+ # puts BitInt::U(8).new(-1) #=> 255
111
+ # puts BitInt::U(8).new(-1, wrap: false) #=> OverflowError
112
+ # puts BitInt::I(8).new(255) #=> -1
113
+ def initialize(int, wrap: true)
114
+ unless wrap || (bounds = self.class::BOUNDS).include?(int)
115
+ raise OverflowError.new(int, bounds)
116
+ end
117
+
118
+ @int = ((int - self.class::MIN.to_i) & self.class::MASK) + self.class::MIN.to_i
119
+ end
120
+
121
+ # Checks to see if +rhs.to_i+ is equal to this class
122
+ #
123
+ # === Example
124
+ # U64 = BitInt::U(64)
125
+ # twelve = U64.new(12)
126
+ #
127
+ # # Behaves as you'd expect.
128
+ # puts twelve == U64.new(12) #=> true
129
+ # puts twelve == U64.new(13) #=> false
130
+ # puts twelve == 12 #=> true
131
+ # puts twelve == 12.0 #=> true
132
+ # puts twelve == 13 #=> false
133
+ # puts twelve == Object.new #=> false
134
+ def ==(rhs) = rhs.respond_to?(:to_i) && @int == rhs.to_i
135
+
136
+ # Overwite rdoc-ref:Numeric#integer? as we're an integer.
137
+ def integer? = true
138
+
139
+ # :section: Conversions
140
+
141
+ # Returns the underlying integer.
142
+ def to_i = @int
143
+ alias to_int to_i
144
+
145
+ # Converts self to a Float.
146
+ def to_f = @int.to_f
147
+
148
+ # Converts self to a String.
149
+ #
150
+ # If no base is given, it just returns a normal string in base 10.
151
+ # If a base is given, a string padded with `0`s will be returned.
152
+ def to_s(base = nil)
153
+ return @int.to_s if base.nil?
154
+
155
+ adjusted = negative? ? (-2*self.class::MIN + self).to_i : @int
156
+ adjusted.to_s(base).rjust(self.class::BITS / Math.log2(base), negative? ? '1' : '0')
157
+ end
158
+
159
+ alias inspect to_s
160
+
161
+ # Returns a base-16 string of +self+. Equivalent to +to_s(16)+.
162
+ #
163
+ # If +upper: true+ is passed, returns an upper-case version.
164
+ #
165
+ # === Example
166
+ # puts BitInt::U16.new(1234).hex #=> 04d2
167
+ # puts BitInt::U16.new(1234, upper: true).hex #=> 04D2
168
+ def hex(upper: false)
169
+ to_s(16).tap { _1.upcase! if upper }
170
+ end
171
+
172
+ # Returns a base-8 string of +self+. Equivalent to +to_s(8)+.
173
+ #
174
+ # === Example
175
+ # puts BitInt::U16.new(1234).oct #=> 02322
176
+ def oct
177
+ to_s(8)
178
+ end
179
+
180
+ # Returns a base-2 string of +self+. Equivalent to +to_s(2)+.
181
+ #
182
+ # === Example
183
+ # puts BitInt::U16.new(54321).bin #=> 0000010011010010
184
+ def bin
185
+ to_s(2)
186
+ end
187
+
188
+ # :section: Math
189
+
190
+ # Numerically negates +self+.
191
+ def -@ = self.class.new(-@int)
192
+
193
+ # Bitwise negates +self+.
194
+ def ~ = self.class.new(~@int)
195
+
196
+ # Compares +self+ to +rhs+.
197
+ def <=>(rhs) = rhs.respond_to?(:to_i) ? @int <=> (_ = rhs).to_i : nil
198
+
199
+ # Adds +self+ to +rhs+.
200
+ def +(rhs) = self.class.new(@int + rhs.to_i)
201
+
202
+ # Subtracts +rhs+ from +self+.
203
+ def -(rhs) = self.class.new(@int - rhs.to_i)
204
+
205
+ # Multiplies +self+ by +rhs+.
206
+ def *(rhs) = self.class.new(@int * rhs.to_i)
207
+
208
+ # Divides +self+ by +rhs+.
209
+ def /(rhs) = self.class.new(@int / rhs.to_i)
210
+
211
+ # Modulos +self+ by +rhs+.
212
+ def %(rhs) = self.class.new(@int % rhs.to_i)
213
+
214
+ # Raises +self+ to the +rhs+th power.
215
+ # Note that `Numeric` only defines `.to_int` (not `.to_i`)
216
+ def **(rhs) = self.class.new((@int ** rhs.to_i).to_int)
217
+
218
+ # Shifts +self+ left by +rhs+ bits.
219
+ def <<(rhs) = self.class.new(@int << rhs.to_i)
220
+
221
+ # Shifts +self+ right by +rhs+ bits.
222
+ def >>(rhs) = self.class.new(@int >> rhs.to_i)
223
+
224
+ # Bitwise ANDs +self+ and +rhs+.
225
+ def &(rhs) = self.class.new(@int & rhs.to_i)
226
+
227
+ # Bitwise ORs +self+ and +rhs+.
228
+ def |(rhs) = self.class.new(@int | rhs.to_i)
229
+
230
+ # Bitwise XORs +self+ and +rhs+.
231
+ def ^(rhs) = self.class.new(@int ^ rhs.to_i)
232
+
233
+ # :section:
234
+
235
+ # Returns whether +self+ is a positive integer. Zero is not positive.
236
+ def positive? = @int.positive?
237
+
238
+ # Return whether +self+ is a negative integer. Zero is not negative.
239
+ def negative? = @int.negative?
240
+
241
+ # Returns whether +self+ is zero.
242
+ def zero? = @int.zero?
243
+
244
+ # Returns a falsey value if zero, otherwise returns +self+.
245
+ def nonzero? = @int.nonzero? && self
246
+
247
+ # Checks to see if +self+ is even.
248
+ def even? = @int.even?
249
+
250
+ # Checks to see if +self+ is odd.
251
+ def odd? = @int.odd?
252
+
253
+ ##################################
254
+ # :section: Bit-level operations #
255
+ ##################################
256
+
257
+ # Gets the bit at index +idx+ or returns +nil+.
258
+ #
259
+ # This is equivalent to +Integer#[]+
260
+ def [](idx) = @int[idx]
261
+
262
+ def anybits?(mask) = @int.anybits?(mask)
263
+ def allbits?(mask) = @int.allbits?(mask)
264
+ def nobits?(mask) = @int.nobits?(mask)
265
+ def bit_length = @int.bit_length
266
+
267
+ def size = (self.class::BITS / 8.0).ceil
268
+
269
+
270
+ PACK_FMT = {
271
+ [:native, 8, false].freeze => 'C',
272
+ [:native, 16, false].freeze => 'S',
273
+ [:native, 32, false].freeze => 'L',
274
+ [:native, 64, false].freeze => 'Q',
275
+ [:native, 8, true].freeze => 'c',
276
+ [:native, 16, true].freeze => 's',
277
+ [:native, 32, true].freeze => 'l',
278
+ [:native, 64, true].freeze => 'q',
279
+
280
+ }.freeze
281
+ private_constant :PACK_FMT
282
+
283
+ def bytes(endian = :native)
284
+ size = {
285
+ 8 => 'C',
286
+ 16 => 'S',
287
+ 32 => 'L',
288
+ 64 => 'Q'
289
+ }[self.class::BITS] or raise ArgumentError, "bytes only works for 8, 16, 32, or 64 rn." or raise ArgumentError, "endian must be :big, :little, or :native"
290
+ size = {8=>'C', 16=>}
291
+ size = case self.class::BITS
292
+ when 8 then 'C'
293
+ when 8 then 'C'
294
+ # sprintf "%0#{self.class::BYTES * 2}x",
295
+ # mask = self.class::MASK_CHAR or raise ArgumentError, "bytes only works (rn) on "
296
+ # pack_char = self.class.pack_Char
297
+ # case endian
298
+ # when :native then
299
+ end
300
+ end
301
+
302
+
303
+ (-128..127).each do |n|
304
+ puts (BitInt::I(8).new(n)).to_s(2)
305
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BitInt
4
+ # An unsigned 8-bit integer
5
+ U8 = U(8)
6
+
7
+ # An unsigned 16-bit integer
8
+ U16 = U(16)
9
+
10
+ # An unsigned 32-bit integer
11
+ U32 = U(32)
12
+
13
+ # An unsigned 64-bit integer
14
+ U64 = U(64)
15
+
16
+ # An unsigned 128-bit integer
17
+ U128 = U(128)
18
+
19
+ # A signed 8-bit integer
20
+ I8 = I(8)
21
+
22
+ # A signed 16-bit integer
23
+ I16 = I(16)
24
+
25
+ # A signed 32-bit integer
26
+ I32 = I(32)
27
+
28
+ # A signed 64-bit integer
29
+ I64 = I(64)
30
+
31
+ # A signed 128-bit integer
32
+ I128 = I(128)
33
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fiddle'
4
+
5
+ class BitInt
6
+ # `BitInt`s that correspond to underlying C integer sizes.
7
+ module Native
8
+ # On big-endian systems, the unpack will equal `0x00AA`.
9
+ @little_endian = [0xAA00].pack('S').unpack('S<') == [0xAA00]
10
+
11
+ module_function
12
+
13
+ # Returns either `:little` or `:big` depending on the underlying system's endianness.
14
+ def endianness
15
+ @little_endian ? :little : :big
16
+ end
17
+ class << self
18
+ alias endian endianness
19
+ end
20
+
21
+ # Returns `true` when on a little endian system.
22
+ def little_endian?
23
+ endianness == :little
24
+ end
25
+
26
+ # Returns `true` when on a big endian system.
27
+ def big_endian?
28
+ endianness == :big
29
+ end
30
+
31
+ # A signed `sizeof(char)`-byte BitInt.
32
+ #
33
+ # Technically C has a difference between `char`, `unsigned char`, and `signed char`. But there's
34
+ # no real easy way to tell from within ruby code. So `CHAR` doesn't exist.
35
+ #
36
+ SCHAR = BitInt.create(bytes: Fiddle::SIZEOF_CHAR, signed: true)
37
+
38
+ # An unsigned `sizeof(char)`-byte BitInt.
39
+ UCHAR = BitInt.create(bytes: Fiddle::SIZEOF_CHAR, signed: false)
40
+
41
+ # A signed `sizeof(short)`-byte BitInt.
42
+ SHORT = BitInt.create(bytes: Fiddle::SIZEOF_SHORT, signed: true)
43
+
44
+ # An unsigned `sizeof(short)`-byte BitInt.
45
+ USHORT = BitInt.create(bytes: Fiddle::SIZEOF_SHORT, signed: false)
46
+
47
+ # A signed `sizeof(int)`-byte BitInt.
48
+ INT = BitInt.create(bytes: Fiddle::SIZEOF_INT, signed: true)
49
+
50
+ # An unsigned `sizeof(short)`-byte BitInt.
51
+ UINT = BitInt.create(bytes: Fiddle::SIZEOF_INT, signed: false)
52
+
53
+ # A signed `sizeof(long)`-byte BitInt.
54
+ LONG = BitInt.create(bytes: Fiddle::SIZEOF_LONG, signed: true)
55
+
56
+ # An unsigned `sizeof(short)`-byte BitInt.
57
+ ULONG = BitInt.create(bytes: Fiddle::SIZEOF_LONG, signed: false)
58
+
59
+ # Some platforms Ruby supports don't actually support `long long`s (in this day and age...)
60
+ if defined? Fiddle::SIZEOF_LONG_LONG
61
+ # A signed `sizeof(long long)`-byte BitInt. Only enabled if the platform supports `long long`.
62
+ LONG_LONG = BitInt.create(bytes: Fiddle::SIZEOF_LONG_LONG, signed: true)
63
+
64
+ # An unsigned `sizeof(long long)`-byte BitInt. Only enabled if the platform supports `long long`.
65
+ ULONG_LONG = BitInt.create(bytes: Fiddle::SIZEOF_LONG_LONG, signed: false)
66
+ end
67
+
68
+ # An unsigned `sizeof(void *)`-byte BitInt.
69
+ VOIDP = BitInt.create(bytes: Fiddle::SIZEOF_VOIDP, signed: false)
70
+
71
+ # An unsigned `sizeof(size_t)`-byte BitInt.
72
+ SIZE_T = BitInt.create(bytes: Fiddle::SIZEOF_SIZE_T, signed: false)
73
+
74
+ # A signed `sizeof(ssize_t)`-byte BitInt.
75
+ SSIZE_T = BitInt.create(bytes: Fiddle::SIZEOF_SSIZE_T, signed: true)
76
+
77
+ # A signed `sizeof(ptrdiff_t)`-byte BitInt.
78
+ PTRDIFF_T = BitInt.create(bytes: Fiddle::SIZEOF_PTRDIFF_T, signed: true)
79
+
80
+ # A signed `sizeof(intptr_t)`-byte BitInt.
81
+ INTPTR_T = BitInt.create(bytes: Fiddle::SIZEOF_INTPTR_T, signed: true)
82
+
83
+ # An unsigned `sizeof(uintptr_t)`-byte BitInt.
84
+ UINTPTR_T = BitInt.create(bytes: Fiddle::SIZEOF_UINTPTR_T, signed: false)
85
+ end
86
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BitInt
4
+ # Refinements to Integer for easy "BitInt literals" (eg `12.u8`)
5
+ module Refinements
6
+ refine Integer do
7
+ # Converts +self+ into an unsigned +bits+-bit integer.
8
+ #
9
+ # Any additional arguments are forwarded to +BitInt#new+
10
+ #
11
+ # === Examples
12
+ # puts BitInt::U(16)::MAX #=> 65535
13
+ #
14
+ def u(bits, ...)
15
+ BitInt::U(bits, ...).new(self)
16
+ end
17
+
18
+ # Converts +self+ into a signed +bits+-bit integer.
19
+ #
20
+ # If no arguments are given, this instead forwards to Numeric#i.
21
+ #
22
+ # Any additional arguments are forwarded to +BitInt#new+
23
+ def i(bits = nil, ...)
24
+ return super if bits.nil?
25
+
26
+ BitInt::i(bits, ...).new(self)
27
+ end
28
+
29
+ # Converts +self+ into an unsigned 8-bit integer.
30
+ #
31
+ # Any additional arguments are forwarded to +BitInt#new+
32
+ def u8(...)
33
+ u(8, ...)
34
+ end
35
+
36
+ # Converts +self+ into an unsigned 16-bit integer.
37
+ #
38
+ # Any additional arguments are forwarded to +BitInt#new+
39
+ def u16(...)
40
+ u(16, ...)
41
+ end
42
+
43
+ # Converts +self+ into an unsigned 32-bit integer.
44
+ #
45
+ # Any additional arguments are forwarded to +BitInt#new+
46
+ def u32(...)
47
+ u(32, ...)
48
+ end
49
+
50
+ # Converts +self+ into an unsigned 64-bit integer.
51
+ #
52
+ # Any additional arguments are forwarded to +BitInt#new+
53
+ def u64(...)
54
+ u(64, ...)
55
+ end
56
+
57
+ # Converts +self+ into an unsigned 128-bit integer.
58
+ #
59
+ # Any additional arguments are forwarded to +BitInt#new+
60
+ def u128(...)
61
+ u(128, ...)
62
+ end
63
+
64
+ # Converts +self+ into a signed 8-bit integer.
65
+ #
66
+ # Any additional arguments are forwarded to +BitInt#new+
67
+ def i8(...)
68
+ i(8, ...)
69
+ end
70
+
71
+ # Converts +self+ into a signed 16-bit integer.
72
+ #
73
+ # Any additional arguments are forwarded to +BitInt#new+
74
+ def i16(...)
75
+ i(16, ...)
76
+ end
77
+
78
+ # Converts +self+ into a signed 32-bit integer.
79
+ #
80
+ # Any additional arguments are forwarded to +BitInt#new+
81
+ def i32(...)
82
+ i(32, ...)
83
+ end
84
+
85
+ # Converts +self+ into a signed 64-bit integer.
86
+ #
87
+ # Any additional arguments are forwarded to +BitInt#new+
88
+ def i64(...)
89
+ i(64, ...)
90
+ end
91
+
92
+ # Converts +self+ into a signed 128-bit integer.
93
+ #
94
+ # Any additional arguments are forwarded to +BitInt#new+
95
+ def i128(...)
96
+ i(128, ...)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BitInt
4
+ # The current version of BitInt.
5
+ VERSION = '0.5.0'
6
+ end
data/lib/bitint.rb ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BitInt < Numeric
4
+ end
5
+
6
+ require_relative 'bitint/version'
7
+ require_relative 'bitint/bitint'
8
+ require_relative 'bitint/refinements'
9
+ require_relative 'bitint/native'
10
+ require_relative 'bitint/constants'
@@ -0,0 +1,62 @@
1
+ module BitInt
2
+ class OutOfBoundError < Error
3
+ attr_reader integer: Integer
4
+
5
+ attr_reader range: untyped
6
+
7
+ def initialize: (untyped integer, untyped range) -> void
8
+ end
9
+
10
+ class BitInt < Numeric
11
+ self.@bits: Integer
12
+ self.@signed: bool
13
+ MIN: instance
14
+ MAX: instance
15
+ BITS: Integer
16
+ MASK: Integer
17
+ ZERO: instance
18
+ ONE: instance
19
+
20
+ def self.in_bounds?: (Integer integer) -> bool
21
+ def self.U: (Integer bits) -> class
22
+ def self.I: (Integer bits) -> class
23
+ def self.[]: (Integer bits, ?signed: bool) -> class
24
+ def self.signed?: () -> bool
25
+ def self.unsigned?: () -> bool
26
+ def self.mask: (Integer int) -> untyped
27
+ def self.setup!: (Integer bits, bool signed) -> void
28
+ def self.inspect: () -> String
29
+ alias self.to_s self.inspect
30
+
31
+ @int: Integer
32
+ def initialize: (Integer int, ?wrap: bool) -> void
33
+ def ==: (Object rhs) -> bool
34
+
35
+ def to_i: () -> Integer
36
+ alias to_int to_i
37
+ def to_f: () -> Float
38
+ def to_s: (?Integer? base) -> String
39
+ alias inspect to_s
40
+
41
+ def hex: () -> String
42
+ def oct: () -> String
43
+ def bin: () -> String
44
+
45
+ def -@: () -> BitInt
46
+ def ~: () -> BitInt
47
+ def []: (int idx) -> Integer?
48
+ def <=>: (Object rhs) -> Integer?
49
+ def +: (_ToI rhs) -> BitInt
50
+ def -: (_ToI rhs) -> BitInt
51
+ def /: (_ToI rhs) -> BitInt
52
+ def *: (_ToI rhs) -> BitInt
53
+ def %: (_ToI rhs) -> BitInt
54
+ def **: (_ToI rhs) -> BitInt
55
+ def <<: (_ToI rhs) -> BitInt
56
+ def >>: (_ToI rhs) -> BitInt
57
+ def &: (_ToI rhs) -> BitInt
58
+ def |: (_ToI rhs) -> BitInt
59
+ def ^: (_ToI rhs) -> BitInt
60
+ def integer?: () -> true
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ module BitInt
2
+ class Error < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module BitInt
2
+ module Refinements
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module BitInt
2
+ VERSION: String
3
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bitint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Sam Westerman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-05-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - mail@sampersand.me
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rdoc_options"
21
+ - Gemfile
22
+ - LICENSE.txt
23
+ - README.md
24
+ - Rakefile
25
+ - Steepfile
26
+ - bin/console
27
+ - bin/setup
28
+ - lib/bitint.rb
29
+ - lib/bitint/bitint.rb
30
+ - lib/bitint/constants.rb
31
+ - lib/bitint/native.rb
32
+ - lib/bitint/refinements.rb
33
+ - lib/bitint/version.rb
34
+ - sig/bitint/bitint.rbs
35
+ - sig/bitint/error.rbs
36
+ - sig/bitint/refinements.rb
37
+ - sig/bitint/version.rbs
38
+ homepage: https://github.com/sampersand/bitint
39
+ licenses:
40
+ - MIT
41
+ metadata:
42
+ source_code_uri: https://github.com/sampersand/bitint
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 3.0.0
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.3.3
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: A 2's-complement integer of arbitrary length
62
+ test_files: []