Skip to content

Instantly share code, notes, and snippets.

@glucero
Last active August 29, 2015 13:56
Show Gist options
  • Save glucero/8910619 to your computer and use it in GitHub Desktop.
Save glucero/8910619 to your computer and use it in GitHub Desktop.
a helper class for experimenting with bit fields
class Field
Bit = Struct.new(:to_s, :to_i, :to_bool, :regex) do
alias to_str to_s
def ===(other) entries.any? { |entry| entry === other } end
end
False = Bit.new(?0, 0, false, /^[0nf]/i)
True = Bit.new(?1, 1, true, /^[1yt]/i)
def to_s; @field.dup end
def to_i; @field.to_i 2 end
def to_f; to_i.to_f end
def to_a(type = :int)
case type
when :str then @field.chars
when :int then @field.chars.map &:to_i
when :bool then @field.chars.map &True.method(:===)
end
end
def [](index, type = :int)
case type
when :str then @field[index]
when :int then @field[index].to_i
when :bool then True === @field[index]
end
end
def []=(index, value)
@field[index] = (True === value) ? True : False
end
def initialize(field = False, bits: 8)
set field, bits: bits
end
def set(field = @field, bits: @bits)
tap do
@bits = bits
@field = string(field)
end
end
attr_reader :bits
def bits=(value) set bits: value end
alias length bits
alias size bits
def min; 0 end
def empty?; self == min end
def empty!; set False end
alias clear empty!
def max; (1 << bits).pred end
def full?; self == max end
def fill!; set max end
def +@; Field.new +to_i end
def -@; Field.new -to_i end
def ~@; Field.new ~to_i end
def next; Field.new to_i.next end
def pred; Field.new to_i.pred end
def reverse; Field.new to_s.reverse end
def invert; set ~to_i end
def toggle(index)
set self ^ ( 1 << (bits.pred - index) )
end
alias flip toggle
def inc; set to_i.next end
def dec; set to_i.pred end
%i(+ - * / % >> << & | ^).each do |operator|
define_method(operator) do |operand|
Field.new to_i.send( operator, integer(operand) )
end
end
%i(> < >= <= == <=>).each do |operator|
define_method(operator) { |operand| to_i.send operator, integer(operand) }
end
def ===(mask) (self & mask) == mask end
# def apply(mask) set (to_i | mask.to_i) end
# def revert(mask) set (to_i ^ mask.to_i) end
private def string(value)
case value
when String then ("#{False.to_s * bits}#{value.to_i}")[-bits..-1]
when Numeric then ("%0#{bits + 3}b" % value)[-bits..-1]
when Array then string value.join
when Field then string value.to_s
else string False
end
end
private def integer(value)
case value
when String then value.to_i(2)
when Numeric then value
when Array then integer value.join
when Field then value.to_i
else integer False
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment