require'thread'require'bindata/base_primitive'moduleBinData# Defines a number of classes that contain a bit based integer.# The integer is defined by endian and number of bits.moduleBitField# :nodoc: all@@mutex=Mutex.newclass<<selfdefdefine_class(name,nbits,endian,signed=:unsigned)@@mutex.synchronizedounlessBinData.const_defined?(name)new_class=Class.new(BinData::BasePrimitive)BitField.define_methods(new_class,nbits,endian.to_sym,signed.to_sym)RegisteredClasses.register(name,new_class)BinData.const_set(name,new_class)endendBinData.const_get(name)enddefdefine_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,signed)}
io.writebits(val, #{nbits}, :#{endian})
end
def do_num_bytes
#{create_nbits_code(nbits)}#{create_do_num_bytes_code(nbits)}
end
def bit_aligned?
true
end
#---------------
private
def read_and_return_value(io)
#{create_nbits_code(nbits)}
val = io.readbits(#{nbits}, :#{endian})
#{create_uint2int_code(nbits,signed)}
val
end
def sensible_default
0
end
ENDenddefcreate_params_code(nbits)ifnbits==:nbits"mandatory_parameter :nbits"else""endenddefcreate_nbits_code(nbits)ifnbits==:nbits"nbits = eval_parameter(:nbits)"else""endenddefcreate_do_num_bytes_code(nbits)ifnbits==:nbits"nbits / 8.0"elsenbits/8.0endenddefcreate_clamp_code(nbits,signed)ifnbits==:nbitscreate_dynamic_clamp_code(signed)elsecreate_fixed_clamp_code(nbits,signed)endenddefcreate_dynamic_clamp_code(signed)ifsigned==:signedmax="(1 << (nbits - 1)) - 1"min="-((#{max}) + 1)"elsemax="(1 << nbits) - 1"min="0"end"val = val.clamp(#{min}, #{max})"enddefcreate_fixed_clamp_code(nbits,signed)ifnbits==1&&signed==:signedraise"signed bitfield must have more than one bit"endifsigned==:signedmax="(1 << (#{nbits} - 1)) - 1"min="-((#{max}) + 1)"elsemin="0"max="(1 << #{nbits}) - 1"endclamp="(val = val.clamp(#{min}, #{max}))"ifnbits==1# allow single bits to be used as booleansclamp="(val == true) ? 1 : (not val) ? 0 : #{clamp}"end"val = #{clamp}"enddefcreate_int2uint_code(nbits,signed)ifsigned!=:signed""elsifnbits==:nbits"val &= (1 << nbits) - 1"else"val &= #{(1<<nbits)-1}"endenddefcreate_uint2int_code(nbits,signed)ifsigned!=:signed""elsifnbits==:nbits"val -= (1 << nbits) if (val >= (1 << (nbits - 1)))"else"val -= #{1<<nbits} if (val >= #{1<<(nbits-1)})"endendendend# 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 demandmoduleBitFieldFactorydefconst_missing(name)mappings={/^Bit(\d+)$/=>:big,/^Bit(\d+)le$/=>:little,/^Sbit(\d+)$/=>[:big,:signed],/^Sbit(\d+)le$/=>[:little,:signed]}mappings.each_pairdo|regex,args|ifregex=~name.to_snbits=$1.to_ireturnBitField.define_class(name,nbits,*args)endendsuper(name)endendBinData.extendBitFieldFactoryend