redshift 1.3.15

Sign up to get free protection for your applications and to get access to all the features.
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