[ruby/fiddle] Improve "offsetof" calculations (https://github.com/ruby/fiddle/pull/90)

I need to get the offset of members inside sub structures.  This patch
adds sub-structure offset support for structs.

https://github.com/ruby/fiddle/commit/cf78eddbb6
This commit is contained in:
Aaron Patterson 2021-08-19 16:43:56 -07:00 committed by Nobuyoshi Nakada
parent 8d2af51a78
commit 0f1e8f38c9
2 changed files with 76 additions and 15 deletions

View File

@ -15,25 +15,53 @@ module Fiddle
def self.offsetof(name, members, types) # :nodoc:
offset = 0
index = 0
member_index = members.index(name)
worklist = name.split('.')
this_type = self
while search_name = worklist.shift
index = 0
member_index = members.index(search_name)
types.each { |type, count = 1|
orig_offset = offset
if type.respond_to?(:entity_class)
align = type.alignment
type_size = type.size
else
align = PackInfo::ALIGN_MAP[type]
type_size = PackInfo::SIZE_MAP[type]
unless member_index
# Possibly a sub-structure
member_index = members.index { |member_name, _|
member_name == search_name
}
return unless member_index
end
offset = PackInfo.align(orig_offset, align)
return offset if index == member_index
types.each { |type, count = 1|
orig_offset = offset
if type.respond_to?(:entity_class)
align = type.alignment
type_size = type.size
else
align = PackInfo::ALIGN_MAP[type]
type_size = PackInfo::SIZE_MAP[type]
end
offset += (type_size * count)
index += 1
}
# Unions shouldn't advance the offset
if this_type.entity_class == CUnionEntity
type_size = 0
end
offset = PackInfo.align(orig_offset, align)
if worklist.empty?
return offset if index == member_index
else
if index == member_index
subtype = types[member_index]
members = subtype.members
types = subtype.types
this_type = subtype
break
end
end
offset += (type_size * count)
index += 1
}
end
nil
end

View File

@ -3,12 +3,45 @@ begin
require_relative 'helper'
require 'fiddle/struct'
require 'fiddle/cparser'
require 'fiddle/import'
rescue LoadError
end
module Fiddle
class TestCStructBuilder < TestCase
include Fiddle::CParser
extend Fiddle::Importer
RBasic = struct ['void * flags',
'void * klass' ]
RObject = struct [
{ 'basic' => RBasic },
{ 'as' => union([
{ 'heap'=> struct([ 'uint32_t numiv',
'void * ivptr',
'void * iv_index_tbl' ]) },
'void *ary[3]' ])}
]
def test_basic_embedded_members
assert_equal 0, RObject.offsetof("basic.flags")
assert_equal Fiddle::SIZEOF_VOIDP, RObject.offsetof("basic.klass")
end
def test_embedded_union_members
assert_equal 2 * Fiddle::SIZEOF_VOIDP, RObject.offsetof("as")
assert_equal 2 * Fiddle::SIZEOF_VOIDP, RObject.offsetof("as.heap")
assert_equal 2 * Fiddle::SIZEOF_VOIDP, RObject.offsetof("as.heap.numiv")
assert_equal 3 * Fiddle::SIZEOF_VOIDP, RObject.offsetof("as.heap.ivptr")
assert_equal 4 * Fiddle::SIZEOF_VOIDP, RObject.offsetof("as.heap.iv_index_tbl")
end
def test_as_ary
assert_equal 2 * Fiddle::SIZEOF_VOIDP, RObject.offsetof("as.ary")
end
def test_offsetof
types, members = parse_struct_signature(['int64_t i','char c'])