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.
- 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
|