Created
February 20, 2010 14:19
-
-
Save rklemme/309694 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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