|
1 | 1 | # frozen_string_literal: true |
2 | 2 |
|
| 3 | +require "bigdecimal" |
| 4 | + |
3 | 5 | module FFTW3 |
4 | 6 | class AlignedMemory |
5 | 7 | attr_reader :pointer, :size, :precision, :type |
@@ -62,37 +64,74 @@ def free! |
62 | 64 | private |
63 | 65 |
|
64 | 66 | def write_real(data) |
65 | | - case @precision |
66 | | - when :double then @pointer.put_array_of_double(0, data) |
67 | | - when :float then @pointer.put_array_of_float(0, data) |
68 | | - end |
| 67 | + write_numeric_values(data) |
69 | 68 | end |
70 | 69 |
|
71 | 70 | def read_real |
72 | | - case @precision |
73 | | - when :double then @pointer.get_array_of_double(0, @count) |
74 | | - when :float then @pointer.get_array_of_float(0, @count) |
75 | | - end |
| 71 | + read_numeric_values(@count) |
76 | 72 | end |
77 | 73 |
|
78 | 74 | def write_complex(data) |
79 | 75 | flat = data.flat_map { |c| |
80 | 76 | c.is_a?(Complex) ? [c.real, c.imaginary] : c |
81 | 77 | } |
82 | | - case @precision |
83 | | - when :double then @pointer.put_array_of_double(0, flat) |
84 | | - when :float then @pointer.put_array_of_float(0, flat) |
85 | | - end |
| 78 | + write_numeric_values(flat) |
86 | 79 | end |
87 | 80 |
|
88 | 81 | def read_complex |
89 | | - flat = case @precision |
90 | | - when :double then @pointer.get_array_of_double(0, @count * 2) |
91 | | - when :float then @pointer.get_array_of_float(0, @count * 2) |
92 | | - end |
| 82 | + flat = read_numeric_values(@count * 2) |
93 | 83 | flat.each_slice(2).map { |re, im| Complex(re, im) } |
94 | 84 | end |
95 | 85 |
|
| 86 | + def write_numeric_values(data) |
| 87 | + case @precision |
| 88 | + when :double |
| 89 | + @pointer.put_array_of_double(0, data) |
| 90 | + when :float |
| 91 | + @pointer.put_array_of_float(0, data) |
| 92 | + when :long_double |
| 93 | + write_generic_values(data, type: :long_double) |
| 94 | + else |
| 95 | + raise_unsupported_precision!(:write) |
| 96 | + end |
| 97 | + end |
| 98 | + |
| 99 | + def read_numeric_values(count) |
| 100 | + case @precision |
| 101 | + when :double |
| 102 | + @pointer.get_array_of_double(0, count) |
| 103 | + when :float |
| 104 | + @pointer.get_array_of_float(0, count) |
| 105 | + when :long_double |
| 106 | + read_generic_values(count, type: :long_double) |
| 107 | + else |
| 108 | + raise_unsupported_precision!(:read) |
| 109 | + end |
| 110 | + end |
| 111 | + |
| 112 | + def write_generic_values(data, type:) |
| 113 | + value_size = ::FFI.type_size(type) |
| 114 | + data.each_with_index do |value, index| |
| 115 | + @pointer.put(type, index * value_size, value) |
| 116 | + end |
| 117 | + rescue TypeError |
| 118 | + raise_unsupported_precision!(:write) |
| 119 | + end |
| 120 | + |
| 121 | + def read_generic_values(count, type:) |
| 122 | + value_size = ::FFI.type_size(type) |
| 123 | + Array.new(count) do |index| |
| 124 | + @pointer.get(type, index * value_size) |
| 125 | + end |
| 126 | + rescue LoadError, TypeError |
| 127 | + raise_unsupported_precision!(:read) |
| 128 | + end |
| 129 | + |
| 130 | + def raise_unsupported_precision!(action) |
| 131 | + raise FFTW3::Error::InvalidArgument, |
| 132 | + "FFI does not support #{action}ing #{@precision} buffers on this platform" |
| 133 | + end |
| 134 | + |
96 | 135 | def self.release(ptr, free_func, freed_flag) |
97 | 136 | proc { |
98 | 137 | unless freed_flag[0] || ptr.null? |
|
0 commit comments