1 int payload_size(reagent x) {
2 x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
3 lookup_memory_core(x, false);
4 return size_of(x);
5 }
6
7 :(before "End type_tree Definition")
8 struct address_element_info {
9
10
11 int offset;
12
13
14
15
16
17
18 const type_tree* payload_type;
19
20 address_element_info(int o, const type_tree* p);
21 address_element_info(const address_element_info& other);
22 ~address_element_info();
23 address_element_info& operator=(const address_element_info& other);
24 };
25 :(code)
26 address_element_info::address_element_info(int o, const type_tree* p) {
27 offset = o;
28 payload_type = p;
29 }
30 address_element_info::address_element_info(const address_element_info& other) {
31 offset = other.offset;
32 payload_type = copy(other.payload_type);
33 }
34 address_element_info::~address_element_info() {
35 if (payload_type) {
36 delete payload_type;
37 payload_type = NULL;
38 }
39 }
40 address_element_info& address_element_info::operator=(const address_element_info& other) {
41 offset = other.offset;
42 if (payload_type) delete payload_type;
43 payload_type = copy(other.payload_type);
44 return *this;
45 }
46
47 :(before "End type_tree Definition")
48
49
50
51 struct tag_condition_info {
52 int offset;
53 int tag;
54 tag_condition_info(int o, int t) :offset(o), tag(t) {}
55 };
56
57 :(before "End container_metadata Fields")
58
59
60
61
62
63 map<set<tag_condition_info>, set<address_element_info> > address;
64 :(code)
65 bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) {
66 if (a.size() != b.size()) return a.size() < b.size();
67 for (set<tag_condition_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) {
68 if (pa->offset != pb->offset) return pa->offset < pb->offset;
69 if (pa->tag != pb->tag) return pa->tag < pb->tag;
70 }
71 return false;
72 }
73 bool operator<(const tag_condition_info& a, const tag_condition_info& b) {
74 if (a.offset != b.offset) return a.offset < b.offset;
75 if (a.tag != b.tag) return a.tag < b.tag;
76 return false;
77 }
78 bool operator<(const set<address_element_info>& a, const set<address_element_info>& b) {
79 if (a.size() != b.size()) return a.size() < b.size();
80 for (set<address_element_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) {
81 if (pa->offset != pb->offset) return pa->offset < pb->offset;
82 }
83 return false;
84 }
85 bool operator<(const address_element_info& a, const address_element_info& b) {
86 if (a.offset != b.offset) return a.offset < b.offset;
87 return false;
88 }
89
90
91
92
93 :(after "Transform.push_back(compute_container_sizes)")
94 Transform.push_back(compute_container_address_offsets);
95 :(code)
96 void compute_container_address_offsets(const recipe_ordinal r) {
97 recipe& caller = get(Recipe, r);
98 trace(9992, "transform") << "--- compute address offsets for " << caller.name << end();
99 for (int i = 0; i < SIZE(caller.steps); ++i) {
100 instruction& inst = caller.steps.at(i);
101 trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end();
102 for (int i = 0; i < SIZE(inst.ingredients); ++i)
103 compute_container_address_offsets(inst.ingredients.at(i), " in '"+inst.original_string+"'");
104 for (int i = 0; i < SIZE(inst.products); ++i)
105 compute_container_address_offsets(inst.products.at(i), " in '"+inst.original_string+"'");
106 }
107 }
108
109 void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) {
110 if (is_literal(r) || is_dummy(r)) return;
111 compute_container_address_offsets(r.type, location_for_error_messages);
112 if (contains_key(Container_metadata, r.type))
113 r.metadata = get(Container_metadata, r.type);
114 }
115
116
117
118 void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) {
119 if (!type) return;
120 if (!type->atom) {
121 if (!type->left->atom) {
122 raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end();
123 return;
124 }
125 if (type->left->name == "address")
126 compute_container_address_offsets(payload_type(type), location_for_error_messages);
127 else if (type->left->name == "array")
128 compute_container_address_offsets(array_element(type), location_for_error_messages);
129
130 }
131 const type_tree* base_type = type;
132
133 if (!contains_key(Type, base_type->value)) return;
134 type_info& info = get(Type, base_type->value);
135 if (info.kind == CONTAINER) {
136 compute_container_address_offsets(info, type, location_for_error_messages);
137 }
138 if (info.kind == EXCLUSIVE_CONTAINER) {
139 compute_exclusive_container_address_offsets(info, type, location_for_error_messages);
140 }
141 }
142
143 void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) {
144 container_metadata& metadata = get(Container_metadata, full_type);
145 if (!metadata.address.empty()) return;
146 trace(9994, "transform") << "compute address offsets for container " << container_info.name << end();
147 append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages);
148 }
149
150 void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) {
151 container_metadata& metadata = get(Container_metadata, full_type);
152 trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end();
153 for (int tag = 0; tag < SIZE(exclusive_container_info.elements); ++tag) {
154 set<tag_condition_info> key;
155 key.insert(tag_condition_info(0, tag));
156 append_addresses(1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages);
157 }
158 }
159
160 void append_addresses(int base_offset, const type_tree* type, map<set<tag_condition_info>, set<address_element_info> >& out, const set<tag_condition_info>& key, const string& location_for_error_messages) {
161 if (is_mu_address(type)) {
162 get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*payload_type(type))));
163 return;
164 }
165 const type_tree* base_type = type;
166
167 const type_info& info = get(Type, base_type->value);
168 if (info.kind == CONTAINER) {
169 for (int curr_index = 0, curr_offset = base_offset; curr_index < SIZE(info.elements); ++curr_index) {
170 trace(9993, "transform") << "checking container " << base_type->name << ", element " << curr_index << end();
171 reagent element = element_type(type, curr_index);
172
173 if (is_mu_address(element)) {
174 trace(9993, "transform") << "address at offset " << curr_offset << end();
175 get_or_insert(out, key).insert(address_element_info(curr_offset, new type_tree(*payload_type(element.type))));
176 ++curr_offset;
177 }
178 else if (is_mu_array(element)) {
179 curr_offset += 1;
180 const type_tree* array_element_type = array_element(element.type);
181 int array_element_size = size_of(array_element_type);
182 for (int i = 0; i < static_array_length(element.type); ++i) {
183 append_addresses(curr_offset, array_element_type, out, key, location_for_error_messages);
184 curr_offset += array_element_size;
185 }
186 }
187 else if (is_mu_container(element)) {
188 append_addresses(curr_offset, element.type, out, key, location_for_error_messages);
189 curr_offset += size_of(element);
190 }
191 else if (is_mu_exclusive_container(element)) {
192 const type_tree* element_base_type = element.type;
193
194 const type_info& element_info = get(Type, element_base_type->value);
195 for (int tag = 0; tag < SIZE(element_info.elements); ++tag) {
196 set<tag_condition_info> new_key = key;
197 new_key.insert(tag_condition_info(curr_offset, tag));
198 if (!contains_key(out, new_key))
199 append_addresses(curr_offset+1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages);
200 }
201 curr_offset += size_of(element);
202 }
203 else {
204
205 ++curr_offset;
206 }
207 }
208 }
209 else if (info.kind == EXCLUSIVE_CONTAINER) {
210 for (int tag = 0; tag < SIZE(info.elements); ++tag) {
211 set<tag_condition_info> new_key = key;
212 new_key.insert(tag_condition_info(base_offset, tag));
213 if (!contains_key(out, new_key))
214 append_addresses(base_offset+1, variant_type(type, tag).type, out, new_key, location_for_error_messages);
215 }
216 }
217 }
218
219
220
221 :(before "End Unit Tests")
222 void test_container_address_offsets_empty() {
223 int old_size = SIZE(Container_metadata);
224
225 reagent r("x:point");
226 compute_container_sizes(r, "");
227
228 compute_container_address_offsets(r, "");
229
230
231 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
232
233 CHECK(r.metadata.address.empty());
234
235 CHECK(contains_key(Container_metadata, r.type));
236 CHECK(get(Container_metadata, r.type).address.empty());
237
238 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
239 }
240
241 void test_container_address_offsets() {
242 int old_size = SIZE(Container_metadata);
243
244 run("container foo [\n"
245 " x:address:num\n"
246 "]\n");
247 reagent r("x:foo");
248 compute_container_sizes(r, "");
249
250 compute_container_address_offsets(r, "");
251
252
253 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
254
255 CHECK_EQ(SIZE(r.metadata.address), 1);
256 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
257 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
258 CHECK_EQ(SIZE(address_offsets), 1);
259 CHECK_EQ(address_offsets.begin()->offset, 0);
260 CHECK(address_offsets.begin()->payload_type->atom);
261 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
262
263 CHECK(contains_key(Container_metadata, r.type));
264 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
265 CHECK_EQ(SIZE(address_offsets2), 1);
266 CHECK_EQ(address_offsets2.begin()->offset, 0);
267 CHECK(address_offsets2.begin()->payload_type->atom);
268 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
269
270 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
271 }
272
273 void test_container_address_offsets_2() {
274 int old_size = SIZE(Container_metadata);
275
276 run("container foo [\n"
277 " x:num\n"
278 " y:address:num\n"
279 "]\n");
280 reagent r("x:foo");
281 compute_container_sizes(r, "");
282
283
284 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
285
286 compute_container_address_offsets(r, "");
287
288 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
289
290 CHECK_EQ(SIZE(r.metadata.address), 1);
291 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
292 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
293 CHECK_EQ(SIZE(address_offsets), 1);
294 CHECK_EQ(address_offsets.begin()->offset, 1);
295 CHECK(address_offsets.begin()->payload_type->atom);
296 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
297
298 CHECK(contains_key(Container_metadata, r.type));
299 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
300 CHECK_EQ(SIZE(address_offsets2), 1);
301 CHECK_EQ(address_offsets2.begin()->offset, 1);
302 CHECK(address_offsets2.begin()->payload_type->atom);
303 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
304 }
305
306 void test_container_address_offsets_nested() {
307 int old_size = SIZE(Container_metadata);
308
309 run("container foo [\n"
310 " x:address:num\n"
311 " y:num\n"
312 "]\n"
313 "container bar [\n"
314 " p:point\n"
315 " f:foo\n"
316 "]\n");
317 reagent r("x:bar");
318 compute_container_sizes(r, "");
319
320
321 CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
322
323 compute_container_address_offsets(r, "");
324
325 CHECK_EQ(SIZE(r.metadata.address), 1);
326 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
327 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
328 CHECK_EQ(SIZE(address_offsets), 1);
329 CHECK_EQ(address_offsets.begin()->offset, 2);
330 CHECK(address_offsets.begin()->payload_type->atom);
331 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
332
333 CHECK(contains_key(Container_metadata, r.type));
334 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
335 CHECK_EQ(SIZE(address_offsets2), 1);
336 CHECK_EQ(address_offsets2.begin()->offset, 2);
337 CHECK(address_offsets2.begin()->payload_type->atom);
338 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
339
340 CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
341 }
342
343 void test_container_address_offsets_from_address() {
344 int old_size = SIZE(Container_metadata);
345
346 run("container foo [\n"
347 " x:address:num\n"
348 "]\n");
349 reagent r("x:address:foo");
350 compute_container_sizes(r, "");
351
352
353 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
354
355 compute_container_address_offsets(r, "");
356
357 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
358
359 reagent container("x:foo");
360 CHECK(contains_key(Container_metadata, container.type));
361 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
362 CHECK_EQ(SIZE(address_offsets2), 1);
363 CHECK_EQ(address_offsets2.begin()->offset, 0);
364 CHECK(address_offsets2.begin()->payload_type->atom);
365 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
366 }
367
368 void test_container_address_offsets_from_array() {
369 int old_size = SIZE(Container_metadata);
370
371 run("container foo [\n"
372 " x:address:num\n"
373 "]\n");
374 reagent r("x:array:foo");
375 compute_container_sizes(r, "");
376
377
378 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
379
380 compute_container_address_offsets(r, "");
381
382 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
383
384 reagent container("x:foo");
385 CHECK(contains_key(Container_metadata, container.type));
386 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
387 CHECK_EQ(SIZE(address_offsets2), 1);
388 CHECK_EQ(address_offsets2.begin()->offset, 0);
389 CHECK(address_offsets2.begin()->payload_type->atom);
390 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
391 }
392
393 void test_container_address_offsets_from_address_to_array() {
394 int old_size = SIZE(Container_metadata);
395
396 run("container foo [\n"
397 " x:address:num\n"
398 "]\n");
399 reagent r("x:address:array:foo");
400 compute_container_sizes(r, "");
401
402
403 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
404
405 compute_container_address_offsets(r, "");
406
407 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
408
409 reagent container("x:foo");
410 CHECK(contains_key(Container_metadata, container.type));
411 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
412 CHECK_EQ(SIZE(address_offsets2), 1);
413 CHECK_EQ(address_offsets2.begin()->offset, 0);
414 CHECK(address_offsets2.begin()->payload_type->atom);
415 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
416 }
417
418 void test_container_address_offsets_from_static_array() {
419 int old_size = SIZE(Container_metadata);
420
421 run("container foo [\n"
422 " x:address:num\n"
423 "]\n");
424 reagent r("x:array:foo:10");
425 compute_container_sizes(r, "");
426
427
428 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
429
430 compute_container_address_offsets(r, "");
431
432 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
433
434 reagent container("x:foo");
435 CHECK(contains_key(Container_metadata, container.type));
436 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
437 CHECK_EQ(SIZE(address_offsets2), 1);
438 CHECK_EQ(address_offsets2.begin()->offset, 0);
439 CHECK(address_offsets2.begin()->payload_type->atom);
440 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
441 }
442
443 void test_container_address_offsets_from_address_to_static_array() {
444 int old_size = SIZE(Container_metadata);
445
446 run("container foo [\n"
447 " x:address:num\n"
448 "]\n");
449 reagent r("x:address:array:foo:10");
450 compute_container_sizes(r, "");
451
452
453 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
454
455 compute_container_address_offsets(r, "");
456
457 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
458
459 reagent container("x:foo");
460 CHECK(contains_key(Container_metadata, container.type));
461 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
462 CHECK_EQ(SIZE(address_offsets2), 1);
463 CHECK_EQ(address_offsets2.begin()->offset, 0);
464 CHECK(address_offsets2.begin()->payload_type->atom);
465 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
466 }
467
468 void test_container_address_offsets_from_repeated_address_and_array_types() {
469 int old_size = SIZE(Container_metadata);
470
471 run("container foo [\n"
472 " x:address:num\n"
473 "]\n");
474
475 reagent r("x:address:array:address:address:array:foo:10");
476 compute_container_sizes(r, "");
477
478
479 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
480 compute_container_address_offsets(r, "");
481
482 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
483
484 reagent container("x:foo");
485 CHECK(contains_key(Container_metadata, container.type));
486 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
487 CHECK_EQ(SIZE(address_offsets2), 1);
488 CHECK_EQ(address_offsets2.begin()->offset, 0);
489 CHECK(address_offsets2.begin()->payload_type->atom);
490 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
491 }
492
493 :(code)
494 bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) {
495 for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) {
496 if (data.at(p->offset) != p->tag)
497 return false;
498 }
499 return true;
500 }
501
502 bool is_mu_container(const reagent& r) {
503 return is_mu_container(r.type);
504 }
505 bool is_mu_container(const type_tree* type) {
506 if (!type) return false;
507
508 if (type->value == 0) return false;
509 if (!contains_key(Type, type->value)) return false;
510 type_info& info = get(Type, type->value);
511 return info.kind == CONTAINER;
512 }
513
514 bool is_mu_exclusive_container(const reagent& r) {
515 return is_mu_exclusive_container(r.type);
516 }
517 bool is_mu_exclusive_container(const type_tree* type) {
518 if (!type) return false;
519
520 if (type->value == 0) return false;
521 if (!contains_key(Type, type->value)) return false;
522 type_info& info = get(Type, type->value);
523 return info.kind == EXCLUSIVE_CONTAINER;
524 }