123456789_123456789_123456789_123456789_123456789_

Class: FFI::Bitmask

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Enum
Instance Chain:
Inherits: FFI::Enum
Defined in: lib/ffi/enum.rb

Overview

Represents a C enum whose values are power of 2

Contrary to classical enums, bitmask values are usually combined when used.

Examples:

enum {
  red = (1<<0),
  green = (1<<1),
  blue = (1<<2)
}

Class Method Summary

Instance Attribute Summary

Enum - Inherited

Instance Method Summary

Enum - Inherited

#[]

Get a symbol or a value from the enum.

#find

Alias for Enum#[].

#from_native,
#symbol_map

Get the symbol map.

#symbols,
#to_h

Alias for Enum#symbol_map.

#to_hash

Alias for Enum#symbol_map.

#to_native

DataConverter - Included

#from_native

Convert from a native type.

#native_type

Get native type.

#to_native

Convert to a native type.

Constructor Details

.new(info, tag = nil) ⇒ Bitmask .new(native_type, info, tag = nil) ⇒ Bitmask

[ GitHub ]

  
# File 'lib/ffi/enum.rb', line 192

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

Instance Method Details

#[](*query) ⇒ Integer #[](query) ⇒ Integer #[](*query) ⇒ Array<Symbol> #[](query) ⇒ Array<Symbol>

Get a symbol list or a value from the bitmask

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'lib/ffi/enum.rb', line 236

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

#from_native(val, ctx) ⇒ Array<Symbol, Integer>

Parameters:

  • val (Integer)
  • ctx

    unused

Returns:

  • (Array<Symbol, Integer>)

    list of symbol names corresponding to val, plus an optional remainder if some bits don’t match any constant

[ GitHub ]

  
# File 'lib/ffi/enum.rb', line 288

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

#to_native(query, ctx) ⇒ Integer #to_native(query, ctx) ⇒ Integer

Get the native value of a bitmask

[ GitHub ]

  
# File 'lib/ffi/enum.rb', line 260

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