lib/bindata/bits.rb in bindata-1.8.2 vs lib/bindata/bits.rb in bindata-1.8.3
- old
+ new
@@ -4,57 +4,106 @@
# Defines a number of classes that contain a bit based integer.
# The integer is defined by endian and number of bits.
module BitField #:nodoc: all
class << self
- def define_class(nbits, endian, signed = :unsigned)
- name = ((signed == :signed ) ? "Sbit" : "Bit") + nbits.to_s
- name << "le" if endian == :little
+ def define_class(name, nbits, endian, signed = :unsigned)
unless BinData.const_defined?(name)
BinData.module_eval <<-END
class #{name} < BinData::BasePrimitive
- BitField.define_methods(self, #{nbits}, :#{endian}, :#{signed})
+ BitField.define_methods(self, #{nbits.inspect}, #{endian.inspect}, #{signed.inspect})
end
END
end
BinData.const_get(name)
end
def define_methods(bit_class, nbits, endian, signed)
bit_class.module_eval <<-END
+ #{create_params_code(nbits)}
+
def assign(val)
+ #{create_nbits_code(nbits)}
#{create_clamp_code(nbits, signed)}
super(val)
end
def do_write(io)
+ #{create_nbits_code(nbits)}
val = _value
- #{create_int2uint_code(nbits) if signed == :signed}
+ #{create_int2uint_code(nbits, signed)}
io.writebits(val, #{nbits}, :#{endian})
end
def do_num_bytes
- #{nbits / 8.0}
+ #{create_nbits_code(nbits)}
+ #{create_do_num_bytes_code(nbits)}
end
#---------------
private
+
def read_and_return_value(io)
+ #{create_nbits_code(nbits)}
val = io.readbits(#{nbits}, :#{endian})
- #{create_uint2int_code(nbits) if signed == :signed}
+ #{create_uint2int_code(nbits, signed)}
val
end
def sensible_default
0
end
END
end
+ def create_params_code(nbits)
+ if nbits == :nbits
+ "mandatory_parameter :nbits"
+ else
+ ""
+ end
+ end
+
+ def create_nbits_code(nbits)
+ if nbits == :nbits
+ "nbits = eval_parameter(:nbits)"
+ else
+ ""
+ end
+ end
+
+ def create_do_num_bytes_code(nbits)
+ if nbits == :nbits
+ "nbits / 8.0"
+ else
+ nbits / 8.0
+ end
+ end
+
def create_clamp_code(nbits, signed)
+ if nbits == :nbits
+ create_dynamic_clamp_code(nbits, signed)
+ else
+ create_fixed_clamp_code(nbits, signed)
+ end
+ end
+
+ def create_dynamic_clamp_code(nbits, signed)
+ if signed == :signed
+ max = "max = (1 << (nbits - 1)) - 1"
+ min = "min = -(max + 1)"
+ else
+ max = "max = (1 << nbits) - 1"
+ min = "min = 0"
+ end
+
+ "#{max}; #{min}; val = (val < min) ? min : (val > max) ? max : val"
+ end
+
+ def create_fixed_clamp_code(nbits, signed)
if nbits == 1 and signed == :signed
raise "signed bitfield must have more than one bit"
end
if signed == :signed
@@ -73,33 +122,53 @@
end
"val = #{clamp}"
end
- def create_int2uint_code(nbits)
- "val = val & #{(1 << nbits) - 1}"
+ def create_int2uint_code(nbits, signed)
+ if signed != :signed
+ ""
+ elsif nbits == :nbits
+ "val &= (1 << nbits) - 1"
+ else
+ "val &= #{(1 << nbits) - 1}"
+ end
end
- def create_uint2int_code(nbits)
- "val = val - #{1 << nbits} if (val >= #{1 << (nbits - 1)})"
+ def create_uint2int_code(nbits, signed)
+ if signed != :signed
+ ""
+ elsif nbits == :nbits
+ "val -= (1 << nbits) if (val >= (1 << (nbits - 1)))"
+ else
+ "val -= #{1 << nbits} if (val >= #{1 << (nbits - 1)})"
+ end
end
end
end
+ # Create classes for dynamic bitfields
+ {
+ "Bit" => :big,
+ "BitLe" => :little,
+ "Sbit" => [:big, :signed],
+ "SbitLe" => [:little, :signed],
+ }.each_pair { |name, args| BitField.define_class(name, :nbits, *args) }
+
# Create classes on demand
module BitFieldFactory
def const_missing(name)
mappings = {
- /^Bit(\d+)$/ => :big,
- /^Bit(\d+)le$/ => :little,
- /^Sbit(\d+)$/ => [:big, :signed],
+ /^Bit(\d+)$/ => :big,
+ /^Bit(\d+)le$/ => :little,
+ /^Sbit(\d+)$/ => [:big, :signed],
/^Sbit(\d+)le$/ => [:little, :signed]
}
mappings.each_pair do |regex, args|
if regex =~ name.to_s
nbits = $1.to_i
- return BitField.define_class(nbits, *args)
+ return BitField.define_class(name, nbits, *args)
end
end
super(name)
end