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


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

  • #[](query) ⇒ Integer

    Get bitmaks value from symbol array

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

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

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

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

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>


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


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