ndav 0.0.1
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 +7 -0
- data/.gitignore +7 -0
- data/.gitlab-ci.yml +14 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +9 -0
- data/Rakefile +49 -0
- data/ext/extconf.rb +3 -0
- data/ext/ndav.c +145 -0
- data/ext/ndav.h +2 -0
- data/lib/ndav/converter.rb +21 -0
- data/lib/ndav/ffi.rb +93 -0
- data/lib/ndav.rb +88 -0
- data/ndav.gemspec +22 -0
- data/test/helper.rb +22 -0
- data/test/test_converter.rb +23 -0
- data/test/test_export.rb +16 -0
- data/test/test_ffi.rb +69 -0
- data/test/test_ndav.rb +31 -0
- data/test/test_package.rb +26 -0
- metadata +196 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6f7a33419819c6f7c3358aba6b51ebc8b0039c96a3ab8266ef88e75d9567bf0b
|
|
4
|
+
data.tar.gz: be7e0f8194bddf00e96e9c52d6cc3757add2e33068c1a478b2d23951ad1e4f34
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 754b518b28f22bf7ca48e41cbfdaa3733fa61dfa4a42032b4a8947a6cc3e8fabfcd2f3c8e30842e04efe3e74e981077850459c6ab79484c1619205966e5e3a71
|
|
7
|
+
data.tar.gz: d142c31e77fd5586ed0ff6284383c912de4b8edc54811bd27243da05ebd3df8b693f4500100200837dbfd77098362dc4e0e2f3cddd3d95d1c12986ea5eee9ccd
|
data/.gitignore
ADDED
data/.gitlab-ci.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (C) 2026 Kitati Makoto. All rights reserved.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions
|
|
5
|
+
are met:
|
|
6
|
+
1. Redistributions of source code must retain the above copyright
|
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
|
10
|
+
documentation and/or other materials provided with the distribution.
|
|
11
|
+
|
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
13
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
14
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
15
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
16
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
17
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
18
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
19
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
20
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
21
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
22
|
+
SUCH DAMAGE.
|
data/README.md
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require "rake/clean"
|
|
2
|
+
require "rake/testtask"
|
|
3
|
+
require "rubygems/tasks"
|
|
4
|
+
|
|
5
|
+
DL_NAME = "ndav".ext(RbConfig::CONFIG["DLEXT"])
|
|
6
|
+
DL_BUILD_PATH = File.join("ext", DL_NAME)
|
|
7
|
+
DL_PATH = File.join("lib", DL_NAME)
|
|
8
|
+
|
|
9
|
+
SRC = FileList["ext/**.{h,c,rb}"]
|
|
10
|
+
|
|
11
|
+
task default: :test
|
|
12
|
+
|
|
13
|
+
Rake::TestTask.new test: DL_PATH
|
|
14
|
+
tasks = Gem::Tasks.new
|
|
15
|
+
gemspec = tasks.build.gem.project.gemspec
|
|
16
|
+
|
|
17
|
+
file DL_PATH => DL_BUILD_PATH do |t|
|
|
18
|
+
copy t.source, t.name
|
|
19
|
+
end
|
|
20
|
+
CLEAN.include DL_PATH
|
|
21
|
+
|
|
22
|
+
MAKEFILE = "ext/Makefile"
|
|
23
|
+
file DL_BUILD_PATH => MAKEFILE do |t|
|
|
24
|
+
chdir "ext" do
|
|
25
|
+
system "make", exception: true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if File.exist? MAKEFILE
|
|
30
|
+
task make_clean: MAKEFILE do
|
|
31
|
+
chdir "ext" do
|
|
32
|
+
system "make clean", exception: true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
task clean: :make_clean
|
|
36
|
+
|
|
37
|
+
task make_dist_clean: MAKEFILE do
|
|
38
|
+
chdir "ext" do
|
|
39
|
+
system "make distclean"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
task clobber: :make_dist_clean
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
file MAKEFILE => SRC do
|
|
46
|
+
chdir "ext" do
|
|
47
|
+
ruby "extconf.rb"
|
|
48
|
+
end
|
|
49
|
+
end
|
data/ext/extconf.rb
ADDED
data/ext/ndav.c
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#include "ndav.h"
|
|
2
|
+
|
|
3
|
+
ID id_to_s;
|
|
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)
|
|
13
|
+
{
|
|
14
|
+
struct fill_size_array_args_t *args = (fill_size_array_args_t *)rb_args;
|
|
15
|
+
for (ssize_t i = 0; i < args->size; i++) {
|
|
16
|
+
VALUE val = rb_ary_entry(args->src, i);
|
|
17
|
+
args->dest[i] = NUM2SSIZET(val);
|
|
18
|
+
}
|
|
19
|
+
return Qnil;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static bool
|
|
23
|
+
ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
24
|
+
{
|
|
25
|
+
bool row_major_requested = (flags & RUBY_MEMORY_VIEW_ROW_MAJOR) == RUBY_MEMORY_VIEW_ROW_MAJOR;
|
|
26
|
+
bool column_major_requested = (flags & RUBY_MEMORY_VIEW_COLUMN_MAJOR) == RUBY_MEMORY_VIEW_COLUMN_MAJOR;
|
|
27
|
+
bool indirect_requested = (flags & RUBY_MEMORY_VIEW_INDIRECT) == RUBY_MEMORY_VIEW_INDIRECT;
|
|
28
|
+
if ((column_major_requested && !row_major_requested) || indirect_requested) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
bool writable_requested = (flags & RUBY_MEMORY_VIEW_WRITABLE) == RUBY_MEMORY_VIEW_WRITABLE;
|
|
32
|
+
// TODO: Handle flags
|
|
33
|
+
|
|
34
|
+
VALUE readonly = rb_iv_get(ndav, "@readonly");
|
|
35
|
+
if (NIL_P(readonly)) {
|
|
36
|
+
if (writable_requested) {
|
|
37
|
+
rb_warn("not writable");
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
view->readonly = true;
|
|
41
|
+
} else {
|
|
42
|
+
view->readonly = RTEST(readonly);
|
|
43
|
+
}
|
|
44
|
+
view->obj = ndav;
|
|
45
|
+
VALUE val = rb_funcall(ndav, id_to_s, 0);
|
|
46
|
+
char *data = StringValuePtr(val);
|
|
47
|
+
view->data = data;
|
|
48
|
+
// TODO: Commonalize
|
|
49
|
+
// TODO: Consider:
|
|
50
|
+
// * Use TypedData?
|
|
51
|
+
// * If so, calling attr readers at Ruby layer has performance disadvantage.
|
|
52
|
+
// * Freezing instance vars in #initialize and then embed them to TypedData may be a solution
|
|
53
|
+
VALUE item_size = rb_iv_get(ndav, "@item_size");
|
|
54
|
+
view->item_size = NUM2SSIZET(item_size);
|
|
55
|
+
VALUE byte_size = rb_iv_get(ndav, "@byte_size");
|
|
56
|
+
view->byte_size = NUM2SSIZET(byte_size);
|
|
57
|
+
VALUE ndim = rb_iv_get(ndav, "@ndim");
|
|
58
|
+
view->ndim = NUM2SSIZET(ndim);
|
|
59
|
+
VALUE format = rb_iv_get(ndav, "@format");
|
|
60
|
+
view->format = StringValueCStr(format);
|
|
61
|
+
|
|
62
|
+
int state;
|
|
63
|
+
|
|
64
|
+
// TODO: Commonalize
|
|
65
|
+
VALUE shape = rb_iv_get(ndav, "@shape");
|
|
66
|
+
if (!RB_TYPE_P(shape, T_ARRAY)) {
|
|
67
|
+
rb_warn("@shape is not an array");
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
ssize_t *view_shape = ALLOC_N(ssize_t, view->ndim);
|
|
71
|
+
fill_size_array_args_t shape_args = {
|
|
72
|
+
shape,
|
|
73
|
+
view_shape,
|
|
74
|
+
view->ndim,
|
|
75
|
+
};
|
|
76
|
+
rb_protect(fill_size_array, (VALUE)&shape_args, &state);
|
|
77
|
+
if (state) {
|
|
78
|
+
xfree(view_shape);
|
|
79
|
+
rb_jump_tag(state);
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
view->shape = view_shape;
|
|
83
|
+
|
|
84
|
+
VALUE strides = rb_iv_get(ndav, "@strides");
|
|
85
|
+
if (!RB_TYPE_P(strides, T_ARRAY)) {
|
|
86
|
+
rb_warn("@strides is not an array");
|
|
87
|
+
xfree((void *)view->shape);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
ssize_t *view_strides = ALLOC_N(ssize_t, view->ndim);
|
|
91
|
+
fill_size_array_args_t strides_args = {
|
|
92
|
+
strides,
|
|
93
|
+
view_strides,
|
|
94
|
+
view->ndim
|
|
95
|
+
};
|
|
96
|
+
rb_protect(fill_size_array, (VALUE)&strides_args, &state);
|
|
97
|
+
if (state) {
|
|
98
|
+
xfree((void *)view_shape);
|
|
99
|
+
xfree((void *)view_strides);
|
|
100
|
+
rb_jump_tag(state);
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
view->strides = view_strides;
|
|
104
|
+
|
|
105
|
+
view->sub_offsets = NULL;
|
|
106
|
+
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static bool
|
|
111
|
+
ndav_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
|
|
112
|
+
{
|
|
113
|
+
if (view->shape) {
|
|
114
|
+
xfree((void *)view->shape);
|
|
115
|
+
view->shape = NULL;
|
|
116
|
+
}
|
|
117
|
+
if (view->strides) {
|
|
118
|
+
xfree((void *)view->strides);
|
|
119
|
+
view->strides = NULL;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static bool
|
|
126
|
+
ndav_memory_view_available_p(const VALUE obj)
|
|
127
|
+
{
|
|
128
|
+
VALUE fmv = rb_iv_get(obj, "@fmv");
|
|
129
|
+
return !NIL_P(fmv);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const struct rb_memory_view_entry ndav_view_entry = {
|
|
133
|
+
ndav_get_memory_view,
|
|
134
|
+
ndav_release_memory_view,
|
|
135
|
+
ndav_memory_view_available_p
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
void
|
|
139
|
+
Init_ndav(void)
|
|
140
|
+
{
|
|
141
|
+
id_to_s = rb_intern("to_s");
|
|
142
|
+
|
|
143
|
+
VALUE cNDAV = rb_define_class("NDAV", rb_cObject);
|
|
144
|
+
rb_memory_view_register(cNDAV, &ndav_view_entry);
|
|
145
|
+
}
|
data/ext/ndav.h
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class NDAV
|
|
2
|
+
class << self
|
|
3
|
+
alias from_memory_view new
|
|
4
|
+
alias from_fiddle_memory_view new
|
|
5
|
+
alias from_fiddle_pointer new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module Converter
|
|
9
|
+
class << self
|
|
10
|
+
def NDAV(array, *, **)
|
|
11
|
+
if array.kind_of? ::NDAV
|
|
12
|
+
array
|
|
13
|
+
elsif array.respond_to?(:to_ndav)
|
|
14
|
+
array.to_ndav(*, **)
|
|
15
|
+
else
|
|
16
|
+
::NDAV.new(array, *, **)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/ndav/ffi.rb
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
require "ffi"
|
|
2
|
+
|
|
3
|
+
class NDAV
|
|
4
|
+
module FFI
|
|
5
|
+
TYPE_SIZE_TO_FORMAT = {
|
|
6
|
+
1 => "c",
|
|
7
|
+
2 => "s",
|
|
8
|
+
4 => "l",
|
|
9
|
+
8 => "q"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module MemoryPointer
|
|
13
|
+
module FromNDAV
|
|
14
|
+
# NOTE: Copies data
|
|
15
|
+
def from_ndav(array)
|
|
16
|
+
from_string(array.to_s)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module ToNDAV
|
|
21
|
+
def to_ndav(format: nil, lifetime: nil, **)
|
|
22
|
+
::NDAV.from_ffi_memory_pointer(self, shape: [size / type_size], format: format || TYPE_SIZE_TO_FORMAT[type_size], lifetime: lifetime || self, **)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module Converter
|
|
27
|
+
def NDAV(array, *, **)
|
|
28
|
+
if array.kind_of? ::FFI::MemoryPointer
|
|
29
|
+
array.to_ndav(**)
|
|
30
|
+
else
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module Pointer
|
|
38
|
+
module FromNDAV
|
|
39
|
+
def from_ndav(array)
|
|
40
|
+
new(array.item_size, array.to_ptr.to_i)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
module ToDAV
|
|
45
|
+
def to_ndav(format: nil, lifetime: nil, **)
|
|
46
|
+
::NDAV.from_ffi_pointer(self, shape: [size / type_size], format: format || TYPE_SIZE_TO_FORMAT[type_size], lifetime: lifetime || self, **)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module Converter
|
|
51
|
+
def NDAV(array, *, **)
|
|
52
|
+
# use instance_of? instead of kind_of? because MemoryPointer < Pointer
|
|
53
|
+
if array.instance_of? ::FFI::Pointer
|
|
54
|
+
array.to_ndav(**)
|
|
55
|
+
else
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module FromFFI
|
|
63
|
+
def from_ffi_memory_pointer(array, shape:, format:, **)
|
|
64
|
+
byte_size = shape.reduce(ITEM_SIZES[format], :*)
|
|
65
|
+
ptr = ::Fiddle::Pointer.new(array.address, byte_size)
|
|
66
|
+
new(ptr, shape:, format:, **)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def from_ffi_pointer(array, lifetime:, **)
|
|
70
|
+
from_ffi_memory_pointer(array, lifetime:, **)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
module ToFFI
|
|
75
|
+
def to_ffi_memory_pointer
|
|
76
|
+
::FFI::MemoryPointer.from_ndav(self)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def to_ffi_pointer
|
|
80
|
+
::FFI::Pointer.from_ndav(self)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
::FFI::MemoryPointer.extend MemoryPointer::FromNDAV
|
|
85
|
+
::FFI::MemoryPointer.include MemoryPointer::ToNDAV
|
|
86
|
+
::FFI::Pointer.extend Pointer::FromNDAV
|
|
87
|
+
::FFI::Pointer.include Pointer::ToDAV
|
|
88
|
+
::NDAV.extend FromFFI
|
|
89
|
+
::NDAV.include ToFFI
|
|
90
|
+
::NDAV::Converter.singleton_class.prepend Pointer::Converter
|
|
91
|
+
::NDAV::Converter.singleton_class.prepend MemoryPointer::Converter
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/ndav.rb
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require "fiddle"
|
|
2
|
+
require "ndav.so"
|
|
3
|
+
require "ndav/converter"
|
|
4
|
+
|
|
5
|
+
# TODO: Manage flags of internal data object
|
|
6
|
+
class NDAV
|
|
7
|
+
# TODO: Want to use return value of rb_memory_view_parse_item_format
|
|
8
|
+
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
|
+
[format, [0].pack(format).bytesize]
|
|
10
|
+
}.to_h
|
|
11
|
+
|
|
12
|
+
attr_reader :ndim, :shape, :format, :item_size, :byte_size, :strides, :lifetime
|
|
13
|
+
|
|
14
|
+
# TODO: More options to trick for the case of MemoryView export is wrong but developer don't fix it
|
|
15
|
+
def initialize(input, shape: nil, format: nil, lifetime: nil)
|
|
16
|
+
@fmv = input.kind_of?(::Fiddle::MemoryView) ? input : ::Fiddle::MemoryView.new(input)
|
|
17
|
+
@lifetime = [@fmv.obj, lifetime].compact
|
|
18
|
+
@lifetime = nil if @lifetime.empty?
|
|
19
|
+
|
|
20
|
+
@format = format || @fmv.format
|
|
21
|
+
raise ArgumentError, %Q|unsupported format: #{@format.to_s.dump}, currently supported: #{ITEM_SIZES.keys}| unless ITEM_SIZES.key?(@format)
|
|
22
|
+
|
|
23
|
+
item_size_by_format = ITEM_SIZES[@format]
|
|
24
|
+
|
|
25
|
+
@byte_size = @fmv.byte_size
|
|
26
|
+
@item_size = input.kind_of?(::Fiddle::Pointer) ? item_size_by_format : @fmv.item_size || item_size_by_format
|
|
27
|
+
@shape = shape || @fmv.shape
|
|
28
|
+
case [@shape, @byte_size]
|
|
29
|
+
in [nil, nil]
|
|
30
|
+
raise ArgumentError, "either shape or byte_size must be present in input or arguments"
|
|
31
|
+
in [*, nil]
|
|
32
|
+
@byte_size = @shape.reduce(@item_size, :*)
|
|
33
|
+
in [nil, *]
|
|
34
|
+
n, r = @byte_size.divmod(@item_size)
|
|
35
|
+
raise ArgumentError, "byte_size must be n-times of item_size" unless r.zero?
|
|
36
|
+
@shape = [n]
|
|
37
|
+
else
|
|
38
|
+
# noop
|
|
39
|
+
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
|
+
@ndim = @shape.size
|
|
45
|
+
@readonly = @fmv.readonly?
|
|
46
|
+
|
|
47
|
+
validate
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def readonly?
|
|
51
|
+
@readonly
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Zero-copy
|
|
55
|
+
def to_s
|
|
56
|
+
# MemoryView#to_s is zero-copy
|
|
57
|
+
# Assign to @data to keep reference to the string to prevent GC
|
|
58
|
+
@data ||= @fmv.to_s
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def to_ptr
|
|
62
|
+
::Fiddle::Pointer[to_s]
|
|
63
|
+
end
|
|
64
|
+
alias to_fiddle_pointer to_ptr
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def validate
|
|
69
|
+
unless @item_size == ITEM_SIZES[@format]
|
|
70
|
+
raise ArgumentError, "item_size does not match format"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if @fmv.sub_offsets
|
|
74
|
+
raise ArgumentError, "suboffsets not supported"
|
|
75
|
+
end
|
|
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"
|
|
81
|
+
end
|
|
82
|
+
stride *= s
|
|
83
|
+
end
|
|
84
|
+
unless stride == @byte_size
|
|
85
|
+
raise ArgumentError, "strides not match byte_size"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/ndav.gemspec
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = "ndav"
|
|
3
|
+
s.version = "0.0.1"
|
|
4
|
+
s.summary = "N-Dimensional Array View"
|
|
5
|
+
s.authors = ["Kitaiti Makoto"]
|
|
6
|
+
s.licenses = ["BSD-2-Clause"]
|
|
7
|
+
|
|
8
|
+
s.files = Dir.chdir(__dir__) {`git ls-files -z`.split("\x0")}
|
|
9
|
+
s.extensions = ["ext/extconf.rb"]
|
|
10
|
+
|
|
11
|
+
s.add_runtime_dependency "fiddle"
|
|
12
|
+
|
|
13
|
+
s.add_development_dependency "rake"
|
|
14
|
+
s.add_development_dependency "test-unit"
|
|
15
|
+
s.add_development_dependency "test-unit-notify"
|
|
16
|
+
s.add_development_dependency "test-unit-rr"
|
|
17
|
+
s.add_development_dependency "terminal-notifier" if RUBY_PLATFORM.match?(/darwin/)
|
|
18
|
+
s.add_development_dependency "rubygems-tasks"
|
|
19
|
+
s.add_development_dependency "rubygems-requirements-system"
|
|
20
|
+
s.add_development_dependency "red-arrow"
|
|
21
|
+
s.add_development_dependency "ffi"
|
|
22
|
+
end
|
data/test/helper.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "test/unit"
|
|
2
|
+
require "test/unit/notify"
|
|
3
|
+
|
|
4
|
+
require "fiddle"
|
|
5
|
+
require "arrow"
|
|
6
|
+
require "ndav"
|
|
7
|
+
require "ndav/ffi"
|
|
8
|
+
|
|
9
|
+
class TestBase < Test::Unit::TestCase
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def assert_int_array(array)
|
|
13
|
+
assert_equal 1, array.ndim
|
|
14
|
+
assert_equal "s", array.format
|
|
15
|
+
assert_equal [3], array.shape
|
|
16
|
+
assert_equal [2], array.strides
|
|
17
|
+
assert_equal 2, array.item_size
|
|
18
|
+
assert_equal 6, array.byte_size
|
|
19
|
+
assert_true array.readonly?
|
|
20
|
+
assert_equal [1, 2, 3].pack("s*"), array.to_s
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative "helper"
|
|
2
|
+
|
|
3
|
+
class TestConverter < TestBase
|
|
4
|
+
def setup
|
|
5
|
+
@array = Arrow::Int16Array.new([1, 2, 3])
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_ndav_from_ndav
|
|
9
|
+
ndav = NDAV.new(@array)
|
|
10
|
+
|
|
11
|
+
assert_same ndav, NDAV::Converter::NDAV(ndav)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_ndav_from_memory_view
|
|
15
|
+
assert_int_array NDAV::Converter::NDAV(@array)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_ndav_from_fiddle_memory_view
|
|
19
|
+
fmv = Fiddle::MemoryView.new(@array)
|
|
20
|
+
|
|
21
|
+
assert_int_array NDAV::Converter::NDAV(fmv)
|
|
22
|
+
end
|
|
23
|
+
end
|
data/test/test_export.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require_relative "helper"
|
|
2
|
+
|
|
3
|
+
class TestExport < TestBase
|
|
4
|
+
def test_export
|
|
5
|
+
mv = Fiddle::MemoryView.new(NDAV.new(Arrow::Int16Array.new([1, 2, 3])))
|
|
6
|
+
assert_equal 1, mv.ndim
|
|
7
|
+
assert_equal "s", mv.format
|
|
8
|
+
assert_equal [3], mv.shape
|
|
9
|
+
assert_equal [2], mv.strides
|
|
10
|
+
assert_equal 2, mv.item_size
|
|
11
|
+
assert_equal 6, mv.byte_size
|
|
12
|
+
assert_true mv.readonly?
|
|
13
|
+
assert_equal [1, 2, 3], mv.to_s.unpack("s*")
|
|
14
|
+
assert_nil mv.sub_offsets
|
|
15
|
+
end
|
|
16
|
+
end
|
data/test/test_ffi.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require_relative "helper"
|
|
2
|
+
|
|
3
|
+
class TestFFI < TestBase
|
|
4
|
+
def test_ndav_from_ffi_memory_pointer
|
|
5
|
+
ptr = ::FFI::MemoryPointer.new(:int16, 3)
|
|
6
|
+
ptr.write_array_of_int16([1, 2, 3])
|
|
7
|
+
ndav = ::NDAV.from_ffi_memory_pointer(ptr, shape: [3], format: "s")
|
|
8
|
+
|
|
9
|
+
assert_int_array ndav
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_ndav_from_ffi_pointer
|
|
13
|
+
str = [1, 2, 3].pack("s*")
|
|
14
|
+
address = ::Fiddle::Pointer[str].to_i
|
|
15
|
+
ptr = ::FFI::Pointer.new(:int16, address)
|
|
16
|
+
ndav = ::NDAV.from_ffi_pointer(ptr, shape: [3], format: "s", lifetime: str)
|
|
17
|
+
|
|
18
|
+
assert_int_array ndav
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_ndav_to_ffi_memory_pointer
|
|
22
|
+
ndav = ::NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
23
|
+
ptr = ndav.to_ffi_memory_pointer
|
|
24
|
+
|
|
25
|
+
assert_equal [1, 2, 3].pack("s*"), ptr.read_string(ndav.byte_size)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_ndav_to_ffi_pointer
|
|
29
|
+
ndav = ::NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
30
|
+
ptr = ndav.to_ffi_pointer
|
|
31
|
+
|
|
32
|
+
assert_equal [1, 2, 3].pack("s*"), ptr.read_string(ndav.byte_size)
|
|
33
|
+
assert_equal ndav.to_ptr.to_i, ptr.address
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_ffi_memory_pointer_from_ndav
|
|
37
|
+
ndav = ::NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
38
|
+
ptr = ::FFI::MemoryPointer.from_ndav(ndav)
|
|
39
|
+
|
|
40
|
+
assert_equal [1, 2, 3].pack("s*"), ptr.read_string(ndav.byte_size)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_ffi_pointer_from_ndav
|
|
44
|
+
ndav = ::NDAV.new(Arrow::Int16Array.new([1, 2, 3]))
|
|
45
|
+
ptr = ::FFI::Pointer.from_ndav(ndav)
|
|
46
|
+
|
|
47
|
+
assert_equal [1, 2, 3].pack("s*"), ptr.read_string(ndav.byte_size)
|
|
48
|
+
assert_equal ndav.to_ptr.to_i, ptr.address
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class TestConverter < self
|
|
52
|
+
def test_ndav_from_ffi_memory_pointer
|
|
53
|
+
ptr = ::FFI::MemoryPointer.new(:int16, 3)
|
|
54
|
+
ptr.write_array_of_int16([1, 2, 3])
|
|
55
|
+
ndav = ::NDAV::Converter::NDAV(ptr)
|
|
56
|
+
|
|
57
|
+
assert_int_array ndav
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_ndav_from_ffi_pointer
|
|
61
|
+
str = [1, 2, 3].pack("s*")
|
|
62
|
+
address = ::Fiddle::Pointer[str].to_i
|
|
63
|
+
ptr = ::FFI::Pointer.new(:int16, address)
|
|
64
|
+
ndav = ::NDAV::Converter::NDAV(ptr, shape: [3])
|
|
65
|
+
|
|
66
|
+
assert_int_array ndav
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/test/test_ndav.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require_relative "helper"
|
|
2
|
+
|
|
3
|
+
class TestNDAV < TestBase
|
|
4
|
+
def setup
|
|
5
|
+
@array = Arrow::Int16Array.new([1, 2, 3])
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_ndav
|
|
9
|
+
ndav = NDAV.new(@array)
|
|
10
|
+
|
|
11
|
+
assert_instance_of NDAV, ndav
|
|
12
|
+
assert_int_array ndav
|
|
13
|
+
assert_instance_of ::Fiddle::Pointer, ndav.to_ptr
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_memory_view
|
|
17
|
+
ndav = NDAV.new(@array)
|
|
18
|
+
mv = Fiddle::MemoryView.new(ndav)
|
|
19
|
+
|
|
20
|
+
assert_int_array mv
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_fiddle_pointer
|
|
24
|
+
ptr = Fiddle::Pointer[[1, 2, 3].pack("s*")]
|
|
25
|
+
ndav = NDAV.new(ptr, format: "s")
|
|
26
|
+
|
|
27
|
+
assert_equal ptr, ndav.to_ptr
|
|
28
|
+
assert_equal ptr, ndav.to_fiddle_pointer
|
|
29
|
+
assert_int_array ndav
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative "helper"
|
|
2
|
+
require "tempfile"
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
|
|
5
|
+
class TestPackage < TestBase
|
|
6
|
+
def test_build
|
|
7
|
+
Tempfile.create do |file|
|
|
8
|
+
assert system("gem", "build", "ndav.gemspec", "--output", file.to_path, exception: true)
|
|
9
|
+
assert file.size > 0
|
|
10
|
+
assert_path_exist file
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_install
|
|
15
|
+
gemspec = Gem::Specification.load("ndav.gemspec")
|
|
16
|
+
Dir.mktmpdir do |dir|
|
|
17
|
+
dir = File.realpath(dir)
|
|
18
|
+
gemfile = File.join(dir, gemspec.file_name)
|
|
19
|
+
system "gem", "build", "ndav.gemspec", "--output", gemfile, exception: true
|
|
20
|
+
install_dir = File.join(dir, "install")
|
|
21
|
+
FileUtils.mkdir install_dir
|
|
22
|
+
system "gem", "install", "--install-dir", install_dir, "--no-document", gemfile, exception: true
|
|
23
|
+
assert_path_exist File.join(install_dir, "extensions", Gem::Platform.local.to_s, RbConfig::CONFIG['ruby_version'], gemspec.full_name, "ndav.#{RbConfig::CONFIG["DLEXT"]}")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ndav
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Kitaiti Makoto
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: fiddle
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: test-unit
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: test-unit-notify
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: test-unit-rr
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: terminal-notifier
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: rubygems-tasks
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: rubygems-requirements-system
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: red-arrow
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '0'
|
|
131
|
+
type: :development
|
|
132
|
+
prerelease: false
|
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">="
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '0'
|
|
138
|
+
- !ruby/object:Gem::Dependency
|
|
139
|
+
name: ffi
|
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - ">="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '0'
|
|
145
|
+
type: :development
|
|
146
|
+
prerelease: false
|
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - ">="
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '0'
|
|
152
|
+
executables: []
|
|
153
|
+
extensions:
|
|
154
|
+
- ext/extconf.rb
|
|
155
|
+
extra_rdoc_files: []
|
|
156
|
+
files:
|
|
157
|
+
- ".gitignore"
|
|
158
|
+
- ".gitlab-ci.yml"
|
|
159
|
+
- Gemfile
|
|
160
|
+
- LICENSE.txt
|
|
161
|
+
- README.md
|
|
162
|
+
- Rakefile
|
|
163
|
+
- ext/extconf.rb
|
|
164
|
+
- ext/ndav.c
|
|
165
|
+
- ext/ndav.h
|
|
166
|
+
- lib/ndav.rb
|
|
167
|
+
- lib/ndav/converter.rb
|
|
168
|
+
- lib/ndav/ffi.rb
|
|
169
|
+
- ndav.gemspec
|
|
170
|
+
- test/helper.rb
|
|
171
|
+
- test/test_converter.rb
|
|
172
|
+
- test/test_export.rb
|
|
173
|
+
- test/test_ffi.rb
|
|
174
|
+
- test/test_ndav.rb
|
|
175
|
+
- test/test_package.rb
|
|
176
|
+
licenses:
|
|
177
|
+
- BSD-2-Clause
|
|
178
|
+
metadata: {}
|
|
179
|
+
rdoc_options: []
|
|
180
|
+
require_paths:
|
|
181
|
+
- lib
|
|
182
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
|
+
requirements:
|
|
184
|
+
- - ">="
|
|
185
|
+
- !ruby/object:Gem::Version
|
|
186
|
+
version: '0'
|
|
187
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
|
+
requirements:
|
|
189
|
+
- - ">="
|
|
190
|
+
- !ruby/object:Gem::Version
|
|
191
|
+
version: '0'
|
|
192
|
+
requirements: []
|
|
193
|
+
rubygems_version: 4.0.6
|
|
194
|
+
specification_version: 4
|
|
195
|
+
summary: N-Dimensional Array View
|
|
196
|
+
test_files: []
|