ruby-changes:63969
From: Kenta <ko1@a...>
Date: Sun, 6 Dec 2020 22:46:36 +0900 (JST)
Subject: [ruby-changes:63969] 51500eedef (master): memory_view.c: Add rb_memory_view_extract_item_members
https://git.ruby-lang.org/ruby.git/commit/?id=51500eedef From 51500eedefa492699668ced3e07e330a9a4d53ee Mon Sep 17 00:00:00 2001 From: Kenta Murata <mrkn@m...> Date: Fri, 4 Dec 2020 15:50:13 +0900 Subject: memory_view.c: Add rb_memory_view_extract_item_members diff --git a/ext/-test-/memory_view/memory_view.c b/ext/-test-/memory_view/memory_view.c index f7c5090..621614b 100644 --- a/ext/-test-/memory_view/memory_view.c +++ b/ext/-test-/memory_view/memory_view.c @@ -80,15 +80,15 @@ memory_view_parse_item_format(VALUE mod, VALUE format) https://github.com/ruby/ruby/blob/trunk/ext/-test-/memory_view/memory_view.c#L80 const char *err = NULL; rb_memory_view_item_component_t *members; - ssize_t n_members; + size_t n_members; ssize_t item_size = rb_memory_view_parse_item_format(c_str, &members, &n_members, &err); VALUE result = rb_ary_new_capa(3); rb_ary_push(result, SSIZET2NUM(item_size)); if (!err) { - VALUE ary = rb_ary_new_capa(n_members); - ssize_t i; + VALUE ary = rb_ary_new_capa((long)n_members); + size_t i; for (i = 0; i < n_members; ++i) { VALUE member = rb_hash_new(); rb_hash_aset(member, sym_format, rb_str_new(&members[i].format, 1)); @@ -231,6 +231,26 @@ memory_view_ref_count_while_exporting(VALUE mod, VALUE obj, VALUE n) https://github.com/ruby/ruby/blob/trunk/ext/-test-/memory_view/memory_view.c#L231 } static VALUE +memory_view_extract_item_members(VALUE mod, VALUE str, VALUE format) +{ + StringValue(str); + StringValue(format); + + rb_memory_view_item_component_t *members; + size_t n_members; + const char *err = NULL; + (void)rb_memory_view_parse_item_format(RSTRING_PTR(format), &members, &n_members, &err); + if (err != NULL) { + rb_raise(rb_eArgError, "Unable to parse item format"); + } + + VALUE item = rb_memory_view_extract_item_members(RSTRING_PTR(str), members, n_members); + xfree(members); + + return item; +} + +static VALUE expstr_initialize(VALUE obj, VALUE s) { if (!NIL_P(s)) { @@ -346,6 +366,7 @@ Init_memory_view(void) https://github.com/ruby/ruby/blob/trunk/ext/-test-/memory_view/memory_view.c#L366 rb_define_module_function(mMemoryViewTestUtils, "get_memory_view_info", memory_view_get_memory_view_info, 1); rb_define_module_function(mMemoryViewTestUtils, "fill_contiguous_strides", memory_view_fill_contiguous_strides, 4); rb_define_module_function(mMemoryViewTestUtils, "ref_count_while_exporting", memory_view_ref_count_while_exporting, 2); + rb_define_module_function(mMemoryViewTestUtils, "extract_item_members", memory_view_extract_item_members, 2); VALUE cExportableString = rb_define_class_under(mMemoryViewTestUtils, "ExportableString", rb_cObject); rb_define_method(cExportableString, "initialize", expstr_initialize, 1); diff --git a/include/ruby/memory_view.h b/include/ruby/memory_view.h index e2c5cd9..7c8ed72 100644 --- a/include/ruby/memory_view.h +++ b/include/ruby/memory_view.h @@ -128,9 +128,10 @@ RBIMPL_ATTR_NOALIAS() https://github.com/ruby/ruby/blob/trunk/include/ruby/memory_view.h#L128 int rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly); ssize_t rb_memory_view_parse_item_format(const char *format, rb_memory_view_item_component_t **members, - ssize_t *n_members, const char **err); + size_t *n_members, const char **err); ssize_t rb_memory_view_item_size_from_format(const char *format, const char **err); void *rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices); +VALUE rb_memory_view_extract_item_members(const void *ptr, const rb_memory_view_item_component_t *members, size_t n_members); int rb_memory_view_available_p(VALUE obj); int rb_memory_view_get(VALUE obj, rb_memory_view_t* memory_view, int flags); diff --git a/memory_view.c b/memory_view.c index 8b2a2c0..2bf3eee 100644 --- a/memory_view.c +++ b/memory_view.c @@ -12,6 +12,18 @@ https://github.com/ruby/ruby/blob/trunk/memory_view.c#L12 #include "internal/util.h" #include "ruby/memory_view.h" +#if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG +# define INTPTR2NUM LL2NUM +# define UINTPTR2NUM ULL2NUM +#elif SIZEOF_INTPTR_T == SIZEOF_LONG +# define INTPTR2NUM LONG2NUM +# define UINTPTR2NUM ULONG2NUM +#else +# define INTPTR2NUM INT2NUM +# define UINTPTR2NUM UINT2NUM +#endif + + #define STRUCT_ALIGNOF(T, result) do { \ (result) = RUBY_ALIGNOF(T); \ } while(0) @@ -394,13 +406,13 @@ calculate_padding(ssize_t total, ssize_t alignment_size) { https://github.com/ruby/ruby/blob/trunk/memory_view.c#L406 ssize_t rb_memory_view_parse_item_format(const char *format, rb_memory_view_item_component_t **members, - ssize_t *n_members, const char **err) + size_t *n_members, const char **err) { if (format == NULL) return 1; VALUE error = Qnil; ssize_t total = 0; - ssize_t len = 0; + size_t len = 0; bool alignment = false; ssize_t max_alignment_size = 0; @@ -558,6 +570,215 @@ rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices) https://github.com/ruby/ruby/blob/trunk/memory_view.c#L570 return ptr; } +static void +switch_endianness(uint8_t *buf, ssize_t len) +{ + RUBY_ASSERT(buf != NULL); + RUBY_ASSERT(len >= 0); + + uint8_t *p = buf; + uint8_t *q = buf + len - 1; + + while (q - p > 0) { + uint8_t t = *p; + *p = *q; + *q = t; + ++p; + --q; + } +} + +static inline VALUE +extract_item_member(const uint8_t *ptr, const rb_memory_view_item_component_t *member, const size_t i, + uint8_t *buf, const size_t buf_size) +{ + RUBY_ASSERT(ptr != NULL); + RUBY_ASSERT(member != NULL); + +#ifdef WORDS_BIGENDIAN + const bool native_endian_p = !member->little_endian_p; +#else + const bool native_endian_p = member->little_endian_p; +#endif + + const uint8_t *p = ptr + member->offset + i * member->size; + + if (member->format == 'c') { + return INT2FIX(*(char *)p); + } + else if (member->format == 'C') { + return INT2FIX(*(unsigned char *)p); + } + + const uint8_t *q = p; + + if (!native_endian_p) { + RUBY_ASSERT(buf != NULL); + MEMCPY(buf, p, uint8_t, member->size); + switch_endianness(buf, member->size); + q = buf; + } + + switch (member->format) { + case 's': + if (member->native_size_p) { + return INT2FIX(*(short *)q); + } + else { + return INT2FIX(*(int16_t *)q); + } + + case 'S': + case 'n': + case 'v': + if (member->native_size_p) { + return UINT2NUM(*(unsigned short *)q); + } + else { + return INT2FIX(*(uint16_t *)q); + } + + case 'i': + return INT2NUM(*(int *)q); + + case 'I': + return UINT2NUM(*(unsigned int *)q); + + case 'l': + if (member->native_size_p) { + return LONG2NUM(*(long *)q); + } + else { + return LONG2NUM(*(int32_t *)q); + } + + case 'L': + case 'N': + case 'V': + if (member->native_size_p) { + return ULONG2NUM(*(unsigned long *)q); + } + else { + return ULONG2NUM(*(uint32_t *)q); + } + + case 'f': + case 'e': + case 'g': + return DBL2NUM(*(float *)q); + + case 'q': + if (member->native_size_p) { + return LL2NUM(*(LONG_LONG *)q); + } + else { +#if SIZEOF_INT64_t == SIZEOF_LONG + return LONG2NUM(*(int64_t *)q); +#else + return LL2NUM(*(int64_t *)q); +#endif + } + + case 'Q': + if (member->native_size_p) { + return ULL2NUM(*(unsigned LONG_LONG *)q); + } + else { +#if SIZEOF_UINT64_t == SIZEOF_LONG + return ULONG2NUM(*(uint64_t *)q); +#else + return ULL2NUM(*(uint64_t *)q); +#endif + } + + case 'd': + case 'E': + case 'G': + return DBL2NUM(*(double *)q); + + case 'j': + return INTPTR2NUM(*(intptr_t *)q); + + case 'J': + return UINTPTR2NUM(*(uintptr_t *)q); + + default: + UNREACHABLE_RETURN(Qnil); + } +} + +/* Return a value of the extracted member. */ +VALUE +rb_memory_view_extract_item_member(const void *ptr, const rb_memory_view_item_component_t *member, const size_t i) +{ + if (ptr == NULL) return Qnil; + if (member == NULL) return Qnil; + if (i >= member->repeat) return Qnil; + +#ifdef WORDS_BIGENDIAN + const bool native_endian_p = !member->little_endian_p; +#else + const bool native_endian_p = member->little_endian_p; +#endif + + VALUE buf_v = 0; + uint8_t *buf; + if (!native_endian_p) { + buf = ALLOCV_N(uint8_t, buf_v, member->size); + } + + VALUE v = extract_item_member(ptr, member, i, buf, member->size); + + if (buf_v) ALLOCV_END(buf_v); + return v; +} + +/* Return a value that consists of item members. + * When an item is a single member, the return value is a single value. + * When an item consists of multiple members, an array will be returned. */ +VALUE +rb_memory_view_extract_item_members(const void *ptr, const rb_memory_view_item_component_t *members, const size_t n_members) +{ + if (ptr == NULL) return Qnil; + if (members == NULL) return Qnil; + if (n_members == 0) return Qnil; + + if (n_members == 1 && members[0].repeat == 1) { + return rb_memory_view_extract_item_member(ptr, members, 0); + } + + size_t i, max_size = 0; + bool need_switch_endianness_p = false; + for (i = 0; i < n_members; ++i) { + if (max_size < members[i].size) { + max_size = members[i].size; + } +#ifdef WORDS_BIGE (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/