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 +7 -0
- data/.rdoc_options +1 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +12 -0
- data/Steepfile +28 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/bitint/bitint.rb +305 -0
- data/lib/bitint/constants.rb +33 -0
- data/lib/bitint/native.rb +86 -0
- data/lib/bitint/refinements.rb +100 -0
- data/lib/bitint/version.rb +6 -0
- data/lib/bitint.rb +10 -0
- data/sig/bitint/bitint.rbs +62 -0
- data/sig/bitint/error.rbs +4 -0
- data/sig/bitint/refinements.rb +4 -0
- data/sig/bitint/version.rbs +3 -0
- metadata +62 -0
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
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
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,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
|
data/lib/bitint.rb
ADDED
@@ -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
|
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: []
|