Class: FFI::StructLayout
- Defined in:
- ext/ffi_c/StructLayout.c,
lib/ffi/struct_layout.rb,
ext/ffi_c/StructLayout.c
Overview
This class aims at defining a struct layout.
Defined Under Namespace
Classes: Array, CharArray, Enum, Field, Function, InnerStruct, Mapped, Number, Pointer, String
Constant Summary
Constants inherited from Type
Instance Method Summary collapse
-
#[](field) ⇒ StructLayout::Field
Get a field from the layout.
- #__union! ⇒ Object
-
#fields ⇒ Array<StructLayout::Field>
Get fields list.
-
#initialize(fields, size, align) ⇒ self
constructor
A new StructLayout instance.
-
#members ⇒ Array<Symbol>
Get list of field names.
-
#offset_of(field_name) ⇒ Integer
Get the offset of a field.
-
#offsets ⇒ Array<Array(Symbol, Integer)>
Get an array of tuples (field name, offset of the field).
-
#to_a ⇒ Array<StructLayout::Field>
Get an array of fields.
Methods inherited from Type
Constructor Details
#initialize(fields, size, align) ⇒ self
A new StructLayout instance.
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 |
# File 'ext/ffi_c/StructLayout.c', line 482 static VALUE struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align) { StructLayout* layout; ffi_type* ltype; int i; TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout); layout->fieldCount = RARRAY_LENINT(fields); RB_OBJ_WRITE(self, &layout->rbFieldMap, rb_hash_new()); RB_OBJ_WRITE(self, &layout->rbFieldNames, rb_ary_new2(layout->fieldCount)); layout->size = (int) FFI_ALIGN(NUM2INT(size), NUM2INT(align)); layout->align = NUM2INT(align); layout->fields = xcalloc(layout->fieldCount, sizeof(StructField *)); layout->ffiTypes = xcalloc(layout->fieldCount + 1, sizeof(ffi_type *)); RB_OBJ_WRITE(self, &layout->rbFields, rb_ary_new2(layout->fieldCount)); layout->referenceFieldCount = 0; layout->base.ffiType->elements = layout->ffiTypes; layout->base.ffiType->size = layout->size; layout->base.ffiType->alignment = layout->align; ltype = layout->base.ffiType; for (i = 0; i < (int) layout->fieldCount; ++i) { VALUE rbField = rb_ary_entry(fields, i); VALUE rbName; StructField* field; ffi_type* ftype; if (!rb_obj_is_kind_of(rbField, rbffi_StructLayoutFieldClass)) { rb_raise(rb_eTypeError, "wrong type for field %d.", i); } rbName = rb_funcall2(rbField, rb_intern("name"), 0, NULL); TypedData_Get_Struct(rbField, StructField, &rbffi_struct_field_data_type, field); layout->fields[i] = field; if (field->type == NULL || field->type->ffiType == NULL) { rb_raise(rb_eRuntimeError, "type of field %d not supported", i); } ftype = field->type->ffiType; if (ftype->size == 0 && i < ((int) layout->fieldCount - 1)) { rb_raise(rb_eTypeError, "type of field %d has zero size", i); } if (field->referenceRequired) { field->referenceIndex = layout->referenceFieldCount++; } layout->ffiTypes[i] = ftype->size > 0 ? ftype : NULL; rb_hash_aset(layout->rbFieldMap, rbName, rbField); rb_ary_push(layout->rbFields, rbField); rb_ary_push(layout->rbFieldNames, rbName); } if (ltype->size == 0) { rb_raise(rb_eRuntimeError, "Struct size is zero"); } rb_obj_freeze(layout->rbFieldMap); rb_obj_freeze(layout->rbFields); rb_obj_freeze(layout->rbFieldNames); rb_obj_freeze(self); return self; } |
Instance Method Details
#[](field) ⇒ StructLayout::Field
Get a field from the layout.
709 710 711 712 713 714 715 716 717 |
# File 'ext/ffi_c/StructLayout.c', line 709 static VALUE struct_layout_aref(VALUE self, VALUE field) { StructLayout* layout; TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout); return rb_hash_aref(layout->rbFieldMap, field); } |
#__union! ⇒ Object
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 |
# File 'ext/ffi_c/StructLayout.c', line 632 static VALUE struct_layout_union_bang(VALUE self) { StructLayout* layout; ffi_type *t = NULL; int count, i; bool float_only = true; const ffi_type *homogeneous = NULL; TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout); /* * __union! replaces the real field types with a repeated filler type. * The filler must be chosen so that libffi uses the same calling convention * as the C compiler would for the real union. * * The rules vary by architecture: * * ARM64: A "Homogeneous Floating-point Aggregate" (HFA) is * passed in floating-point registers (d0-d3). An HFA requires all members * to be the *same* float type. {double, double} is an HFA; {float, double} * is NOT. Non-HFAs use integer registers. * * x86_64 targets using the System V ABI (Linux/macOS/BSD, not Windows): * an eightbyte containing only float/double fields is classified as SSE * and passed in XMM registers, regardless of whether the float types are * mixed. {float, double} is SSE; {int, double} is INTEGER. * * Strategy: * 1. If all fields are the same float type, use that type directly. * Correct on all platforms. * 2. If fields are mixed float types (e.g. {float, double}): * - On ARM64: not an HFA, use integer filler. * - On x86_64 System V targets: still SSE class, use float filler. * 3. Otherwise: use integer filler. */ homogeneous = find_homogeneous_leaf_type(layout->base.ffiType, &float_only); if (homogeneous != NULL && float_only) { /* Case 1: all fields are the same float type. */ t = (ffi_type *) homogeneous; } #if defined(__x86_64__) && !defined(_WIN32) else if (float_only) { /* Case 2: mixed float types use float filler on SysV x86_64. */ t = (ffi_type *) find_type_by_alignment(get_float_types(), layout->align); } #endif if (t == NULL) { /* Case 3: integer or mixed int/float |
#fields ⇒ Array<StructLayout::Field>
Get fields list.
724 725 726 727 728 729 730 731 732 |
# File 'ext/ffi_c/StructLayout.c', line 724 static VALUE struct_layout_fields(VALUE self) { StructLayout* layout; TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout); return rb_ary_dup(layout->rbFields); } |
#members ⇒ Array<Symbol>
Get list of field names.
739 740 741 742 743 744 745 746 747 |
# File 'ext/ffi_c/StructLayout.c', line 739 static VALUE struct_layout_members(VALUE self) { StructLayout* layout; TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout); return rb_ary_dup(layout->rbFieldNames); } |
#offset_of(field_name) ⇒ Integer
Get the offset of a field.
46 47 48 |
# File 'lib/ffi/struct_layout.rb', line 46 def offset_of(field_name) self[field_name].offset end |
#offsets ⇒ Array<Array(Symbol, Integer)>
Get an array of tuples (field name, offset of the field).
40 41 42 |
# File 'lib/ffi/struct_layout.rb', line 40 def offsets members.map { |m| [ m, self[m].offset ] } end |
#to_a ⇒ Array<StructLayout::Field>
Get an array of fields.
754 755 756 757 758 759 760 761 762 |
# File 'ext/ffi_c/StructLayout.c', line 754 static VALUE struct_layout_to_a(VALUE self) { StructLayout* layout; TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout); return rb_ary_dup(layout->rbFields); } |