ruby-changes:67230
From: Aaron <ko1@a...>
Date: Tue, 24 Aug 2021 16:32:46 +0900 (JST)
Subject: [ruby-changes:67230] 0f1e8f38c9 (master): [ruby/fiddle] Improve "offsetof" calculations (https://github.com/ruby/fiddle/pull/90)
https://git.ruby-lang.org/ruby.git/commit/?id=0f1e8f38c9 From 0f1e8f38c9cd008eb24e6c957388a183eac910ca Mon Sep 17 00:00:00 2001 From: Aaron Patterson <tenderlove@r...> Date: Thu, 19 Aug 2021 16:43:56 -0700 Subject: [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 --- ext/fiddle/lib/fiddle/struct.rb | 60 ++++++++++++++++++++++++++---------- test/fiddle/test_c_struct_builder.rb | 33 ++++++++++++++++++++ 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/ext/fiddle/lib/fiddle/struct.rb b/ext/fiddle/lib/fiddle/struct.rb index 2353edc..6d05bbd 100644 --- a/ext/fiddle/lib/fiddle/struct.rb +++ b/ext/fiddle/lib/fiddle/struct.rb @@ -15,25 +15,53 @@ module Fiddle https://github.com/ruby/ruby/blob/trunk/ext/fiddle/lib/fiddle/struct.rb#L15 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 diff --git a/test/fiddle/test_c_struct_builder.rb b/test/fiddle/test_c_struct_builder.rb index 187424c..ca44c6c 100644 --- a/test/fiddle/test_c_struct_builder.rb +++ b/test/fiddle/test_c_struct_builder.rb @@ -3,12 +3,45 @@ begin https://github.com/ruby/ruby/blob/trunk/test/fiddle/test_c_struct_builder.rb#L3 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']) -- cgit v1.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/