ndav 0.0.5 → 0.0.7
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 +4 -4
- data/.yardopts +1 -1
- data/README.md +14 -2
- data/ext/ndav.c +137 -106
- data/lib/ndav/ffi.rb +3 -3
- data/lib/ndav/flags.rb +9 -5
- data/lib/ndav/import.rb +9 -0
- data/lib/ndav/item_component.rb +13 -0
- data/lib/ndav/memory_viewable.rb +96 -25
- data/lib/ndav.rb +131 -32
- data/ndav.gemspec +1 -2
- data/test/test_flags.rb +28 -0
- data/test/test_ndav.rb +160 -0
- metadata +4 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ddc0e563bff86b51222b18b00f243b94b0f2e5a69dad3e7694c80a349775bf30
|
|
4
|
+
data.tar.gz: 0afbc73643e49372d2b5104358acdc7460b26d7e6cc8892d45a67e4530cbe3d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f3a264a0204009e7f6b7505cae42667abe159e7ce7cbc5a27ffa88578c5691138b1b938795e14083b6f4cc9605dbc53b70a3990df495443ec9f5a8ebd664d5b5
|
|
7
|
+
data.tar.gz: bafa151218a7e1acb22acd915fe08acb5147228980a2f441cd928ba66ae4425fb4fcd7bf9509e8ac28f5113e555ee9927b9a71b3d13ca2064134f144a524958c
|
data/.yardopts
CHANGED
data/README.md
CHANGED
|
@@ -9,6 +9,10 @@ It provides an interoperability layer for multi-dimensional arrays which can be
|
|
|
9
9
|
|
|
10
10
|

|
|
11
11
|
|
|
12
|
+
* Homepage: https://kitaitimakoto.gitlab.io/ndav/
|
|
13
|
+
* Source Code: https://gitlab.com/KitaitiMakoto/ndav
|
|
14
|
+
* RubyGems: https://rubygems.org/gems/ndav
|
|
15
|
+
|
|
12
16
|
SYNOPSIS
|
|
13
17
|
--------
|
|
14
18
|
|
|
@@ -57,7 +61,9 @@ It might not be difficult, but a little bit cumbersome. Additionally, Red Arrow
|
|
|
57
61
|
USAGE
|
|
58
62
|
-----
|
|
59
63
|
|
|
60
|
-
`ndav` gem is just a base library. You need to install bridges as well.
|
|
64
|
+
`ndav` gem is just a base library. You need to install bridges as well.
|
|
65
|
+
|
|
66
|
+
Say, assume you want to make conversions between Numo::NArray each other.
|
|
61
67
|
|
|
62
68
|
require "numo/narray"
|
|
63
69
|
require "ndav"
|
|
@@ -106,6 +112,12 @@ On the other hand, it also exports MemoryView. You can pass NDAV arrays *directl
|
|
|
106
112
|
samples = waveform.to_ndav
|
|
107
113
|
whisper.full(params, samples)
|
|
108
114
|
|
|
115
|
+
Additinally, classes that `include` `NDAV::MemoryViewable`, including `Numo::NArray`, `OnnxRuntime::OrtValue` and `Torch::Tensor`, export MemoryViews:
|
|
116
|
+
|
|
117
|
+
memory_view = Fiddle::MemoryView.new(numo)
|
|
118
|
+
memory_view = Fiddle::MemoryView.new(ort_value)
|
|
119
|
+
memory_view = Fiddle::MemoryView.new(torch_tensor)
|
|
120
|
+
|
|
109
121
|
### Notice On Memory Sharing ###
|
|
110
122
|
|
|
111
123
|
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 +159,7 @@ Refer to existing bridge implementations listed above to create your bridge.
|
|
|
147
159
|
|
|
148
160
|
The points are:
|
|
149
161
|
|
|
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
|
|
162
|
+
* 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
163
|
* 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
164
|
* 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
165
|
|
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
|
|
5
|
+
static VALUE sym_addr;
|
|
6
6
|
static VALUE sym_shape;
|
|
7
7
|
static VALUE sym_strides;
|
|
8
8
|
static VALUE sym_format;
|
|
@@ -11,8 +11,8 @@ static VALUE sym_readonly_p;
|
|
|
11
11
|
static VALUE sym_sub_offsets;
|
|
12
12
|
static VALUE sym_ndim;
|
|
13
13
|
static VALUE sym_item_size;
|
|
14
|
-
static
|
|
15
|
-
static VALUE
|
|
14
|
+
static ID id_new;
|
|
15
|
+
static VALUE cItemComponent;
|
|
16
16
|
|
|
17
17
|
typedef struct {
|
|
18
18
|
VALUE descriptor;
|
|
@@ -31,155 +31,115 @@ 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
|
-
|
|
52
|
+
ndav_memory_viewable_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
36
53
|
{
|
|
37
|
-
bool row_major_requested = (flags & RUBY_MEMORY_VIEW_ROW_MAJOR) == RUBY_MEMORY_VIEW_ROW_MAJOR;
|
|
38
|
-
bool column_major_requested = (flags & RUBY_MEMORY_VIEW_COLUMN_MAJOR) == RUBY_MEMORY_VIEW_COLUMN_MAJOR;
|
|
39
|
-
bool indirect_requested = (flags & RUBY_MEMORY_VIEW_INDIRECT) == RUBY_MEMORY_VIEW_INDIRECT;
|
|
40
54
|
VALUE desc = rb_funcall(ndav, id_ndav_validated_descriptor, 1, INT2NUM(flags));
|
|
41
55
|
if (!RB_TYPE_P(desc, T_HASH)) {
|
|
42
56
|
rb_warn("descriptor not Hash");
|
|
43
57
|
return false;
|
|
44
58
|
}
|
|
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);
|
|
47
|
-
if (row_major_requested && column_major_requested) { // row-major OR column-major requested
|
|
48
|
-
if (!row_major_contiguous && !column_major_contiguous) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// Currently, non-contiguous array not supported
|
|
53
|
-
else if (row_major_requested && !row_major_contiguous) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
// Currently, non-contiguous array not supported
|
|
57
|
-
else if (column_major_requested && !column_major_contiguous) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
bool writable_requested = (flags & RUBY_MEMORY_VIEW_WRITABLE) == RUBY_MEMORY_VIEW_WRITABLE;
|
|
61
|
-
// TODO: Handle flags
|
|
62
59
|
|
|
63
60
|
VALUE readonly_v = rb_hash_aref(desc, sym_readonly_p);
|
|
64
61
|
bool readonly = NIL_P(readonly_v) || RTEST(readonly_v);
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
VALUE byte_size_v = rb_hash_aref(desc, sym_byte_size);
|
|
63
|
+
ssize_t byte_size = NUM2SSIZET(byte_size_v);
|
|
64
|
+
VALUE addr = rb_hash_aref(desc, sym_addr);
|
|
65
|
+
rb_memory_view_t tmp = {0};
|
|
66
|
+
if (!rb_memory_view_init_as_byte_array(&tmp, ndav, NUM2PTR(addr), byte_size, readonly)) {
|
|
67
|
+
rb_warn("failed to initialize");
|
|
67
68
|
return false;
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
VALUE val = rb_hash_aref(desc, sym_data);
|
|
72
|
-
char *data = StringValuePtr(val);
|
|
73
|
-
view->data = data;
|
|
70
|
+
tmp.readonly = readonly;
|
|
71
|
+
tmp.obj = ndav;
|
|
74
72
|
// TODO: Commonalize
|
|
75
|
-
// TODO: Consider:
|
|
76
|
-
// * Use TypedData?
|
|
77
|
-
// * If so, calling attr readers at Ruby layer has performance disadvantage.
|
|
78
|
-
// * Freezing instance vars in #initialize and then embed them to TypedData may be a solution
|
|
79
73
|
VALUE item_size = rb_hash_aref(desc, sym_item_size);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
view->byte_size = NUM2SSIZET(byte_size);
|
|
74
|
+
tmp.item_size = NUM2SSIZET(item_size);
|
|
75
|
+
tmp.byte_size = byte_size;
|
|
83
76
|
VALUE ndim = rb_hash_aref(desc, sym_ndim);
|
|
84
|
-
|
|
77
|
+
tmp.ndim = NUM2SSIZET(ndim);
|
|
85
78
|
VALUE format = rb_hash_aref(desc, sym_format);
|
|
86
|
-
|
|
79
|
+
tmp.format = StringValueCStr(format);
|
|
87
80
|
|
|
88
81
|
// TODO: Commonalize
|
|
89
82
|
VALUE shape = rb_hash_aref(desc, sym_shape);
|
|
90
|
-
|
|
91
|
-
rb_warn("@shape is not an array");
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
ssize_t *view_shape = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
|
|
83
|
+
ssize_t *view_shape = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
|
|
95
84
|
if (!view_shape) {
|
|
85
|
+
release_memview_common(&tmp);
|
|
96
86
|
return false;
|
|
97
87
|
}
|
|
98
|
-
if (!fill_size_array(shape, view_shape,
|
|
99
|
-
free(
|
|
88
|
+
if (!fill_size_array(shape, view_shape, tmp.ndim)) {
|
|
89
|
+
free(view_shape);
|
|
90
|
+
release_memview_common(&tmp);
|
|
100
91
|
return false;
|
|
101
92
|
}
|
|
102
|
-
|
|
93
|
+
tmp.shape = view_shape;
|
|
103
94
|
|
|
104
95
|
VALUE strides = rb_hash_aref(desc, sym_strides);
|
|
105
|
-
|
|
106
|
-
rb_warn("@strides is not an array");
|
|
107
|
-
free((void *)view->shape);
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
ssize_t *view_strides = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
|
|
96
|
+
ssize_t *view_strides = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
|
|
111
97
|
if (!view_strides) {
|
|
112
|
-
|
|
98
|
+
release_memview_common(&tmp);
|
|
113
99
|
return false;
|
|
114
100
|
}
|
|
115
|
-
if (!fill_size_array(strides, view_strides,
|
|
116
|
-
free(
|
|
117
|
-
|
|
101
|
+
if (!fill_size_array(strides, view_strides, tmp.ndim)) {
|
|
102
|
+
free(view_strides);
|
|
103
|
+
release_memview_common(&tmp);
|
|
118
104
|
return false;
|
|
119
105
|
}
|
|
120
|
-
|
|
106
|
+
tmp.strides = view_strides;
|
|
121
107
|
|
|
122
108
|
VALUE sub_offsets = rb_hash_aref(desc, sym_sub_offsets);
|
|
123
|
-
if (NIL_P(sub_offsets)) {
|
|
124
|
-
|
|
125
|
-
rb_warn("indirect requested but sub_offsets is NULL");
|
|
126
|
-
free((void *)view->shape);
|
|
127
|
-
free((void *)view->strides);
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
view->sub_offsets = NULL;
|
|
131
|
-
} else if (!RB_TYPE_P(sub_offsets, T_ARRAY)) {
|
|
132
|
-
rb_warn("sub_offsets is not an array");
|
|
133
|
-
free((void *)view->shape);
|
|
134
|
-
free((void *)view->strides);
|
|
135
|
-
return false;
|
|
136
|
-
} else {
|
|
137
|
-
ssize_t *view_sub_offsets = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
|
|
109
|
+
if (!NIL_P(sub_offsets)) {
|
|
110
|
+
ssize_t *view_sub_offsets = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
|
|
138
111
|
if (!view_sub_offsets) {
|
|
139
|
-
|
|
140
|
-
free((void *)view->strides);
|
|
112
|
+
release_memview_common(&tmp);
|
|
141
113
|
return false;
|
|
142
114
|
}
|
|
143
|
-
if (!fill_size_array(sub_offsets, view_sub_offsets,
|
|
144
|
-
free(
|
|
145
|
-
|
|
146
|
-
free((void *)view_sub_offsets);
|
|
115
|
+
if (!fill_size_array(sub_offsets, view_sub_offsets, tmp.ndim)) {
|
|
116
|
+
free(view_sub_offsets);
|
|
117
|
+
release_memview_common(&tmp);
|
|
147
118
|
return false;
|
|
148
119
|
}
|
|
149
|
-
|
|
120
|
+
tmp.sub_offsets = view_sub_offsets;
|
|
150
121
|
}
|
|
151
122
|
|
|
152
123
|
private_data_t *private_data = malloc(sizeof(private_data_t));
|
|
153
124
|
if (!private_data) {
|
|
154
|
-
|
|
155
|
-
free((void *)view->strides);
|
|
156
|
-
free((void *)view->sub_offsets);
|
|
125
|
+
release_memview_common(&tmp);
|
|
157
126
|
rb_warn("failed to alloc private_data");
|
|
158
127
|
return false;
|
|
159
128
|
}
|
|
160
129
|
private_data->descriptor = Qnil;
|
|
161
130
|
rb_gc_register_address(&private_data->descriptor);
|
|
162
131
|
private_data->descriptor = desc;
|
|
163
|
-
|
|
132
|
+
tmp.private_data = private_data;
|
|
133
|
+
|
|
134
|
+
*view = tmp;
|
|
164
135
|
|
|
165
136
|
return true;
|
|
166
137
|
}
|
|
167
138
|
|
|
168
139
|
static bool
|
|
169
|
-
|
|
140
|
+
ndav_memory_viewable_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
|
|
170
141
|
{
|
|
171
|
-
|
|
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
|
-
}
|
|
142
|
+
release_memview_common(view);
|
|
183
143
|
if (view->private_data) {
|
|
184
144
|
private_data_t *private_data = (private_data_t *)view->private_data;
|
|
185
145
|
rb_gc_unregister_address(&private_data->descriptor);
|
|
@@ -191,16 +151,21 @@ ndav_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
|
|
|
191
151
|
}
|
|
192
152
|
|
|
193
153
|
static bool
|
|
194
|
-
|
|
154
|
+
ndav_memory_viewable_memory_view_available_p(const VALUE obj)
|
|
195
155
|
{
|
|
196
156
|
VALUE descriptor = rb_funcall(obj, id_ndav_validated_descriptor, 0);
|
|
197
|
-
|
|
157
|
+
if (RB_TYPE_P(descriptor, T_HASH)) {
|
|
158
|
+
return true;
|
|
159
|
+
} else {
|
|
160
|
+
rb_warn("descriptor not Hash");
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
198
163
|
}
|
|
199
164
|
|
|
200
165
|
const struct rb_memory_view_entry ndav_view_entry = {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
166
|
+
ndav_memory_viewable_get_memory_view,
|
|
167
|
+
ndav_memory_viewable_release_memory_view,
|
|
168
|
+
ndav_memory_viewable_memory_view_available_p
|
|
204
169
|
};
|
|
205
170
|
|
|
206
171
|
static VALUE
|
|
@@ -214,11 +179,74 @@ ndav_memory_viewable_s_register(VALUE mod, VALUE klass)
|
|
|
214
179
|
return Qtrue;
|
|
215
180
|
}
|
|
216
181
|
|
|
182
|
+
typedef struct init_item_components_args {
|
|
183
|
+
rb_memory_view_item_component_t *members;
|
|
184
|
+
size_t n_members;
|
|
185
|
+
} init_item_components_args;
|
|
186
|
+
|
|
187
|
+
static VALUE
|
|
188
|
+
init_item_components(VALUE args_v)
|
|
189
|
+
{
|
|
190
|
+
init_item_components_args *args = (init_item_components_args *)args_v;
|
|
191
|
+
VALUE members = rb_ary_new_capa(args->n_members);
|
|
192
|
+
|
|
193
|
+
for (size_t i = 0; i < args->n_members; i++) {
|
|
194
|
+
rb_ary_push(members, rb_funcall(
|
|
195
|
+
cItemComponent,
|
|
196
|
+
id_new,
|
|
197
|
+
6,
|
|
198
|
+
rb_str_new(&args->members[i].format, 1),
|
|
199
|
+
args->members[i].native_size_p ? Qtrue : Qfalse,
|
|
200
|
+
args->members[i].little_endian_p ? Qtrue : Qfalse,
|
|
201
|
+
SIZET2NUM(args->members[i].offset),
|
|
202
|
+
SIZET2NUM(args->members[i].size),
|
|
203
|
+
SIZET2NUM(args->members[i].repeat)
|
|
204
|
+
));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return members;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Want to be implemented in Fiddle gem
|
|
211
|
+
static VALUE
|
|
212
|
+
ndav_s_parse_item_format(VALUE klass, VALUE format)
|
|
213
|
+
{
|
|
214
|
+
rb_memory_view_item_component_t *members;
|
|
215
|
+
size_t n_members;
|
|
216
|
+
const char *err;
|
|
217
|
+
|
|
218
|
+
ssize_t byte_size = rb_memory_view_parse_item_format(
|
|
219
|
+
StringValueCStr(format),
|
|
220
|
+
&members,
|
|
221
|
+
&n_members,
|
|
222
|
+
&err
|
|
223
|
+
);
|
|
224
|
+
if (byte_size < 0) {
|
|
225
|
+
rb_raise(rb_eRuntimeError, "Parse error at: %s", err);
|
|
226
|
+
}
|
|
227
|
+
if (n_members == 0) {
|
|
228
|
+
xfree(members);
|
|
229
|
+
return rb_ary_new();
|
|
230
|
+
}
|
|
231
|
+
init_item_components_args args = {
|
|
232
|
+
.members = members,
|
|
233
|
+
.n_members = n_members
|
|
234
|
+
};
|
|
235
|
+
int state = 0;
|
|
236
|
+
VALUE members_v = rb_protect(init_item_components, (VALUE)&args, &state);
|
|
237
|
+
xfree(members);
|
|
238
|
+
if (state != 0) {
|
|
239
|
+
rb_jump_tag(state);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return members_v;
|
|
243
|
+
}
|
|
244
|
+
|
|
217
245
|
void
|
|
218
246
|
Init_ndav(void)
|
|
219
247
|
{
|
|
220
248
|
id_ndav_validated_descriptor = rb_intern("ndav_validated_descriptor");
|
|
221
|
-
|
|
249
|
+
sym_addr = ID2SYM(rb_intern("addr"));
|
|
222
250
|
sym_shape = ID2SYM(rb_intern("shape"));
|
|
223
251
|
sym_strides = ID2SYM(rb_intern("strides"));
|
|
224
252
|
sym_format = ID2SYM(rb_intern("format"));
|
|
@@ -227,10 +255,13 @@ Init_ndav(void)
|
|
|
227
255
|
sym_sub_offsets = ID2SYM(rb_intern("sub_offsets"));
|
|
228
256
|
sym_ndim = ID2SYM(rb_intern("ndim"));
|
|
229
257
|
sym_item_size = ID2SYM(rb_intern("item_size"));
|
|
230
|
-
|
|
231
|
-
sym_column_major_contiguous_p = ID2SYM(rb_intern("column_major_contiguous?"));
|
|
258
|
+
id_new = rb_intern("new");
|
|
232
259
|
|
|
233
260
|
VALUE cNDAV = rb_define_class("NDAV", rb_cObject);
|
|
234
261
|
VALUE mMemoryViewable = rb_define_module_under(cNDAV, "MemoryViewable");
|
|
235
262
|
rb_define_singleton_method(mMemoryViewable, "register", ndav_memory_viewable_s_register, 1);
|
|
263
|
+
|
|
264
|
+
rb_require("ndav/item_component");
|
|
265
|
+
cItemComponent = rb_path2class("NDAV::ItemComponent");
|
|
266
|
+
rb_define_singleton_method(cNDAV, "parse_item_format", ndav_s_parse_item_format, 1);
|
|
236
267
|
}
|
data/lib/ndav/ffi.rb
CHANGED
|
@@ -20,7 +20,7 @@ class NDAV
|
|
|
20
20
|
module ToNDAV
|
|
21
21
|
def to_ndav(format: TYPE_SIZE_TO_FORMAT[type_size], lifetime: self, **)
|
|
22
22
|
shape = [size / type_size]
|
|
23
|
-
byte_size = shape.reduce(ITEM_SIZES[format], :*)
|
|
23
|
+
byte_size = shape.reduce(::NDAV::ITEM_SIZES[format], :*)
|
|
24
24
|
ptr = ::Fiddle::Pointer.new(address, byte_size)
|
|
25
25
|
::NDAV.new(ptr, shape:, format:, lifetime:, **)
|
|
26
26
|
end
|
|
@@ -30,7 +30,7 @@ class NDAV
|
|
|
30
30
|
def ndav_descriptor(**)
|
|
31
31
|
shape = [size / type_size]
|
|
32
32
|
format = TYPE_SIZE_TO_FORMAT[type_size]
|
|
33
|
-
item_size = ITEM_SIZES[format]
|
|
33
|
+
item_size = ::NDAV::ITEM_SIZES[format]
|
|
34
34
|
byte_size = shape.reduce(item_size, :*)
|
|
35
35
|
ptr = ::Fiddle::Pointer.new(address, byte_size)
|
|
36
36
|
|
|
@@ -69,7 +69,7 @@ class NDAV
|
|
|
69
69
|
|
|
70
70
|
module ToNDAV
|
|
71
71
|
def to_ndav(shape:, format: TYPE_SIZE_TO_FORMAT[type_size], lifetime: self, **)
|
|
72
|
-
byte_size = shape.reduce(ITEM_SIZES[format], :*)
|
|
72
|
+
byte_size = shape.reduce(::NDAV::ITEM_SIZES[format], :*)
|
|
73
73
|
ptr = ::Fiddle::Pointer.new(address, byte_size)
|
|
74
74
|
::NDAV.new(ptr, shape:, format:, lifetime:, **)
|
|
75
75
|
end
|
data/lib/ndav/flags.rb
CHANGED
|
@@ -15,11 +15,15 @@ class NDAV
|
|
|
15
15
|
|
|
16
16
|
def decode(flags)
|
|
17
17
|
FLAGS.each_with_object({}) {|(name, value), state|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
state[name] = case name
|
|
19
|
+
when :simple
|
|
20
|
+
flags == value
|
|
21
|
+
when :any_contiguous
|
|
22
|
+
(flags & FLAGS[:row_major]) == FLAGS[:row_major] ||
|
|
23
|
+
(flags & FLAGS[:column_major]) == FLAGS[:column_major]
|
|
24
|
+
else
|
|
25
|
+
flags & value == value
|
|
26
|
+
end
|
|
23
27
|
}
|
|
24
28
|
end
|
|
25
29
|
end
|
data/lib/ndav/import.rb
ADDED
data/lib/ndav/memory_viewable.rb
CHANGED
|
@@ -1,43 +1,114 @@
|
|
|
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 keyword 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:,
|
|
25
|
+
# writable:,
|
|
26
|
+
# format:,
|
|
27
|
+
# multi_dimensional:,
|
|
28
|
+
# strides:,
|
|
29
|
+
# row_major:,
|
|
30
|
+
# column_major:,
|
|
31
|
+
# any_contiguous:,
|
|
32
|
+
# indirect:
|
|
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)
|
|
5
|
-
|
|
49
|
+
register base
|
|
6
50
|
end
|
|
7
51
|
end
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
56
|
+
flags = ::NDAV::Flags.decode(flags)
|
|
57
|
+
desc = ndav_descriptor(**flags).to_h
|
|
58
|
+
desc => {data:, shape:, strides:, format:, byte_size:, readonly?: readonly}
|
|
59
|
+
sub_offsets = desc[:sub_offsets]
|
|
60
|
+
|
|
30
61
|
[:data, :shape, :strides, :format, :byte_size, :readonly?].each do |key|
|
|
31
|
-
|
|
32
|
-
warn ":#{key}
|
|
62
|
+
if desc[key].nil?
|
|
63
|
+
warn ":#{key} is nil"
|
|
64
|
+
return false
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
[:shape, :strides].each do |key|
|
|
68
|
+
unless desc[key].instance_of? Array
|
|
69
|
+
warn "#{key} not Array"
|
|
33
70
|
return false
|
|
34
71
|
end
|
|
35
72
|
end
|
|
73
|
+
if sub_offsets && !sub_offsets.instance_of?(Array)
|
|
74
|
+
warn "sub_offsets not Array"
|
|
75
|
+
return false
|
|
76
|
+
end
|
|
77
|
+
item_size = ::NDAV::ITEM_SIZES[format]
|
|
78
|
+
unless shape.reduce(item_size, :*) == byte_size
|
|
79
|
+
warn "item size from format and shape not match byte_size"
|
|
80
|
+
return false
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
if flags[:writable] && readonly
|
|
84
|
+
warn "not writable"
|
|
85
|
+
return false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# TODO: Research the meaning of MULTI_DIMENSIONAL and validate it
|
|
89
|
+
|
|
90
|
+
if flags[:indirect] && !sub_offsets
|
|
91
|
+
warn "indirect requested but sub_offsets is NULL"
|
|
92
|
+
return false
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
row_major_contiguous = ::NDAV.row_major_contiguous?(format:, shape:, strides:)
|
|
96
|
+
column_major_contiguous = ::NDAV.column_major_contiguous?(format:, shape:, strides:)
|
|
97
|
+
if flags[:row_major] && !row_major_contiguous
|
|
98
|
+
return false
|
|
99
|
+
end
|
|
100
|
+
if flags[:column_major] && !column_major_contiguous
|
|
101
|
+
return false
|
|
102
|
+
end
|
|
103
|
+
if flags[:any_contiguous] && !row_major_contiguous && !column_major_contiguous
|
|
104
|
+
return false
|
|
105
|
+
end
|
|
106
|
+
|
|
36
107
|
desc.merge(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
108
|
+
addr: ::Fiddle::Pointer.to_ptr(data).to_i,
|
|
109
|
+
ndim: shape.length,
|
|
110
|
+
item_size:,
|
|
111
|
+
sub_offsets:
|
|
41
112
|
)
|
|
42
113
|
rescue => err
|
|
43
114
|
warn err
|
data/lib/ndav.rb
CHANGED
|
@@ -3,19 +3,52 @@ require "ndav.so"
|
|
|
3
3
|
require "ndav/flags"
|
|
4
4
|
require "ndav/converter"
|
|
5
5
|
require "ndav/memory_viewable"
|
|
6
|
+
require "ndav/import"
|
|
6
7
|
|
|
7
|
-
# TODO: Manage flags of internal data object
|
|
8
8
|
class NDAV
|
|
9
9
|
include MemoryViewable
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
ITEM_SIZES = Hash.new {|sizes, format| sizes[format] = item_size_from_format(format)}
|
|
12
|
+
ITEM_DESCS = Hash.new {|descs, format| descs[format] = parse_item_format(format)}
|
|
13
|
+
DEFAULT_FORMATS = {
|
|
14
|
+
1 => "C",
|
|
15
|
+
2 => "s",
|
|
16
|
+
4 => "l",
|
|
17
|
+
8 => "q"
|
|
18
|
+
}
|
|
15
19
|
|
|
16
|
-
attr_reader :ndim, :shape, :format, :item_size, :byte_size, :strides, :to_s, :lifetime
|
|
20
|
+
attr_reader :ndim, :shape, :format, :item_size, :byte_size, :strides, :sub_offsets, :to_s, :lifetime
|
|
17
21
|
|
|
18
22
|
class << self
|
|
23
|
+
# * Doesn't modify byte_size
|
|
24
|
+
# * Keyword arguments override obj's MemoryView members
|
|
25
|
+
# * Overrides obj's members as required by keyword arguments
|
|
26
|
+
# * ex) format: "C" requires item_size = 1 even if obj's item_size isn't it
|
|
27
|
+
# * Raises exception if keyword arguments conflict
|
|
28
|
+
alias new_override new
|
|
29
|
+
|
|
30
|
+
# * Raises exception when a keyword argument is not nil and obj's corresponding member is not nil
|
|
31
|
+
def new(obj, shape: nil, strides: nil, format: nil, lifetime: nil)
|
|
32
|
+
is_fmv = obj.kind_of? Fiddle::MemoryView
|
|
33
|
+
fmv = is_fmv ? obj : Fiddle::MemoryView.new(obj)
|
|
34
|
+
|
|
35
|
+
if shape && fmv.shape
|
|
36
|
+
raise ArgumentError, "shape is already set. Cannot override."
|
|
37
|
+
end
|
|
38
|
+
if strides && fmv.strides
|
|
39
|
+
raise ArgumentError, "strides is already set. Cannot override."
|
|
40
|
+
end
|
|
41
|
+
if format && fmv.format
|
|
42
|
+
raise ArgumentError, "format is already set. Cannot override."
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
new_override(obj, shape:, strides:, format:, lifetime:)
|
|
46
|
+
ensure
|
|
47
|
+
unless is_fmv
|
|
48
|
+
fmv&.release
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
19
52
|
def default_strides(shape:, item_size:, row_major: true)
|
|
20
53
|
each_shape = row_major ? shape.reverse_each : shape.each
|
|
21
54
|
each_shape.reduce([[], item_size]) {|(strides, stride), s|
|
|
@@ -57,50 +90,78 @@ class NDAV
|
|
|
57
90
|
|
|
58
91
|
true
|
|
59
92
|
end
|
|
93
|
+
|
|
94
|
+
def item_size_from_format(format)
|
|
95
|
+
err = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
|
|
96
|
+
size = Import.rb_memory_view_item_size_from_format(format, err)
|
|
97
|
+
if size < 0
|
|
98
|
+
raise ArgumentError, "Invalid format character: #{err.ptr.to_s}"
|
|
99
|
+
else
|
|
100
|
+
size
|
|
101
|
+
end
|
|
102
|
+
ensure
|
|
103
|
+
err&.free
|
|
104
|
+
end
|
|
60
105
|
end
|
|
61
106
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
107
|
+
def initialize(obj, readonly: nil, format: nil, item_size: nil, shape: nil, strides: nil, sub_offsets: nil, lifetime: nil)
|
|
108
|
+
# We cannot determine flags until ndav_descriptor is called but some MemoryView producer like Fiddle::Pointer and IO::Buffer determines some members by flags.
|
|
109
|
+
# For instance, Fiddle::Pointer's MemoryView is readonly when writable flag is not passed and is not readonly when writable flag is passed.
|
|
110
|
+
# How should we solve this mismatching? Delaying to determine the flags?
|
|
111
|
+
# Considers when it becomes actual problem.
|
|
112
|
+
@fmv = obj.kind_of?(::Fiddle::MemoryView) ? obj : ::Fiddle::MemoryView.new(obj)
|
|
65
113
|
# Fiddle::MemoryView#to_s is zero-copy
|
|
66
114
|
# Fiddle::MemoryView#to_s embeds obj into the String, so we can prevent GC from collecting it
|
|
67
|
-
@to_s = fmv.to_s
|
|
115
|
+
@to_s = @fmv.to_s
|
|
68
116
|
@lifetime = lifetime
|
|
117
|
+
@byte_size = @fmv.byte_size
|
|
69
118
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
119
|
+
case [format, item_size]
|
|
120
|
+
in [nil, nil]
|
|
121
|
+
@format = @fmv.format || "C"
|
|
122
|
+
@item_size = @fmv.item_size
|
|
123
|
+
in [_, nil]
|
|
124
|
+
@format = format
|
|
125
|
+
@item_size = ITEM_SIZES[@format]
|
|
126
|
+
in [nil, _]
|
|
127
|
+
@item_size = item_size
|
|
128
|
+
@format = DEFAULT_FORMATS[@item_size] || @fmv.format
|
|
129
|
+
else
|
|
130
|
+
@format = format
|
|
131
|
+
@item_size = item_size
|
|
132
|
+
end
|
|
74
133
|
|
|
75
|
-
|
|
76
|
-
@item_size = obj.kind_of?(::Fiddle::Pointer) ? item_size_by_format : fmv.item_size || item_size_by_format
|
|
77
|
-
@shape = shape || fmv.shape
|
|
78
|
-
case [@shape, @byte_size]
|
|
134
|
+
case [shape, @byte_size]
|
|
79
135
|
in [nil, nil]
|
|
80
|
-
|
|
136
|
+
@shape = @fmv.shape
|
|
137
|
+
@byte_size = @shape.reduce(@item_size, :*)
|
|
81
138
|
in [_, nil]
|
|
139
|
+
@shape = shape
|
|
82
140
|
@byte_size = @shape.reduce(@item_size, :*)
|
|
83
141
|
in [nil, _]
|
|
84
|
-
|
|
85
|
-
raise ArgumentError, "byte_size must be n-times of item_size" unless r.zero?
|
|
86
|
-
@shape = [n]
|
|
142
|
+
@shape = @fmv.shape || [@byte_size / @item_size]
|
|
87
143
|
else
|
|
88
|
-
|
|
144
|
+
@shape = shape
|
|
89
145
|
end
|
|
146
|
+
|
|
90
147
|
@ndim = @shape.size
|
|
91
|
-
@readonly = fmv.readonly?
|
|
92
|
-
@strides = strides || fmv.strides || self.class.default_strides(shape: @shape, item_size: @item_size)
|
|
93
|
-
@sub_offsets = fmv.sub_offsets
|
|
148
|
+
@readonly = readonly.nil? ? @fmv.readonly? : readonly
|
|
149
|
+
@strides = strides || @fmv.strides || self.class.default_strides(shape: @shape, item_size: @item_size)
|
|
150
|
+
@sub_offsets = sub_offsets || @fmv.sub_offsets
|
|
94
151
|
@row_major_contiguous = self.class.row_major_contiguous?(format: @format, shape: @shape, strides: @strides)
|
|
95
152
|
@column_major_contiguous = self.class.column_major_contiguous?(format: @format, shape: @shape, strides: @strides)
|
|
96
153
|
|
|
97
|
-
validate
|
|
154
|
+
validate
|
|
98
155
|
end
|
|
99
156
|
|
|
100
157
|
def readonly?
|
|
101
158
|
@readonly
|
|
102
159
|
end
|
|
103
160
|
|
|
161
|
+
def item_desc
|
|
162
|
+
ITEM_DESCS[@format]
|
|
163
|
+
end
|
|
164
|
+
|
|
104
165
|
def row_major_contiguous?
|
|
105
166
|
@row_major_contiguous
|
|
106
167
|
end
|
|
@@ -114,9 +175,16 @@ class NDAV
|
|
|
114
175
|
end
|
|
115
176
|
alias to_fiddle_pointer to_ptr
|
|
116
177
|
|
|
178
|
+
def release
|
|
179
|
+
@fmv.release
|
|
180
|
+
@fmv = @ndim = @readonly = @shape = @format = @item_size = @byte_size = @strides = @sub_offsets = @lifetime = @to_s = @row_major_contiguous = @column_major_contiguous = nil
|
|
181
|
+
end
|
|
182
|
+
|
|
117
183
|
private
|
|
118
184
|
|
|
119
185
|
def ndav_descriptor(**)
|
|
186
|
+
return false unless @fmv
|
|
187
|
+
|
|
120
188
|
{
|
|
121
189
|
data: @to_s,
|
|
122
190
|
shape: @shape,
|
|
@@ -128,16 +196,47 @@ class NDAV
|
|
|
128
196
|
}
|
|
129
197
|
end
|
|
130
198
|
|
|
131
|
-
def validate
|
|
199
|
+
def validate
|
|
200
|
+
raise ArgumentError, "byte_size must be present" unless @byte_size
|
|
201
|
+
|
|
132
202
|
unless @item_size == ITEM_SIZES[@format]
|
|
133
|
-
raise ArgumentError, "item_size does not match format"
|
|
203
|
+
raise ArgumentError, "item_size does not match format. item_size: #{@item_size.inspect}, format: #{@format.inspect}"
|
|
134
204
|
end
|
|
135
205
|
|
|
206
|
+
r = @byte_size % @item_size
|
|
207
|
+
raise ArgumentError, "byte_size must be n-times of item_size" unless r.zero?
|
|
208
|
+
|
|
209
|
+
raise ArgumentError, "shape length doen't match ndim" unless @shape.length == @ndim
|
|
136
210
|
if @row_major_contiguous || @column_major_contiguous
|
|
137
|
-
byte_size
|
|
138
|
-
|
|
139
|
-
|
|
211
|
+
unless @byte_size == @shape.reduce(@item_size, :*)
|
|
212
|
+
raise ArgumentError, "shape not match byte_size"
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
raise ArgumentError, "strides length doen't match ndim" unless @strides.length == @ndim
|
|
217
|
+
if @row_major_contiguous
|
|
218
|
+
stride = @item_size
|
|
219
|
+
@strides.reverse_each.with_index do |s, i|
|
|
220
|
+
raise ArgumentError, "invalid strides" unless s == stride
|
|
221
|
+
stride *= @shape[@ndim - i - 1]
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
max_offset = 0
|
|
225
|
+
min_offset = 0
|
|
226
|
+
@shape.zip(@strides) do |s, stride|
|
|
227
|
+
next if s == 0
|
|
228
|
+
|
|
229
|
+
extent = (s - 1) * stride
|
|
230
|
+
max_offset += [extent, 0].max
|
|
231
|
+
min_offset += [extent, 0].min
|
|
232
|
+
end
|
|
233
|
+
if min_offset < 0
|
|
234
|
+
# NDAV uses Fiddle::MemoryView#to_s and it doesn't allow negative min offset
|
|
235
|
+
# Some MemoryView might allow negative min offset
|
|
236
|
+
# Remove this check if such the MemoryView producer is found
|
|
237
|
+
raise ArgumentError, "min offset must be positive"
|
|
140
238
|
end
|
|
239
|
+
raise ArgumentError, "max offset too large" if max_offset + @item_size > @byte_size
|
|
141
240
|
end
|
|
142
241
|
end
|
|
143
242
|
end
|
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.
|
|
3
|
+
s.version = "0.0.7"
|
|
4
4
|
s.summary = "N-Dimensional Array View"
|
|
5
5
|
s.authors = ["Kitaiti Makoto"]
|
|
6
6
|
s.licenses = ["BSD-2-Clause"]
|
|
@@ -22,5 +22,4 @@ Gem::Specification.new do |s|
|
|
|
22
22
|
s.add_development_dependency "red-arrow"
|
|
23
23
|
s.add_development_dependency "ffi"
|
|
24
24
|
s.add_development_dependency "yard"
|
|
25
|
-
s.add_development_dependency "commonmarker"
|
|
26
25
|
end
|
data/test/test_flags.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require_relative "helper"
|
|
2
|
+
|
|
3
|
+
class TestFlags < TestBase
|
|
4
|
+
include NDAV::Flags
|
|
5
|
+
|
|
6
|
+
def test_any_contiguous
|
|
7
|
+
decoded = decode(combine_flags(:any_contiguous))
|
|
8
|
+
assert_true decoded[:row_major]
|
|
9
|
+
assert_true decoded[:column_major]
|
|
10
|
+
assert_true decoded[:any_contiguous]
|
|
11
|
+
|
|
12
|
+
decoded = decode(combine_flags(:row_major))
|
|
13
|
+
assert_true decoded[:row_major]
|
|
14
|
+
assert_false decoded[:column_major]
|
|
15
|
+
assert_true decoded[:any_contiguous]
|
|
16
|
+
|
|
17
|
+
decoded = decode(combine_flags(:column_major))
|
|
18
|
+
assert_false decoded[:row_major]
|
|
19
|
+
assert_true decoded[:column_major]
|
|
20
|
+
assert_true decoded[:any_contiguous]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def combine_flags(*flags)
|
|
26
|
+
flags.reduce(0) {|composed, name| composed | FLAGS[name]}
|
|
27
|
+
end
|
|
28
|
+
end
|
data/test/test_ndav.rb
CHANGED
|
@@ -36,6 +36,19 @@ class TestNDAV < TestBase
|
|
|
36
36
|
assert_int_array ndav
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
def test_item_descs
|
|
40
|
+
assert_equal [
|
|
41
|
+
NDAV::ItemComponent.new(
|
|
42
|
+
format: "s",
|
|
43
|
+
native_size_p: false,
|
|
44
|
+
little_endian_p: true,
|
|
45
|
+
offset: 0,
|
|
46
|
+
size: 2,
|
|
47
|
+
repeat: 1
|
|
48
|
+
)
|
|
49
|
+
], NDAV.new(@array).item_desc
|
|
50
|
+
end
|
|
51
|
+
|
|
39
52
|
def test_column_major
|
|
40
53
|
str = [1, 2, 3,
|
|
41
54
|
4, 5, 6].pack("s*")
|
|
@@ -43,4 +56,151 @@ class TestNDAV < TestBase
|
|
|
43
56
|
|
|
44
57
|
assert_true ndav.column_major_contiguous?
|
|
45
58
|
end
|
|
59
|
+
|
|
60
|
+
def test_release
|
|
61
|
+
ndav = NDAV.new(@array)
|
|
62
|
+
|
|
63
|
+
ndav.release
|
|
64
|
+
[:ndim, :shape, :format, :item_size, :byte_size, :strides, :sub_offsets, :lifetime, :to_s].each do |attr|
|
|
65
|
+
assert_nil ndav.send(attr)
|
|
66
|
+
end
|
|
67
|
+
assert_nil ndav.readonly?
|
|
68
|
+
assert_nil ndav.row_major_contiguous?
|
|
69
|
+
assert_nil ndav.column_major_contiguous?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_parse_item_format
|
|
73
|
+
assert_equal [
|
|
74
|
+
NDAV::ItemComponent.new("f", false, IO::Buffer::HOST_ENDIAN == IO::Buffer::LITTLE_ENDIAN, 0, 4, 1)
|
|
75
|
+
], NDAV.parse_item_format("f")
|
|
76
|
+
|
|
77
|
+
assert_equal [
|
|
78
|
+
NDAV::ItemComponent.new("s", false, true, 0, 2, 1)
|
|
79
|
+
], NDAV.parse_item_format("s<")
|
|
80
|
+
|
|
81
|
+
assert_equal [
|
|
82
|
+
NDAV::ItemComponent.new("C", false, true, 0, 1, 1),
|
|
83
|
+
NDAV::ItemComponent.new("C", false, true, 1, 1, 1),
|
|
84
|
+
NDAV::ItemComponent.new("C", false, true, 2, 1, 1),
|
|
85
|
+
], NDAV.parse_item_format("CCC")
|
|
86
|
+
|
|
87
|
+
assert_equal [
|
|
88
|
+
NDAV::ItemComponent.new("C", false, true, 0, 1, 3)
|
|
89
|
+
], NDAV.parse_item_format("C3")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class TestOverwrite < self
|
|
93
|
+
def test_format
|
|
94
|
+
assert_raise ArgumentError do
|
|
95
|
+
NDAV.new(@array, format: "C")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
ndav = NDAV.new_override(@array, format: "C")
|
|
99
|
+
Fiddle::MemoryView.export ndav do |memview|
|
|
100
|
+
assert_equal "C", memview.format
|
|
101
|
+
assert_equal 1, memview.item_size
|
|
102
|
+
assert_equal 6, memview.byte_size
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
assert_raise ArgumentError do
|
|
106
|
+
NDAV.new(@array, format: "f")
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_item_size
|
|
111
|
+
assert_raise ArgumentError do
|
|
112
|
+
NDAV.new(@array, item_size: 1)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
ndav = NDAV.new_override(@array, item_size: 1)
|
|
116
|
+
Fiddle::MemoryView.export ndav do |memview|
|
|
117
|
+
assert_equal 1, memview.item_size
|
|
118
|
+
assert_equal "C", memview.format
|
|
119
|
+
assert_equal 6, memview.byte_size
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
assert_raise ArgumentError do
|
|
123
|
+
NDAV.new_override(@array, item_size: 4)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_format_and_item_size
|
|
128
|
+
assert_raise ArgumentError do
|
|
129
|
+
NDAV.new(@array, format: "C", item_size: 1)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
ndav = NDAV.new_override(@array, format: "C", item_size: 1)
|
|
133
|
+
Fiddle::MemoryView.export ndav do |memview|
|
|
134
|
+
assert_equal "C", memview.format
|
|
135
|
+
assert_equal 1, memview.item_size
|
|
136
|
+
assert_equal 6, memview.byte_size
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
assert_raise ArgumentError do
|
|
140
|
+
NDAV.new_override(@array, format: "C", item_size: 2)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def test_shape
|
|
145
|
+
array_with_shape = NDAV.new(@array)
|
|
146
|
+
assert_raise ArgumentError do
|
|
147
|
+
NDAV.new(array_with_shape, shape: [3, 1])
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
ndav = NDAV.new_override(@array, shape: [3, 1])
|
|
151
|
+
Fiddle::MemoryView.export ndav do |memview|
|
|
152
|
+
assert_equal [3, 1], memview.shape
|
|
153
|
+
assert_equal 2, memview.ndim
|
|
154
|
+
assert_equal 6, memview.byte_size
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
assert_raise ArgumentError do
|
|
158
|
+
NDAV.new_override(@array, shape: [2, 3, 4])
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_strides
|
|
163
|
+
array_with_shape = NDAV.new(@array)
|
|
164
|
+
assert_raise ArgumentError do
|
|
165
|
+
NDAV.new(array_with_shape, strides: [2])
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
ndav = NDAV.new_override(@array, strides: [2])
|
|
169
|
+
Fiddle::MemoryView.export ndav do |memview|
|
|
170
|
+
assert_equal [2], memview.strides
|
|
171
|
+
assert_equal [3], memview.shape
|
|
172
|
+
assert_equal 2, memview.item_size
|
|
173
|
+
assert_equal 6, memview.byte_size
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
assert_raise ArgumentError do
|
|
177
|
+
NDAV.new_override(@array, strides: [4])
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
assert_raise ArgumentError do
|
|
181
|
+
NDAV.new_override(@array, strides: [6])
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_shape_and_strides
|
|
186
|
+
ndav = NDAV.new_override(@array, shape: [1, 3], strides: [6, 2])
|
|
187
|
+
Fiddle::MemoryView.export ndav do |memview|
|
|
188
|
+
assert_equal [1, 3], memview.shape
|
|
189
|
+
assert_equal [6, 2], memview.strides
|
|
190
|
+
assert_equal 6, memview.byte_size
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def test_overwrite_readonly?
|
|
195
|
+
assert_raise ArgumentError do
|
|
196
|
+
NDAV.new(@array, readonly: false)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
ndav = NDAV.new_override(@array, readonly: false)
|
|
200
|
+
Fiddle::MemoryView.export ndav do |memview|
|
|
201
|
+
assert_false memview.readonly?
|
|
202
|
+
assert_equal 6, memview.byte_size
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
46
206
|
end
|
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.
|
|
4
|
+
version: 0.0.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kitaiti Makoto
|
|
@@ -163,20 +163,6 @@ dependencies:
|
|
|
163
163
|
- - ">="
|
|
164
164
|
- !ruby/object:Gem::Version
|
|
165
165
|
version: '0'
|
|
166
|
-
- !ruby/object:Gem::Dependency
|
|
167
|
-
name: commonmarker
|
|
168
|
-
requirement: !ruby/object:Gem::Requirement
|
|
169
|
-
requirements:
|
|
170
|
-
- - ">="
|
|
171
|
-
- !ruby/object:Gem::Version
|
|
172
|
-
version: '0'
|
|
173
|
-
type: :development
|
|
174
|
-
prerelease: false
|
|
175
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
176
|
-
requirements:
|
|
177
|
-
- - ">="
|
|
178
|
-
- !ruby/object:Gem::Version
|
|
179
|
-
version: '0'
|
|
180
166
|
executables: []
|
|
181
167
|
extensions:
|
|
182
168
|
- ext/extconf.rb
|
|
@@ -195,12 +181,15 @@ files:
|
|
|
195
181
|
- lib/ndav/converter.rb
|
|
196
182
|
- lib/ndav/ffi.rb
|
|
197
183
|
- lib/ndav/flags.rb
|
|
184
|
+
- lib/ndav/import.rb
|
|
185
|
+
- lib/ndav/item_component.rb
|
|
198
186
|
- lib/ndav/memory_viewable.rb
|
|
199
187
|
- ndav.gemspec
|
|
200
188
|
- test/helper.rb
|
|
201
189
|
- test/test_converter.rb
|
|
202
190
|
- test/test_export.rb
|
|
203
191
|
- test/test_ffi.rb
|
|
192
|
+
- test/test_flags.rb
|
|
204
193
|
- test/test_ndav.rb
|
|
205
194
|
- test/test_package.rb
|
|
206
195
|
- test/test_ractor.rb
|