lib/bindata/int.rb in bindata-0.5.1 vs lib/bindata/int.rb in bindata-0.6.0
- old
+ new
@@ -2,170 +2,170 @@
module BinData
# Provides a number of classes that contain an integer. The integer
# is defined by endian, signedness and number of bytes.
- module BaseUint #:nodoc: all
+ module Integer #:nodoc: all
+ def self.create_int_methods(klass, nbits, endian)
+ max = (1 << (nbits - 1)) - 1
+ min = -(max + 1)
+ clamp = "val = (val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val"
- def value=(val)
- super(clamp(val))
- end
+ int2uint = "val = val & #{(1 << nbits) - 1}"
+ uint2int = "val = ((val & #{1 << (nbits - 1)}).zero?) ? " +
+ "val & #{max} : -(((~val) & #{max}) + 1)"
- #---------------
- private
+ read = create_read_code(nbits, endian)
+ to_s = create_to_s_code(nbits, endian)
- def sensible_default
- 0
+ define_methods(klass, nbits / 8, clamp, read, to_s, int2uint, uint2int)
end
- def val_to_str(val)
- _val_to_str(clamp(val))
- end
-
- # Clamps +val+ to the range 0 .. max_val
- def clamp(val)
- v = val
- nbytes = val_num_bytes(0)
+ def self.create_uint_methods(klass, nbits, endian)
min = 0
- max = (1 << (nbytes * 8)) - 1
- val = min if val < min
- val = max if val > max
- val
- end
- end
+ max = (1 << nbits) - 1
+ clamp = "val = (val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val"
- module BaseInt #:nodoc: all
- def uint2int(val)
- nbytes = val_num_bytes(0)
- mask = (1 << (nbytes * 8 - 1)) - 1
- msb = (val >> (nbytes * 8 - 1)) & 0x1
- (msb == 1) ? -(((~val) & mask) + 1) : val & mask
- end
+ read = create_read_code(nbits, endian)
+ to_s = create_to_s_code(nbits, endian)
- def int2uint(val)
- nbytes = val_num_bytes(0)
- mask = (1 << (nbytes * 8)) - 1
- val & mask
+ define_methods(klass, nbits / 8, clamp, read, to_s)
end
- def value=(val)
- super(clamp(val))
+ def self.create_read_code(nbits, endian)
+ c16 = (endian == :little) ? 'v' : 'n'
+ c32 = (endian == :little) ? 'V' : 'N'
+ b1 = (endian == :little) ? 0 : 1
+ b2 = (endian == :little) ? 1 : 0
+
+ case nbits
+ when 8; "readbytes(io,1)[0]"
+ when 16; "readbytes(io,2).unpack('#{c16}').at(0)"
+ when 32; "readbytes(io,4).unpack('#{c32}').at(0)"
+ when 64; "(a = readbytes(io,8).unpack('#{c32 * 2}'); " +
+ "(a.at(#{b2}) << 32) + a.at(#{b1}))"
+ else
+ raise "unknown nbits '#{nbits}'"
+ end
end
- #---------------
- private
+ def self.create_to_s_code(nbits, endian)
+ c16 = (endian == :little) ? 'v' : 'n'
+ c32 = (endian == :little) ? 'V' : 'N'
+ v1 = (endian == :little) ? 'val' : '(val >> 32)'
+ v2 = (endian == :little) ? '(val >> 32)' : 'val'
- def sensible_default
- 0
+ case nbits
+ when 8; "val.chr"
+ when 16; "[val].pack('#{c16}')"
+ when 32; "[val].pack('#{c32}')"
+ when 64; "[#{v1} & 0xffffffff, #{v2} & 0xffffffff].pack('#{c32 * 2}')"
+ else
+ raise "unknown nbits '#{nbits}'"
+ end
end
- def val_to_str(val)
- _val_to_str(int2uint(clamp(val)))
- end
+ def self.define_methods(klass, nbytes, clamp, read, to_s,
+ int2uint = nil, uint2int = nil)
+ # define methods in the given class
+ klass.module_eval <<-END
+ def value=(val)
+ #{clamp}
+ super(val)
+ end
- def read_val(io)
- uint2int(_read_val(io))
- end
+ def _num_bytes(ignored)
+ #{nbytes}
+ end
- # Clamps +val+ to the range min_val .. max_val, where min and max
- # are the largest representable integers.
- def clamp(val)
- nbytes = val_num_bytes(0)
- max = (1 << (nbytes * 8 - 1)) - 1
- min = -(max + 1)
- val = min if val < min
- val = max if val > max
- val
+ #---------------
+ private
+
+ def sensible_default
+ 0
+ end
+
+ def val_to_str(val)
+ #{clamp}
+ #{int2uint unless int2uint.nil?}
+ #{to_s}
+ end
+
+ def read_val(io)
+ val = #{read}
+ #{uint2int unless uint2int.nil?}
+ end
+ END
end
end
# Unsigned 1 byte integer.
class Uint8 < Single
- include BaseUint
- private
- def val_num_bytes(val) 1 end
- def read_val(io) readbytes(io,1)[0] end
- def _val_to_str(val) val.chr end
+ Integer.create_uint_methods(self, 8, :little)
end
# Unsigned 2 byte little endian integer.
class Uint16le < Single
- include BaseUint
- private
- def val_num_bytes(val) 2 end
- def read_val(io) readbytes(io,2).unpack("v")[0] end
- def _val_to_str(val) [val].pack("v") end
+ Integer.create_uint_methods(self, 16, :little)
end
# Unsigned 2 byte big endian integer.
class Uint16be < Single
- include BaseUint
- private
- def val_num_bytes(val) 2 end
- def read_val(io) readbytes(io,2).unpack("n")[0] end
- def _val_to_str(val) [val].pack("n") end
+ Integer.create_uint_methods(self, 16, :big)
end
# Unsigned 4 byte little endian integer.
class Uint32le < Single
- include BaseUint
- private
- def val_num_bytes(val) 4 end
- def read_val(io) readbytes(io,4).unpack("V")[0] end
- def _val_to_str(val) [val].pack("V") end
+ Integer.create_uint_methods(self, 32, :little)
end
# Unsigned 4 byte big endian integer.
class Uint32be < Single
- include BaseUint
- private
- def val_num_bytes(val) 4 end
- def read_val(io) readbytes(io,4).unpack("N")[0] end
- def _val_to_str(val) [val].pack("N") end
+ Integer.create_uint_methods(self, 32, :big)
end
+ # Unsigned 8 byte little endian integer.
+ class Uint64le < Single
+ Integer.create_uint_methods(self, 64, :little)
+ end
+
+ # Unsigned 8 byte big endian integer.
+ class Uint64be < Single
+ Integer.create_uint_methods(self, 64, :big)
+ end
+
# Signed 1 byte integer.
class Int8 < Single
- include BaseInt
- private
- def val_num_bytes(val) 1 end
- def _read_val(io) readbytes(io,1)[0] end
- def _val_to_str(val) val.chr end
+ Integer.create_int_methods(self, 8, :little)
end
# Signed 2 byte little endian integer.
class Int16le < Single
- include BaseInt
- private
- def val_num_bytes(val) 2 end
- def _read_val(io) readbytes(io,2).unpack("v")[0] end
- def _val_to_str(val) [val].pack("v") end
+ Integer.create_int_methods(self, 16, :little)
end
# Signed 2 byte big endian integer.
class Int16be < Single
- include BaseInt
- private
- def val_num_bytes(val) 2 end
- def _read_val(io) readbytes(io,2).unpack("n")[0] end
- def _val_to_str(val) [val].pack("n") end
+ Integer.create_int_methods(self, 16, :big)
end
# Signed 4 byte little endian integer.
class Int32le < Single
- include BaseInt
- private
- def val_num_bytes(val) 4 end
- def _read_val(io) readbytes(io,4).unpack("V")[0] end
- def _val_to_str(val) [val].pack("V") end
+ Integer.create_int_methods(self, 32, :little)
end
# Signed 4 byte big endian integer.
class Int32be < Single
- include BaseInt
- private
- def val_num_bytes(val) 4 end
- def _read_val(io) readbytes(io,4).unpack("N")[0] end
- def _val_to_str(val) [val].pack("N") end
+ Integer.create_int_methods(self, 32, :big)
+ end
+
+ # Signed 8 byte little endian integer.
+ class Int64le < Single
+ Integer.create_int_methods(self, 64, :little)
+ end
+
+ # Signed 8 byte big endian integer.
+ class Int64be < Single
+ Integer.create_int_methods(self, 64, :big)
end
end