Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

grm: add support for converting args #74

Merged
merged 1 commit into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions examples/grm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@
y = n.times.map { |i| Math.cos(x[i]) * x[i] }
z = n.times.map { |i| Math.sin(x[i]) * x[i] }

args = GRM.args_new
GRM.args_push(args, 'kind', 's', :const_string, 'plot3')
GRM.args_push(args, 'x', 'nD', :int, n, :voidp, x.pack('d*'))
GRM.args_push(args, 'y', 'nD', :int, n, :voidp, y.pack('d*'))
GRM.args_push(args, 'z', 'nD', :int, n, :voidp, z.pack('d*'))

GRM.plot(args)

GRM.plot(kind: "plot3",
x: x,
y: y,
z: z)
gets

GRM.args_delete(args)
6 changes: 5 additions & 1 deletion lib/gr_commons/define_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ def define_ffi_methods(ffi_module, prefix: '', default_type: :double)
when ->(x) { defined?(Numo::NArray) && x.is_a?(Numo::NArray) }
GRCommonUtils.public_send(default_type, arg)
else
arg
if arg.respond_to?(:to_gr)
arg.to_gr
else
arg
end
end
end
ffi_module.public_send(method, *args)
Expand Down
106 changes: 106 additions & 0 deletions lib/grm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,112 @@ class << self
# a Fiddley::MemoryPointer in the GRBase class.
extend GRMBase

class Args
class << self
def try_convert(value)
case value
when Hash
new(**value)
else
nil
end
end
end

def initialize(**args)
@args = GRM.args_new
@args.free = FFI["grm_args_delete"]
@references = []
args.each do |key, value|
push(key, value)
end
end

def push(key, value)
key = key.to_s if key.is_a?(Symbol)
case value
when String
GRM.args_push(@args, key, "s", :const_string, value)
when Integer
GRM.args_push(@args, key, "i", :int, value)
when Float
GRM.args_push(@args, key, "d", :double, value)
when Args
GRM.args_push(@args, key, "a", :voidp, value.address)
value.to_gr.free = nil
when Array
case value[0]
when String
addresses = value.collect {|v| Fiddle::Pointer[v].to_i}
GRM.args_push(@args, key, "nS",
:int, value.size,
:voidp, addresses.pack("J*"))
when Integer
GRM.args_push(@args, key, "nI",
:int, value.size,
:voidp, value.pack("i*"))
when Float
GRM.args_push(@args, key, "nD",
:int, value.size,
:voidp, value.pack("d*"))
when Args
GRM.args_push(@args, key, "nA",
:int, value.size,
:voidp, value.collect(&:address).pack("J*"))
value.each do |v|
v.to_gr.free = nil
end
else
vs = value.collect {|v| Args.new(**v)}
@references.concat(vs)
GRM.args_push(@args, key, "nA",
:int, value.size,
:voidp, vs.collect(&:address).pack("J*"))
vs.each do |v|
v.to_gr.free = nil
end
end
else
v = Args.new(**value)
@references << v
GRM.args_push(@args, key, "a", :voidp, v.address)
v.to_gr.free = nil
end
end

def clear
GRM.args_clear(@args)
@references.clear
end

def address
@args.to_i
end

def to_gr
@args
end
end

class << self
def merge(args=nil)
super(Args.try_convert(args) || args)
end

def merge_extended(args=nil, hold=0, identifiator=nil)
super(Args.try_convert(args) || args, hold, identificator)
end

def merge_hold(args=nil)
super(Args.try_convert(args) || args)
end

def merge_named(args=nil, identifiator=nil)
super(Args.try_convert(args) || args, identificator)
end

def plot(args=nil)
super(Args.try_convert(args) || args)
end
end
end
112 changes: 112 additions & 0 deletions test/grm_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,116 @@ def test_grm_ffi_lib
def test_version
assert_kind_of(String, GRM::VERSION)
end

class ArgsTest < self
def test_empty
GRM::Args.new
end

def test_string
args = GRM::Args.new(x: "hello")
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "s", :voidp, output)
assert_equal("hello", Fiddle::Pointer.read(output[0, output.size].unpack("J")[0], 5))
end
end

def test_integer
args = GRM::Args.new(x: 29)
Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "i", :voidp, output)
assert_equal([29], output[0, output.size].unpack("i"))
end
end

def test_float
args = GRM::Args.new(x: 2.9)
Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "d", :voidp, output)
assert_equal([2.9], output[0, output.size].unpack("d"))
end
end

def test_args
sub_args = GRM::Args.new
args = GRM::Args.new(x: sub_args)
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "a", :voidp, output)
assert_equal(sub_args.address, output[0, output.size].unpack("J")[0])
end
end

def test_hash
args = GRM::Args.new(x: {sub: 29})
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "a", :voidp, output)
address = output[0, output.size].unpack("J")[0]
Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE) do |sub_output|
GRM.args_values(address, "sub", "i", :voidp, sub_output)
assert_equal([29], sub_output[0, sub_output.size].unpack("i"))
end
end
end

def test_array_string
args = GRM::Args.new(x: ["hello", "world"])
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "S", :voidp, output)
address = output[0, output.size].unpack("J")[0]
value_addresses = Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP * 2).unpack("J*")
values = value_addresses.collect do |value_address|
Fiddle::Pointer.read(value_address, 5)
end
assert_equal(["hello", "world"], values)
end
end

def test_array_integer
args = GRM::Args.new(x: [2, 9])
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "I", :voidp, output)
address = output[0, output.size].unpack("J")[0]
assert_equal([2, 9], Fiddle::Pointer.read(address, Fiddle::SIZEOF_INT * 2).unpack("i*"))
end
end

def test_array_float
args = GRM::Args.new(x: [2.9, -9.2])
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "D", :voidp, output)
address = output[0, output.size].unpack("J")[0]
assert_equal([2.9, -9.2],
Fiddle::Pointer.read(address, Fiddle::SIZEOF_DOUBLE * 2).unpack("d*"))
end
end

def test_array_args
sub_args1 = GRM::Args.new
sub_args2 = GRM::Args.new
args = GRM::Args.new(x: [sub_args1, sub_args2])
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "A", :voidp, output)
address = output[0, output.size].unpack("J")[0]
assert_equal([sub_args1.address, sub_args2.address],
Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP * 2).unpack("J*"))
end
end

def test_array_hash
args = GRM::Args.new(x: [{sub1: 29}, {sub2: 2.9}])
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |output|
GRM.args_values(args, "x", "A", :voidp, output)
address = output[0, output.size].unpack("J")[0]
args_addresses = Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP * 2).unpack("J*")
Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE) do |sub1_output|
GRM.args_values(args_addresses[0], "sub1", "i", :voidp, sub1_output)
assert_equal([29], sub1_output[0, sub1_output.size].unpack("i"))
end
Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE, Fiddle::RUBY_FREE) do |sub2_output|
GRM.args_values(args_addresses[1], "sub2", "d", :voidp, sub2_output)
assert_equal([2.9], sub2_output[0, sub2_output.size].unpack("d"))
end
end
end
end
end