Class: FFI::Bitmask

Inherits:
Enum
  • Object
show all
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)
}

Instance Attribute Summary

Attributes inherited from Enum

#native_type, #tag

Instance Method Summary collapse

Methods inherited from Enum

#symbol_map, #symbols

Methods included from DataConverter

#native_type

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



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/ffi/enum.rb', line 193

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)


236
237
238
239
240
241
242
243
244
245
246
247
248
249
# 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>

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



282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/ffi/enum.rb', line 282

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



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/ffi/enum.rb', line 260

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