redshift 1.3.15

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.
Files changed (107) hide show
  1. data/.gitignore +8 -0
  2. data/README +5 -0
  3. data/RELEASE-NOTES +455 -0
  4. data/TODO +431 -0
  5. data/bench/alg-state.rb +61 -0
  6. data/bench/bench +26 -0
  7. data/bench/bench.rb +10 -0
  8. data/bench/continuous.rb +76 -0
  9. data/bench/diff-bench +86 -0
  10. data/bench/discrete.rb +101 -0
  11. data/bench/euler.rb +50 -0
  12. data/bench/formula.rb +78 -0
  13. data/bench/half-strict.rb +103 -0
  14. data/bench/inertness.rb +116 -0
  15. data/bench/queue.rb +92 -0
  16. data/bench/run +66 -0
  17. data/bench/simple.rb +74 -0
  18. data/bench/strictness.rb +86 -0
  19. data/examples/ball-tkar.rb +72 -0
  20. data/examples/ball.rb +123 -0
  21. data/examples/collide.rb +70 -0
  22. data/examples/connect-parallel.rb +48 -0
  23. data/examples/connect.rb +109 -0
  24. data/examples/constants.rb +27 -0
  25. data/examples/delay.rb +80 -0
  26. data/examples/derivative.rb +77 -0
  27. data/examples/euler.rb +46 -0
  28. data/examples/external-lib.rb +33 -0
  29. data/examples/guard-debugger.rb +77 -0
  30. data/examples/lotka-volterra.rb +33 -0
  31. data/examples/persist-ball.rb +68 -0
  32. data/examples/pid.rb +87 -0
  33. data/examples/ports.rb +60 -0
  34. data/examples/queue.rb +56 -0
  35. data/examples/queue2.rb +98 -0
  36. data/examples/reset-with-event-val.rb +28 -0
  37. data/examples/scheduler.rb +104 -0
  38. data/examples/set-dest.rb +23 -0
  39. data/examples/simulink/README +1 -0
  40. data/examples/simulink/delay.mdl +827 -0
  41. data/examples/simulink/derivative.mdl +655 -0
  42. data/examples/step-discrete-profiler.rb +103 -0
  43. data/examples/subsystem.rb +109 -0
  44. data/examples/sync-deadlock.rb +32 -0
  45. data/examples/sync-queue.rb +91 -0
  46. data/examples/sync-retry.rb +20 -0
  47. data/examples/sync.rb +51 -0
  48. data/examples/thermostat.rb +53 -0
  49. data/examples/zeno.rb +53 -0
  50. data/lib/accessible-index.rb +47 -0
  51. data/lib/redshift.rb +1 -0
  52. data/lib/redshift/component.rb +412 -0
  53. data/lib/redshift/meta.rb +183 -0
  54. data/lib/redshift/mixins/zeno-debugger.rb +69 -0
  55. data/lib/redshift/port.rb +57 -0
  56. data/lib/redshift/queue.rb +104 -0
  57. data/lib/redshift/redshift.rb +111 -0
  58. data/lib/redshift/state.rb +31 -0
  59. data/lib/redshift/syntax.rb +558 -0
  60. data/lib/redshift/target/c.rb +37 -0
  61. data/lib/redshift/target/c/component-gen.rb +1303 -0
  62. data/lib/redshift/target/c/flow-gen.rb +325 -0
  63. data/lib/redshift/target/c/flow/algebraic.rb +85 -0
  64. data/lib/redshift/target/c/flow/buffer.rb +74 -0
  65. data/lib/redshift/target/c/flow/delay.rb +203 -0
  66. data/lib/redshift/target/c/flow/derivative.rb +101 -0
  67. data/lib/redshift/target/c/flow/euler.rb +67 -0
  68. data/lib/redshift/target/c/flow/expr.rb +113 -0
  69. data/lib/redshift/target/c/flow/rk4.rb +80 -0
  70. data/lib/redshift/target/c/library.rb +85 -0
  71. data/lib/redshift/target/c/world-gen.rb +1370 -0
  72. data/lib/redshift/target/spec.rb +34 -0
  73. data/lib/redshift/world.rb +300 -0
  74. data/rakefile +37 -0
  75. data/test/test.rb +52 -0
  76. data/test/test_buffer.rb +58 -0
  77. data/test/test_connect.rb +242 -0
  78. data/test/test_connect_parallel.rb +47 -0
  79. data/test/test_connect_strict.rb +135 -0
  80. data/test/test_constant.rb +74 -0
  81. data/test/test_delay.rb +145 -0
  82. data/test/test_derivative.rb +48 -0
  83. data/test/test_discrete.rb +592 -0
  84. data/test/test_discrete_isolated.rb +92 -0
  85. data/test/test_exit.rb +59 -0
  86. data/test/test_flow.rb +200 -0
  87. data/test/test_flow_link.rb +288 -0
  88. data/test/test_flow_sub.rb +100 -0
  89. data/test/test_flow_trans.rb +292 -0
  90. data/test/test_inherit.rb +127 -0
  91. data/test/test_inherit_event.rb +74 -0
  92. data/test/test_inherit_flow.rb +139 -0
  93. data/test/test_inherit_link.rb +65 -0
  94. data/test/test_inherit_setup.rb +56 -0
  95. data/test/test_inherit_state.rb +66 -0
  96. data/test/test_inherit_transition.rb +168 -0
  97. data/test/test_numerics.rb +34 -0
  98. data/test/test_queue.rb +90 -0
  99. data/test/test_queue_alone.rb +115 -0
  100. data/test/test_reset.rb +209 -0
  101. data/test/test_setup.rb +119 -0
  102. data/test/test_strict_continuity.rb +410 -0
  103. data/test/test_strict_reset_error.rb +30 -0
  104. data/test/test_strictness_error.rb +32 -0
  105. data/test/test_sync.rb +185 -0
  106. data/test/test_world.rb +328 -0
  107. metadata +204 -0
@@ -0,0 +1,325 @@
1
+ module RedShift
2
+ require "redshift/target/c/flow/delay" if DelayFlow.needed
3
+ require "redshift/target/c/flow/derivative" if DerivativeFlow.needed
4
+ require "redshift/target/c/flow/euler" if EulerDifferentialFlow.needed
5
+ require "redshift/target/c/flow/algebraic" if AlgebraicFlow.needed
6
+ require "redshift/target/c/flow/rk4" if RK4DifferentialFlow.needed
7
+ require "redshift/target/c/flow/expr"
8
+ end
9
+
10
+ module RedShift; class Flow
11
+ def translate flow_fn, result_var, rk_level, cl, orig_formula = nil
12
+ translation = {}
13
+ setup = [] ## should use accumulator
14
+
15
+ orig_formula ||= @formula
16
+ c_formula = orig_formula.dup
17
+ strict = true
18
+
19
+ re = /(?:([A-Za-z_]\w*)\.)?([A-Za-z_]\w*)(?!\w*\s*[(])/
20
+
21
+ c_formula.gsub! re do |expr|
22
+
23
+ unless translation[expr]
24
+ link, var = $1, $2
25
+ if link
26
+ result =
27
+ translate_link(link, var, translation, flow_fn, cl, expr, rk_level)
28
+ strict &&= result # Don't combine with method call!!!
29
+
30
+ else # expr == 'var'
31
+ varsym = var.intern
32
+
33
+ link_type, link_strictness = cl.link_variables[varsym]
34
+
35
+ if link_type
36
+ # l ==> link_l
37
+ strict &&= (link_strictness == :strict)
38
+
39
+ link = var
40
+ link_cname = "link_#{link}"
41
+ unless translation[link]
42
+ translation[link] = "ct.#{link_cname}"
43
+
44
+ ct_struct = make_ct_struct(flow_fn, cl)
45
+
46
+ link_type_ssn = link_type.shadow_struct.name
47
+ ct_struct.declare link_cname => "#{link_type_ssn} *#{link_cname}"
48
+ flow_fn.setup link_cname => "ct.#{link_cname} = shadow->#{link}"
49
+ end
50
+
51
+ elsif (kind = cl.constant_variables[varsym])
52
+ strict &&= (kind == :strict)
53
+ translation[var] = "shadow->#{var}"
54
+
55
+ elsif (kind = cl.continuous_variables[varsym])
56
+ # x ==> var_x
57
+ strict &&= (kind == :strict)
58
+
59
+ var_cname = "var_#{var}"
60
+ sh_cname = "shadow"
61
+ cs_cname = "cont_state"
62
+ cont_var = "#{cs_cname}->#{var}"
63
+ translation[var] = var_cname
64
+
65
+ flow_fn.declare var_cname => "double #{var_cname}"
66
+ flow_fn.setup var_cname => %{
67
+ if (#{cont_var}.algebraic) {
68
+ if (#{cont_var}.rk_level < shadow->world->rk_level ||
69
+ (shadow->world->rk_level == 0 &&
70
+ (#{cont_var}.strict ? !#{cont_var}.d_tick :
71
+ #{cont_var}.d_tick != shadow->world->d_tick)
72
+ ))
73
+ (*#{cont_var}.flow)((ComponentShadow *)#{sh_cname});
74
+ }
75
+ else {
76
+ #{cont_var}.d_tick = shadow->world->d_tick;
77
+ }
78
+ }
79
+ # The d_tick assignment is explained in component-gen.rb.
80
+ setup << "#{var_cname} = #{cont_var}.value_#{rk_level};"
81
+
82
+ elsif (kind = cl.input_variables[varsym])
83
+ # x ==> var_x
84
+ strict &&= (kind == :strict)
85
+ # note that we check in Component#connect that the
86
+ # source var is strict
87
+
88
+ var_cname = "var_#{var}"
89
+ translation[var] = var_cname
90
+ src_comp = cl.src_comp(varsym)
91
+
92
+ flow_fn.declare var_cname => "double #{var_cname}"
93
+ flow_fn.setup var_cname => %{\
94
+ #{var_cname} = rs_eval_input_var(shadow, &shadow->#{src_comp});
95
+ }
96
+
97
+ elsif (event_idx = cl.exported_events[varsym])
98
+ unless self.kind_of? ResetExpr
99
+ raise NoValueError,
100
+ "Event #{varsym.inspect} has no value in this context."
101
+ end
102
+
103
+ strict = false # strict doesn't matter
104
+
105
+ var_cname = "event_#{var}"
106
+ translation[var] = var_cname
107
+ flow_fn.declare var_cname => "double #{var_cname}"
108
+ flow_fn.setup var_cname => %{\
109
+ VALUE event_values, event_val;
110
+ event_values = shadow->event_values;
111
+ assert(event_values != Qnil);
112
+ event_val = RARRAY(event_values)->ptr[#{event_idx}];
113
+ #{var_cname} = NUM2DBL(event_val);
114
+ }
115
+
116
+ elsif /\A[eE]\z/ =~ var
117
+ translation[expr] = expr # scientific notation
118
+
119
+ elsif cl.const_defined?(var)
120
+ translation[expr] = cl.const_get(var)
121
+
122
+ elsif external_constant?(var)
123
+ translation[expr] = expr
124
+
125
+ else
126
+ raise NameError, "Unknown variable: #{var}"
127
+ end
128
+
129
+ end
130
+ end
131
+ translation[expr]
132
+ end
133
+
134
+ yield strict if block_given? ## funky way to return another value
135
+
136
+ setup << "#{result_var} = (#{c_formula})"
137
+
138
+ rescue NameError, ArgumentError => ex
139
+ ex.message << "\nclass: #{cl.name}\nformula:\n#{orig_formula}\n\n"
140
+ raise ex
141
+ end
142
+
143
+ def external_constant? var
144
+ RedShift.library.external_constant? var
145
+ end
146
+
147
+ CT_STRUCT_NAME = "Context"
148
+
149
+ # Since MSVC doesn't support nested functions...
150
+ def make_ct_struct(flow_fn, cl)
151
+ sf = flow_fn.parent
152
+ ct_struct = sf.declare![CT_STRUCT_NAME]
153
+
154
+ if ct_struct
155
+ ct_struct = ct_struct[1] ## hacky
156
+
157
+ else
158
+ ct_struct = sf.declare_struct(CT_STRUCT_NAME)
159
+
160
+ ct_struct.declare :shadow => "#{cl.shadow_struct.name} *shadow"
161
+
162
+ flow_fn.declare :ct => "#{CT_STRUCT_NAME} ct"
163
+ flow_fn.setup :ct_shadow => "ct.shadow = shadow"
164
+ end
165
+
166
+ ct_struct
167
+ end
168
+
169
+ # l.x ==> get_l__x()->value_n
170
+ def translate_link(link, var, translation, flow_fn, cl, expr, rk_level)
171
+ link_type, link_strictness = cl.link_variables[link.intern]
172
+ raise(NameError, "No such link, #{link}") unless link_type
173
+ strict = (link_strictness == :strict)
174
+
175
+ flow_fn.include link_type.shadow_library_include_file
176
+
177
+ link_cname = "link_#{link}"
178
+ get_var_cname = "get_#{link}__#{var}"
179
+
180
+ ct_struct = make_ct_struct(flow_fn, cl)
181
+
182
+ varsym = var.intern
183
+ if (kind = link_type.constant_variables[varsym])
184
+ var_type = :constant
185
+ elsif (kind = link_type.continuous_variables[varsym])
186
+ var_type = :continuous
187
+ elsif (kind = link_type.input_variables[varsym])
188
+ var_type = :input
189
+ elsif (a = link_type.link_variables[varsym])
190
+ var_type = :link
191
+ link_link_type, kind = a
192
+ elsif (event_idx = link_type.exported_events[varsym])
193
+ unless self.kind_of? ResetExpr
194
+ raise NoValueError, "Event #{varsym.inspect} has no value in this context."
195
+ end
196
+ var_type = :event
197
+ kind = false # strict doesn't matter
198
+ else
199
+ raise NameError, "Unknown variable: #{var} in #{link_type}"
200
+ end
201
+
202
+ strict &&= (kind == :strict)
203
+
204
+ if var_type == :continuous or var_type == :input
205
+ checked_var_cname = "checked_#{link}__#{var}" ## not quite unambig.
206
+ ct_struct.declare checked_var_cname => "int #{checked_var_cname}"
207
+ flow_fn.setup checked_var_cname => "ct.#{checked_var_cname} = 0"
208
+ end
209
+
210
+ if var_type == :continuous
211
+ link_cs_ssn = link_type.cont_state_class.shadow_struct.name
212
+ link_cs_cname = "link_cs_#{link}"
213
+ ct_struct.declare link_cs_cname => "#{link_cs_ssn} *#{link_cs_cname}"
214
+ end
215
+
216
+ unless translation[link + "."]
217
+ translation[link + "."] = true # just so we know we've handled it
218
+
219
+ unless translation[link]
220
+ translation[link] = link_cname
221
+ link_type_ssn = link_type.shadow_struct.name
222
+ ct_struct.declare link_cname => "#{link_type_ssn} *#{link_cname}"
223
+ flow_fn.setup link_cname => "ct.#{link_cname} = shadow->#{link}"
224
+ end ## same as below
225
+ end
226
+
227
+ sf = flow_fn.parent
228
+
229
+ exc_nil = flow_fn.declare_class(NilLinkError) ## class var
230
+ msg_nil = "Link #{link} is nil."
231
+
232
+ case var_type
233
+ when :continuous
234
+ cs_cname = "ct->#{link_cs_cname}"
235
+ cont_var = "#{cs_cname}->#{var}"
236
+ sf.declare get_var_cname => %{
237
+ inline static ContVar *#{get_var_cname}(#{CT_STRUCT_NAME} *ct) {
238
+ if (!ct->#{checked_var_cname}) {
239
+ ct->#{checked_var_cname} = 1;
240
+ if (!ct->#{link_cname})
241
+ rs_raise(#{exc_nil}, ct->shadow->self, #{msg_nil.inspect});
242
+ #{cs_cname} = (#{link_cs_ssn} *)ct->#{link_cname}->cont_state;
243
+ if (#{cont_var}.algebraic) {
244
+ if (#{cont_var}.rk_level < ct->shadow->world->rk_level ||
245
+ (ct->shadow->world->rk_level == 0 &&
246
+ (#{cont_var}.strict ? !#{cont_var}.d_tick :
247
+ #{cont_var}.d_tick != ct->shadow->world->d_tick)
248
+ ))
249
+ (*#{cont_var}.flow)((ComponentShadow *)ct->#{link_cname});
250
+ }
251
+ else {
252
+ #{cont_var}.d_tick = ct->shadow->world->d_tick;
253
+ }
254
+ }
255
+ return &(#{cont_var});
256
+ }
257
+ } ## algebraic test is same as above
258
+
259
+ translation[expr] = "#{get_var_cname}(&ct)->value_#{rk_level}"
260
+
261
+ when :constant
262
+ sf.declare get_var_cname => %{
263
+ inline static double #{get_var_cname}(#{CT_STRUCT_NAME} *ct) {
264
+ if (!ct->#{link_cname})
265
+ rs_raise(#{exc_nil}, ct->shadow->self, #{msg_nil.inspect});
266
+ return ct->#{link_cname}->#{var};
267
+ }
268
+ }
269
+
270
+ translation[expr] = "#{get_var_cname}(&ct)"
271
+
272
+ when :link
273
+ link_link_type_ssn = link_link_type.shadow_struct.name
274
+ sf.declare get_var_cname => %{
275
+ inline static #{link_link_type_ssn} *#{get_var_cname}(#{CT_STRUCT_NAME} *ct) {
276
+ if (!ct->#{link_cname})
277
+ rs_raise(#{exc_nil}, ct->shadow->self, #{msg_nil.inspect});
278
+ return ct->#{link_cname}->#{var};
279
+ }
280
+ }
281
+
282
+ translation[expr] = "#{get_var_cname}(&ct)"
283
+
284
+ when :input
285
+ src_comp = link_type.src_comp(var.intern)
286
+ result_name = "value_#{link}__#{var}"
287
+ ct_struct.declare result_name => "double #{result_name}"
288
+
289
+ sf.declare get_var_cname => %{
290
+ inline static double #{get_var_cname}(#{CT_STRUCT_NAME} *ct) {
291
+ if (!ct->#{checked_var_cname}) {
292
+ ct->#{checked_var_cname} = 1;
293
+ if (!ct->#{link_cname})
294
+ rs_raise(#{exc_nil}, ct->shadow->self, #{msg_nil.inspect});
295
+ ct->#{result_name} = rs_eval_input_var(ct->#{link_cname},
296
+ &ct->#{link_cname}->#{src_comp});
297
+ }
298
+ return ct->#{result_name};
299
+ }
300
+ }
301
+
302
+ translation[expr] = "#{get_var_cname}(&ct)"
303
+
304
+ when :event
305
+ sf.declare get_var_cname => %{
306
+ inline static double #{get_var_cname}(#{CT_STRUCT_NAME} *ct) {
307
+ VALUE event_values, event_val;
308
+ if (!ct->#{link_cname})
309
+ rs_raise(#{exc_nil}, ct->shadow->self, #{msg_nil.inspect});
310
+ event_values = ct->#{link_cname}->event_values;
311
+ assert(event_values != Qnil);
312
+ event_val = RARRAY(event_values)->ptr[#{event_idx}];
313
+ return NUM2DBL(event_val);
314
+ }
315
+ }
316
+
317
+ translation[expr] = "#{get_var_cname}(&ct)"
318
+
319
+ else
320
+ raise ArgumentError, "Bad var_type: #{var_type.inspect}"
321
+ end
322
+
323
+ return strict
324
+ end
325
+ end; end
@@ -0,0 +1,85 @@
1
+ module RedShift; class AlgebraicFlow
2
+ def flow_wrapper cl, state
3
+ var_name = @var
4
+ flow = self
5
+ flow_name = "flow_#{CGenerator.make_c_name cl.name}_#{var_name}_#{state}"
6
+
7
+ Component::FlowWrapper.make_subclass flow_name do
8
+ @inspect_str = "#{cl.name}:#{state}: #{var_name} = #{flow.formula}"
9
+
10
+ ssn = cl.shadow_struct.name
11
+ cont_state_ssn = cl.cont_state_class.shadow_struct.name
12
+
13
+ # We need the struct
14
+ shadow_library_source_file.include(cl.shadow_library_include_file)
15
+
16
+ shadow_library_source_file.define(flow_name).instance_eval do
17
+ arguments "ComponentShadow *comp_shdw"
18
+ declare :shadow => %{
19
+ struct #{ssn} *shadow;
20
+ struct #{cont_state_ssn} *cont_state;
21
+ ContVar *var;
22
+ }
23
+ exc = declare_class CircularDefinitionError
24
+ msg = "Circularity in algebraic formula for #{var_name} in state " +
25
+ "#{state} of class #{cl.name}."
26
+ setup :shadow => %{
27
+ shadow = (#{ssn} *)comp_shdw;
28
+ cont_state = (#{cont_state_ssn} *)shadow->cont_state;
29
+ var = &cont_state->#{var_name};
30
+ assert(var->algebraic);
31
+ if (shadow->world->alg_nest > 100) {
32
+ shadow->world->alg_nest = 0;
33
+ rs_raise(#{exc}, shadow->self, #{msg.inspect});
34
+ }
35
+ shadow->world->alg_nest++;
36
+ }
37
+ ## 100 not always enough, so could increase limit exponentially,
38
+ ## and look in subsequent iterations for repeats of this [var, obj].
39
+
40
+ ## optimization: it might be possible to translate once and
41
+ ## use gsub to make each of the four versions, or use a template.
42
+ body %{
43
+ switch (shadow->world->rk_level) {
44
+ case 0:
45
+ #{flow.translate(self, "var->value_0", 0, cl).join("
46
+ ")};
47
+ var->d_tick = shadow->world->d_tick;
48
+ break;
49
+
50
+ case 1:
51
+ #{flow.translate(self, "var->value_1", 1, cl).join("
52
+ ")};
53
+ var->rk_level = shadow->world->rk_level;
54
+ break;
55
+
56
+ case 2:
57
+ #{flow.translate(self, "var->value_2", 2, cl).join("
58
+ ")};
59
+ var->rk_level = shadow->world->rk_level;
60
+ break;
61
+
62
+ case 3:
63
+ #{flow.translate(self, "var->value_3", 3, cl){|strict|
64
+ flow.instance_eval {@strict = strict}
65
+ }.join("
66
+ ")};
67
+ var->rk_level = shadow->world->rk_level;
68
+ break;
69
+
70
+ default:
71
+ rb_raise(#{declare_class RuntimeError},
72
+ "Bad rk_level, %d!", shadow->world->rk_level);
73
+ }
74
+
75
+ shadow->world->alg_nest--;
76
+ }
77
+ end # Case 0 applies during discrete update.
78
+ # alg flows are lazy
79
+
80
+ define_c_method :calc_function_pointer do
81
+ body "shadow->flow = &#{flow_name}", "shadow->algebraic = 1"
82
+ end
83
+ end
84
+ end
85
+ end; end
@@ -0,0 +1,74 @@
1
+ class RedShift::Library
2
+ def define_buffer
3
+ return if @define_buffer
4
+ @define_buffer = true
5
+
6
+ include_file, source_file = add_file "buffer"
7
+
8
+ include_file.declare :Buffer => %{
9
+ typedef struct {
10
+ long len;
11
+ double *ptr;
12
+ } Buffer;
13
+ }.tabto(0)
14
+
15
+ source_file.define_c_function(:buffer_inhale_array).instance_eval {
16
+ arguments "Buffer *buf", "VALUE ary"
17
+ scope :extern
18
+ body %{
19
+ int size, i;
20
+
21
+ Check_Type(ary, T_ARRAY);
22
+
23
+ size = RARRAY(ary)->len;
24
+ if (buf->ptr) {
25
+ REALLOC_N(buf->ptr, double, size);
26
+ }
27
+ else {
28
+ buf->ptr = ALLOC_N(double, size);
29
+ }
30
+ buf->len = size;
31
+
32
+ for (i = 0; i < size; i++) {
33
+ buf->ptr[i] = NUM2DBL(RARRAY(ary)->ptr[i]);
34
+ }
35
+ }
36
+ }
37
+
38
+ source_file.define_c_function(:buffer_exhale_array).instance_eval {
39
+ arguments "Buffer *buf"
40
+ return_type "VALUE"
41
+ returns "ary"
42
+ scope :extern
43
+ declare :size => "int size",
44
+ :i => "int i",
45
+ :ary => "VALUE ary"
46
+ body %{
47
+ size = buf->len;
48
+ ary = rb_ary_new2(size);
49
+ RARRAY(ary)->len = size;
50
+ for (i = 0; i < size; i++) {
51
+ RARRAY(ary)->ptr[i] = rb_float_new(buf->ptr[i]);
52
+ }
53
+ }
54
+ }
55
+ end
56
+
57
+ # An embedded struct that holds a pointer +ptr+ to an externally stored
58
+ # array of doubles of length +len+.
59
+ class BufferAttribute < CShadow::CNativeAttribute
60
+ @pattern = /\A(Buffer)\s+(\w+)\z/
61
+
62
+ def initialize(*args)
63
+ super
64
+ lib = owner_class.shadow_library
65
+ owner_class.shadow_library_include_file.include "buffer.h"
66
+
67
+ @reader = "result = buffer_exhale_array(&shadow->#{@cvar})"
68
+ @writer = "buffer_inhale_array(&shadow->#{@cvar}, arg)"
69
+ @dump = "rb_ary_push(result, buffer_exhale_array(&shadow->#{@cvar}))"
70
+ @load = "buffer_inhale_array(&shadow->#{@cvar}, rb_ary_shift(from_array))"
71
+ @free = "free(shadow->#{@cvar}.ptr)"
72
+ end
73
+ end
74
+ end