|
12 | 12 | #include "internal/util.h" |
13 | 13 | #include "ruby/memory_view.h" |
14 | 14 |
|
| 15 | +#if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG |
| 16 | +# define INTPTR2NUM LL2NUM |
| 17 | +# define UINTPTR2NUM ULL2NUM |
| 18 | +#elif SIZEOF_INTPTR_T == SIZEOF_LONG |
| 19 | +# define INTPTR2NUM LONG2NUM |
| 20 | +# define UINTPTR2NUM ULONG2NUM |
| 21 | +#else |
| 22 | +# define INTPTR2NUM INT2NUM |
| 23 | +# define UINTPTR2NUM UINT2NUM |
| 24 | +#endif |
| 25 | + |
| 26 | + |
15 | 27 | #define STRUCT_ALIGNOF(T, result) do { \ |
16 | 28 | (result) = RUBY_ALIGNOF(T); \ |
17 | 29 | } while(0) |
@@ -394,13 +406,13 @@ calculate_padding(ssize_t total, ssize_t alignment_size) { |
394 | 406 | ssize_t |
395 | 407 | rb_memory_view_parse_item_format(const char *format, |
396 | 408 | rb_memory_view_item_component_t **members, |
397 | | - ssize_t *n_members, const char **err) |
| 409 | + size_t *n_members, const char **err) |
398 | 410 | { |
399 | 411 | if (format == NULL) return 1; |
400 | 412 |
|
401 | 413 | VALUE error = Qnil; |
402 | 414 | ssize_t total = 0; |
403 | | - ssize_t len = 0; |
| 415 | + size_t len = 0; |
404 | 416 | bool alignment = false; |
405 | 417 | ssize_t max_alignment_size = 0; |
406 | 418 |
|
@@ -558,6 +570,200 @@ rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices) |
558 | 570 | return ptr; |
559 | 571 | } |
560 | 572 |
|
| 573 | +static void |
| 574 | +switch_endianness(uint8_t *buf, ssize_t len) |
| 575 | +{ |
| 576 | + RUBY_ASSERT(buf != NULL); |
| 577 | + RUBY_ASSERT(len >= 0); |
| 578 | + |
| 579 | + uint8_t *p = buf; |
| 580 | + uint8_t *q = buf + len - 1; |
| 581 | + |
| 582 | + while (q - p > 0) { |
| 583 | + uint8_t t = *p; |
| 584 | + *p = *q; |
| 585 | + *q = t; |
| 586 | + ++p; |
| 587 | + --q; |
| 588 | + } |
| 589 | +} |
| 590 | + |
| 591 | +static inline VALUE |
| 592 | +extract_item_member(const uint8_t *ptr, const rb_memory_view_item_component_t *member, const size_t i) |
| 593 | +{ |
| 594 | + RUBY_ASSERT(ptr != NULL); |
| 595 | + RUBY_ASSERT(member != NULL); |
| 596 | + RUBY_ASSERT(i < member->repeat); |
| 597 | + |
| 598 | +#ifdef WORDS_BIGENDIAN |
| 599 | + const bool native_endian_p = !member->little_endian_p; |
| 600 | +#else |
| 601 | + const bool native_endian_p = member->little_endian_p; |
| 602 | +#endif |
| 603 | + |
| 604 | + const uint8_t *p = ptr + member->offset + i * member->size; |
| 605 | + |
| 606 | + if (member->format == 'c') { |
| 607 | + return INT2FIX(*(char *)p); |
| 608 | + } |
| 609 | + else if (member->format == 'C') { |
| 610 | + return INT2FIX(*(unsigned char *)p); |
| 611 | + } |
| 612 | + |
| 613 | + union { |
| 614 | + short s; |
| 615 | + unsigned short us; |
| 616 | + int i; |
| 617 | + unsigned int ui; |
| 618 | + long l; |
| 619 | + unsigned long ul; |
| 620 | + LONG_LONG ll; |
| 621 | + unsigned LONG_LONG ull; |
| 622 | + int16_t i16; |
| 623 | + uint16_t u16; |
| 624 | + int32_t i32; |
| 625 | + uint32_t u32; |
| 626 | + int64_t i64; |
| 627 | + uint64_t u64; |
| 628 | + intptr_t iptr; |
| 629 | + uintptr_t uptr; |
| 630 | + float f; |
| 631 | + double d; |
| 632 | + } val; |
| 633 | + |
| 634 | + if (!native_endian_p) { |
| 635 | + MEMCPY(&val, p, uint8_t, member->size); |
| 636 | + switch_endianness((uint8_t *)&val, member->size); |
| 637 | + } |
| 638 | + else { |
| 639 | + MEMCPY(&val, p, uint8_t, member->size); |
| 640 | + } |
| 641 | + |
| 642 | + switch (member->format) { |
| 643 | + case 's': |
| 644 | + if (member->native_size_p) { |
| 645 | + return INT2FIX(val.s); |
| 646 | + } |
| 647 | + else { |
| 648 | + return INT2FIX(val.i16); |
| 649 | + } |
| 650 | + |
| 651 | + case 'S': |
| 652 | + case 'n': |
| 653 | + case 'v': |
| 654 | + if (member->native_size_p) { |
| 655 | + return UINT2NUM(val.us); |
| 656 | + } |
| 657 | + else { |
| 658 | + return INT2FIX(val.u16); |
| 659 | + } |
| 660 | + |
| 661 | + case 'i': |
| 662 | + return INT2NUM(val.i); |
| 663 | + |
| 664 | + case 'I': |
| 665 | + return UINT2NUM(val.ui); |
| 666 | + |
| 667 | + case 'l': |
| 668 | + if (member->native_size_p) { |
| 669 | + return LONG2NUM(val.l); |
| 670 | + } |
| 671 | + else { |
| 672 | + return LONG2NUM(val.i32); |
| 673 | + } |
| 674 | + |
| 675 | + case 'L': |
| 676 | + case 'N': |
| 677 | + case 'V': |
| 678 | + if (member->native_size_p) { |
| 679 | + return ULONG2NUM(val.ul); |
| 680 | + } |
| 681 | + else { |
| 682 | + return ULONG2NUM(val.u32); |
| 683 | + } |
| 684 | + |
| 685 | + case 'f': |
| 686 | + case 'e': |
| 687 | + case 'g': |
| 688 | + return DBL2NUM(val.f); |
| 689 | + |
| 690 | + case 'q': |
| 691 | + if (member->native_size_p) { |
| 692 | + return LL2NUM(val.ll); |
| 693 | + } |
| 694 | + else { |
| 695 | +#if SIZEOF_INT64_t == SIZEOF_LONG |
| 696 | + return LONG2NUM(val.i64); |
| 697 | +#else |
| 698 | + return LL2NUM(val.i64); |
| 699 | +#endif |
| 700 | + } |
| 701 | + |
| 702 | + case 'Q': |
| 703 | + if (member->native_size_p) { |
| 704 | + return ULL2NUM(val.ull); |
| 705 | + } |
| 706 | + else { |
| 707 | +#if SIZEOF_UINT64_t == SIZEOF_LONG |
| 708 | + return ULONG2NUM(val.u64); |
| 709 | +#else |
| 710 | + return ULL2NUM(val.u64); |
| 711 | +#endif |
| 712 | + } |
| 713 | + |
| 714 | + case 'd': |
| 715 | + case 'E': |
| 716 | + case 'G': |
| 717 | + return DBL2NUM(val.d); |
| 718 | + |
| 719 | + case 'j': |
| 720 | + return INTPTR2NUM(val.iptr); |
| 721 | + |
| 722 | + case 'J': |
| 723 | + return UINTPTR2NUM(val.uptr); |
| 724 | + |
| 725 | + default: |
| 726 | + UNREACHABLE_RETURN(Qnil); |
| 727 | + } |
| 728 | +} |
| 729 | + |
| 730 | +/* Return a value of the extracted member. */ |
| 731 | +VALUE |
| 732 | +rb_memory_view_extract_item_member(const void *ptr, const rb_memory_view_item_component_t *member, const size_t i) |
| 733 | +{ |
| 734 | + if (ptr == NULL) return Qnil; |
| 735 | + if (member == NULL) return Qnil; |
| 736 | + if (i >= member->repeat) return Qnil; |
| 737 | + |
| 738 | + return extract_item_member(ptr, member, i); |
| 739 | +} |
| 740 | + |
| 741 | +/* Return a value that consists of item members. |
| 742 | + * When an item is a single member, the return value is a single value. |
| 743 | + * When an item consists of multiple members, an array will be returned. */ |
| 744 | +VALUE |
| 745 | +rb_memory_view_extract_item_members(const void *ptr, const rb_memory_view_item_component_t *members, const size_t n_members) |
| 746 | +{ |
| 747 | + if (ptr == NULL) return Qnil; |
| 748 | + if (members == NULL) return Qnil; |
| 749 | + if (n_members == 0) return Qnil; |
| 750 | + |
| 751 | + if (n_members == 1 && members[0].repeat == 1) { |
| 752 | + return rb_memory_view_extract_item_member(ptr, members, 0); |
| 753 | + } |
| 754 | + |
| 755 | + size_t i, j; |
| 756 | + VALUE item = rb_ary_new(); |
| 757 | + for (i = 0; i < n_members; ++i) { |
| 758 | + for (j = 0; j < members[i].repeat; ++j) { |
| 759 | + VALUE v = extract_item_member(ptr, &members[i], j); |
| 760 | + rb_ary_push(item, v); |
| 761 | + } |
| 762 | + } |
| 763 | + |
| 764 | + return item; |
| 765 | +} |
| 766 | + |
561 | 767 | static const rb_memory_view_entry_t * |
562 | 768 | lookup_memory_view_entry(VALUE klass) |
563 | 769 | { |
|
0 commit comments