[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]