redshift 1.3.15
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/README +5 -0
- data/RELEASE-NOTES +455 -0
- data/TODO +431 -0
- data/bench/alg-state.rb +61 -0
- data/bench/bench +26 -0
- data/bench/bench.rb +10 -0
- data/bench/continuous.rb +76 -0
- data/bench/diff-bench +86 -0
- data/bench/discrete.rb +101 -0
- data/bench/euler.rb +50 -0
- data/bench/formula.rb +78 -0
- data/bench/half-strict.rb +103 -0
- data/bench/inertness.rb +116 -0
- data/bench/queue.rb +92 -0
- data/bench/run +66 -0
- data/bench/simple.rb +74 -0
- data/bench/strictness.rb +86 -0
- data/examples/ball-tkar.rb +72 -0
- data/examples/ball.rb +123 -0
- data/examples/collide.rb +70 -0
- data/examples/connect-parallel.rb +48 -0
- data/examples/connect.rb +109 -0
- data/examples/constants.rb +27 -0
- data/examples/delay.rb +80 -0
- data/examples/derivative.rb +77 -0
- data/examples/euler.rb +46 -0
- data/examples/external-lib.rb +33 -0
- data/examples/guard-debugger.rb +77 -0
- data/examples/lotka-volterra.rb +33 -0
- data/examples/persist-ball.rb +68 -0
- data/examples/pid.rb +87 -0
- data/examples/ports.rb +60 -0
- data/examples/queue.rb +56 -0
- data/examples/queue2.rb +98 -0
- data/examples/reset-with-event-val.rb +28 -0
- data/examples/scheduler.rb +104 -0
- data/examples/set-dest.rb +23 -0
- data/examples/simulink/README +1 -0
- data/examples/simulink/delay.mdl +827 -0
- data/examples/simulink/derivative.mdl +655 -0
- data/examples/step-discrete-profiler.rb +103 -0
- data/examples/subsystem.rb +109 -0
- data/examples/sync-deadlock.rb +32 -0
- data/examples/sync-queue.rb +91 -0
- data/examples/sync-retry.rb +20 -0
- data/examples/sync.rb +51 -0
- data/examples/thermostat.rb +53 -0
- data/examples/zeno.rb +53 -0
- data/lib/accessible-index.rb +47 -0
- data/lib/redshift.rb +1 -0
- data/lib/redshift/component.rb +412 -0
- data/lib/redshift/meta.rb +183 -0
- data/lib/redshift/mixins/zeno-debugger.rb +69 -0
- data/lib/redshift/port.rb +57 -0
- data/lib/redshift/queue.rb +104 -0
- data/lib/redshift/redshift.rb +111 -0
- data/lib/redshift/state.rb +31 -0
- data/lib/redshift/syntax.rb +558 -0
- data/lib/redshift/target/c.rb +37 -0
- data/lib/redshift/target/c/component-gen.rb +1303 -0
- data/lib/redshift/target/c/flow-gen.rb +325 -0
- data/lib/redshift/target/c/flow/algebraic.rb +85 -0
- data/lib/redshift/target/c/flow/buffer.rb +74 -0
- data/lib/redshift/target/c/flow/delay.rb +203 -0
- data/lib/redshift/target/c/flow/derivative.rb +101 -0
- data/lib/redshift/target/c/flow/euler.rb +67 -0
- data/lib/redshift/target/c/flow/expr.rb +113 -0
- data/lib/redshift/target/c/flow/rk4.rb +80 -0
- data/lib/redshift/target/c/library.rb +85 -0
- data/lib/redshift/target/c/world-gen.rb +1370 -0
- data/lib/redshift/target/spec.rb +34 -0
- data/lib/redshift/world.rb +300 -0
- data/rakefile +37 -0
- data/test/test.rb +52 -0
- data/test/test_buffer.rb +58 -0
- data/test/test_connect.rb +242 -0
- data/test/test_connect_parallel.rb +47 -0
- data/test/test_connect_strict.rb +135 -0
- data/test/test_constant.rb +74 -0
- data/test/test_delay.rb +145 -0
- data/test/test_derivative.rb +48 -0
- data/test/test_discrete.rb +592 -0
- data/test/test_discrete_isolated.rb +92 -0
- data/test/test_exit.rb +59 -0
- data/test/test_flow.rb +200 -0
- data/test/test_flow_link.rb +288 -0
- data/test/test_flow_sub.rb +100 -0
- data/test/test_flow_trans.rb +292 -0
- data/test/test_inherit.rb +127 -0
- data/test/test_inherit_event.rb +74 -0
- data/test/test_inherit_flow.rb +139 -0
- data/test/test_inherit_link.rb +65 -0
- data/test/test_inherit_setup.rb +56 -0
- data/test/test_inherit_state.rb +66 -0
- data/test/test_inherit_transition.rb +168 -0
- data/test/test_numerics.rb +34 -0
- data/test/test_queue.rb +90 -0
- data/test/test_queue_alone.rb +115 -0
- data/test/test_reset.rb +209 -0
- data/test/test_setup.rb +119 -0
- data/test/test_strict_continuity.rb +410 -0
- data/test/test_strict_reset_error.rb +30 -0
- data/test/test_strictness_error.rb +32 -0
- data/test/test_sync.rb +185 -0
- data/test/test_world.rb +328 -0
- 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
|