Skip to content

Instantly share code, notes, and snippets.

@rklemme
Created February 20, 2010 14:19
Show Gist options
  • Save rklemme/309694 to your computer and use it in GitHub Desktop.
Save rklemme/309694 to your computer and use it in GitHub Desktop.
class HexNum < Numeric
# Create a new instance from an int or String.
def initialize(val)
case val
when String
@i = parse_string(val)
@s = val.frozen? ? val : val.dup.freeze
when Numeric
@i = val.to_i
else
raise ArgumentError, 'Cannot convert %p' % val
end
end
# conversions
def to_s
@s ||= (@i < 0 ? '-0x%x' % -@i : '0x%x' % @i).freeze
end
def to_i
@i
end
alias to_int to_i
def to_hex
self
end
# equivalence
def eql?(num)
self.class.equal?(num.class) && @i == num.to_i
end
alias == eql?
# hash code calculation
def hash
@i.hash
end
# various tests that Fixnum also has
def zero?
@i.zero?
end
def nonzero?
@i.nonzero?
end
def odd?
@i.odd?
end
def even?
@i.even?
end
def between?(a, b)
@i.between? a, b
end
def integer?
true
end
def real?
true
end
# coercion
def coerce(o)
[HexNum.new(o.to_int), self]
end
# comparability
include Comparable
def <=>(o)
case o
when HexNum
@i <=> o.to_i
when Numeric
@i <=> o
else
a, b = o.coerce(self)
a <=> b
end rescue nil
end
# unary operators
def +@
self
end
def -@
HexNum.new(-@i)
end
# binary operators
def +(o)
op(:+, o)
end
def -(o)
op(:-, o)
end
def *(o)
op(:*, o)
end
def /(o)
op(:/, o)
end
# asymmetric binary operators
def **(o)
op(:**, o)
end
def <<(o)
HexNum.new(@i << o.to_int)
end
def >>(o)
HexNum.new(@i >> o.to_int)
end
# bit operators
def &(o)
HexNum.new(@i & o.to_int)
end
def |(o)
HexNum.new(@i | o.to_int)
end
# freeze
def freeze
to_s
super
end
private
# Parse a string with valid format (0x1234).
def parse_string(str)
if %r{\A[-+]?(?:0x)?[a-h0-9]+\z}i =~ str
str.to_i(16)
else
raise ArgumentError, 'Cannot parse %p' % str
end
end
# generic operator implementation
def op(sym, o)
case o
when HexNum
HexNum.new(@i.send(sym, o.to_i))
when Numeric
HexNum.new(@i.send(sym, o))
else
a, b = o.coerce(self)
a.send(sym, b)
end
end
end
# more conversions
def HexNum(i)
HexNum.new(Integer(i))
end
class Object
def to_hex
HexNum.new(to_i)
end
end
# ===== Test Code ===================================================
h1 = HexNum.new 83
h2 = 83.to_hex
printf "%-30s %p\n", 'h1 = HexNum.new 83', h1
printf "%-30s %p\n", 'h1.to_i', h1.to_i
printf "%-30s %p\n", 'h2 = 83.to_hex', h2
printf "%-30s %p\n", 'h2.to_int', h2.to_int
printf "%-30s %p\n", 'h1 == h2', h1 == h2
printf "%-30s %p\n", 'h2.eql? h1', h2.eql?(h1)
# printf "%-30s %p\n", 'h1.odd?', h1.odd?
printf "%-30s %p\n", 'h1 <=> h2', h1 <=> h2
h3 = h1 + 17
h4 = 17 + h2
printf "%-30s %p\n", 'h3 = h1 + 17', h3
printf "%-30s %p\n", 'h4 = 17 + h1', h4
printf "%-30s %p\n", 'h1 < h3', h1 < h3
printf "%-30s %p\n", 'h2 >= h4', h2 >= h4
h5 = -h1
printf "%-30s %p\n", 'negated', h5
printf "%-30s %p\n", 'neg sum', h5 + h2
printf "%-30s %p\n", 'h1 / 1.2', h1 / 1.2
printf "%-30s %p\n", 'h3 / h1', h3 / h1
ha = (1..10).map { HexNum(rand(100)) }
printf "%-30s %p\n", 'random array', ha.map {|h| h.to_s}
printf "%-30s %p\n", 'sorted', ha.sort.map {|h| h.to_s}
[80, 83, 84, 80.1, 83.0, 84.3, 1 << 40, -(1 << 40)].each do |n|
printf "%20s %-10p h1<=>n %2d n<=>h1 %2d\n", n, n.class, h1 <=> n, n <=> h1
end
class HexNum < Numeric
# Create a new instance from an int or String.
def initialize(val)
case val
when String
@i = parse_string(val)
@s = val.frozen? ? val : val.dup.freeze
when Numeric
@i = val.to_i
else
raise ArgumentError, 'Cannot convert %p' % val
end
end
# conversions
def to_s
@s ||= (@i < 0 ? '-0x%x' % -@i : '0x%x' % @i).freeze
end
def to_i
@i
end
alias to_int to_i
def to_hex
self
end
# equivalence
def eql?(num)
self.class.equal?(num.class) && @i == num.to_i
end
alias == eql?
# hash code calculation
def hash
@i.hash
end
# various tests that Fixnum also has
def zero?
@i.zero?
end
def nonzero?
@i.nonzero?
end
def odd?
@i.odd?
end
def even?
@i.even?
end
def between?(a, b)
@i.between? a, b
end
def integer?
true
end
def real?
true
end
# coercion
def coerce(o)
[HexNum.new(o.to_int), self]
end
# comparability
include Comparable
def <=>(o)
case o
when HexNum
@i <=> o.to_i
when Numeric
@i <=> o
else
a, b = o.coerce(self)
a <=> b
end rescue nil
end
# unary operators
def +@
self
end
def -@
HexNum.new(-@i)
end
# binary operators
def +(o)
case o
when Integer
HexNum.new(@i + o)
when Numeric
HexNum.new(@i + o.to_i)
else
a, b = o.coerce(self)
a + b
end
end
def -(o)
case o
when Integer
HexNum.new(@i - o)
when Numeric
HexNum.new(@i - o.to_i)
else
a, b = o.coerce(self)
a - b
end
end
def *(o)
case o
when HexNum
HexNum.new(@i * o.to_i)
when Numeric
HexNum.new(@i * o)
else
a, b = o.coerce(self)
a * b
end
end
def /(o)
case o
when HexNum
HexNum.new(@i / o.to_i)
when Numeric
HexNum.new(@i / o)
else
a, b = o.coerce(self)
a / b
end
end
# asymmetric binary operators
def **(o)
case o
when HexNum
HexNum.new(@i ** o.to_i)
when Numeric
HexNum.new(@i ** o)
else
a, b = o.coerce(self)
a ** b
end
end
def <<(o)
HexNum.new(@i << o.to_int)
end
def >>(o)
HexNum.new(@i >> o.to_int)
end
# bit operators
def &(o)
HexNum.new(@i & o.to_int)
end
def |(o)
HexNum.new(@i | o.to_int)
end
# freeze
def freeze
to_s
super
end
private
# Parse a string with valid format (0x1234).
def parse_string(str)
if %r{\A[-+]?(?:0x)?[a-h0-9]+\z}i =~ str
str.to_i(16)
else
raise ArgumentError, 'Cannot parse %p' % str
end
end
end
# more conversions
def HexNum(i)
HexNum.new(Integer(i))
end
class Object
def to_hex
HexNum.new(to_i)
end
end
# ===== Test Code ===================================================
h1 = HexNum.new 83
h2 = 83.to_hex
printf "%-30s %p\n", 'h1 = HexNum.new 83', h1
printf "%-30s %p\n", 'h1.to_i', h1.to_i
printf "%-30s %p\n", 'h2 = 83.to_hex', h2
printf "%-30s %p\n", 'h2.to_int', h2.to_int
printf "%-30s %p\n", 'h1 == h2', h1 == h2
printf "%-30s %p\n", 'h2.eql? h1', h2.eql?(h1)
# printf "%-30s %p\n", 'h1.odd?', h1.odd?
printf "%-30s %p\n", 'h1 <=> h2', h1 <=> h2
h3 = h1 + 17
h4 = 17 + h2
printf "%-30s %p\n", 'h3 = h1 + 17', h3
printf "%-30s %p\n", 'h4 = 17 + h1', h4
printf "%-30s %p\n", 'h1 < h3', h1 < h3
printf "%-30s %p\n", 'h2 >= h4', h2 >= h4
h5 = -h1
printf "%-30s %p\n", 'negated', h5
printf "%-30s %p\n", 'neg sum', h5 + h2
printf "%-30s %p\n", 'h1 / 1.2', h1 / 1.2
printf "%-30s %p\n", 'h3 / h1', h3 / h1
ha = (1..10).map { HexNum(rand(100)) }
printf "%-30s %p\n", 'random array', ha.map {|h| h.to_s}
printf "%-30s %p\n", 'sorted', ha.sort.map {|h| h.to_s}
[80, 83, 84, 80.1, 83.0, 84.3, 1 << 40, -(1 << 40)].each do |n|
printf "%20s %-10p h1<=>n %2d n<=>h1 %2d\n", n, n.class, h1 <=> n, n <=> h1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment