Ruby: memory_view.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

memory_view.c
Go to the documentation of this file.
1/**********************************************************************
2
3 memory_view.c - Memory View
4
5 Copyright (C) 2020 Kenta Murata <mrkn@mrkn.jp>
6
7**********************************************************************/
8
9#include "internal.h"
10#include "internal/hash.h"
11#include "internal/variable.h"
12#include "internal/util.h"
13#include "ruby/memory_view.h"
14#include "vm_sync.h"
15
16#if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
17# define INTPTR2NUM LL2NUM
18# define UINTPTR2NUM ULL2NUM
19#elif SIZEOF_INTPTR_T == SIZEOF_LONG
20# define INTPTR2NUM LONG2NUM
21# define UINTPTR2NUM ULONG2NUM
22#else
23# define INTPTR2NUM INT2NUM
24# define UINTPTR2NUM UINT2NUM
25#endif
26
27
28#define STRUCT_ALIGNOF(T, result) do { \
29 (result) = RUBY_ALIGNOF(T); \
30} while(0)
31
32// Exported Object Registry
33
34static st_table *exported_object_table = NULL;
35 VALUE rb_memory_view_exported_object_registry = Qundef;
36
37static int
38exported_object_registry_mark_key_i(st_data_t key, st_data_t value, st_data_t data)
39{
40 rb_gc_mark(key);
41 return ST_CONTINUE;
42}
43
44static void
45exported_object_registry_mark(void *ptr)
46{
47 // Don't use RB_VM_LOCK_ENTER here. It is unnecessary during GC.
48 st_foreach(exported_object_table, exported_object_registry_mark_key_i, 0);
49}
50
51static void
52exported_object_registry_free(void *ptr)
53{
54 RB_VM_LOCK_ENTER();
55 st_clear(exported_object_table);
56 st_free_table(exported_object_table);
57 exported_object_table = NULL;
58 RB_VM_LOCK_LEAVE();
59}
60
61 const rb_data_type_t rb_memory_view_exported_object_registry_data_type = {
62 "memory_view/exported_object_registry",
63 {
64 exported_object_registry_mark,
65 exported_object_registry_free,
66 0,
67 },
68 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
69};
70
71static int
72exported_object_add_ref(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
73{
74 ASSERT_vm_locking();
75
76 if (existing) {
77 *val += 1;
78 }
79 else {
80 *val = 1;
81 }
82 return ST_CONTINUE;
83}
84
85static int
86exported_object_dec_ref(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
87{
88 ASSERT_vm_locking();
89
90 if (existing) {
91 *val -= 1;
92 if (*val == 0) {
93 return ST_DELETE;
94 }
95 }
96 return ST_CONTINUE;
97}
98
99static void
100register_exported_object(VALUE obj)
101{
102 RB_VM_LOCK_ENTER();
103 st_update(exported_object_table, (st_data_t)obj, exported_object_add_ref, 0);
104 RB_VM_LOCK_LEAVE();
105}
106
107static void
108unregister_exported_object(VALUE obj)
109{
110 RB_VM_LOCK_ENTER();
111 st_update(exported_object_table, (st_data_t)obj, exported_object_dec_ref, 0);
112 RB_VM_LOCK_LEAVE();
113}
114
115// MemoryView
116
117static ID id_memory_view;
118
119static const rb_data_type_t memory_view_entry_data_type = {
120 "memory_view/entry",
121 {
122 0,
123 0,
124 0,
125 },
126 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
127};
128
129/* Register memory view functions for the given class */
130bool
131 rb_memory_view_register(VALUE klass, const rb_memory_view_entry_t *entry) {
132 Check_Type(klass, T_CLASS);
133 VALUE entry_obj = rb_ivar_lookup(klass, id_memory_view, Qnil);
134 if (! NIL_P(entry_obj)) {
135 rb_warning("Duplicated registration of memory view to %"PRIsVALUE, klass);
136 return false;
137 }
138 else {
139 entry_obj = TypedData_Wrap_Struct(0, &memory_view_entry_data_type, (void *)entry);
140 rb_ivar_set(klass, id_memory_view, entry_obj);
141 return true;
142 }
143}
144
145/* Examine whether the given memory view has row-major order strides. */
146bool
147 rb_memory_view_is_row_major_contiguous(const rb_memory_view_t *view)
148{
149 const ssize_t ndim = view->ndim;
150 const ssize_t *shape = view->shape;
151 const ssize_t *strides = view->strides;
152 ssize_t n = view->item_size;
153 ssize_t i;
154 for (i = ndim - 1; i >= 0; --i) {
155 if (strides[i] != n) return false;
156 n *= shape[i];
157 }
158 return true;
159}
160
161/* Examine whether the given memory view has column-major order strides. */
162bool
163 rb_memory_view_is_column_major_contiguous(const rb_memory_view_t *view)
164{
165 const ssize_t ndim = view->ndim;
166 const ssize_t *shape = view->shape;
167 const ssize_t *strides = view->strides;
168 ssize_t n = view->item_size;
169 ssize_t i;
170 for (i = 0; i < ndim; ++i) {
171 if (strides[i] != n) return false;
172 n *= shape[i];
173 }
174 return true;
175}
176
177/* Initialize strides array to represent the specified contiguous array. */
178void
179 rb_memory_view_fill_contiguous_strides(const ssize_t ndim, const ssize_t item_size, const ssize_t *const shape, const bool row_major_p, ssize_t *const strides)
180{
181 ssize_t i, n = item_size;
182 if (row_major_p) {
183 for (i = ndim - 1; i >= 0; --i) {
184 strides[i] = n;
185 n *= shape[i];
186 }
187 }
188 else { // column-major
189 for (i = 0; i < ndim; ++i) {
190 strides[i] = n;
191 n *= shape[i];
192 }
193 }
194}
195
196/* Initialize view to expose a simple byte array */
197bool
198 rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly)
199{
200 view->obj = obj;
201 view->data = data;
202 view->byte_size = len;
203 view->readonly = readonly;
204 view->format = NULL;
205 view->item_size = 1;
206 view->item_desc.components = NULL;
207 view->item_desc.length = 0;
208 view->ndim = 1;
209 view->shape = NULL;
210 view->strides = NULL;
211 view->sub_offsets = NULL;
212 *((void **)&view->private) = NULL;
213
214 return true;
215}
216
217#ifdef HAVE_TRUE_LONG_LONG
218static const char native_types[] = "sSiIlLqQjJ";
219#else
220static const char native_types[] = "sSiIlLjJ";
221#endif
222static const char endianness_types[] = "sSiIlLqQjJ";
223
224 typedef enum {
225 ENDIANNESS_NATIVE,
226 ENDIANNESS_LITTLE,
227 ENDIANNESS_BIG
228} endianness_t;
229
230static ssize_t
231get_format_size(const char *format, bool *native_p, ssize_t *alignment, endianness_t *endianness, ssize_t *count, const char **next_format, VALUE *error)
232{
233 RUBY_ASSERT(format != NULL);
234 RUBY_ASSERT(native_p != NULL);
235 RUBY_ASSERT(endianness != NULL);
236 RUBY_ASSERT(count != NULL);
237 RUBY_ASSERT(next_format != NULL);
238
239 *native_p = false;
240 *endianness = ENDIANNESS_NATIVE;
241 *count = 1;
242
243 const int type_char = *format;
244
245 int i = 1;
246 while (format[i]) {
247 switch (format[i]) {
248 case '!':
249 case '_':
250 if (strchr(native_types, type_char)) {
251 *native_p = true;
252 ++i;
253 }
254 else {
255 if (error) {
256 *error = rb_exc_new_str(rb_eArgError,
257 rb_sprintf("Unable to specify native size for '%c'", type_char));
258 }
259 return -1;
260 }
261 continue;
262
263 case '<':
264 case '>':
265 if (!strchr(endianness_types, type_char)) {
266 if (error) {
267 *error = rb_exc_new_str(rb_eArgError,
268 rb_sprintf("Unable to specify endianness for '%c'", type_char));
269 }
270 return -1;
271 }
272 if (*endianness != ENDIANNESS_NATIVE) {
273 *error = rb_exc_new_cstr(rb_eArgError, "Unable to use both '<' and '>' multiple times");
274 return -1;
275 }
276 *endianness = (format[i] == '<') ? ENDIANNESS_LITTLE : ENDIANNESS_BIG;
277 ++i;
278 continue;
279
280 default:
281 break;
282 }
283
284 break;
285 }
286
287 // parse count
288 int ch = format[i];
289 if ('0' <= ch && ch <= '9') {
290 ssize_t n = 0;
291 while ('0' <= (ch = format[i]) && ch <= '9') {
292 n = 10*n + ruby_digit36_to_number_table[ch];
293 ++i;
294 }
295 *count = n;
296 }
297
298 *next_format = &format[i];
299
300 switch (type_char) {
301 case 'x': // padding
302 return 1;
303
304 case 'c': // signed char
305 case 'C': // unsigned char
306 return sizeof(char);
307
308 case 's': // s for int16_t, s! for signed short
309 case 'S': // S for uint16_t, S! for unsigned short
310 if (*native_p) {
311 STRUCT_ALIGNOF(short, *alignment);
312 return sizeof(short);
313 }
314 // fall through
315
316 case 'n': // n for big-endian 16bit unsigned integer
317 case 'v': // v for little-endian 16bit unsigned integer
318 STRUCT_ALIGNOF(int16_t, *alignment);
319 return 2;
320
321 case 'i': // i and i! for signed int
322 case 'I': // I and I! for unsigned int
323 STRUCT_ALIGNOF(int, *alignment);
324 return sizeof(int);
325
326 case 'l': // l for int32_t, l! for signed long
327 case 'L': // L for uint32_t, L! for unsigned long
328 if (*native_p) {
329 STRUCT_ALIGNOF(long, *alignment);
330 return sizeof(long);
331 }
332 // fall through
333
334 case 'N': // N for big-endian 32bit unsigned integer
335 case 'V': // V for little-endian 32bit unsigned integer
336 STRUCT_ALIGNOF(int32_t, *alignment);
337 return 4;
338
339 case 'f': // f for native float
340 case 'e': // e for little-endian float
341 case 'g': // g for big-endian float
342 STRUCT_ALIGNOF(float, *alignment);
343 return sizeof(float);
344
345 case 'q': // q for int64_t, q! for signed long long
346 case 'Q': // Q for uint64_t, Q! for unsigned long long
347 if (*native_p) {
348 STRUCT_ALIGNOF(LONG_LONG, *alignment);
349 return sizeof(LONG_LONG);
350 }
351 STRUCT_ALIGNOF(int64_t, *alignment);
352 return 8;
353
354 case 'd': // d for native double
355 case 'E': // E for little-endian double
356 case 'G': // G for big-endian double
357 STRUCT_ALIGNOF(double, *alignment);
358 return sizeof(double);
359
360 case 'j': // j for intptr_t
361 case 'J': // J for uintptr_t
362 STRUCT_ALIGNOF(intptr_t, *alignment);
363 return sizeof(intptr_t);
364
365 default:
366 *alignment = -1;
367 if (error) {
368 *error = rb_exc_new_str(rb_eArgError, rb_sprintf("Invalid type character '%c'", type_char));
369 }
370 return -1;
371 }
372}
373
374static inline ssize_t
375calculate_padding(ssize_t total, ssize_t alignment_size) {
376 if (alignment_size > 1) {
377 ssize_t res = total % alignment_size;
378 if (res > 0) {
379 return alignment_size - res;
380 }
381 }
382 return 0;
383}
384
385ssize_t
386 rb_memory_view_parse_item_format(const char *format,
387 rb_memory_view_item_component_t **members,
388 size_t *n_members, const char **err)
389{
390 if (format == NULL) return 1;
391
392 VALUE error = Qnil;
393 ssize_t total = 0;
394 size_t len = 0;
395 bool alignment = false;
396 ssize_t max_alignment_size = 0;
397
398 const char *p = format;
399 if (*p == '|') { // alginment specifier
400 alignment = true;
401 ++format;
402 ++p;
403 }
404 while (*p) {
405 const char *q = p;
406
407 // ignore spaces
408 if (ISSPACE(*p)) {
409 while (ISSPACE(*p)) ++p;
410 continue;
411 }
412
413 bool native_size_p = false;
414 ssize_t alignment_size = 0;
415 endianness_t endianness = ENDIANNESS_NATIVE;
416 ssize_t count = 0;
417 const ssize_t size = get_format_size(p, &native_size_p, &alignment_size, &endianness, &count, &p, &error);
418 if (size < 0) {
419 if (err) *err = q;
420 return -1;
421 }
422 if (max_alignment_size < alignment_size) {
423 max_alignment_size = alignment_size;
424 }
425
426 const ssize_t padding = alignment ? calculate_padding(total, alignment_size) : 0;
427 total += padding + size * count;
428
429 if (*q != 'x') {
430 ++len;
431 }
432 }
433
434 // adjust total size with the alignment size of the largest element
435 if (alignment && max_alignment_size > 0) {
436 const ssize_t padding = calculate_padding(total, max_alignment_size);
437 total += padding;
438 }
439
440 if (members && n_members) {
441 rb_memory_view_item_component_t *buf = ALLOC_N(rb_memory_view_item_component_t, len);
442
443 ssize_t i = 0, offset = 0;
444 const char *p = format;
445 while (*p) {
446 const int type_char = *p;
447
448 bool native_size_p;
449 ssize_t alignment_size = 0;
450 endianness_t endianness = ENDIANNESS_NATIVE;
451 ssize_t count = 0;
452 const ssize_t size = get_format_size(p, &native_size_p, &alignment_size, &endianness, &count, &p, NULL);
453
454 const ssize_t padding = alignment ? calculate_padding(offset, alignment_size) : 0;
455 offset += padding;
456
457 if (type_char != 'x') {
458#ifdef WORDS_BIGENDIAN
459 bool little_endian_p = (endianness == ENDIANNESS_LITTLE);
460#else
461 bool little_endian_p = (endianness != ENDIANNESS_BIG);
462#endif
463
464 switch (type_char) {
465 case 'e':
466 case 'E':
467 case 'v':
468 case 'V':
469 little_endian_p = true;
470 break;
471 case 'g':
472 case 'G':
473 case 'n':
474 case 'N':
475 little_endian_p = false;
476 break;
477 default:
478 break;
479 }
480
481 buf[i++] = (rb_memory_view_item_component_t){
482 .format = type_char,
483 .native_size_p = native_size_p,
484 .little_endian_p = little_endian_p,
485 .offset = offset,
486 .size = size,
487 .repeat = count
488 };
489 }
490
491 offset += size * count;
492 }
493
494 *members = buf;
495 *n_members = len;
496 }
497
498 return total;
499}
500
501/* Return the item size. */
502ssize_t
503 rb_memory_view_item_size_from_format(const char *format, const char **err)
504{
505 return rb_memory_view_parse_item_format(format, NULL, NULL, err);
506}
507
508/* Return the pointer to the item located by the given indices. */
509void *
510 rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices)
511{
512 uint8_t *ptr = view->data;
513
514 if (view->ndim == 1) {
515 ssize_t stride = view->strides != NULL ? view->strides[0] : view->item_size;
516 return ptr + indices[0] * stride;
517 }
518
519 assert(view->shape != NULL);
520
521 ssize_t i;
522 if (view->strides == NULL) {
523 // row-major contiguous array
524 ssize_t stride = view->item_size;
525 for (i = 0; i < view->ndim; ++i) {
526 stride *= view->shape[i];
527 }
528 for (i = 0; i < view->ndim; ++i) {
529 stride /= view->shape[i];
530 ptr += indices[i] * stride;
531 }
532 }
533 else if (view->sub_offsets == NULL) {
534 // flat strided array
535 for (i = 0; i < view->ndim; ++i) {
536 ptr += indices[i] * view->strides[i];
537 }
538 }
539 else {
540 // indirect strided array
541 for (i = 0; i < view->ndim; ++i) {
542 ptr += indices[i] * view->strides[i];
543 if (view->sub_offsets[i] >= 0) {
544 ptr = *(uint8_t **)ptr + view->sub_offsets[i];
545 }
546 }
547 }
548
549 return ptr;
550}
551
552static void
553switch_endianness(uint8_t *buf, ssize_t len)
554{
555 RUBY_ASSERT(buf != NULL);
556 RUBY_ASSERT(len >= 0);
557
558 uint8_t *p = buf;
559 uint8_t *q = buf + len - 1;
560
561 while (q - p > 0) {
562 uint8_t t = *p;
563 *p = *q;
564 *q = t;
565 ++p;
566 --q;
567 }
568}
569
570static inline VALUE
571extract_item_member(const uint8_t *ptr, const rb_memory_view_item_component_t *member, const size_t i)
572{
573 RUBY_ASSERT(ptr != NULL);
574 RUBY_ASSERT(member != NULL);
575 RUBY_ASSERT(i < member->repeat);
576
577#ifdef WORDS_BIGENDIAN
578 const bool native_endian_p = !member->little_endian_p;
579#else
580 const bool native_endian_p = member->little_endian_p;
581#endif
582
583 const uint8_t *p = ptr + member->offset + i * member->size;
584
585 if (member->format == 'c') {
586 return INT2FIX(*(char *)p);
587 }
588 else if (member->format == 'C') {
589 return INT2FIX(*(unsigned char *)p);
590 }
591
592 union {
593 short s;
594 unsigned short us;
595 int i;
596 unsigned int ui;
597 long l;
598 unsigned long ul;
599 LONG_LONG ll;
600 unsigned LONG_LONG ull;
601 int16_t i16;
602 uint16_t u16;
603 int32_t i32;
604 uint32_t u32;
605 int64_t i64;
606 uint64_t u64;
607 intptr_t iptr;
608 uintptr_t uptr;
609 float f;
610 double d;
611 } val;
612
613 if (!native_endian_p) {
614 MEMCPY(&val, p, uint8_t, member->size);
615 switch_endianness((uint8_t *)&val, member->size);
616 }
617 else {
618 MEMCPY(&val, p, uint8_t, member->size);
619 }
620
621 switch (member->format) {
622 case 's':
623 if (member->native_size_p) {
624 return INT2FIX(val.s);
625 }
626 else {
627 return INT2FIX(val.i16);
628 }
629
630 case 'S':
631 case 'n':
632 case 'v':
633 if (member->native_size_p) {
634 return UINT2NUM(val.us);
635 }
636 else {
637 return INT2FIX(val.u16);
638 }
639
640 case 'i':
641 return INT2NUM(val.i);
642
643 case 'I':
644 return UINT2NUM(val.ui);
645
646 case 'l':
647 if (member->native_size_p) {
648 return LONG2NUM(val.l);
649 }
650 else {
651 return LONG2NUM(val.i32);
652 }
653
654 case 'L':
655 case 'N':
656 case 'V':
657 if (member->native_size_p) {
658 return ULONG2NUM(val.ul);
659 }
660 else {
661 return ULONG2NUM(val.u32);
662 }
663
664 case 'f':
665 case 'e':
666 case 'g':
667 return DBL2NUM(val.f);
668
669 case 'q':
670 if (member->native_size_p) {
671 return LL2NUM(val.ll);
672 }
673 else {
674#if SIZEOF_INT64_t == SIZEOF_LONG
675 return LONG2NUM(val.i64);
676#else
677 return LL2NUM(val.i64);
678#endif
679 }
680
681 case 'Q':
682 if (member->native_size_p) {
683 return ULL2NUM(val.ull);
684 }
685 else {
686#if SIZEOF_UINT64_t == SIZEOF_LONG
687 return ULONG2NUM(val.u64);
688#else
689 return ULL2NUM(val.u64);
690#endif
691 }
692
693 case 'd':
694 case 'E':
695 case 'G':
696 return DBL2NUM(val.d);
697
698 case 'j':
699 return INTPTR2NUM(val.iptr);
700
701 case 'J':
702 return UINTPTR2NUM(val.uptr);
703
704 default:
705 UNREACHABLE_RETURN(Qnil);
706 }
707}
708
709/* Return a value of the extracted member. */
710 VALUE
711rb_memory_view_extract_item_member(const void *ptr, const rb_memory_view_item_component_t *member, const size_t i)
712{
713 if (ptr == NULL) return Qnil;
714 if (member == NULL) return Qnil;
715 if (i >= member->repeat) return Qnil;
716
717 return extract_item_member(ptr, member, i);
718}
719
720/* Return a value that consists of item members.
721 * When an item is a single member, the return value is a single value.
722 * When an item consists of multiple members, an array will be returned. */
723 VALUE
724 rb_memory_view_extract_item_members(const void *ptr, const rb_memory_view_item_component_t *members, const size_t n_members)
725{
726 if (ptr == NULL) return Qnil;
727 if (members == NULL) return Qnil;
728 if (n_members == 0) return Qnil;
729
730 if (n_members == 1 && members[0].repeat == 1) {
731 return rb_memory_view_extract_item_member(ptr, members, 0);
732 }
733
734 size_t i, j;
735 VALUE item = rb_ary_new();
736 for (i = 0; i < n_members; ++i) {
737 for (j = 0; j < members[i].repeat; ++j) {
738 VALUE v = extract_item_member(ptr, &members[i], j);
739 rb_ary_push(item, v);
740 }
741 }
742
743 return item;
744}
745
746void
747 rb_memory_view_prepare_item_desc(rb_memory_view_t *view)
748{
749 if (view->item_desc.components == NULL) {
750 const char *err;
751 rb_memory_view_item_component_t **p_components =
752 (rb_memory_view_item_component_t **)&view->item_desc.components;
753 ssize_t n = rb_memory_view_parse_item_format(view->format, p_components, &view->item_desc.length, &err);
754 if (n < 0) {
755 rb_raise(rb_eRuntimeError,
756 "Unable to parse item format at %"PRIdSIZE" in \"%s\"",
757 (err - view->format), view->format);
758 }
759 }
760}
761
762/* Return a value that consists of item members in the given memory view. */
763 VALUE
764 rb_memory_view_get_item(rb_memory_view_t *view, const ssize_t *indices)
765{
766 void *ptr = rb_memory_view_get_item_pointer(view, indices);
767
768 if (view->format == NULL) {
769 return INT2FIX(*(uint8_t *)ptr);
770 }
771
772 if (view->item_desc.components == NULL) {
773 rb_memory_view_prepare_item_desc(view);
774 }
775
776 return rb_memory_view_extract_item_members(ptr, view->item_desc.components, view->item_desc.length);
777}
778
779static const rb_memory_view_entry_t *
780lookup_memory_view_entry(VALUE klass)
781{
782 VALUE entry_obj = rb_ivar_lookup(klass, id_memory_view, Qnil);
783 while (NIL_P(entry_obj)) {
784 klass = rb_class_get_superclass(klass);
785
786 if (klass == rb_cBasicObject || klass == rb_cObject)
787 return NULL;
788
789 entry_obj = rb_ivar_lookup(klass, id_memory_view, Qnil);
790 }
791
792 if (! rb_typeddata_is_kind_of(entry_obj, &memory_view_entry_data_type))
793 return NULL;
794
795 return (const rb_memory_view_entry_t *)RTYPEDDATA_DATA(entry_obj);
796}
797
798/* Examine whether the given object supports memory view. */
799bool
800 rb_memory_view_available_p(VALUE obj)
801{
802 VALUE klass = CLASS_OF(obj);
803 const rb_memory_view_entry_t *entry = lookup_memory_view_entry(klass);
804 if (entry)
805 return (* entry->available_p_func)(obj);
806 else
807 return false;
808}
809
810/* Obtain a memory view from obj, and substitute the information to view. */
811bool
812 rb_memory_view_get(VALUE obj, rb_memory_view_t* view, int flags)
813{
814 VALUE klass = CLASS_OF(obj);
815 const rb_memory_view_entry_t *entry = lookup_memory_view_entry(klass);
816 if (entry) {
817 if (!(*entry->available_p_func)(obj)) {
818 return false;
819 }
820
821 bool rv = (*entry->get_func)(obj, view, flags);
822 if (rv) {
823 register_exported_object(view->obj);
824 }
825 return rv;
826 }
827 else
828 return false;
829}
830
831/* Release the memory view obtained from obj. */
832bool
833 rb_memory_view_release(rb_memory_view_t* view)
834{
835 VALUE klass = CLASS_OF(view->obj);
836 const rb_memory_view_entry_t *entry = lookup_memory_view_entry(klass);
837 if (entry) {
838 bool rv = true;
839 if (entry->release_func) {
840 rv = (*entry->release_func)(view->obj, view);
841 }
842 if (rv) {
843 unregister_exported_object(view->obj);
844 view->obj = Qnil;
845 if (view->item_desc.components) {
846 xfree((void *)view->item_desc.components);
847 }
848 }
849 return rv;
850 }
851 else
852 return false;
853}
854
855void
856Init_MemoryView(void)
857{
858 exported_object_table = rb_init_identtable();
859
860 // exported_object_table is referred through rb_memory_view_exported_object_registry
861 // in -test-/memory_view extension.
862 VALUE obj = TypedData_Wrap_Struct(
863 0, &rb_memory_view_exported_object_registry_data_type,
864 exported_object_table);
865 rb_gc_register_mark_object(obj);
866 rb_memory_view_exported_object_registry = obj;
867
868 id_memory_view = rb_intern_const("__memory_view__");
869}
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:749
RUBY_ASSERT
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy iff RUBY_DEBUG is truthy.
Definition: assert.h:177
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Definition: assume.h:31
ISSPACE
#define ISSPACE
Definition: ctype.h:38
ptr
struct RIMemo * ptr
Definition: debug.c:88
strchr
char * strchr(char *, char)
assert
#define assert(x)
Definition: dlmalloc.c:1176
DBL2NUM
#define DBL2NUM
Definition: double.h:29
len
uint8_t len
Definition: escape.c:17
ruby_digit36_to_number_table
const signed char ruby_digit36_to_number_table[]
Definition: util.c:79
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6112
rb_gc_register_mark_object
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8022
CLASS_OF
#define CLASS_OF
Definition: globals.h:153
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_typeddata_is_kind_of
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:1007
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:1055
rb_exc_new_str
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Definition: error.c:1107
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_warning
void rb_warning(const char *fmt,...)
Definition: error.c:439
rb_class_get_superclass
VALUE rb_class_get_superclass(VALUE)
Returns the superclass of klass The return value might be an iclass of a module, unlike rb_class_supe...
Definition: object.c:1999
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:49
rb_cBasicObject
VALUE rb_cBasicObject
BasicObject class.
Definition: object.c:47
rb_init_identtable
st_table * rb_init_identtable(void)
Definition: hash.c:4451
rb_exc_new_cstr
#define rb_exc_new_cstr(exc, str)
Definition: string.h:271
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1493
INT2NUM
#define INT2NUM
Definition: int.h:43
UINT2NUM
#define UINT2NUM
Definition: int.h:46
LL2NUM
#define LL2NUM
Definition: long_long.h:30
ULL2NUM
#define ULL2NUM
Definition: long_long.h:31
hash.h
Internal header for Hash.
util.h
Internal header corresponding util.c.
rb_ivar_lookup
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
Definition: variable.c:1192
internal.h
PRIdSIZE
#define PRIdSIZE
Definition: inttypes.h:124
size
voidpf void uLong size
Definition: ioapi.h:138
long
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
offset
voidpf uLong offset
Definition: ioapi.h:144
int
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
buf
voidpf void * buf
Definition: ioapi.h:138
INT2FIX
#define INT2FIX
Definition: long.h:48
ULONG2NUM
#define ULONG2NUM
Definition: long.h:60
LONG2NUM
#define LONG2NUM
Definition: long.h:50
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
ALLOC_N
#define ALLOC_N
Definition: memory.h:133
rb_memory_view_get_item_pointer
void * rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices)
Definition: memory_view.c:510
rb_memory_view_is_row_major_contiguous
bool rb_memory_view_is_row_major_contiguous(const rb_memory_view_t *view)
Definition: memory_view.c:147
rb_memory_view_release
bool rb_memory_view_release(rb_memory_view_t *view)
Definition: memory_view.c:833
rb_memory_view_extract_item_members
VALUE rb_memory_view_extract_item_members(const void *ptr, const rb_memory_view_item_component_t *members, const size_t n_members)
Definition: memory_view.c:724
rb_memory_view_item_size_from_format
ssize_t rb_memory_view_item_size_from_format(const char *format, const char **err)
Definition: memory_view.c:503
UINTPTR2NUM
#define UINTPTR2NUM
Definition: memory_view.c:18
rb_memory_view_get
bool rb_memory_view_get(VALUE obj, rb_memory_view_t *view, int flags)
Definition: memory_view.c:812
Init_MemoryView
void Init_MemoryView(void)
Definition: memory_view.c:856
rb_memory_view_fill_contiguous_strides
void rb_memory_view_fill_contiguous_strides(const ssize_t ndim, const ssize_t item_size, const ssize_t *const shape, const bool row_major_p, ssize_t *const strides)
Definition: memory_view.c:179
INTPTR2NUM
#define INTPTR2NUM
Definition: memory_view.c:17
endianness_t
endianness_t
Definition: memory_view.c:224
ENDIANNESS_LITTLE
@ ENDIANNESS_LITTLE
Definition: memory_view.c:226
ENDIANNESS_NATIVE
@ ENDIANNESS_NATIVE
Definition: memory_view.c:225
ENDIANNESS_BIG
@ ENDIANNESS_BIG
Definition: memory_view.c:227
rb_memory_view_available_p
bool rb_memory_view_available_p(VALUE obj)
Definition: memory_view.c:800
rb_memory_view_is_column_major_contiguous
bool rb_memory_view_is_column_major_contiguous(const rb_memory_view_t *view)
Definition: memory_view.c:163
rb_memory_view_exported_object_registry
VALUE rb_memory_view_exported_object_registry
Definition: memory_view.c:35
rb_memory_view_register
bool rb_memory_view_register(VALUE klass, const rb_memory_view_entry_t *entry)
Definition: memory_view.c:131
rb_memory_view_extract_item_member
VALUE rb_memory_view_extract_item_member(const void *ptr, const rb_memory_view_item_component_t *member, const size_t i)
Definition: memory_view.c:711
rb_memory_view_init_as_byte_array
bool rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly)
Definition: memory_view.c:198
rb_memory_view_get_item
VALUE rb_memory_view_get_item(rb_memory_view_t *view, const ssize_t *indices)
Definition: memory_view.c:764
rb_memory_view_parse_item_format
ssize_t rb_memory_view_parse_item_format(const char *format, rb_memory_view_item_component_t **members, size_t *n_members, const char **err)
Definition: memory_view.c:386
STRUCT_ALIGNOF
#define STRUCT_ALIGNOF(T, result)
Definition: memory_view.c:28
rb_memory_view_prepare_item_desc
void rb_memory_view_prepare_item_desc(rb_memory_view_t *view)
Definition: memory_view.c:747
rb_memory_view_exported_object_registry_data_type
const rb_data_type_t rb_memory_view_exported_object_registry_data_type
Definition: memory_view.c:61
memory_view.h
Memory View.
count
int count
Definition: nkf.c:5055
key
key
Definition: openssl_missing.h:185
u32
uint32_t u32[type_roomof(hash_salt_t, uint32_t)]
Definition: random.c:1609
NULL
#define NULL
Definition: regenc.h:69
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Definition: rtypeddata.h:47
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: rtypeddata.h:101
RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
uint32_t
unsigned int uint32_t
Definition: sha2.h:101
uint64_t
unsigned long long uint64_t
Definition: sha2.h:102
uint8_t
unsigned char uint8_t
Definition: sha2.h:100
u64
uint64_t u64[4]
Definition: siphash.c:136
Qundef
#define Qundef
Definition: special_consts.h:53
Qnil
#define Qnil
Definition: special_consts.h:51
NIL_P
#define NIL_P
Definition: special_consts.h:46
f
#define f
rb_sprintf
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
ST_DELETE
@ ST_DELETE
Definition: st.h:99
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
st_data_t
unsigned long st_data_t
Definition: st.h:22
st_foreach
#define st_foreach
Definition: st.h:142
st_clear
#define st_clear
Definition: st.h:160
st_free_table
#define st_free_table
Definition: st.h:156
st_update
#define st_update
Definition: st.h:136
rb_data_type_struct
Definition: rtypeddata.h:70
rb_memory_view_entry_t
Definition: memory_view.h:112
rb_memory_view_entry_t::release_func
rb_memory_view_release_func_t release_func
Definition: memory_view.h:114
rb_memory_view_entry_t::available_p_func
rb_memory_view_available_p_func_t available_p_func
Definition: memory_view.h:115
rb_memory_view_entry_t::get_func
rb_memory_view_get_func_t get_func
Definition: memory_view.h:113
rb_memory_view_item_component_t
Definition: memory_view.h:30
rb_memory_view_item_component_t::native_size_p
unsigned native_size_p
Definition: memory_view.h:32
rb_memory_view_item_component_t::little_endian_p
unsigned little_endian_p
Definition: memory_view.h:33
rb_memory_view_item_component_t::size
size_t size
Definition: memory_view.h:35
rb_memory_view_item_component_t::format
char format
Definition: memory_view.h:31
rb_memory_view_item_component_t::repeat
size_t repeat
Definition: memory_view.h:36
rb_memory_view_item_component_t::offset
size_t offset
Definition: memory_view.h:34
rb_memory_view_t
Definition: memory_view.h:39
rb_memory_view_t::components
const rb_memory_view_item_component_t * components
Definition: memory_view.h:83
rb_memory_view_t::item_size
ssize_t item_size
Definition: memory_view.h:76
rb_memory_view_t::strides
const ssize_t * strides
Definition: memory_view.h:98
rb_memory_view_t::ndim
ssize_t ndim
Definition: memory_view.h:90
rb_memory_view_t::private
void *const private
Definition: memory_view.h:105
rb_memory_view_t::data
void * data
Definition: memory_view.h:46
rb_memory_view_t::obj
VALUE obj
Definition: memory_view.h:43
rb_memory_view_t::sub_offsets
const ssize_t * sub_offsets
Definition: memory_view.h:102
rb_memory_view_t::shape
const ssize_t * shape
Definition: memory_view.h:94
rb_memory_view_t::length
size_t length
Definition: memory_view.h:86
rb_memory_view_t::format
const char * format
Definition: memory_view.h:72
rb_memory_view_t::byte_size
ssize_t byte_size
Definition: memory_view.h:49
rb_memory_view_t::item_desc
struct rb_memory_view_t::@106 item_desc
rb_memory_view_t::readonly
bool readonly
Definition: memory_view.h:52
st_table
Definition: st.h:79
t
#define t
Definition: symbol.c:253
error
void error(const char *msg)
Definition: untgz.c:593
VALUE
unsigned long VALUE
Definition: value.h:38
ID
unsigned long ID
Definition: value.h:39
T_CLASS
#define T_CLASS
Definition: value_type.h:57
vm_sync.h
ASSERT_vm_locking
#define ASSERT_vm_locking()
Definition: vm_sync.h:134
RB_VM_LOCK_ENTER
#define RB_VM_LOCK_ENTER()
Definition: vm_sync.h:121
RB_VM_LOCK_LEAVE
#define RB_VM_LOCK_LEAVE()
Definition: vm_sync.h:122
err
int err
Definition: win32.c:142
intptr_t
int intptr_t
Definition: win32.h:90
uintptr_t
unsigned int uintptr_t
Definition: win32.h:106
xfree
#define xfree
Definition: xmalloc.h:49