Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 44 additions & 16 deletions lib/fiddle/struct.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,53 @@ def CStruct.entity_class

def self.offsetof(name, members, types) # :nodoc:
offset = 0
index = 0
member_index = members.index(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]
worklist = name.split('.')
this_type = self
while search_name = worklist.shift
index = 0
member_index = members.index(search_name)

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

# Unions shouldn't advance the offset
if this_type.entity_class == CUnionEntity
type_size = 0
end

offset += (type_size * count)
index += 1
}
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

Expand Down
33 changes: 33 additions & 0 deletions test/fiddle/test_c_struct_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,45 @@
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'])
Expand Down