class FFI::Bitmask

when used.
Contrary to classical enums, bitmask values are usually combined
}
blue = (1<<2)
green = (1<<1),
red = (1<<0),
enum {
@example
Represents a C enum whose values are power of 2

def [](*query)

Returns:
  • (Array) -
  • (Array) -
  • (Integer) -
  • (Integer) -

Parameters:
  • query (Array) --
  • query (Integer) --
  • query (Array) --
  • query (Symbol) --

Overloads:
  • [](query)
  • [](*query)
  • [](query)
  • [](*query)
def [](*query)
  flat_query = query.flatten
  raise ArgumentError, "query should be homogeneous, #{query.inspect}" unless flat_query.all? { |o| o.is_a?(Symbol) } || flat_query.all? { |o| o.is_a?(Integer) || o.respond_to?(:to_int) }
  case flat_query[0]
  when Symbol
    flat_query.inject(0) do |val, o|
      v = @kv_map[o]
      if v then val | v else val end
    end
  when Integer, ->(o) { o.respond_to?(:to_int) }
    val = flat_query.inject(0) { |mask, o| mask |= o.to_int }
    @kv_map.select { |_, v| v & val != 0 }.keys
  end
end

def from_native(val, ctx)

Returns:
  • (Array) - list of symbol names corresponding to val, plus an optional remainder if some bits don't match any constant

Parameters:
  • ctx () -- unused
  • val (Integer) --
def from_native(val, ctx)
  flags = @kv_map.select { |_, v| v & val != 0 }
  list = flags.keys
  # force an unsigned value of the correct size
  val &= (1 << (@native_type.size * 8)) - 1 if @signed
  # If there are unmatch flags,
  # return them in an integer,
  # else information can be lost.
  # Similar to Enum behavior.
  remainder = val ^ flags.values.reduce(0, :|)
  list.push remainder unless remainder == 0
  return list
end

def initialize(*args)

Parameters:
  • tag (nil, Symbol) -- name of new Bitmask
  • info (nil, Enumerable) -- symbols and bit rank for new Bitmask
  • native_type (FFI::Type) -- Native type for new Bitmask
  • tag (nil, Symbol) -- name of new Bitmask
  • info (nil, Enumerable) -- symbols and bit rank for new Bitmask

Overloads:
  • initialize(native_type, info, tag=nil)
  • initialize(info, tag=nil)
def initialize(*args)
  @native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT
  @signed = [Type::INT8, Type::INT16, Type::INT32, Type::INT64].include?(@native_type)
  info, @tag = *args
  @kv_map = Hash.new
  unless info.nil?
    last_cst = nil
    value = 0
    info.each do |i|
      case i
      when Symbol
        raise ArgumentError, "duplicate bitmask key" if @kv_map.has_key?(i)
        @kv_map[i] = 1 << value
        last_cst = i
        value += 1
      when Integer
        raise ArgumentError, "bitmask index should be positive" if i<0
        @kv_map[last_cst] = 1 << i
        value = i+1
      end
    end
  end
  @vk_map = @kv_map.invert
end

def to_native(query, ctx)

Returns:
  • (Integer) - value of a bitmask
  • (Integer) - value of a bitmask

Parameters:
  • ctx () -- unused
  • query (Array) --
  • ctx () -- unused
  • query (Symbol, Integer, #to_int) --

Overloads:
  • to_native(query, ctx)
  • to_native(query, ctx)
def to_native(query, ctx)
  return 0 if query.nil?
  flat_query = [query].flatten
  res = flat_query.inject(0) do |val, o|
    case o
    when Symbol
      v = @kv_map[o]
      raise ArgumentError, "invalid bitmask value, #{o.inspect}" unless v
      val | v
    when Integer
      val | o
    when ->(obj) { obj.respond_to?(:to_int) }
      val | o.to_int
    else
      raise ArgumentError, "invalid bitmask value, #{o.inspect}"
    end
  end
  # Take two's complement of positive values bigger than the max value
  # for the type when native type is signed.
  if @signed && res >= (1 << (@native_type.size * 8 - 1))
    res = -(-res & ((1 << (@native_type.size * 8)) - 1))
  end
  res
end