ndav 0.0.4 → 0.0.5
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 +2 -1
- data/README.md +18 -8
- data/ext/ndav.c +155 -64
- data/lib/ndav/converter.rb +13 -0
- data/lib/ndav/ffi.rb +19 -0
- data/lib/ndav/flags.rb +26 -0
- data/lib/ndav/memory_viewable.rb +47 -0
- data/lib/ndav.rb +92 -37
- data/ndav.gemspec +2 -1
- data/test/test_ffi.rb +8 -0
- data/test/test_ndav.rb +8 -0
- data/test/test_ractor.rb +79 -0
- metadata +19 -4
- data/NDAV.png +0 -0
- data/ext/ndav.h +0 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0648fef27ca47ec51a45cacb90330e5fb2de53071d4223604752c04746ad9c2d'
|
|
4
|
+
data.tar.gz: 4af1dacda9bfa1258552bc271d773136b06ea414cce61c75c194c590f1361850
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b81a17db0cc3814963b47e590e2f3e021e86792326a98ad1f246df8f887c4f1e49aec42808c82aeceb522e28f05f7dac9d3a6eb65417fbfc9ff785cb75284723
|
|
7
|
+
data.tar.gz: 798ed5c4f2f84fa73b262af460e0054454a78d6f8a9eeacbb191f0b866c6c4e98ae72ed296af23b7a67d98d6894a988cc22dfc23484267d1773bd91ed7043a63
|
data/.yardopts
CHANGED
data/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A thin wrapper around [MemoryView][] ("buffer protocol" for Ruby).
|
|
|
7
7
|
|
|
8
8
|
It provides an interoperability layer for multi-dimensional arrays which can be shared between libraries.
|
|
9
9
|
|
|
10
|
-

|
|
11
11
|
|
|
12
12
|
SYNOPSIS
|
|
13
13
|
--------
|
|
@@ -70,7 +70,7 @@ USAGE
|
|
|
70
70
|
ndav = NDAV.from_numo_narray(numo) # => NDAV
|
|
71
71
|
|
|
72
72
|
include NDAV::Converter
|
|
73
|
-
numo = NumoNArray(ndav)
|
|
73
|
+
numo = NumoNArray(ndav) # => Numo::SFloat
|
|
74
74
|
ndav = NDAV(numo) # => NDAV
|
|
75
75
|
|
|
76
76
|
For `Torch::Tensor` and `OnnxRuntime::OrtValue`, you can do the same operation, therefore you may convert them to each other, like this:
|
|
@@ -100,7 +100,7 @@ NDAV can be initialized *directly* from libraries which export [MemoryView][] su
|
|
|
100
100
|
arrow = Arrow::Int16Array.new([1, 2, 3])
|
|
101
101
|
ndav = NDAV.new(arrow)
|
|
102
102
|
|
|
103
|
-
On the other hand, it also exports MemoryView. You can pass NDAV arrays *directly* to methods which accept MemoryView such as whispercpp without bridge libraries:
|
|
103
|
+
On the other hand, it also exports MemoryView. You can pass NDAV arrays *directly* to methods which accept MemoryView such as [whispercpp][] without bridge libraries:
|
|
104
104
|
|
|
105
105
|
waveform, sample_rate = TorchAudio.load("path/to/audio.wav")
|
|
106
106
|
samples = waveform.to_ndav
|
|
@@ -128,12 +128,18 @@ BRIDGES
|
|
|
128
128
|
|
|
129
129
|
There are some bridges using NDAV:
|
|
130
130
|
|
|
131
|
-
*
|
|
131
|
+
* {file:ndav/ffi ndav/ffi}: [`FFI::MemoryPointer`][FFI Pointer], [`FFI::Pointer`][FFI Pointer] <-> `NDAV`
|
|
132
132
|
* [ndav-numo-narray][]: [`Numo::NArray`][Numo::NArray] <-> `NDAV`
|
|
133
133
|
* [ndav-ort_value][]: [`OnnxRuntime::OrtValue`][ONNX Runtime Ruby] <-> `NDAV`
|
|
134
134
|
* [ndav-torch-tensor][]: [`Torch::Tensor`][Torch.rb] <-> `NDAV`
|
|
135
135
|
* [onnxruntime-torch-tensor][]: [`Torch::Tensor`][Torch.rb] <-> [`OnnxRuntime::OrtValue`][ONNX Runtime Ruby] via `NDAV`
|
|
136
136
|
|
|
137
|
+
APPLICATIONS AND LIBRARIES WHICH USE NDAV
|
|
138
|
+
-----------------------------------------
|
|
139
|
+
|
|
140
|
+
* [GTCRN][] - An audio speech enhancement (noise reduction) library. It uses [TorchAudio][] for loading and preprocessing audio before passing it to ONNX Runtime, then performs post-processing on the result and writes it back to a file.
|
|
141
|
+
* [Itak][] - An audio processing tool for podcasters. After reducing noise with the GTCRN mentioned above, it uses the VAD function of [whispercpp][] to remove silent periods. Although whispercpp does not accept existing tensor libraries, it does accept MemoryView, so it can be passed via NDAV.
|
|
142
|
+
|
|
137
143
|
CREATING BRIDGES
|
|
138
144
|
----------------
|
|
139
145
|
|
|
@@ -141,8 +147,8 @@ Refer to existing bridge implementations listed above to create your bridge.
|
|
|
141
147
|
|
|
142
148
|
The points are:
|
|
143
149
|
|
|
144
|
-
* Implement `FromNDAV#from_ndav`, `ToNDAV#to_ndav
|
|
145
|
-
* When initializing NDAV object from your object, use `lifetime` keyword argument for
|
|
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
|
|
151
|
+
* 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
|
|
146
152
|
* 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
|
|
147
153
|
|
|
148
154
|
An advantage of NDAV over raw MemoryView is that you can write bridges in pure Ruby in most cases. It helps prototyping and experimentation. As an exception, I had to write C code for ndav-numo-narray because Numo::NArray only provides methods that access data by copying and does not directly expose its raw data pointer to Ruby API. However, in even such case, pure Ruby bridge remains a viable option for prototyping and experiments where a single initial copy is acceptable.
|
|
@@ -157,7 +163,7 @@ If [MemoryView][] gets popular enough in the Ruby ecosystem, this library will e
|
|
|
157
163
|
LICENSE
|
|
158
164
|
-------
|
|
159
165
|
|
|
160
|
-
BSD-2-Clause license. See LICENSE.txt file.
|
|
166
|
+
BSD-2-Clause license. See {file:LICENSE.txt} file.
|
|
161
167
|
|
|
162
168
|
[MemoryView]: https://docs.ruby-lang.org/en/master/contributing/memory_view_md.html
|
|
163
169
|
[Numo::NArray]: https://ruby-numo.github.io/narray/
|
|
@@ -165,9 +171,13 @@ BSD-2-Clause license. See LICENSE.txt file.
|
|
|
165
171
|
[ONNX Runtime Ruby]: https://github.com/ankane/onnxruntime-ruby
|
|
166
172
|
[Red Arrow]: https://github.com/apache/arrow/tree/main/ruby
|
|
167
173
|
[Red Arrow Numo::NArray]: https://github.com/red-data-tools/red-arrow-numo-narray
|
|
168
|
-
[ndav/ffi]: https://gitlab.com/KitaitiMakoto/ndav/-/blob/main/lib/ndav/ffi.rb
|
|
174
|
+
[ndav/ffi]: https://gitlab.com/KitaitiMakoto/ndav/-/blob/main/lib/ndav/ffi.rb
|
|
169
175
|
[FFI Pointer]: https://github.com/ffi/ffi/wiki/Pointers
|
|
176
|
+
[whispercpp]: https://github.com/ggml-org/whisper.cpp/tree/master/bindings/ruby
|
|
170
177
|
[ndav-numo-narray]: https://gitlab.com/KitaitiMakoto/ndav-numo-narray
|
|
171
178
|
[ndav-ort_value]: https://gitlab.com/KitaitiMakoto/ndav-ort_value
|
|
172
179
|
[ndav-torch-tensor]: https://gitlab.com/KitaitiMakoto/ndav-torch-tensor
|
|
173
180
|
[onnxruntime-torch-tensor]: https://gitlab.com/KitaitiMakoto/onnxruntime-torch-tensor
|
|
181
|
+
[GTCRN]: https://gitlab.com/KitaitiMakoto/gtcrn
|
|
182
|
+
[TorchAudio]: https://github.com/ankane/torchaudio-ruby
|
|
183
|
+
[Itak]: https://gitlab.com/KitaitiMakoto/itak
|
data/ext/ndav.c
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
#include
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include <ruby/memory_view.h>
|
|
3
|
+
|
|
4
|
+
static ID id_ndav_validated_descriptor;
|
|
5
|
+
static VALUE sym_data;
|
|
6
|
+
static VALUE sym_shape;
|
|
7
|
+
static VALUE sym_strides;
|
|
8
|
+
static VALUE sym_format;
|
|
9
|
+
static VALUE sym_byte_size;
|
|
10
|
+
static VALUE sym_readonly_p;
|
|
11
|
+
static VALUE sym_sub_offsets;
|
|
12
|
+
static VALUE sym_ndim;
|
|
13
|
+
static VALUE sym_item_size;
|
|
14
|
+
static VALUE sym_row_major_contiguous_p;
|
|
15
|
+
static VALUE sym_column_major_contiguous_p;
|
|
16
|
+
|
|
17
|
+
typedef struct {
|
|
18
|
+
VALUE descriptor;
|
|
19
|
+
} private_data_t;
|
|
2
20
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
typedef struct fill_size_array_args_t {
|
|
6
|
-
VALUE src;
|
|
7
|
-
ssize_t *dest;
|
|
8
|
-
ssize_t size;
|
|
9
|
-
} fill_size_array_args_t;
|
|
10
|
-
|
|
11
|
-
static VALUE
|
|
12
|
-
fill_size_array(VALUE rb_args)
|
|
21
|
+
static bool
|
|
22
|
+
fill_size_array(VALUE src, ssize_t *dest, ssize_t size)
|
|
13
23
|
{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
for (ssize_t i = 0; i < size; i++) {
|
|
25
|
+
VALUE val = rb_ary_entry(src, i);
|
|
26
|
+
if (!RB_INTEGER_TYPE_P(val)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
dest[i] = NUM2SSIZET(val);
|
|
18
30
|
}
|
|
19
|
-
return
|
|
31
|
+
return true;
|
|
20
32
|
}
|
|
21
33
|
|
|
22
34
|
static bool
|
|
@@ -25,24 +37,38 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
|
25
37
|
bool row_major_requested = (flags & RUBY_MEMORY_VIEW_ROW_MAJOR) == RUBY_MEMORY_VIEW_ROW_MAJOR;
|
|
26
38
|
bool column_major_requested = (flags & RUBY_MEMORY_VIEW_COLUMN_MAJOR) == RUBY_MEMORY_VIEW_COLUMN_MAJOR;
|
|
27
39
|
bool indirect_requested = (flags & RUBY_MEMORY_VIEW_INDIRECT) == RUBY_MEMORY_VIEW_INDIRECT;
|
|
28
|
-
|
|
40
|
+
VALUE desc = rb_funcall(ndav, id_ndav_validated_descriptor, 1, INT2NUM(flags));
|
|
41
|
+
if (!RB_TYPE_P(desc, T_HASH)) {
|
|
42
|
+
rb_warn("descriptor not Hash");
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
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) {
|
|
29
58
|
return false;
|
|
30
59
|
}
|
|
31
60
|
bool writable_requested = (flags & RUBY_MEMORY_VIEW_WRITABLE) == RUBY_MEMORY_VIEW_WRITABLE;
|
|
32
61
|
// TODO: Handle flags
|
|
33
62
|
|
|
34
|
-
VALUE
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
view->readonly = true;
|
|
41
|
-
} else {
|
|
42
|
-
view->readonly = RTEST(readonly);
|
|
63
|
+
VALUE readonly_v = rb_hash_aref(desc, sym_readonly_p);
|
|
64
|
+
bool readonly = NIL_P(readonly_v) || RTEST(readonly_v);
|
|
65
|
+
if (writable_requested && readonly) {
|
|
66
|
+
rb_warn("not writable");
|
|
67
|
+
return false;
|
|
43
68
|
}
|
|
69
|
+
view->readonly = readonly;
|
|
44
70
|
view->obj = ndav;
|
|
45
|
-
VALUE val =
|
|
71
|
+
VALUE val = rb_hash_aref(desc, sym_data);
|
|
46
72
|
char *data = StringValuePtr(val);
|
|
47
73
|
view->data = data;
|
|
48
74
|
// TODO: Commonalize
|
|
@@ -50,59 +76,91 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
|
50
76
|
// * Use TypedData?
|
|
51
77
|
// * If so, calling attr readers at Ruby layer has performance disadvantage.
|
|
52
78
|
// * Freezing instance vars in #initialize and then embed them to TypedData may be a solution
|
|
53
|
-
VALUE item_size =
|
|
79
|
+
VALUE item_size = rb_hash_aref(desc, sym_item_size);
|
|
54
80
|
view->item_size = NUM2SSIZET(item_size);
|
|
55
|
-
VALUE byte_size =
|
|
81
|
+
VALUE byte_size = rb_hash_aref(desc, sym_byte_size);
|
|
56
82
|
view->byte_size = NUM2SSIZET(byte_size);
|
|
57
|
-
VALUE ndim =
|
|
83
|
+
VALUE ndim = rb_hash_aref(desc, sym_ndim);
|
|
58
84
|
view->ndim = NUM2SSIZET(ndim);
|
|
59
|
-
VALUE format =
|
|
85
|
+
VALUE format = rb_hash_aref(desc, sym_format);
|
|
60
86
|
view->format = StringValueCStr(format);
|
|
61
87
|
|
|
62
|
-
int state;
|
|
63
|
-
|
|
64
88
|
// TODO: Commonalize
|
|
65
|
-
VALUE shape =
|
|
89
|
+
VALUE shape = rb_hash_aref(desc, sym_shape);
|
|
66
90
|
if (!RB_TYPE_P(shape, T_ARRAY)) {
|
|
67
91
|
rb_warn("@shape is not an array");
|
|
68
92
|
return false;
|
|
69
93
|
}
|
|
70
|
-
ssize_t *view_shape =
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
rb_protect(fill_size_array, (VALUE)&shape_args, &state);
|
|
77
|
-
if (state) {
|
|
78
|
-
xfree(view_shape);
|
|
79
|
-
rb_jump_tag(state);
|
|
94
|
+
ssize_t *view_shape = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
|
|
95
|
+
if (!view_shape) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (!fill_size_array(shape, view_shape, view->ndim)) {
|
|
99
|
+
free((void *)view_shape);
|
|
80
100
|
return false;
|
|
81
101
|
}
|
|
82
102
|
view->shape = view_shape;
|
|
83
103
|
|
|
84
|
-
VALUE strides =
|
|
104
|
+
VALUE strides = rb_hash_aref(desc, sym_strides);
|
|
85
105
|
if (!RB_TYPE_P(strides, T_ARRAY)) {
|
|
86
106
|
rb_warn("@strides is not an array");
|
|
87
|
-
|
|
107
|
+
free((void *)view->shape);
|
|
88
108
|
return false;
|
|
89
109
|
}
|
|
90
|
-
ssize_t *view_strides =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
xfree((void *)view_shape);
|
|
99
|
-
xfree((void *)view_strides);
|
|
100
|
-
rb_jump_tag(state);
|
|
110
|
+
ssize_t *view_strides = (ssize_t *)malloc(sizeof(ssize_t) * view->ndim);
|
|
111
|
+
if (!view_strides) {
|
|
112
|
+
free((void *)view->shape);
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (!fill_size_array(strides, view_strides, view->ndim)) {
|
|
116
|
+
free((void *)view->shape);
|
|
117
|
+
free((void *)view_strides);
|
|
101
118
|
return false;
|
|
102
119
|
}
|
|
103
120
|
view->strides = view_strides;
|
|
104
121
|
|
|
105
|
-
|
|
122
|
+
VALUE sub_offsets = rb_hash_aref(desc, sym_sub_offsets);
|
|
123
|
+
if (NIL_P(sub_offsets)) {
|
|
124
|
+
if (indirect_requested) {
|
|
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);
|
|
138
|
+
if (!view_sub_offsets) {
|
|
139
|
+
free((void *)view->shape);
|
|
140
|
+
free((void *)view->strides);
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
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);
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
view->sub_offsets = view_sub_offsets;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private_data_t *private_data = malloc(sizeof(private_data_t));
|
|
153
|
+
if (!private_data) {
|
|
154
|
+
free((void *)view->shape);
|
|
155
|
+
free((void *)view->strides);
|
|
156
|
+
free((void *)view->sub_offsets);
|
|
157
|
+
rb_warn("failed to alloc private_data");
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
private_data->descriptor = Qnil;
|
|
161
|
+
rb_gc_register_address(&private_data->descriptor);
|
|
162
|
+
private_data->descriptor = desc;
|
|
163
|
+
view->private_data = private_data;
|
|
106
164
|
|
|
107
165
|
return true;
|
|
108
166
|
}
|
|
@@ -111,13 +169,23 @@ static bool
|
|
|
111
169
|
ndav_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
|
|
112
170
|
{
|
|
113
171
|
if (view->shape) {
|
|
114
|
-
|
|
172
|
+
free((void *)view->shape);
|
|
115
173
|
view->shape = NULL;
|
|
116
174
|
}
|
|
117
175
|
if (view->strides) {
|
|
118
|
-
|
|
176
|
+
free((void *)view->strides);
|
|
119
177
|
view->strides = NULL;
|
|
120
178
|
}
|
|
179
|
+
if (view->sub_offsets) {
|
|
180
|
+
free((void *)view->sub_offsets);
|
|
181
|
+
view->sub_offsets = NULL;
|
|
182
|
+
}
|
|
183
|
+
if (view->private_data) {
|
|
184
|
+
private_data_t *private_data = (private_data_t *)view->private_data;
|
|
185
|
+
rb_gc_unregister_address(&private_data->descriptor);
|
|
186
|
+
free(private_data);
|
|
187
|
+
view->private_data = NULL;
|
|
188
|
+
}
|
|
121
189
|
|
|
122
190
|
return true;
|
|
123
191
|
}
|
|
@@ -125,8 +193,8 @@ ndav_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
|
|
|
125
193
|
static bool
|
|
126
194
|
ndav_memory_view_available_p(const VALUE obj)
|
|
127
195
|
{
|
|
128
|
-
VALUE
|
|
129
|
-
return
|
|
196
|
+
VALUE descriptor = rb_funcall(obj, id_ndav_validated_descriptor, 0);
|
|
197
|
+
return RTEST(descriptor);
|
|
130
198
|
}
|
|
131
199
|
|
|
132
200
|
const struct rb_memory_view_entry ndav_view_entry = {
|
|
@@ -135,11 +203,34 @@ const struct rb_memory_view_entry ndav_view_entry = {
|
|
|
135
203
|
ndav_memory_view_available_p
|
|
136
204
|
};
|
|
137
205
|
|
|
206
|
+
static VALUE
|
|
207
|
+
ndav_memory_viewable_s_register(VALUE mod, VALUE klass)
|
|
208
|
+
{
|
|
209
|
+
if (!rb_memory_view_register(klass, &ndav_view_entry)) {
|
|
210
|
+
// error message output in rb_memory_view_register()
|
|
211
|
+
rb_raise(rb_eArgError, "");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return Qtrue;
|
|
215
|
+
}
|
|
216
|
+
|
|
138
217
|
void
|
|
139
218
|
Init_ndav(void)
|
|
140
219
|
{
|
|
141
|
-
|
|
220
|
+
id_ndav_validated_descriptor = rb_intern("ndav_validated_descriptor");
|
|
221
|
+
sym_data = ID2SYM(rb_intern("data"));
|
|
222
|
+
sym_shape = ID2SYM(rb_intern("shape"));
|
|
223
|
+
sym_strides = ID2SYM(rb_intern("strides"));
|
|
224
|
+
sym_format = ID2SYM(rb_intern("format"));
|
|
225
|
+
sym_byte_size = ID2SYM(rb_intern("byte_size"));
|
|
226
|
+
sym_readonly_p = ID2SYM(rb_intern("readonly?"));
|
|
227
|
+
sym_sub_offsets = ID2SYM(rb_intern("sub_offsets"));
|
|
228
|
+
sym_ndim = ID2SYM(rb_intern("ndim"));
|
|
229
|
+
sym_item_size = ID2SYM(rb_intern("item_size"));
|
|
230
|
+
sym_row_major_contiguous_p = ID2SYM(rb_intern("row_major_contiguous?"));
|
|
231
|
+
sym_column_major_contiguous_p = ID2SYM(rb_intern("column_major_contiguous?"));
|
|
142
232
|
|
|
143
233
|
VALUE cNDAV = rb_define_class("NDAV", rb_cObject);
|
|
144
|
-
|
|
234
|
+
VALUE mMemoryViewable = rb_define_module_under(cNDAV, "MemoryViewable");
|
|
235
|
+
rb_define_singleton_method(mMemoryViewable, "register", ndav_memory_viewable_s_register, 1);
|
|
145
236
|
}
|
data/lib/ndav/converter.rb
CHANGED
|
@@ -17,6 +17,19 @@ class NDAV
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
if mdl.const_defined?(:MemoryViewable)
|
|
21
|
+
cls.include ::NDAV::MemoryViewable
|
|
22
|
+
cls.include mdl::MemoryViewable
|
|
23
|
+
|
|
24
|
+
unless mdl.const_defined?(:ToNDAV)
|
|
25
|
+
mdl.const_set(:ToNDAV, Module.new {
|
|
26
|
+
def to_ndav(lifetime: self, **)
|
|
27
|
+
::NDAV.new(self, lifetime:, **)
|
|
28
|
+
end
|
|
29
|
+
})
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
20
33
|
if mdl.const_defined?(:ToNDAV)
|
|
21
34
|
cls.include mdl::ToNDAV
|
|
22
35
|
|
data/lib/ndav/ffi.rb
CHANGED
|
@@ -26,6 +26,25 @@ class NDAV
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
module MemoryViewable
|
|
30
|
+
def ndav_descriptor(**)
|
|
31
|
+
shape = [size / type_size]
|
|
32
|
+
format = TYPE_SIZE_TO_FORMAT[type_size]
|
|
33
|
+
item_size = ITEM_SIZES[format]
|
|
34
|
+
byte_size = shape.reduce(item_size, :*)
|
|
35
|
+
ptr = ::Fiddle::Pointer.new(address, byte_size)
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
data: Fiddle::MemoryView.new(ptr).to_s,
|
|
39
|
+
shape:,
|
|
40
|
+
strides: ::NDAV.default_strides(shape:, item_size:),
|
|
41
|
+
format:,
|
|
42
|
+
byte_size:,
|
|
43
|
+
readonly?: true
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
29
48
|
module Converter
|
|
30
49
|
def FFIMemoryPointer(array, *, **)
|
|
31
50
|
if ::FFI::MemoryPointer === array
|
data/lib/ndav/flags.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class NDAV
|
|
2
|
+
module Flags
|
|
3
|
+
FLAGS = {}
|
|
4
|
+
FLAGS[:simple] = 0
|
|
5
|
+
FLAGS[:writable] = (1<<0)
|
|
6
|
+
FLAGS[:format] = (1<<1)
|
|
7
|
+
FLAGS[:multi_dimensional] = (1<<2)
|
|
8
|
+
FLAGS[:strides] = (1<<3) | FLAGS[:multi_dimensional]
|
|
9
|
+
FLAGS[:row_major] = (1<<4) | FLAGS[:strides]
|
|
10
|
+
FLAGS[:column_major] = (1<<5) | FLAGS[:strides]
|
|
11
|
+
FLAGS[:any_contiguous] = FLAGS[:row_major] | FLAGS[:column_major]
|
|
12
|
+
FLAGS[:indirect] = (1<<6) | FLAGS[:strides]
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def decode(flags)
|
|
17
|
+
FLAGS.each_with_object({}) {|(name, value), state|
|
|
18
|
+
if name == :simple
|
|
19
|
+
state[name] = flags == 0
|
|
20
|
+
else
|
|
21
|
+
state[name] = flags & value == value
|
|
22
|
+
end
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
class NDAV
|
|
2
|
+
module MemoryViewable
|
|
3
|
+
class << self
|
|
4
|
+
def included(base)
|
|
5
|
+
::NDAV::MemoryViewable.register base
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
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
|
+
def ndav_validated_descriptor(flags = ::NDAV::Flags::FLAGS[:simple])
|
|
25
|
+
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
|
+
[:data, :shape, :strides, :format, :byte_size, :readonly?].each do |key|
|
|
31
|
+
unless desc.key? key
|
|
32
|
+
warn ":#{key} not in descriptor"
|
|
33
|
+
return false
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
desc.merge(
|
|
37
|
+
ndim: desc[:shape].length,
|
|
38
|
+
item_size: NDAV::ITEM_SIZES[desc[:format]],
|
|
39
|
+
row_major_contiguous?: ::NDAV.row_major_contiguous?(**desc),
|
|
40
|
+
column_major_contiguous?: ::NDAV.column_major_contiguous?(**desc)
|
|
41
|
+
)
|
|
42
|
+
rescue => err
|
|
43
|
+
warn err
|
|
44
|
+
return false
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/ndav.rb
CHANGED
|
@@ -1,88 +1,143 @@
|
|
|
1
1
|
require "fiddle"
|
|
2
2
|
require "ndav.so"
|
|
3
|
+
require "ndav/flags"
|
|
3
4
|
require "ndav/converter"
|
|
5
|
+
require "ndav/memory_viewable"
|
|
4
6
|
|
|
5
7
|
# TODO: Manage flags of internal data object
|
|
6
8
|
class NDAV
|
|
9
|
+
include MemoryViewable
|
|
10
|
+
|
|
7
11
|
# TODO: Want to use return value of rb_memory_view_parse_item_format
|
|
8
12
|
ITEM_SIZES = ["c", "C", "s", "S", "l", "L", "q", "Q", "f", "d", "s!", "S!", "n", "v", "i", "i!", "I", "I!", "l!", "L!", "N", "V", "e", "g", "q!", "Q!", "E", "G"].collect {|format|
|
|
9
13
|
[format, [0].pack(format).bytesize]
|
|
10
14
|
}.to_h
|
|
11
15
|
|
|
12
|
-
attr_reader :ndim, :shape, :format, :item_size, :byte_size, :strides, :lifetime
|
|
16
|
+
attr_reader :ndim, :shape, :format, :item_size, :byte_size, :strides, :to_s, :lifetime
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def default_strides(shape:, item_size:, row_major: true)
|
|
20
|
+
each_shape = row_major ? shape.reverse_each : shape.each
|
|
21
|
+
each_shape.reduce([[], item_size]) {|(strides, stride), s|
|
|
22
|
+
if row_major
|
|
23
|
+
strides.unshift stride
|
|
24
|
+
else
|
|
25
|
+
strides << stride
|
|
26
|
+
end
|
|
27
|
+
[strides, stride * s]
|
|
28
|
+
}[0]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Algorithm stolen from memory_view.c
|
|
32
|
+
def row_major_contiguous?(format:, shape:, strides:, **)
|
|
33
|
+
ndim = shape.length
|
|
34
|
+
n = ITEM_SIZES[format]
|
|
35
|
+
return strides[0] == n if ndim == 1
|
|
36
|
+
|
|
37
|
+
(ndim - 1).downto 0 do |i|
|
|
38
|
+
return false unless strides[i] == n
|
|
39
|
+
|
|
40
|
+
n *= shape[i]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Algorithm stolen from memory_view.c
|
|
47
|
+
def column_major_contiguous?(format:, shape:, strides:, **)
|
|
48
|
+
ndim = shape.length
|
|
49
|
+
n = ITEM_SIZES[format]
|
|
50
|
+
return strides[0] == n if ndim == 1
|
|
51
|
+
|
|
52
|
+
0.upto(ndim - 1) do |i|
|
|
53
|
+
return false unless strides[i] == n
|
|
54
|
+
|
|
55
|
+
n *= shape[i]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
true
|
|
59
|
+
end
|
|
60
|
+
end
|
|
13
61
|
|
|
14
62
|
# TODO: More options to trick for the case of MemoryView export is wrong but developer don't fix it
|
|
15
|
-
def initialize(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
63
|
+
def initialize(obj, shape: nil, strides: nil, format: nil, lifetime: nil)
|
|
64
|
+
fmv = obj.kind_of?(::Fiddle::MemoryView) ? obj : ::Fiddle::MemoryView.new(obj)
|
|
65
|
+
# Fiddle::MemoryView#to_s is zero-copy
|
|
66
|
+
# Fiddle::MemoryView#to_s embeds obj into the String, so we can prevent GC from collecting it
|
|
67
|
+
@to_s = fmv.to_s
|
|
68
|
+
@lifetime = lifetime
|
|
19
69
|
|
|
20
|
-
@format = format ||
|
|
70
|
+
@format = format || fmv.format
|
|
21
71
|
raise ArgumentError, %Q|unsupported format: #{@format.to_s.dump}, currently supported: #{ITEM_SIZES.keys}| unless ITEM_SIZES.key?(@format)
|
|
22
72
|
|
|
23
73
|
item_size_by_format = ITEM_SIZES[@format]
|
|
24
74
|
|
|
25
|
-
@byte_size =
|
|
26
|
-
@item_size =
|
|
27
|
-
@shape = shape ||
|
|
75
|
+
@byte_size = fmv.byte_size
|
|
76
|
+
@item_size = obj.kind_of?(::Fiddle::Pointer) ? item_size_by_format : fmv.item_size || item_size_by_format
|
|
77
|
+
@shape = shape || fmv.shape
|
|
28
78
|
case [@shape, @byte_size]
|
|
29
79
|
in [nil, nil]
|
|
30
|
-
raise ArgumentError, "either shape or byte_size must be present in
|
|
31
|
-
in [
|
|
80
|
+
raise ArgumentError, "either shape or byte_size must be present in obj or arguments"
|
|
81
|
+
in [_, nil]
|
|
32
82
|
@byte_size = @shape.reduce(@item_size, :*)
|
|
33
|
-
in [nil,
|
|
83
|
+
in [nil, _]
|
|
34
84
|
n, r = @byte_size.divmod(@item_size)
|
|
35
85
|
raise ArgumentError, "byte_size must be n-times of item_size" unless r.zero?
|
|
36
86
|
@shape = [n]
|
|
37
87
|
else
|
|
38
88
|
# noop
|
|
39
89
|
end
|
|
40
|
-
@strides = @fmv.strides || @shape.reverse_each.reduce([[], @item_size]) {|(strides, stride), s|
|
|
41
|
-
strides.unshift(stride)
|
|
42
|
-
[strides, stride * s]
|
|
43
|
-
}[0]
|
|
44
90
|
@ndim = @shape.size
|
|
45
|
-
@readonly =
|
|
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
|
|
94
|
+
@row_major_contiguous = self.class.row_major_contiguous?(format: @format, shape: @shape, strides: @strides)
|
|
95
|
+
@column_major_contiguous = self.class.column_major_contiguous?(format: @format, shape: @shape, strides: @strides)
|
|
46
96
|
|
|
47
|
-
validate
|
|
97
|
+
validate fmv
|
|
48
98
|
end
|
|
49
99
|
|
|
50
100
|
def readonly?
|
|
51
101
|
@readonly
|
|
52
102
|
end
|
|
53
103
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
104
|
+
def row_major_contiguous?
|
|
105
|
+
@row_major_contiguous
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def column_major_contiguous?
|
|
109
|
+
@column_major_contiguous
|
|
59
110
|
end
|
|
60
111
|
|
|
61
112
|
def to_ptr
|
|
62
|
-
::Fiddle::Pointer[to_s]
|
|
113
|
+
::Fiddle::Pointer[@to_s]
|
|
63
114
|
end
|
|
64
115
|
alias to_fiddle_pointer to_ptr
|
|
65
116
|
|
|
66
117
|
private
|
|
67
118
|
|
|
68
|
-
def
|
|
119
|
+
def ndav_descriptor(**)
|
|
120
|
+
{
|
|
121
|
+
data: @to_s,
|
|
122
|
+
shape: @shape,
|
|
123
|
+
strides: @strides,
|
|
124
|
+
format: @format,
|
|
125
|
+
byte_size: @byte_size,
|
|
126
|
+
readonly?: @readonly,
|
|
127
|
+
sub_offsets: @sub_offsets
|
|
128
|
+
}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def validate(fmv)
|
|
69
132
|
unless @item_size == ITEM_SIZES[@format]
|
|
70
133
|
raise ArgumentError, "item_size does not match format"
|
|
71
134
|
end
|
|
72
135
|
|
|
73
|
-
if @
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
stride = @item_size
|
|
78
|
-
@shape.reverse_each.with_index do |s, i|
|
|
79
|
-
unless @strides[@ndim - 1 - i] == stride
|
|
80
|
-
raise ArgumentError, "only row-major contiguous strides is supported"
|
|
136
|
+
if @row_major_contiguous || @column_major_contiguous
|
|
137
|
+
byte_size = @shape.reduce(@item_size, :*)
|
|
138
|
+
unless byte_size == @byte_size
|
|
139
|
+
raise ArgumentError, "strides not match byte_size"
|
|
81
140
|
end
|
|
82
|
-
stride *= s
|
|
83
|
-
end
|
|
84
|
-
unless stride == @byte_size
|
|
85
|
-
raise ArgumentError, "strides not match byte_size"
|
|
86
141
|
end
|
|
87
142
|
end
|
|
88
143
|
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.5"
|
|
4
4
|
s.summary = "N-Dimensional Array View"
|
|
5
5
|
s.authors = ["Kitaiti Makoto"]
|
|
6
6
|
s.licenses = ["BSD-2-Clause"]
|
|
@@ -22,4 +22,5 @@ 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"
|
|
25
26
|
end
|
data/test/test_ffi.rb
CHANGED
|
@@ -48,6 +48,14 @@ class TestFFI < TestBase
|
|
|
48
48
|
assert_equal ndav.to_ptr.to_i, ptr.address
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
def test_memory_view_from_ffi_memory_pointer
|
|
52
|
+
ptr = ::FFI::MemoryPointer.new(:int16, 3)
|
|
53
|
+
ptr.write_array_of_int16([1, 2, 3])
|
|
54
|
+
fmv = Fiddle::MemoryView.new(ptr)
|
|
55
|
+
|
|
56
|
+
assert_int_array fmv
|
|
57
|
+
end
|
|
58
|
+
|
|
51
59
|
class TestConverter < self
|
|
52
60
|
def test_ndav_from_ffi_memory_pointer
|
|
53
61
|
ptr = ::FFI::MemoryPointer.new(:int16, 3)
|
data/test/test_ndav.rb
CHANGED
|
@@ -35,4 +35,12 @@ class TestNDAV < TestBase
|
|
|
35
35
|
|
|
36
36
|
assert_int_array ndav
|
|
37
37
|
end
|
|
38
|
+
|
|
39
|
+
def test_column_major
|
|
40
|
+
str = [1, 2, 3,
|
|
41
|
+
4, 5, 6].pack("s*")
|
|
42
|
+
ndav = NDAV.from_string(str, format: "s", shape: [2, 3], strides: [2, 4])
|
|
43
|
+
|
|
44
|
+
assert_true ndav.column_major_contiguous?
|
|
45
|
+
end
|
|
38
46
|
end
|
data/test/test_ractor.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require_relative "helper"
|
|
2
|
+
|
|
3
|
+
class TestRactor < TestBase
|
|
4
|
+
ractor
|
|
5
|
+
|
|
6
|
+
def test_ractor
|
|
7
|
+
ractor = Ractor.new {
|
|
8
|
+
Ractor.receive
|
|
9
|
+
}
|
|
10
|
+
ndav = NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
11
|
+
ractor << ndav
|
|
12
|
+
result = ractor.value
|
|
13
|
+
|
|
14
|
+
assert_not_same ndav, result
|
|
15
|
+
assert_int_array result
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_ractor_from_string
|
|
19
|
+
ractor = Ractor.new {
|
|
20
|
+
Ractor.receive
|
|
21
|
+
}
|
|
22
|
+
ndav = NDAV.from_string([1, 2, 3].pack("s*"), format: "s")
|
|
23
|
+
ractor << ndav
|
|
24
|
+
result = ractor.value
|
|
25
|
+
|
|
26
|
+
assert_int_array result
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_ractor_share
|
|
30
|
+
ractor = Ractor.new {
|
|
31
|
+
Ractor.receive
|
|
32
|
+
}
|
|
33
|
+
ndav = NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
34
|
+
Ractor.make_shareable(ndav)
|
|
35
|
+
ractor << ndav
|
|
36
|
+
result = ractor.value
|
|
37
|
+
|
|
38
|
+
assert_same ndav, result
|
|
39
|
+
assert_int_array result
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_port
|
|
43
|
+
ractor = Ractor.new {
|
|
44
|
+
ndav, port = Ractor.receive
|
|
45
|
+
port << ndav
|
|
46
|
+
}
|
|
47
|
+
ndav = NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
48
|
+
port = Ractor::Port.new
|
|
49
|
+
ractor << [ndav, port]
|
|
50
|
+
result = port.receive
|
|
51
|
+
|
|
52
|
+
assert_not_same ndav, result
|
|
53
|
+
assert_int_array result
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_port_share
|
|
57
|
+
ractor = Ractor.new {
|
|
58
|
+
ndav, port = Ractor.receive
|
|
59
|
+
port << ndav
|
|
60
|
+
}
|
|
61
|
+
ndav = NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
62
|
+
Ractor.make_shareable(ndav)
|
|
63
|
+
port = Ractor::Port.new
|
|
64
|
+
ractor << [ndav, port]
|
|
65
|
+
result = port.receive
|
|
66
|
+
|
|
67
|
+
assert_same ndav, result
|
|
68
|
+
assert_int_array result
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_ractor_not_initializable
|
|
72
|
+
ractor = Ractor.new {
|
|
73
|
+
NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
74
|
+
}
|
|
75
|
+
assert_raise Ractor::RemoteError do
|
|
76
|
+
ractor.value
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
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.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kitaiti Makoto
|
|
@@ -163,6 +163,20 @@ 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'
|
|
166
180
|
executables: []
|
|
167
181
|
extensions:
|
|
168
182
|
- ext/extconf.rb
|
|
@@ -173,15 +187,15 @@ files:
|
|
|
173
187
|
- ".yardopts"
|
|
174
188
|
- Gemfile
|
|
175
189
|
- LICENSE.txt
|
|
176
|
-
- NDAV.png
|
|
177
190
|
- README.md
|
|
178
191
|
- Rakefile
|
|
179
192
|
- ext/extconf.rb
|
|
180
193
|
- ext/ndav.c
|
|
181
|
-
- ext/ndav.h
|
|
182
194
|
- lib/ndav.rb
|
|
183
195
|
- lib/ndav/converter.rb
|
|
184
196
|
- lib/ndav/ffi.rb
|
|
197
|
+
- lib/ndav/flags.rb
|
|
198
|
+
- lib/ndav/memory_viewable.rb
|
|
185
199
|
- ndav.gemspec
|
|
186
200
|
- test/helper.rb
|
|
187
201
|
- test/test_converter.rb
|
|
@@ -189,6 +203,7 @@ files:
|
|
|
189
203
|
- test/test_ffi.rb
|
|
190
204
|
- test/test_ndav.rb
|
|
191
205
|
- test/test_package.rb
|
|
206
|
+
- test/test_ractor.rb
|
|
192
207
|
homepage: https://kitaitimakoto.gitlab.io/ndav
|
|
193
208
|
licenses:
|
|
194
209
|
- BSD-2-Clause
|
|
@@ -208,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
208
223
|
- !ruby/object:Gem::Version
|
|
209
224
|
version: '0'
|
|
210
225
|
requirements: []
|
|
211
|
-
rubygems_version: 4.0.
|
|
226
|
+
rubygems_version: 4.0.16
|
|
212
227
|
specification_version: 4
|
|
213
228
|
summary: N-Dimensional Array View
|
|
214
229
|
test_files: []
|
data/NDAV.png
DELETED
|
Binary file
|
data/ext/ndav.h
DELETED