Skip to content

Commit

Permalink
grm: add support for converting args
Browse files Browse the repository at this point in the history
Before:

    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)
    gets
    GRM.args_delete(args)

After:

    GRM.plot(kind: "plot3",
             x: x,
             y: y,
             z: z)
    gets
  • Loading branch information
kou committed Aug 2, 2024
1 parent a28532a commit 14231f5
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 11 deletions.
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_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, sub2_output.size].unpack("i"))
end
Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE, Fiddle::RUBY_FREE) do |sub2_output|
GRM.args_values(args_addresses[0], "sub2", "d", :voidp, sub2_output)
assert_equal([2.9], sub2_output[0, sub2_output.size].unpack("d"))
end
end
end
end
end

0 comments on commit 14231f5

Please sign in to comment.