Class: FFI::Bitmask
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
Enum
|
|
Instance Chain:
self,
Enum ,
DataConverter
|
|
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.
Class Method Summary
Instance Attribute Summary
Enum
- Inherited
Instance Method Summary
-
#[](*query) ⇒ Integer
Get a symbol list or a value from the bitmask.
- #from_native(val, ctx) ⇒ Array<Symbol, Integer>
-
#to_native(query, ctx) ⇒ Integer
Get the native value of a bitmask.
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
Bitmask
.new(native_type, info, tag = nil) ⇒ Bitmask
# 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
>
Integer
#[](query) ⇒ Integer
#[](*query) ⇒ Array
<Symbol
>
#[](query) ⇒ Array
<Symbol
>
Get a symbol list or a value from the bitmask
# 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
>
# 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
Integer
#to_native(query, ctx) ⇒ Integer
Get the native value of a bitmask
# 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