bitint 0.6.1 → 0.7.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 +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +30 -0
- data/Steepfile +3 -3
- data/lib/bitint/base.rb +552 -0
- data/lib/bitint/bitint.rb +33 -300
- data/lib/bitint/constants.rb +18 -2
- data/lib/bitint/native.rb +99 -43
- data/lib/bitint/overflow_error.rb +15 -0
- data/lib/bitint/refinements.rb +17 -16
- data/lib/bitint/version.rb +3 -2
- data/lib/bitint.rb +3 -1
- data/sig/{bitint/version.rbs → bitint.rbs} +0 -1
- data/sig/generated/bitint/base.rbs +422 -0
- data/sig/generated/bitint/bitint.rbs +51 -0
- data/sig/generated/bitint/constants.rbs +33 -0
- data/sig/generated/bitint/native.rbs +74 -0
- data/sig/generated/bitint/overflow_error.rbs +12 -0
- data/sig/generated/bitint/refinements.rbs +72 -0
- data/sig/generated/bitint/version.rbs +6 -0
- metadata +14 -11
- data/sig/bitint/bitint.rbs +0 -62
- data/sig/bitint/error.rbs +0 -4
- data/sig/bitint/refinements.rb +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c40be3354b42569bfb904d8dbbe9306f8f706688fd36264554cf8f872816af5b
|
|
4
|
+
data.tar.gz: d49b4008e93fdba7bbe61e55cdea7a8b4c67c8ce3fe72acfca78bbb2e7ea5838
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21eec32c4ee6bd2d0d0653d7301b3167d291493dc787e6cb2ace1c823560706745917dafe8dd535dca62471001cac012ed46fc7c415cbe03337e7c975f7d3618
|
|
7
|
+
data.tar.gz: 21df6c3d3736745f52990347c6be33b40a2b520f86949bb75fb8f54c0ecdf9aa25b51bdd2bee98a3b53ed5818102e4e46ae58be6b8c3998cb1107c733a862575
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
bitint (0.7.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
logger (1.7.0)
|
|
10
|
+
minitest (5.26.0)
|
|
11
|
+
prism (1.6.0)
|
|
12
|
+
rake (13.3.0)
|
|
13
|
+
rbs (3.9.5)
|
|
14
|
+
logger
|
|
15
|
+
rbs-inline (0.12.0)
|
|
16
|
+
prism (>= 0.29)
|
|
17
|
+
rbs (>= 3.8.0)
|
|
18
|
+
|
|
19
|
+
PLATFORMS
|
|
20
|
+
arm64-darwin-23
|
|
21
|
+
ruby
|
|
22
|
+
|
|
23
|
+
DEPENDENCIES
|
|
24
|
+
bitint!
|
|
25
|
+
minitest (~> 5.0)
|
|
26
|
+
rake (~> 13.0)
|
|
27
|
+
rbs-inline (~> 0.12.0)
|
|
28
|
+
|
|
29
|
+
BUNDLED WITH
|
|
30
|
+
2.7.0.dev
|
data/Steepfile
CHANGED
|
@@ -3,11 +3,11 @@ D = Steep::Diagnostic
|
|
|
3
3
|
target :lib do
|
|
4
4
|
signature "sig"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
check "lib/bitint/bitint.rb"
|
|
6
|
+
check "lib" # Directory name
|
|
7
|
+
# check "lib/bitint/bitint.rb"
|
|
8
8
|
# check "Gemfile" # File name
|
|
9
|
-
check "app/models/**/*.rb" # Glob
|
|
10
9
|
# ignore "lib/templates/*.rb"
|
|
10
|
+
ignore 'lib/bitint/refinements.rb'
|
|
11
11
|
|
|
12
12
|
# library "pathname", "set" # Standard libraries
|
|
13
13
|
# library "strong_json" # Gems
|
data/lib/bitint/base.rb
ADDED
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module BitInt
|
|
5
|
+
# @abstract Subclasses must be created via `Base.create`
|
|
6
|
+
class Base < Numeric
|
|
7
|
+
# :stopdoc:
|
|
8
|
+
# List of classes; used in `create` to ensure duplicate classes for bits and signed-ness aren't created
|
|
9
|
+
@classes = {} #: Hash[[Integer, bool], Class]
|
|
10
|
+
# :startdoc:
|
|
11
|
+
|
|
12
|
+
# @rbs self.@classes: Hash[[Integer, bool], Class]
|
|
13
|
+
# @rbs self.@bits: Integer
|
|
14
|
+
# @rbs self.@signed: bool
|
|
15
|
+
# @rbs @wrap: bool
|
|
16
|
+
# @rbs @int: Integer
|
|
17
|
+
|
|
18
|
+
# @rbs!
|
|
19
|
+
# BITS: Integer
|
|
20
|
+
# BYTES: Integer
|
|
21
|
+
# MASK: Integer
|
|
22
|
+
# ZERO: Base
|
|
23
|
+
# ONE: Base
|
|
24
|
+
# MIN: Base
|
|
25
|
+
# MAX: Base
|
|
26
|
+
# BOUNDS: Range[Base]
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
|
|
30
|
+
# Creates a new {BitInt::Base} subclass.
|
|
31
|
+
#
|
|
32
|
+
# @param bits [Integer?] the amount of bits the subclass should have. Must be at least +1+.
|
|
33
|
+
# @param bytes [Integer?] convenience argument; if supplied, sets +bits+ to +bytes * 8+. Cannot be used with +bits+
|
|
34
|
+
# @param signed [bool] Whether the subclass is a signed.
|
|
35
|
+
#
|
|
36
|
+
# @return [singleton(Base)] A subclass of {BitInt::Base}; subclasses are cached, so repeated calls return the same subclass.
|
|
37
|
+
#
|
|
38
|
+
# @raise [ArgumentError] When +bits+ is negative or zero
|
|
39
|
+
# @raise [ArgumentError] If both +bits+ and +bytes+ are supplied
|
|
40
|
+
#
|
|
41
|
+
# === Example
|
|
42
|
+
# puts BitInt::Base.create(bits: 8, signed: true).new(128) #=> -127
|
|
43
|
+
# puts BitInt::Base.create(bytes: 1, signed: false).new(256) #=> 0
|
|
44
|
+
#
|
|
45
|
+
# @rbs (bits: Integer, signed: bool) -> untyped
|
|
46
|
+
# | (bytes: Integer, signed: bool) -> untyped
|
|
47
|
+
def create(bits: nil, bytes: nil, signed:)
|
|
48
|
+
if bits.nil? == bytes.nil?
|
|
49
|
+
raise ArgumentError, "exactly one of 'bits' or 'bytes' must be supplied", caller(1)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
bits ||= (_ = bytes) * 8
|
|
53
|
+
|
|
54
|
+
unless bits.positive?
|
|
55
|
+
raise ArgumentError, 'bit count must be positive', caller(1)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
key = [bits, signed].freeze #: [Integer, bool]
|
|
59
|
+
@classes[key] ||= Class.new(Base) do |cls|
|
|
60
|
+
(_ = cls).setup!(bits, signed)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# :stopdoc:
|
|
65
|
+
# @rbs (Integer, bool) -> void
|
|
66
|
+
protected def setup!(bits, signed)
|
|
67
|
+
@bits = bits
|
|
68
|
+
@signed = signed
|
|
69
|
+
|
|
70
|
+
create = ->(int) {
|
|
71
|
+
allocate.tap { |x| x.instance_variable_set :@int, int }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class << self
|
|
75
|
+
public :new
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
const_set :BITS, @bits
|
|
79
|
+
const_set :BYTES, (@bits / 8.0).ceil
|
|
80
|
+
const_set :MASK, (1 << @bits).pred
|
|
81
|
+
const_set :ZERO, create[0]
|
|
82
|
+
const_set :ONE, create[1]
|
|
83
|
+
const_set :MIN, create[signed? ? -(1 << @bits.pred) : 0]
|
|
84
|
+
const_set :MAX, create[signed? ? (1 << @bits.pred).pred : (1 << @bits).pred]
|
|
85
|
+
const_set :BOUNDS, self::MIN .. self::MAX
|
|
86
|
+
end
|
|
87
|
+
# :startdoc:
|
|
88
|
+
|
|
89
|
+
# Returns whether this class represents a signed integer.
|
|
90
|
+
#
|
|
91
|
+
# @abstract Only defined on subclasses
|
|
92
|
+
#
|
|
93
|
+
# === Example
|
|
94
|
+
# puts BitInt::U8.signed? #=> false
|
|
95
|
+
# puts BitInt::I8.signed? #=> true
|
|
96
|
+
#
|
|
97
|
+
# @rbs () -> bool
|
|
98
|
+
def signed? = @signed
|
|
99
|
+
|
|
100
|
+
# Returns whether this class represents an unsigned integer.
|
|
101
|
+
#
|
|
102
|
+
# @abstract Only defined on subclasses
|
|
103
|
+
#
|
|
104
|
+
# === Example
|
|
105
|
+
# puts BitInt::U8.unsigned? #=> true
|
|
106
|
+
# puts BitInt::I8.unsigned? #=> false
|
|
107
|
+
#
|
|
108
|
+
# @rbs () -> bool
|
|
109
|
+
def unsigned? = !signed?
|
|
110
|
+
|
|
111
|
+
# Returns a debugging string representation of this class
|
|
112
|
+
#
|
|
113
|
+
# If the class is one of the builtins (eg +BitInt::U16+), it uses its name
|
|
114
|
+
# as the string, otherwise it uses a debugging representation
|
|
115
|
+
#
|
|
116
|
+
# === Example
|
|
117
|
+
# p BitInt::U16 #=> BitInt::U16
|
|
118
|
+
# p BitInt::U(17) #=> #<BitInt::Base @bits=17 @signed=false>
|
|
119
|
+
#
|
|
120
|
+
# @rbs () -> String
|
|
121
|
+
def inspect = name || "#<BitInt::Base @bits=#@bits @signed=#@signed>"
|
|
122
|
+
alias to_s inspect
|
|
123
|
+
|
|
124
|
+
# Wraps an +integer+ to be within the bounds of +self+
|
|
125
|
+
#
|
|
126
|
+
# @param integer [Integer] the integer to wrap
|
|
127
|
+
# @return [Integer] an integer guaranteed to be within +self::BOUNDS+.
|
|
128
|
+
#
|
|
129
|
+
# @abstract Only defined on subclasses
|
|
130
|
+
#
|
|
131
|
+
# === Example
|
|
132
|
+
# puts BitInt::I8.wrap(127) #=> 127
|
|
133
|
+
# puts BitInt::I8.wrap(128) #=> -128
|
|
134
|
+
# puts BitInt::I8.wrap(0xFF_FF_FF_FF_FF) #=> -1
|
|
135
|
+
#
|
|
136
|
+
# @rbs (Integer) -> Integer
|
|
137
|
+
def wrap(integer)
|
|
138
|
+
((integer - self::MIN.to_i) & self::MASK) + self::MIN.to_i
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Check to see if +integer+ is in bounds for +self+
|
|
142
|
+
#
|
|
143
|
+
# @abstract Only defined on subclasses
|
|
144
|
+
#
|
|
145
|
+
# @param integer [Integer] the integer to check
|
|
146
|
+
# @return [bool] whether the integer is in bounds
|
|
147
|
+
#
|
|
148
|
+
# === Example
|
|
149
|
+
# puts BitInt::I16.in_bounds?(32767) #=> true
|
|
150
|
+
# puts BitInt::I16.in_bounds?(32768) #=> false
|
|
151
|
+
# puts BitInt::U32.in_bounds?(-1) #=> false
|
|
152
|
+
#
|
|
153
|
+
# @rbs (Integer) -> bool
|
|
154
|
+
def in_bounds?(integer)
|
|
155
|
+
# TODO: use `self::BOUNDS`
|
|
156
|
+
(self::MIN.to_i .. self::MAX.to_i).include? integer
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Creates a new instance with the +integer+.
|
|
161
|
+
#
|
|
162
|
+
# @param integer [Integer] the integer to use
|
|
163
|
+
# @param wrap [bool] changes how {Base.in_bounds? out-of-bounds} integers are handled. When true,
|
|
164
|
+
# they're {Base.wrap wrapped}; when false, an +OverflowError+ to be raised.
|
|
165
|
+
# @raise [OverflowError] raised when +wrap+ is +false+ and +integer+ is out of bounds.
|
|
166
|
+
#
|
|
167
|
+
# === Example
|
|
168
|
+
# puts BitInt::U8.new(27) #=> 27
|
|
169
|
+
# puts BitInt::U8.new(-1) #=> 255
|
|
170
|
+
# puts BitInt::U8.new(-1, wrap: false) #=> OverflowError
|
|
171
|
+
# puts BitInt::I8.new(255) #=> -1
|
|
172
|
+
#
|
|
173
|
+
# @rbs (Integer, ?wrap: boolish) -> void
|
|
174
|
+
def initialize(integer, wrap: true)
|
|
175
|
+
unless wrap || self.class.in_bounds?(integer)
|
|
176
|
+
exc = OverflowError.new(integer, self.class::BOUNDS)
|
|
177
|
+
exc.set_backtrace(
|
|
178
|
+
caller_locations(1) #: Array[Thread::Backtrace::Location]
|
|
179
|
+
)
|
|
180
|
+
raise exc
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
@int = self.class.wrap(integer)
|
|
184
|
+
@wrap = wrap
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
################################################################################################
|
|
188
|
+
# Conversions #
|
|
189
|
+
################################################################################################
|
|
190
|
+
|
|
191
|
+
# :section: Conversions
|
|
192
|
+
|
|
193
|
+
# Returns the underlying integer.
|
|
194
|
+
#
|
|
195
|
+
# @rbs () -> Integer
|
|
196
|
+
def to_i = @int
|
|
197
|
+
alias to_int to_i
|
|
198
|
+
|
|
199
|
+
# Converts +self+ to a +Float+.
|
|
200
|
+
#
|
|
201
|
+
# @rbs () -> Float
|
|
202
|
+
def to_f = @int.to_f
|
|
203
|
+
|
|
204
|
+
# Converts +self+ to a +Rational+.
|
|
205
|
+
#
|
|
206
|
+
# @rbs () -> Rational
|
|
207
|
+
def to_r = @int.to_r
|
|
208
|
+
|
|
209
|
+
# (no need for `.to_c` as `Numeric` defines it)
|
|
210
|
+
|
|
211
|
+
# Converts +self+ to a +String+.
|
|
212
|
+
#
|
|
213
|
+
# If no +base+ is given, it just returns a normal String in base 10.
|
|
214
|
+
# If a base is given, a string padded with `0`s will be returned.
|
|
215
|
+
#
|
|
216
|
+
# === Examples
|
|
217
|
+
# puts BitInt::U16.new(1234).to_s #=> 1234
|
|
218
|
+
# puts BitInt::U16.new(1234).to_s(16) #=> 04d2
|
|
219
|
+
#
|
|
220
|
+
# @rbs (?int? base) -> String
|
|
221
|
+
def to_s(base = nil)
|
|
222
|
+
return @int.to_s unless base
|
|
223
|
+
base = base.to_int
|
|
224
|
+
|
|
225
|
+
adjusted = negative? ? (-2*self.class::MIN.to_i + @int).to_i : @int
|
|
226
|
+
adjusted.to_s(base).rjust(self.class::BITS / Math.log2(base), negative? ? '1' : '0')
|
|
227
|
+
end
|
|
228
|
+
alias inspect to_s
|
|
229
|
+
|
|
230
|
+
# Returns a base-16 string of +self+. Equivalent to +to_s(16)+.
|
|
231
|
+
#
|
|
232
|
+
# If +upper: true+ is passed, returns an upper-case version.
|
|
233
|
+
#
|
|
234
|
+
# === Examples
|
|
235
|
+
# puts BitInt::U16.new(1234).hex #=> 04d2
|
|
236
|
+
# puts BitInt::U16.new(1234, upper: true).hex #=> 04D2
|
|
237
|
+
#
|
|
238
|
+
# @rbs (?upper: boolish) -> String
|
|
239
|
+
def hex(upper: false) = to_s(16).tap { _1.upcase! if upper }
|
|
240
|
+
|
|
241
|
+
# Returns a base-8 string of +self+. Equivalent to +to_s(8)+.
|
|
242
|
+
#
|
|
243
|
+
# === Example
|
|
244
|
+
# puts BitInt::U16.new(12345).oct #=> 30071
|
|
245
|
+
#
|
|
246
|
+
# @rbs () -> String
|
|
247
|
+
def oct = to_s(8)
|
|
248
|
+
|
|
249
|
+
# Returns a base-2 string of +self+. Equivalent to +to_s(2)+.
|
|
250
|
+
#
|
|
251
|
+
# === Example
|
|
252
|
+
# puts BitInt::U16.new(54321).bin #=> 0000010011010010
|
|
253
|
+
#
|
|
254
|
+
# @rbs () -> String
|
|
255
|
+
def bin = to_s(2)
|
|
256
|
+
|
|
257
|
+
# Converts +other+ to an instance of +self+, and returns a tuple of +[<converted>, self]+
|
|
258
|
+
#
|
|
259
|
+
# @rbs (int) -> [instance, self]
|
|
260
|
+
def coerce(other) = [new_instance(other.to_int), self]
|
|
261
|
+
|
|
262
|
+
################################################################################################
|
|
263
|
+
# ... #
|
|
264
|
+
################################################################################################
|
|
265
|
+
|
|
266
|
+
# Checks to see if +rhs+ is equal to +selF+
|
|
267
|
+
#
|
|
268
|
+
# === Example
|
|
269
|
+
# U64 = BitInt::U(64)
|
|
270
|
+
# twelve = U64.new(12)
|
|
271
|
+
#
|
|
272
|
+
# # Behaves as you'd expect.
|
|
273
|
+
# puts twelve == U64.new(12) #=> true
|
|
274
|
+
# puts twelve == U64.new(13) #=> false
|
|
275
|
+
# puts twelve == 12 #=> true
|
|
276
|
+
# puts twelve == 12.0 #=> true
|
|
277
|
+
# puts twelve == 13 #=> false
|
|
278
|
+
# puts twelve == Object.new #=> false
|
|
279
|
+
#
|
|
280
|
+
# @rbs (untyped) -> boolish
|
|
281
|
+
def ==(rhs)
|
|
282
|
+
defined?(rhs.to_i) && @int == rhs.to_i
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Checks to see if +rhs+ is another +BitInt::Base+ of the same class, and
|
|
286
|
+
# have the same contents.
|
|
287
|
+
#
|
|
288
|
+
# @rbs (untyped) -> bool
|
|
289
|
+
def eql?(rhs)
|
|
290
|
+
rhs.is_a?(self.class) && @int == rhs.to_i
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Returns a hash code for this class.
|
|
294
|
+
#
|
|
295
|
+
# @rbs () -> Integer
|
|
296
|
+
def hash = [self.class, @int].hash
|
|
297
|
+
|
|
298
|
+
# Always return +true+, as +BitInt::Base+s are always integers.
|
|
299
|
+
#
|
|
300
|
+
# @rbs () -> true
|
|
301
|
+
def integer? = true
|
|
302
|
+
|
|
303
|
+
# @rbs (Integer, ?wrap: bool) -> instance
|
|
304
|
+
private def new_instance(int, wrap: @wrap) = self.class.new(int, wrap:)
|
|
305
|
+
|
|
306
|
+
################################################################################################
|
|
307
|
+
# Math #
|
|
308
|
+
################################################################################################
|
|
309
|
+
|
|
310
|
+
# Numerically negates +self+.
|
|
311
|
+
#
|
|
312
|
+
# @rbs () -> instance
|
|
313
|
+
def -@ = new_instance(-@int)
|
|
314
|
+
|
|
315
|
+
# Compares +self+ to +rhs+.
|
|
316
|
+
#
|
|
317
|
+
# @rbs (_ToI) -> (-1 | 0 | 1)
|
|
318
|
+
# | (untyped) -> Integer?
|
|
319
|
+
def <=>(rhs) = defined?(rhs.to_i) ? @int <=> (_ = rhs).to_i : nil
|
|
320
|
+
|
|
321
|
+
# Adds +self+ to +rhs+.
|
|
322
|
+
#
|
|
323
|
+
# @rbs (int) -> instance
|
|
324
|
+
def +(rhs) = new_instance(@int + rhs.to_int)
|
|
325
|
+
|
|
326
|
+
# Subtracts +rhs+ from +self+.
|
|
327
|
+
#
|
|
328
|
+
# @rbs (int) -> instance
|
|
329
|
+
def -(rhs) = new_instance(@int - rhs.to_int)
|
|
330
|
+
|
|
331
|
+
# Multiplies +self+ by +rhs+.
|
|
332
|
+
#
|
|
333
|
+
# @rbs (int) -> instance
|
|
334
|
+
def *(rhs) = new_instance(@int * rhs.to_int)
|
|
335
|
+
|
|
336
|
+
# Divides +self+ by +rhs+.
|
|
337
|
+
#
|
|
338
|
+
# @rbs (int) -> instance
|
|
339
|
+
def /(rhs) = new_instance(@int / rhs.to_int)
|
|
340
|
+
|
|
341
|
+
# Modulos +self+ by +rhs+.
|
|
342
|
+
#
|
|
343
|
+
# @rbs (int) -> instance
|
|
344
|
+
def %(rhs) = new_instance(@int % rhs.to_int)
|
|
345
|
+
|
|
346
|
+
# Raises +self+ to the +rhs+th power.
|
|
347
|
+
#
|
|
348
|
+
# @rbs (int) -> instance
|
|
349
|
+
def **(rhs) = new_instance((@int ** rhs.to_int).to_int) # TODO: use `Integer#pow(int, int)`
|
|
350
|
+
|
|
351
|
+
# :section:
|
|
352
|
+
|
|
353
|
+
# Returns whether +self+ is a positive integer. Zero is not positive.
|
|
354
|
+
#
|
|
355
|
+
# @rbs () -> bool
|
|
356
|
+
def positive? = @int.positive?
|
|
357
|
+
|
|
358
|
+
# Return whether +self+ is a negative integer. Zero is not negative.
|
|
359
|
+
#
|
|
360
|
+
# @rbs () -> bool
|
|
361
|
+
def negative? = @int.negative?
|
|
362
|
+
|
|
363
|
+
# Returns whether +self+ is zero.
|
|
364
|
+
#
|
|
365
|
+
# @rbs () -> bool
|
|
366
|
+
def zero? = @int.zero?
|
|
367
|
+
|
|
368
|
+
# Returns a falsey value if zero, otherwise returns +self+.
|
|
369
|
+
#
|
|
370
|
+
# @rbs () -> self?
|
|
371
|
+
def nonzero? = @int.nonzero? && self
|
|
372
|
+
|
|
373
|
+
# Checks to see if +self+ is even.
|
|
374
|
+
#
|
|
375
|
+
# @rbs () -> bool
|
|
376
|
+
def even? = @int.even?
|
|
377
|
+
|
|
378
|
+
# Checks to see if +self+ is odd.
|
|
379
|
+
#
|
|
380
|
+
# @rbs () -> bool
|
|
381
|
+
def odd? = @int.odd?
|
|
382
|
+
|
|
383
|
+
# Same as +Integer#times+, but returns instances of +self+.
|
|
384
|
+
#
|
|
385
|
+
# @rbs () -> Enumerator[instance, self]
|
|
386
|
+
# | () { (instance) -> void } -> self
|
|
387
|
+
def times
|
|
388
|
+
return to_enum(_ = __method__) unless block_given?
|
|
389
|
+
|
|
390
|
+
@int.times do |int|
|
|
391
|
+
yield new_instance int
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
self
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Same as +Integer#downto+, but returns instances of +self+.
|
|
398
|
+
#
|
|
399
|
+
# @rbs (Numeric) -> Enumerator[instance, self]
|
|
400
|
+
# | (Numeric) { (instance) -> void } -> self
|
|
401
|
+
def downto(what)
|
|
402
|
+
return to_enum(_ = __method__) unless block_given?
|
|
403
|
+
|
|
404
|
+
@int.downto what do |int|
|
|
405
|
+
yield new_instance int
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
self
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Same as +Integer#downto+, but returns instances of +self+.
|
|
412
|
+
#
|
|
413
|
+
# @rbs (Numeric) -> Enumerator[instance, self]
|
|
414
|
+
# | (Numeric) { (instance) -> void } -> self
|
|
415
|
+
def upto(what)
|
|
416
|
+
return to_enum(_ = __method__) unless block_given?
|
|
417
|
+
|
|
418
|
+
@int.upto what do |int|
|
|
419
|
+
yield new_instance int
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
self
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Gets the next value, or throws a {OverFlowError} if at the top.
|
|
426
|
+
#
|
|
427
|
+
# @rbs () -> instance
|
|
428
|
+
def succ
|
|
429
|
+
# TODO: this changes `@wrap`; that's weird
|
|
430
|
+
new_instance(@int + 1, wrap: false)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
# Gets the next value, or throws a {OverFlowError} if at the top.
|
|
434
|
+
#
|
|
435
|
+
# @rbs () -> instance
|
|
436
|
+
def pred
|
|
437
|
+
# TODO: this changes `@wrap`; that's weird
|
|
438
|
+
new_instance(@int - 1, wrap: false)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
## TODO: SUCC
|
|
442
|
+
|
|
443
|
+
################################################################################################
|
|
444
|
+
# Bitwise Methods #
|
|
445
|
+
################################################################################################
|
|
446
|
+
|
|
447
|
+
# Bitwise negates +self+.
|
|
448
|
+
#
|
|
449
|
+
# @rbs () -> instance
|
|
450
|
+
def ~ = new_instance(~@int)
|
|
451
|
+
|
|
452
|
+
# Shifts +self+ left by +rhs+ bits.
|
|
453
|
+
#
|
|
454
|
+
# @rbs (int) -> instance
|
|
455
|
+
def <<(rhs) = new_instance(@int << rhs.to_int)
|
|
456
|
+
|
|
457
|
+
# Shifts +self+ right by +rhs+ bits.
|
|
458
|
+
#
|
|
459
|
+
# @rbs (int) -> instance
|
|
460
|
+
def >>(rhs) = new_instance(@int >> rhs.to_int)
|
|
461
|
+
|
|
462
|
+
# Bitwise ANDs +self+ and +rhs+.
|
|
463
|
+
#
|
|
464
|
+
# @rbs (int) -> instance
|
|
465
|
+
def &(rhs) = new_instance(@int & rhs.to_int)
|
|
466
|
+
|
|
467
|
+
# Bitwise ORs +self+ and +rhs+.
|
|
468
|
+
#
|
|
469
|
+
# @rbs (int) -> instance
|
|
470
|
+
def |(rhs) = new_instance(@int | rhs.to_int)
|
|
471
|
+
|
|
472
|
+
# Bitwise XORs +self+ and +rhs+.
|
|
473
|
+
#
|
|
474
|
+
# @rbs (int) -> instance
|
|
475
|
+
def ^(rhs) = new_instance(@int ^ rhs.to_int)
|
|
476
|
+
|
|
477
|
+
# Gets the bit at index +idx+ or returns +nil+.
|
|
478
|
+
#
|
|
479
|
+
# This is equivalent to +Integer#[]+
|
|
480
|
+
# @rbs (int, ?int) -> Integer?
|
|
481
|
+
# | (range[int]) -> Integer?
|
|
482
|
+
def [](...) = __skip__ = @int.[](...)
|
|
483
|
+
|
|
484
|
+
# Returns true if any bit in `mask` is set in +self+.
|
|
485
|
+
#
|
|
486
|
+
# @rbs (int) -> bool
|
|
487
|
+
def anybits?(mask) = @int.anybits?(mask)
|
|
488
|
+
|
|
489
|
+
# Returns true if all bits in `mask` are set in +self+.
|
|
490
|
+
#
|
|
491
|
+
# @rbs (int) -> bool
|
|
492
|
+
def allbits?(mask) = @int.allbits?(mask)
|
|
493
|
+
|
|
494
|
+
# Returns true if no bits in `mask` are set in +self+.
|
|
495
|
+
#
|
|
496
|
+
# @rbs (int) -> bool
|
|
497
|
+
def nobits?(mask) = @int.nobits?(mask)
|
|
498
|
+
|
|
499
|
+
# Returns the amount of bits required to represent +self+
|
|
500
|
+
#
|
|
501
|
+
# Unlike +Integer#bit_length+, this never changes and is equivalent
|
|
502
|
+
# to +self.class::BITS+.
|
|
503
|
+
#
|
|
504
|
+
# @rbs () -> Integer
|
|
505
|
+
def bit_length = self.class::BITS
|
|
506
|
+
|
|
507
|
+
# Returns the amount of bytes required to represent +self+
|
|
508
|
+
#
|
|
509
|
+
# This is equivalent to +self.class::BYTES+
|
|
510
|
+
#
|
|
511
|
+
# @rbs () -> Integer
|
|
512
|
+
def byte_length = self.class::BYTES
|
|
513
|
+
|
|
514
|
+
# Returns all the bytes that're used represent +self+
|
|
515
|
+
#
|
|
516
|
+
# @rbs (?:native | :big | :little) -> Array[U8]
|
|
517
|
+
def bytes(endian = :native)
|
|
518
|
+
each_byte(endian).to_a
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# Executes the block once for each byte in +self+.
|
|
522
|
+
#
|
|
523
|
+
# Bytes are converted to +U8+. If no block is given, returns an +Enumerator+
|
|
524
|
+
#
|
|
525
|
+
# @rbs (?:native | :big | :little) { (U8) -> void } -> self
|
|
526
|
+
# | (?:native | :big | :little) -> Enumerator[U8, self]
|
|
527
|
+
def each_byte(endian = :native)
|
|
528
|
+
return to_enum(_ = __method__, endian) unless block_given?
|
|
529
|
+
|
|
530
|
+
template = '_CS_L___Q'[self.class::BYTES]
|
|
531
|
+
if template.nil? || template == '_'
|
|
532
|
+
raise ArgumentError, 'bytes only works for sizes of 8, 16, 32, or 64.'
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
template.downcase! if self.class.signed?
|
|
536
|
+
|
|
537
|
+
case endian
|
|
538
|
+
when :native then # do nothing
|
|
539
|
+
when :little then template.concat '<' unless self.class::BYTES == 1
|
|
540
|
+
when :big then template.concat '>' unless self.class::BYTES == 1
|
|
541
|
+
else
|
|
542
|
+
raise ArgumentError, 'endian must be :big, :little, or :native'
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
[@int].pack(template).unpack('C*').each do |byte| #: Integer
|
|
546
|
+
yield U8.new(byte)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
self
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
end
|