mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[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.
cf78eddbb6
This commit is contained in:
parent
8d2af51a78
commit
0f1e8f38c9
2 changed files with 76 additions and 15 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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'])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue