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 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
@@ -0,0 +1,7 @@
1
+ Gemfile.lock
2
+ ext/Makefile
3
+ *.so
4
+ *bundle
5
+ *dll
6
+ *.o
7
+ *.bundle.dSYM
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,14 @@
1
+ default:
2
+ image: ruby:4.0
3
+ before_script:
4
+ - bundle config set path.system true
5
+ - bundle install
6
+ - bundle env
7
+
8
+ test:
9
+ cache:
10
+ key: gems
11
+ paths:
12
+ - /root/.local/share/gem/ruby
13
+ script:
14
+ - rake test
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ plugin "rubygems-requirements-system"
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
@@ -0,0 +1,9 @@
1
+ NDAV - N-Dimensional Array View
2
+ ===============================
3
+
4
+ Wrapper for MemoryView and pointer.
5
+
6
+ LICENSE
7
+ -------
8
+
9
+ BSD-2-Clause license. See LICENSE.txt file.
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
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile "ndav"
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,2 @@
1
+ #include <ruby.h>
2
+ #include <ruby/memory_view.h>
@@ -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
@@ -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: []