ndav 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0648fef27ca47ec51a45cacb90330e5fb2de53071d4223604752c04746ad9c2d'
4
- data.tar.gz: 4af1dacda9bfa1258552bc271d773136b06ea414cce61c75c194c590f1361850
3
+ metadata.gz: '0194ddf5f19c3e973cb1ef947c125b598295db76eeca5998776612a592c40067'
4
+ data.tar.gz: 59f077dfdf2cdb48c675cde2e9addd7094a01417210fe28f8d786b93213ff8f8
5
5
  SHA512:
6
- metadata.gz: b81a17db0cc3814963b47e590e2f3e021e86792326a98ad1f246df8f887c4f1e49aec42808c82aeceb522e28f05f7dac9d3a6eb65417fbfc9ff785cb75284723
7
- data.tar.gz: 798ed5c4f2f84fa73b262af460e0054454a78d6f8a9eeacbb191f0b866c6c4e98ae72ed296af23b7a67d98d6894a988cc22dfc23484267d1773bd91ed7043a63
6
+ metadata.gz: e0ff36126d7192ace3dba90a706ec0f45032c590dd5085c0ca1e4166c6a6708b518ad7077ef9af54a6def14911e3a62c3bbda0e0d904cea0dd51ab46a9fb25dd
7
+ data.tar.gz: 97026defa9b86987290f46a5f04ae0133ca280a87bea04989954fb49055ccc230a5f33d5ac90a8d68c046a05dcfaa97c46c7d6f93fda90f4234f7bf074ae1293
data/README.md CHANGED
@@ -57,7 +57,9 @@ It might not be difficult, but a little bit cumbersome. Additionally, Red Arrow
57
57
  USAGE
58
58
  -----
59
59
 
60
- `ndav` gem is just a base library. You need to install bridges as well. Say, assume you want to make conversions between Numo::NArray each other.
60
+ `ndav` gem is just a base library. You need to install bridges as well.
61
+
62
+ Say, assume you want to make conversions between Numo::NArray each other.
61
63
 
62
64
  require "numo/narray"
63
65
  require "ndav"
@@ -106,6 +108,12 @@ On the other hand, it also exports MemoryView. You can pass NDAV arrays *directl
106
108
  samples = waveform.to_ndav
107
109
  whisper.full(params, samples)
108
110
 
111
+ Additinally, classes that `include` `NDAV::MemoryViewable`, including `Numo::NArray`, `OnnxRuntime::OrtValue` and `Torch::Tensor`, export MemoryViews:
112
+
113
+ memory_view = Fiddle::MemoryView.new(numo)
114
+ memory_view = Fiddle::MemoryView.new(ort_value)
115
+ memory_view = Fiddle::MemoryView.new(torch_tensor)
116
+
109
117
  ### Notice On Memory Sharing ###
110
118
 
111
119
  Notice that NDAV is just a memory view and libraries share a memory address. If you change source data destructively, it affects converted data.
@@ -147,7 +155,7 @@ Refer to existing bridge implementations listed above to create your bridge.
147
155
 
148
156
  The points are:
149
157
 
150
- * Implement `FromNDAV#from_ndav`, `ToNDAV#to_ndav`, {NDAV.register register} them, and `NDAV.from_your_data` and `NDAV#to_your_data` are automatically derived
158
+ * Implement `FromNDAV#from_ndav`, `MemoryViewable#ndav_descriptor`, optionally `ToNDAV#to_ndav`, {NDAV.register register} them, and `NDAV.from_your_data` and `NDAV#to_your_data` are automatically derived and the array become to able to export a MemoryView
151
159
  * When initializing NDAV object from your object, use `lifetime` keyword argument for {NDAV#initialize} effectively to prevent Ruby from GCing your object, which would lead to a dangling pointer
152
160
  * When initializing your object from NDAV object, keep NDAV object alive to prevent Ruby from GCing NDAV object, which would lead to a dangling pointer, [ndav-numo-narray][], for instance, embeds the NDAV object in an instance variable
153
161
 
data/ext/ndav.c CHANGED
@@ -2,7 +2,7 @@
2
2
  #include <ruby/memory_view.h>
3
3
 
4
4
  static ID id_ndav_validated_descriptor;
5
- static VALUE sym_data;
5
+ static VALUE sym_addr;
6
6
  static VALUE sym_shape;
7
7
  static VALUE sym_strides;
8
8
  static VALUE sym_format;
@@ -31,8 +31,25 @@ fill_size_array(VALUE src, ssize_t *dest, ssize_t size)
31
31
  return true;
32
32
  }
33
33
 
34
+ static void
35
+ release_memview_common(rb_memory_view_t *view)
36
+ {
37
+ if (view->shape) {
38
+ free((void *)view->shape);
39
+ view->shape = NULL;
40
+ }
41
+ if (view->strides) {
42
+ free((void *)view->strides);
43
+ view->strides = NULL;
44
+ }
45
+ if (view->sub_offsets) {
46
+ free((void *)view->sub_offsets);
47
+ view->sub_offsets = NULL;
48
+ }
49
+ }
50
+
34
51
  static bool
35
- ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
52
+ ndav_memory_viewable_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
36
53
  {
37
54
  bool row_major_requested = (flags & RUBY_MEMORY_VIEW_ROW_MAJOR) == RUBY_MEMORY_VIEW_ROW_MAJOR;
38
55
  bool column_major_requested = (flags & RUBY_MEMORY_VIEW_COLUMN_MAJOR) == RUBY_MEMORY_VIEW_COLUMN_MAJOR;
@@ -42,8 +59,8 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
42
59
  rb_warn("descriptor not Hash");
43
60
  return false;
44
61
  }
45
- bool row_major_contiguous = rb_hash_aref(desc, sym_row_major_contiguous_p);
46
- bool column_major_contiguous = rb_hash_aref(desc, sym_column_major_contiguous_p);
62
+ bool row_major_contiguous = RTEST(rb_hash_aref(desc, sym_row_major_contiguous_p));
63
+ bool column_major_contiguous = RTEST(rb_hash_aref(desc, sym_column_major_contiguous_p));
47
64
  if (row_major_requested && column_major_requested) { // row-major OR column-major requested
48
65
  if (!row_major_contiguous && !column_major_contiguous) {
49
66
  return false;
@@ -58,7 +75,7 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
58
75
  return false;
59
76
  }
60
77
  bool writable_requested = (flags & RUBY_MEMORY_VIEW_WRITABLE) == RUBY_MEMORY_VIEW_WRITABLE;
61
- // TODO: Handle flags
78
+ // TODO: Handle other flags
62
79
 
63
80
  VALUE readonly_v = rb_hash_aref(desc, sym_readonly_p);
64
81
  bool readonly = NIL_P(readonly_v) || RTEST(readonly_v);
@@ -66,120 +83,112 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
66
83
  rb_warn("not writable");
67
84
  return false;
68
85
  }
69
- view->readonly = readonly;
70
- view->obj = ndav;
71
- VALUE val = rb_hash_aref(desc, sym_data);
72
- char *data = StringValuePtr(val);
73
- view->data = data;
86
+ VALUE byte_size_v = rb_hash_aref(desc, sym_byte_size);
87
+ ssize_t byte_size = NUM2SSIZET(byte_size_v);
88
+ VALUE addr = rb_hash_aref(desc, sym_addr);
89
+ rb_memory_view_t tmp = {0};
90
+ if (!rb_memory_view_init_as_byte_array(&tmp, ndav, NUM2PTR(addr), byte_size, readonly)) {
91
+ rb_warn("failed to initialize");
92
+ return false;
93
+ }
94
+ tmp.readonly = readonly;
95
+ tmp.obj = ndav;
74
96
  // TODO: Commonalize
75
97
  // TODO: Consider:
76
98
  // * Use TypedData?
77
99
  // * If so, calling attr readers at Ruby layer has performance disadvantage.
78
100
  // * Freezing instance vars in #initialize and then embed them to TypedData may be a solution
79
101
  VALUE item_size = rb_hash_aref(desc, sym_item_size);
80
- view->item_size = NUM2SSIZET(item_size);
81
- VALUE byte_size = rb_hash_aref(desc, sym_byte_size);
82
- view->byte_size = NUM2SSIZET(byte_size);
102
+ tmp.item_size = NUM2SSIZET(item_size);
103
+ tmp.byte_size = byte_size;
83
104
  VALUE ndim = rb_hash_aref(desc, sym_ndim);
84
- view->ndim = NUM2SSIZET(ndim);
105
+ tmp.ndim = NUM2SSIZET(ndim);
85
106
  VALUE format = rb_hash_aref(desc, sym_format);
86
- view->format = StringValueCStr(format);
107
+ tmp.format = StringValueCStr(format);
87
108
 
88
109
  // TODO: Commonalize
89
110
  VALUE shape = rb_hash_aref(desc, sym_shape);
90
111
  if (!RB_TYPE_P(shape, T_ARRAY)) {
91
- rb_warn("@shape is not an array");
112
+ release_memview_common(&tmp);
113
+ rb_warn("shape is not an array");
92
114
  return false;
93
115
  }
94
- ssize_t *view_shape = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
116
+ ssize_t *view_shape = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
95
117
  if (!view_shape) {
118
+ release_memview_common(&tmp);
96
119
  return false;
97
120
  }
98
- if (!fill_size_array(shape, view_shape, view->ndim)) {
99
- free((void *)view_shape);
121
+ if (!fill_size_array(shape, view_shape, tmp.ndim)) {
122
+ free(view_shape);
123
+ release_memview_common(&tmp);
100
124
  return false;
101
125
  }
102
- view->shape = view_shape;
126
+ tmp.shape = view_shape;
103
127
 
104
128
  VALUE strides = rb_hash_aref(desc, sym_strides);
105
129
  if (!RB_TYPE_P(strides, T_ARRAY)) {
106
- rb_warn("@strides is not an array");
107
- free((void *)view->shape);
130
+ release_memview_common(&tmp);
131
+ rb_warn("strides is not an array");
108
132
  return false;
109
133
  }
110
- ssize_t *view_strides = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
134
+ ssize_t *view_strides = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
111
135
  if (!view_strides) {
112
- free((void *)view->shape);
136
+ release_memview_common(&tmp);
113
137
  return false;
114
138
  }
115
- if (!fill_size_array(strides, view_strides, view->ndim)) {
116
- free((void *)view->shape);
117
- free((void *)view_strides);
139
+ if (!fill_size_array(strides, view_strides, tmp.ndim)) {
140
+ free(view_strides);
141
+ release_memview_common(&tmp);
118
142
  return false;
119
143
  }
120
- view->strides = view_strides;
144
+ tmp.strides = view_strides;
121
145
 
122
146
  VALUE sub_offsets = rb_hash_aref(desc, sym_sub_offsets);
123
147
  if (NIL_P(sub_offsets)) {
124
148
  if (indirect_requested) {
149
+ release_memview_common(&tmp);
125
150
  rb_warn("indirect requested but sub_offsets is NULL");
126
- free((void *)view->shape);
127
- free((void *)view->strides);
128
151
  return false;
129
152
  }
130
- view->sub_offsets = NULL;
153
+ tmp.sub_offsets = NULL;
131
154
  } else if (!RB_TYPE_P(sub_offsets, T_ARRAY)) {
155
+ release_memview_common(&tmp);
132
156
  rb_warn("sub_offsets is not an array");
133
- free((void *)view->shape);
134
- free((void *)view->strides);
135
157
  return false;
136
158
  } else {
137
- ssize_t *view_sub_offsets = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
159
+ ssize_t *view_sub_offsets = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
138
160
  if (!view_sub_offsets) {
139
- free((void *)view->shape);
140
- free((void *)view->strides);
161
+ release_memview_common(&tmp);
141
162
  return false;
142
163
  }
143
- if (!fill_size_array(sub_offsets, view_sub_offsets, view->ndim)) {
144
- free((void *)view->shape);
145
- free((void *)view->strides);
146
- free((void *)view_sub_offsets);
164
+ if (!fill_size_array(sub_offsets, view_sub_offsets, tmp.ndim)) {
165
+ free(view_sub_offsets);
166
+ release_memview_common(&tmp);
147
167
  return false;
148
168
  }
149
- view->sub_offsets = view_sub_offsets;
169
+ tmp.sub_offsets = view_sub_offsets;
150
170
  }
151
171
 
152
172
  private_data_t *private_data = malloc(sizeof(private_data_t));
153
173
  if (!private_data) {
154
- free((void *)view->shape);
155
- free((void *)view->strides);
156
- free((void *)view->sub_offsets);
174
+ release_memview_common(&tmp);
157
175
  rb_warn("failed to alloc private_data");
158
176
  return false;
159
177
  }
160
178
  private_data->descriptor = Qnil;
161
179
  rb_gc_register_address(&private_data->descriptor);
162
180
  private_data->descriptor = desc;
163
- view->private_data = private_data;
181
+ tmp.private_data = private_data;
182
+
183
+ *view = tmp;
164
184
 
165
185
  return true;
166
186
  }
167
187
 
168
188
  static bool
169
- ndav_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
189
+ ndav_memory_viewable_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
170
190
  {
171
- if (view->shape) {
172
- free((void *)view->shape);
173
- view->shape = NULL;
174
- }
175
- if (view->strides) {
176
- free((void *)view->strides);
177
- view->strides = NULL;
178
- }
179
- if (view->sub_offsets) {
180
- free((void *)view->sub_offsets);
181
- view->sub_offsets = NULL;
182
- }
191
+ release_memview_common(view);
183
192
  if (view->private_data) {
184
193
  private_data_t *private_data = (private_data_t *)view->private_data;
185
194
  rb_gc_unregister_address(&private_data->descriptor);
@@ -191,16 +200,21 @@ ndav_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
191
200
  }
192
201
 
193
202
  static bool
194
- ndav_memory_view_available_p(const VALUE obj)
203
+ ndav_memory_viewable_memory_view_available_p(const VALUE obj)
195
204
  {
196
205
  VALUE descriptor = rb_funcall(obj, id_ndav_validated_descriptor, 0);
197
- return RTEST(descriptor);
206
+ if (RB_TYPE_P(descriptor, T_HASH)) {
207
+ return true;
208
+ } else {
209
+ rb_warn("descriptor not Hash");
210
+ return false;
211
+ }
198
212
  }
199
213
 
200
214
  const struct rb_memory_view_entry ndav_view_entry = {
201
- ndav_get_memory_view,
202
- ndav_release_memory_view,
203
- ndav_memory_view_available_p
215
+ ndav_memory_viewable_get_memory_view,
216
+ ndav_memory_viewable_release_memory_view,
217
+ ndav_memory_viewable_memory_view_available_p
204
218
  };
205
219
 
206
220
  static VALUE
@@ -218,7 +232,7 @@ void
218
232
  Init_ndav(void)
219
233
  {
220
234
  id_ndav_validated_descriptor = rb_intern("ndav_validated_descriptor");
221
- sym_data = ID2SYM(rb_intern("data"));
235
+ sym_addr = ID2SYM(rb_intern("addr"));
222
236
  sym_shape = ID2SYM(rb_intern("shape"));
223
237
  sym_strides = ID2SYM(rb_intern("strides"));
224
238
  sym_format = ID2SYM(rb_intern("format"));
@@ -1,4 +1,48 @@
1
1
  class NDAV
2
+ # +include+ this module and define +#ndav_descriptor+ method in your class,
3
+ # and then the class exports a MemoryView.
4
+ #
5
+ # +#ndav_descriptor+'s arguments are flags of MemoryView including
6
+ # +simple+, +writable+, +format+, +multi_dimensional+, +strides+, +row_major+, +column_major+, +any_contiguous+, +indirect+.
7
+ # For the meaning of them, see MemoryView document.
8
+ #
9
+ # It must return a Hash whose keys includes:
10
+ #
11
+ # * +:data+: Required. Binary +String+, pointer address +Integer+ or +Fiddle::Pointer+. This is passed to +Fiddle::Pointer.to_ptr+, so should be valid for the method.
12
+ # * +:shape+: Required. See MemoryView document.
13
+ # * +:strides+: Required. See MemoryView document.
14
+ # * +:format+: Required. See MemoryView document.
15
+ # * +:byte_size+: Required. See MemoryView document.
16
+ # * +:readonly?+: Required. See MemoryView document.
17
+ # * +:sub_offsets+: Optional. See MemoryView document.
18
+ #
19
+ # @example
20
+ # class YourClass
21
+ # include NDAV::MemoryViewable
22
+ # # :
23
+ # def ndav_descriptor(
24
+ # simple: true,
25
+ # writable: false,
26
+ # format: false,
27
+ # multi_dimensional: false,
28
+ # strides: false,
29
+ # row_major: false,
30
+ # column_major: false,
31
+ # any_contiguous: false,
32
+ # indirect: false
33
+ # )
34
+ # {
35
+ # data:,
36
+ # shape:,
37
+ # strides:,
38
+ # format:,
39
+ # byte_size:,
40
+ # readonly?:,
41
+ # sub_offsets:
42
+ # }
43
+ # end
44
+ # # :
45
+ # end
2
46
  module MemoryViewable
3
47
  class << self
4
48
  def included(base)
@@ -8,34 +52,23 @@ class NDAV
8
52
 
9
53
  private
10
54
 
11
- # Overwrite this method or define each ndav_xxx method
12
- def ndav_descriptor(simple: true, writable: false, format: false, multi_dimensional: false, strides: false, row_major: false, column_major: false, any_contiguous: false, indirect: false)
13
- {
14
- data: ndav_data,
15
- shape: ndav_shape,
16
- strides: ndav_strides,
17
- format: ndav_format,
18
- byte_size: ndav_byte_size,
19
- readonly?: ndav_readonly?,
20
- sub_offsets: ndav_sub_offsets
21
- }
22
- end
23
-
24
55
  def ndav_validated_descriptor(flags = ::NDAV::Flags::FLAGS[:simple])
25
56
  desc = ndav_descriptor(**NDAV::Flags.decode(flags)).to_h
26
- unless desc.kind_of? Hash
27
- warn "descriptor not Hash"
28
- return false
29
- end
30
57
  [:data, :shape, :strides, :format, :byte_size, :readonly?].each do |key|
31
58
  unless desc.key? key
32
59
  warn ":#{key} not in descriptor"
33
60
  return false
34
61
  end
35
62
  end
63
+ item_size = NDAV::ITEM_SIZES[desc[:format]]
64
+ unless desc[:shape].reduce(item_size, :*) == desc[:byte_size]
65
+ warn "item size from format and shape not match byte_size"
66
+ return false
67
+ end
36
68
  desc.merge(
69
+ addr: ::Fiddle::Pointer.to_ptr(desc[:data]).to_i,
37
70
  ndim: desc[:shape].length,
38
- item_size: NDAV::ITEM_SIZES[desc[:format]],
71
+ item_size:,
39
72
  row_major_contiguous?: ::NDAV.row_major_contiguous?(**desc),
40
73
  column_major_contiguous?: ::NDAV.column_major_contiguous?(**desc)
41
74
  )
data/ndav.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ndav"
3
- s.version = "0.0.5"
3
+ s.version = "0.0.6"
4
4
  s.summary = "N-Dimensional Array View"
5
5
  s.authors = ["Kitaiti Makoto"]
6
6
  s.licenses = ["BSD-2-Clause"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ndav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kitaiti Makoto