Class: FFI::Bitmask

Inherits:
Enum
  • Object
show all
Defined in:
lib/ffi/bitmask.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)
}

Instance Method Summary collapse

Constructor Details

#initialize(info, tag = nil) ⇒ Bitmask #initialize(native_type, info, tag = nil) ⇒ Bitmask

Returns a new instance of Bitmask.

Overloads:

  • #initialize(info, tag = nil) ⇒ Bitmask

    Parameters:

    • info (nil, Enumerable)

      symbols and bit rank for new Bitmask

    • tag (nil, Symbol) (defaults to: nil)

      name of new Bitmask

  • #initialize(native_type, info, tag = nil) ⇒ Bitmask

    Parameters:

    • native_type (FFI::Type)

      Native type for new Bitmask

    • info (nil, Enumerable)

      symbols and bit rank for new Bitmask

    • tag (nil, Symbol) (defaults to: nil)

      name of new Bitmask



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ffi/bitmask.rb', line 84

def initialize(*args)
  @native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT
  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

Overloads:

  • #[](*query) ⇒ Integer

    Get bitmask value from symbol list

    Parameters:

    • query (Symbol)

    Returns:

    • (Integer)
  • #[](query) ⇒ Integer

    Get bitmaks value from symbol array

    Parameters:

    • query (Array<Symbol>)

    Returns:

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

    Get a list of bitmask symbols corresponding to the or reduction of a list of integer

    Parameters:

    • query (Integer)

    Returns:

    • (Array<Symbol>)
  • #[](query) ⇒ Array<Symbol>

    Get a list of bitmask symbols corresponding to the or reduction of a list of integer

    Parameters:

    • query (Array<Integer>)

    Returns:

    • (Array<Symbol>)

Raises:

  • (ArgumentError)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/ffi/bitmask.rb', line 127

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>

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

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



173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/ffi/bitmask.rb', line 173

def from_native(val, ctx)
  list = @kv_map.select { |_, v| v & val != 0 }.keys
  # If there are unmatch flags,
  # return them in an integer,
  # else information can be lost.
  # Similar to Enum behavior.
  remainder = val ^ list.inject(0) do |tmp, o|
    v = @kv_map[o]
    if v then tmp |= v else tmp end
  end
  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

Overloads:

  • #to_native(query, ctx) ⇒ Integer

    Returns value of a bitmask.

    Parameters:

    • query (Symbol, Integer, #to_int)
    • ctx

      unused

    Returns:

    • (Integer)

      value of a bitmask

  • #to_native(query, ctx) ⇒ Integer

    Returns value of a bitmask.

    Parameters:

    • query (Array<Symbol, Integer, #to_int>)
    • ctx

      unused

    Returns:

    • (Integer)

      value of a bitmask



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/ffi/bitmask.rb', line 151

def to_native(query, ctx)
  return 0 if query.nil?
  flat_query = [query].flatten
  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
end