Ruby  3.1.0dev(2021-09-10revisionb76ad15ed0da636161de0243c547ee1e6fc95681)
memory_view.c
Go to the documentation of this file.
1 #include <fiddle.h>
2 
3 #ifdef HAVE_RUBY_MEMORY_VIEW_H
4 
5 #include <stdbool.h>
6 #include <ruby/ruby.h>
7 #include <ruby/encoding.h>
8 #include <ruby/memory_view.h>
9 
10 #if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
11 # define INTPTR2NUM LL2NUM
12 # define UINTPTR2NUM ULL2NUM
13 #elif SIZEOF_INTPTR_T == SIZEOF_LONG
14 # define INTPTR2NUM LONG2NUM
15 # define UINTPTR2NUM ULONG2NUM
16 #else
17 # define INTPTR2NUM INT2NUM
18 # define UINTPTR2NUM UINT2NUM
19 #endif
20 
22 
23 struct memview_data {
26  size_t n_members;
27 };
28 
29 static void
30 fiddle_memview_mark(void *ptr)
31 {
32  const struct memview_data *data = ptr;
33  rb_gc_mark(data->view.obj);
34 }
35 
36 static void
37 fiddle_memview_release(struct memview_data *data)
38 {
39  if (NIL_P(data->view.obj)) return;
40 
42  data->view.obj = Qnil;
43  data->view.byte_size = 0;
44  if (data->members) {
45  xfree(data->members);
46  data->members = NULL;
47  data->n_members = 0;
48  }
49 }
50 
51 static void
52 fiddle_memview_free(void *ptr)
53 {
54  struct memview_data *data = ptr;
55  fiddle_memview_release(data);
56  xfree(ptr);
57 }
58 
59 static size_t
60 fiddle_memview_memsize(const void *ptr)
61 {
62  const struct memview_data *data = ptr;
63  return sizeof(*data) + sizeof(rb_memory_view_item_component_t)*data->n_members + (size_t)data->view.byte_size;
64 }
65 
66 static const rb_data_type_t fiddle_memview_data_type = {
67  "fiddle/memory_view",
68  {fiddle_memview_mark, fiddle_memview_free, fiddle_memview_memsize,},
69 };
70 
71 static VALUE
72 rb_fiddle_memview_s_allocate(VALUE klass)
73 {
74  struct memview_data *data;
75  VALUE obj = TypedData_Make_Struct(klass, struct memview_data, &fiddle_memview_data_type, data);
76  data->view.obj = Qnil;
77  data->view.byte_size = 0;
78  data->members = NULL;
79  data->n_members = 0;
80  return obj;
81 }
82 
83 static VALUE
84 rb_fiddle_memview_release(VALUE obj)
85 {
86  struct memview_data *data;
87  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
88 
89  if (NIL_P(data->view.obj)) return Qnil;
90  fiddle_memview_release(data);
91  return Qnil;
92 }
93 
94 static VALUE
95 rb_fiddle_memview_s_export(VALUE klass, VALUE target)
96 {
97  ID id_new;
98  CONST_ID(id_new, "new");
99  VALUE memview = rb_funcall(klass, id_new, 1, target);
100  return rb_ensure(rb_yield, memview, rb_fiddle_memview_release, memview);
101 }
102 
103 static VALUE
104 rb_fiddle_memview_initialize(VALUE obj, VALUE target)
105 {
106  struct memview_data *data;
107  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
108 
109  if (!rb_memory_view_get(target, &data->view, 0)) {
110  data->view.obj = Qnil;
111  rb_raise(rb_eArgError, "Unable to get a memory view from %+"PRIsVALUE, target);
112  }
113 
114  return Qnil;
115 }
116 
117 static VALUE
118 rb_fiddle_memview_get_obj(VALUE obj)
119 {
120  struct memview_data *data;
121  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
122 
123  return data->view.obj;
124 }
125 
126 static VALUE
127 rb_fiddle_memview_get_byte_size(VALUE obj)
128 {
129  struct memview_data *data;
130  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
131 
132  if (NIL_P(data->view.obj)) return Qnil;
133  return SSIZET2NUM(data->view.byte_size);
134 }
135 
136 static VALUE
137 rb_fiddle_memview_get_readonly(VALUE obj)
138 {
139  struct memview_data *data;
140  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
141 
142  if (NIL_P(data->view.obj)) return Qnil;
143  return data->view.readonly ? Qtrue : Qfalse;
144 }
145 
146 static VALUE
147 rb_fiddle_memview_get_format(VALUE obj)
148 {
149  struct memview_data *data;
150  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
151 
152  if (NIL_P(data->view.obj)) return Qnil;
153  return data->view.format == NULL ? Qnil : rb_str_new_cstr(data->view.format);
154 }
155 
156 static VALUE
157 rb_fiddle_memview_get_item_size(VALUE obj)
158 {
159  struct memview_data *data;
160  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
161 
162  if (NIL_P(data->view.obj)) return Qnil;
163  return SSIZET2NUM(data->view.item_size);
164 }
165 
166 static VALUE
167 rb_fiddle_memview_get_ndim(VALUE obj)
168 {
169  struct memview_data *data;
170  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
171 
172  if (NIL_P(data->view.obj)) return Qnil;
173  return SSIZET2NUM(data->view.ndim);
174 }
175 
176 static VALUE
177 rb_fiddle_memview_get_shape(VALUE obj)
178 {
179  struct memview_data *data;
180  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
181 
182  if (NIL_P(data->view.obj)) return Qnil;
183  if (data->view.shape == NULL) return Qnil;
184 
185  const ssize_t ndim = data->view.ndim;
186  VALUE shape = rb_ary_new_capa(ndim);
187  ssize_t i;
188  for (i = 0; i < ndim; ++i) {
189  rb_ary_push(shape, SSIZET2NUM(data->view.shape[i]));
190  }
191  return shape;
192 }
193 
194 static VALUE
195 rb_fiddle_memview_get_strides(VALUE obj)
196 {
197  struct memview_data *data;
198  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
199 
200  if (NIL_P(data->view.obj)) return Qnil;
201  if (data->view.strides == NULL) return Qnil;
202 
203  const ssize_t ndim = data->view.ndim;
204  VALUE strides = rb_ary_new_capa(ndim);
205  ssize_t i;
206  for (i = 0; i < ndim; ++i) {
207  rb_ary_push(strides, SSIZET2NUM(data->view.strides[i]));
208  }
209  return strides;
210 }
211 
212 static VALUE
213 rb_fiddle_memview_get_sub_offsets(VALUE obj)
214 {
215  struct memview_data *data;
216  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
217 
218  if (NIL_P(data->view.obj)) return Qnil;
219  if (data->view.sub_offsets == NULL) return Qnil;
220 
221  const ssize_t ndim = data->view.ndim;
222  VALUE sub_offsets = rb_ary_new_capa(ndim);
223  ssize_t i;
224  for (i = 0; i < ndim; ++i) {
225  rb_ary_push(sub_offsets, SSIZET2NUM(data->view.sub_offsets[i]));
226  }
227  return sub_offsets;
228 }
229 
230 static VALUE
231 rb_fiddle_memview_aref(int argc, VALUE *argv, VALUE obj)
232 {
233  struct memview_data *data;
234  TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
235 
236  if (NIL_P(data->view.obj)) return Qnil;
237 
238  const ssize_t ndim = data->view.ndim;
239  if (argc != ndim) {
240  rb_raise(rb_eIndexError, "wrong number of index (%d for %"PRIdSIZE")", argc, ndim);
241  }
242 
243  VALUE indices_v = 0;
244  ssize_t *indices = ALLOCV_N(ssize_t, indices_v, ndim);
245 
246  ssize_t i;
247  for (i = 0; i < ndim; ++i) {
248  ssize_t x = NUM2SSIZET(argv[i]);
249  indices[i] = x;
250  }
251 
252  uint8_t *ptr = rb_memory_view_get_item_pointer(&data->view, indices);
253  ALLOCV_END(indices_v);
254 
255  if (data->view.format == NULL) {
256  return INT2FIX(*ptr);
257  }
258 
259  if (!data->members) {
260  const char *err;
261  if (rb_memory_view_parse_item_format(data->view.format, &data->members, &data->n_members, &err) < 0) {
262  rb_raise(rb_eRuntimeError, "Unable to recognize item format at %"PRIdSIZE" in \"%s\"",
263  err - data->view.format, data->view.format);
264  }
265  }
266 
268 }
269 
270 static VALUE
271 rb_fiddle_memview_to_s(VALUE self)
272 {
273  struct memview_data *data;
274  const char *raw_data;
275  long byte_size;
276  VALUE string;
277 
279  struct memview_data,
280  &fiddle_memview_data_type,
281  data);
282 
283  if (NIL_P(data->view.obj)) {
284  raw_data = NULL;
285  byte_size = 0;
286  } else {
287  raw_data = data->view.data;
288  byte_size = data->view.byte_size;
289  }
290 
291  string = rb_enc_str_new_static(raw_data, byte_size, rb_ascii8bit_encoding());
292  {
293  ID id_memory_view;
294  CONST_ID(id_memory_view, "memory_view");
295  rb_ivar_set(string, id_memory_view, self);
296  }
297  return rb_obj_freeze(string);
298 }
299 
300 void
302 {
304  rb_define_alloc_func(rb_cMemoryView, rb_fiddle_memview_s_allocate);
305  rb_define_singleton_method(rb_cMemoryView, "export", rb_fiddle_memview_s_export, 1);
306  rb_define_method(rb_cMemoryView, "initialize", rb_fiddle_memview_initialize, 1);
307  rb_define_method(rb_cMemoryView, "release", rb_fiddle_memview_release, 0);
308  rb_define_method(rb_cMemoryView, "obj", rb_fiddle_memview_get_obj, 0);
309  rb_define_method(rb_cMemoryView, "byte_size", rb_fiddle_memview_get_byte_size, 0);
310  rb_define_method(rb_cMemoryView, "readonly?", rb_fiddle_memview_get_readonly, 0);
311  rb_define_method(rb_cMemoryView, "format", rb_fiddle_memview_get_format, 0);
312  rb_define_method(rb_cMemoryView, "item_size", rb_fiddle_memview_get_item_size, 0);
313  rb_define_method(rb_cMemoryView, "ndim", rb_fiddle_memview_get_ndim, 0);
314  rb_define_method(rb_cMemoryView, "shape", rb_fiddle_memview_get_shape, 0);
315  rb_define_method(rb_cMemoryView, "strides", rb_fiddle_memview_get_strides, 0);
316  rb_define_method(rb_cMemoryView, "sub_offsets", rb_fiddle_memview_get_sub_offsets, 0);
317  rb_define_method(rb_cMemoryView, "[]", rb_fiddle_memview_aref, -1);
318  rb_define_method(rb_cMemoryView, "to_s", rb_fiddle_memview_to_s, 0);
319 }
320 
321 #endif /* HAVE_RUBY_MEMORY_VIEW_H */
rb_ary_new_capa
VALUE rb_ary_new_capa(long capa)
Definition: array.c:748
rb_memory_view_t::format
const char * format
Definition: memory_view.h:70
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:670
rb_memory_view_t::obj
VALUE obj
Definition: memory_view.h:41
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1500
mFiddle
VALUE mFiddle
Definition: fiddle.c:3
rb_memory_view_t::item_size
ssize_t item_size
Definition: memory_view.h:74
encoding.h
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1377
PRIsVALUE
#define PRIsVALUE
Definition: inttypes.h:77
ALLOCV_N
#define ALLOCV_N
Definition: memory.h:139
fiddle.h
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1094
xfree
#define xfree
Definition: xmalloc.h:49
memview_data::members
rb_memory_view_item_component_t * members
Definition: memory_view.c:25
INT2FIX
#define INT2FIX
Definition: long.h:48
rb_memory_view_t::data
void * data
Definition: memory_view.h:44
rb_memory_view_t::sub_offsets
const ssize_t * sub_offsets
Definition: memory_view.h:100
memview_data::view
rb_memory_view_t view
Definition: memory_view.c:24
rb_eIndexError
VALUE rb_eIndexError
Definition: error.c:1095
argv
char ** argv
Definition: ruby.c:243
ID
unsigned long ID
Definition: value.h:39
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:726
memview_data
Definition: memory_view.c:23
ptr
struct RIMemo * ptr
Definition: debug.c:87
stdbool.h
C99 shim for <stdbool.h>
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: rtypeddata.h:122
ruby.h
rb_enc_str_new_static
VALUE rb_enc_str_new_static(const char *, long, rb_encoding *)
Definition: string.c:944
rb_memory_view_get
bool rb_memory_view_get(VALUE obj, rb_memory_view_t *view, int flags)
Definition: memory_view.c:814
rb_memory_view_t::readonly
bool readonly
Definition: memory_view.h:50
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:3022
NIL_P
#define NIL_P
Definition: special_consts.h:46
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:388
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:512
rb_ascii8bit_encoding
rb_encoding * rb_ascii8bit_encoding(void)
Definition: encoding.c:1527
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:50
Qfalse
#define Qfalse
Definition: special_consts.h:50
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1312
Qnil
#define Qnil
Definition: special_consts.h:51
rb_obj_freeze
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
Definition: object.c:1143
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:1091
NULL
#define NULL
Definition: regenc.h:69
rb_memory_view_t
Definition: memory_view.h:39
uint8_t
unsigned char uint8_t
Definition: sha2.h:100
memory_view.h
Memory View.
rb_memory_view_release
bool rb_memory_view_release(rb_memory_view_t *view)
Definition: memory_view.c:835
Qtrue
#define Qtrue
Definition: special_consts.h:52
VALUE
unsigned long VALUE
Definition: value.h:38
ALLOCV_END
#define ALLOCV_END
Definition: memory.h:140
rb_memory_view_t::byte_size
ssize_t byte_size
Definition: memory_view.h:47
SSIZET2NUM
#define SSIZET2NUM
Definition: size_t.h:54
Init_fiddle_memory_view
void Init_fiddle_memory_view(void)
Definition: memory_view.c:301
rb_memory_view_t::strides
const ssize_t * strides
Definition: memory_view.h:96
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1113
CONST_ID
#define CONST_ID
Definition: symbol.h:47
rb_memory_view_t::ndim
ssize_t ndim
Definition: memory_view.h:88
PRIdSIZE
#define PRIdSIZE
Definition: inttypes.h:124
argc
int argc
Definition: ruby.c:242
err
int err
Definition: win32.c:143
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: rtypeddata.h:130
rb_data_type_struct
Definition: rtypeddata.h:70
rb_memory_view_t::shape
const ssize_t * shape
Definition: memory_view.h:92
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6836
rb_str_new_cstr
#define rb_str_new_cstr(str)
Definition: string.h:219
rb_memory_view_item_component_t
Definition: memory_view.h:30
NUM2SSIZET
#define NUM2SSIZET
Definition: size_t.h:53
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:809
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:655
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1144
memview_data::n_members
size_t n_members
Definition: memory_view.c:26
rb_cMemoryView
VALUE rb_cMemoryView
Definition: memory_view.c:21