nitg-se: MProperty layout does not depend anymore on opt_typing used
[nit.git] / src / coloring.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Graph coloring tools
16 module coloring
17
18 import typing
19
20 # Layouts
21
22 class TypingLayout[E]
23 # Unic ids or each element
24 var ids: Map[E, Int] = new HashMap[E, Int]
25 # Fixed positions of each element in all tables
26 var pos: Map[E, Int] = new HashMap[E, Int]
27 end
28
29 class PHTypingLayout[E]
30 super TypingLayout[E]
31 # Masks used by hash function
32 var masks: Map[E, Int] = new HashMap[E, Int]
33 # Positions of each element for each tables
34 var hashes: Map[E, Map[E, Int]] = new HashMap[E, Map[E, Int]]
35 end
36
37 class PropertyLayout[E]
38 # Fixed positions of each element in all tables
39 var pos: Map[E, Int] = new HashMap[E, Int]
40 end
41
42 # Layout for resolution tables
43 class ResolutionLayout
44 # Unic ids for each resolved type
45 var ids: Map[MType, Int] = new HashMap[MType, Int]
46 # Fixed positions of resolved type
47 var pos: Map[MType, Int] = new HashMap[MType, Int]
48 end
49
50 class PHResolutionLayout
51 super ResolutionLayout
52 # Masks associated to each owner of a resolution table
53 var masks: Map[MClassType, Int] = new HashMap[MClassType, Int]
54 # Positions of each resolvec type for resolution tables
55 var hashes: Map[MClassType, Map[MType, Int]] = new HashMap[MClassType, Map[MType, Int]]
56 end
57
58 # Builders
59
60 abstract class TypingLayoutBuilder[E]
61
62 type LAYOUT: TypingLayout[E]
63
64 private var mmodule: MModule
65 init(mmodule: MModule) do self.mmodule = mmodule
66
67 # Compute elements ids and position
68 fun build_layout(elements: Set[E]): LAYOUT is abstract
69
70 # Give each MType a unic id using a descending linearization of the `mtypes` set
71 private fun compute_ids(elements: Set[E]): Map[E, Int] do
72 var ids = new HashMap[E, Int]
73 var lin = self.reverse_linearize(elements)
74 for element in lin do
75 ids[element] = ids.length
76 end
77 return ids
78 end
79
80 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
81 end
82
83 # Layout builder for MType using Binary Matrix (BM)
84 class BMTypeLayoutBuilder
85 super TypingLayoutBuilder[MType]
86
87 init(mmodule: MModule) do super
88
89 # Compute mtypes ids and position using BM
90 redef fun build_layout(mtypes) do
91 var result = new TypingLayout[MType]
92 result.ids = self.compute_ids(mtypes)
93 result.pos = result.ids
94 return result
95 end
96
97 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
98 end
99
100 # Layout builder for MType using Coloring (CL)
101 class CLTypeLayoutBuilder
102 super TypingLayoutBuilder[MType]
103
104 private var colorer: MTypeColorer
105
106 init(mmodule: MModule) do
107 super
108 self.colorer = new MTypeColorer(mmodule)
109 end
110
111 # Compute mtypes ids and position using BM
112 redef fun build_layout(mtypes) do
113 var result = new TypingLayout[MType]
114 result.ids = self.compute_ids(mtypes)
115 result.pos = self.colorer.colorize(mtypes)
116 return result
117 end
118
119 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
120 end
121
122 # Layout builder for MType using Perfect Hashing (PH)
123 class PHTypeLayoutBuilder
124 super TypingLayoutBuilder[MType]
125
126 redef type LAYOUT: PHTypingLayout[MType]
127
128 private var hasher: MTypeHasher
129
130 init(mmodule: MModule, operator: PHOperator) do
131 super
132 self.hasher = new MTypeHasher(mmodule, operator)
133 end
134
135 # Compute mtypes ids and position using BM
136 redef fun build_layout(mtypes) do
137 var result = new PHTypingLayout[MType]
138 result.ids = self.compute_ids(mtypes)
139 result.masks = self.hasher.compute_masks(mtypes, result.ids)
140 result.hashes = self.hasher.compute_hashes(mtypes, result.ids, result.masks)
141 return result
142 end
143
144 # Ids start from 1 instead of 0
145 redef fun compute_ids(mtypes) do
146 var ids = new HashMap[MType, Int]
147 var lin = self.mmodule.reverse_linearize_mtypes(mtypes)
148 for mtype in lin do
149 ids[mtype] = ids.length + 1
150 end
151 return ids
152 end
153
154 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
155 end
156
157 # Layout builder for MClass using Binary Matrix (BM)
158 class BMClassLayoutBuilder
159 super TypingLayoutBuilder[MClass]
160
161 init(mmodule: MModule) do super
162
163 # Compute mclasses ids and position using BM
164 redef fun build_layout(mclasses) do
165 var result = new TypingLayout[MClass]
166 result.ids = self.compute_ids(mclasses)
167 result.pos = result.ids
168 return result
169 end
170
171 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
172 end
173
174 # Layout builder for MClass using Coloring (CL)
175 class CLClassLayoutBuilder
176 super TypingLayoutBuilder[MClass]
177
178 private var colorer: MClassColorer
179
180 init(mmodule: MModule) do
181 super
182 self.colorer = new MClassColorer(mmodule)
183 end
184
185 # Compute mclasses ids and position using BM
186 redef fun build_layout(mclasses) do
187 var result = new TypingLayout[MClass]
188 result.ids = self.compute_ids(mclasses)
189 result.pos = self.colorer.colorize(mclasses)
190 return result
191 end
192
193 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
194 end
195
196 # Layout builder for MClass using Perfect Hashing (PH)
197 class PHClassLayoutBuilder
198 super TypingLayoutBuilder[MClass]
199
200 redef type LAYOUT: PHTypingLayout[MClass]
201
202 private var hasher: MClassHasher
203
204 init(mmodule: MModule, operator: PHOperator) do
205 super
206 self.hasher = new MClassHasher(mmodule, operator)
207 end
208
209 # Compute mclasses ids and position using BM
210 redef fun build_layout(mclasses) do
211 var result = new PHTypingLayout[MClass]
212 result.ids = self.compute_ids(mclasses)
213 result.masks = self.hasher.compute_masks(mclasses, result.ids)
214 result.hashes = self.hasher.compute_hashes(mclasses, result.ids, result.masks)
215 return result
216 end
217
218 # Ids start from 1 instead of 0
219 redef fun compute_ids(mclasses) do
220 var ids = new HashMap[MClass, Int]
221 var lin = self.mmodule.reverse_linearize_mclasses(mclasses)
222 for mclass in lin do
223 ids[mclass] = ids.length + 1
224 end
225 return ids
226 end
227
228 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
229 end
230
231 abstract class PropertyLayoutBuilder[E: MProperty]
232
233 type LAYOUT: PropertyLayout[E]
234
235 private var mmodule: MModule
236 init(mmodule: MModule) do self.mmodule = mmodule
237
238 # Compute properties ids and position
239 fun build_layout(mclasses: Set[MClass]): LAYOUT is abstract
240 end
241
242 # Layout builder for MProperty using Coloring (CL)
243 class CLPropertyLayoutBuilder[E: MProperty]
244 super PropertyLayoutBuilder[E]
245
246 private var colorer: MPropertyColorer[E]
247
248 init(mmodule: MModule) do
249 super
250 self.colorer = new MPropertyColorer[E](mmodule)
251 end
252
253 # Compute mclasses ids and position using BM
254 redef fun build_layout(mclasses) do
255 var result = new PropertyLayout[E]
256 result.pos = self.colorer.colorize(mclasses)
257 return result
258 end
259 end
260
261 # Layout builder for MProperty using Perfect Hashing (PH)
262 # TODO implement this class without sublcassing CL builder
263 class PHPropertyLayoutBuilder[E: MProperty]
264 super CLPropertyLayoutBuilder[E]
265 end
266
267 abstract class ResolutionLayoutBuilder
268
269 type LAYOUT: ResolutionLayout
270
271 init do end
272
273 fun build_layout(elements: Map[MClassType, Set[MType]]): LAYOUT is abstract
274
275 fun compute_ids(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
276 var ids = new HashMap[MType, Int]
277 var color = 0
278 for mclasstype, mclasstypes in elements do
279 for element in mclasstypes do
280 if ids.has_key(element) then continue
281 ids[element] = color
282 color += 1
283 end
284 end
285 return ids
286 end
287 end
288
289 # Layout builder for MClass using Binary Matrix (BM)
290 class BMResolutionLayoutBuilder
291 super ResolutionLayoutBuilder
292
293 init do super
294
295 # Compute resolved types position using BM
296 redef fun build_layout(elements) do
297 var result = new ResolutionLayout
298 result.ids = self.compute_ids(elements)
299 result.pos = result.ids
300 return result
301 end
302 end
303
304 # Layout builder for resolution tables using Coloring (CL)
305 class CLResolutionLayoutBuilder
306 super ResolutionLayoutBuilder
307
308 private var colorer: ResolutionColorer = new ResolutionColorer
309
310 init do super
311
312 # Compute resolved types colors
313 redef fun build_layout(elements) do
314 var result = new ResolutionLayout
315 result.ids = self.compute_ids(elements)
316 result.pos = self.colorer.colorize(elements)
317 return result
318 end
319 end
320
321 # Layout builder for resolution table using Perfect Hashing (PH)
322 class PHResolutionLayoutBuilder
323 super ResolutionLayoutBuilder
324
325 redef type LAYOUT: PHResolutionLayout
326
327 private var hasher: ResolutionHasher
328
329 init(operator: PHOperator) do self.hasher = new ResolutionHasher(operator)
330
331 # Compute resolved types masks and hashes
332 redef fun build_layout(elements) do
333 var result = new PHResolutionLayout
334 result.ids = self.compute_ids(elements)
335 result.pos = result.ids
336 result.masks = self.hasher.compute_masks(elements, result.ids)
337 result.hashes = self.hasher.compute_hashes(elements, result.ids, result.masks)
338 return result
339 end
340
341 redef fun compute_ids(elements) do
342 var ids = new HashMap[MType, Int]
343 var color = 1
344 for mclasstype, mclasstypes in elements do
345 for element in mclasstypes do
346 if ids.has_key(element) then continue
347 ids[element] = color
348 color += 1
349 end
350 end
351 return ids
352 end
353 end
354
355 # Colorers
356
357 abstract class AbstractColorer[E: Object]
358
359 private var core: Set[E] = new HashSet[E]
360 private var crown: Set[E] = new HashSet[E]
361 private var border: Set[E] = new HashSet[E]
362
363 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
364
365 init do end
366
367 fun colorize(elements: Set[E]): Map[E, Int] do
368 tag_elements(elements)
369 build_conflicts_graph(elements)
370 colorize_elements(core)
371 colorize_elements(border)
372 colorize_elements(crown)
373 return coloration_result
374 end
375
376 # Colorize a collection of elements
377 private fun colorize_elements(elements: Set[E]) do
378 var min_color = 0
379
380 var lin = reverse_linearize(elements)
381 for element in lin do
382 var color = min_color
383 while not self.is_color_free(element, elements, color) do
384 color += 1
385 end
386 coloration_result[element] = color
387 color = min_color
388 end
389 end
390
391 # Check if a related element to the element already use the color
392 private fun is_color_free(element: E, elements: Set[E], color: Int): Bool do
393 if conflicts_graph.has_key(element) then
394 for st in conflicts_graph[element] do
395 if coloration_result.has_key(st) and coloration_result[st] == color then return false
396 end
397 end
398 for st in self.super_elements(element, elements) do
399 if coloration_result.has_key(st) and coloration_result[st] == color then return false
400 end
401 return true
402 end
403
404 # Tag elements as core, crown or border
405 private fun tag_elements(elements: Set[E]) do
406 for element in elements do
407 # Check if sub elements are all in single inheritance
408 var all_subelements_si = true
409 for subelem in self.sub_elements(element, elements) do
410 if self.is_element_mi(subelem, elements) then
411 all_subelements_si = false
412 break
413 end
414 end
415
416 # Tag as core, crown or border
417 if self.is_element_mi(element, elements) then
418 core.add_all(self.super_elements(element, elements))
419 core.add(element)
420 if all_subelements_si then
421 border.add(element)
422 end
423 else if not all_subelements_si then
424 core.add_all(self.super_elements(element, elements))
425 core.add(element)
426 else
427 crown.add(element)
428 end
429 end
430 end
431
432 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
433 private fun build_conflicts_graph(elements: Set[E]) do
434 self.conflicts_graph = new HashMap[E, HashSet[E]]
435 var core = reverse_linearize(self.core)
436 for t in core do
437 for i in self.linear_extension(t, elements) do
438 if t == i then continue
439
440 var lin_i = self.linear_extension(i, elements)
441
442 for j in self.linear_extension(t, elements) do
443 if i == j or j == t then continue
444 var lin_j = self.linear_extension(j, elements)
445
446 var d_ij = lin_i - lin_j
447 var d_ji = lin_j - lin_i
448
449 for ed1 in d_ij do
450 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
451 # add ed1 x ed2 to conflicts graph
452 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
453 end
454 for ed1 in d_ij do
455 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
456 # add ed1 x ed2 to conflicts graph
457 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
458 end
459 end
460 end
461 end
462 end
463
464 private var conflicts_graph: nullable HashMap[E, Set[E]]
465
466 # cache for linear_extensions
467 private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
468
469 # Return a linear_extension of super_elements of the element
470 private fun linear_extension(element: E, elements: Set[E]): Array[E] do
471 if not self.linear_extensions_cache.has_key(element) then
472 var supers = new HashSet[E]
473 supers.add(element)
474 supers.add_all(self.super_elements(element, elements))
475 self.linear_extensions_cache[element] = self.linearize(supers)
476 end
477 return self.linear_extensions_cache[element]
478 end
479
480 private fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
481 private fun sub_elements(element: E, elements: Set[E]): Set[E] is abstract
482 private fun is_element_mi(element: E, elements: Set[E]): Bool is abstract
483 private fun linearize(elements: Set[E]): Array[E] is abstract
484 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
485 end
486
487 # MType coloring
488 private class MTypeColorer
489 super AbstractColorer[MType]
490
491 var mmodule: MModule
492
493 init(mmodule: MModule) do self.mmodule = mmodule
494
495 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
496 redef fun is_element_mi(element, elements) do return self.super_elements(element, elements).length > 1
497 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mtypes(element, elements)
498 redef fun linearize(elements) do return self.mmodule.linearize_mtypes(elements)
499 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
500 end
501
502 # MClass coloring
503 private class MClassColorer
504 super AbstractColorer[MClass]
505
506 private var mmodule: MModule
507
508 init(mmodule: MModule) do self.mmodule = mmodule
509
510 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
511 fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
512 redef fun is_element_mi(element, elements) do return self.parent_elements(element).length > 1
513 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mclasses(element)
514 redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
515 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
516 end
517
518 # MProperty coloring
519 private class MPropertyColorer[E: MProperty]
520
521 private var mmodule: MModule
522 private var class_colorer: MClassColorer
523 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
524
525 init(mmodule: MModule) do
526 self.mmodule = mmodule
527 self.class_colorer = new MClassColorer(mmodule)
528 end
529
530 fun colorize(mclasses: Set[MClass]): Map[E, Int] do
531 self.class_colorer.tag_elements(mclasses)
532 self.class_colorer.build_conflicts_graph(mclasses)
533 self.colorize_core(self.class_colorer.core)
534 self.colorize_crown(self.class_colorer.crown)
535 return self.coloration_result
536 end
537
538 # Colorize properties of the core hierarchy
539 private fun colorize_core(mclasses: Set[MClass]) do
540 var min_color = 0
541 for mclass in mclasses do
542 var color = min_color
543
544 # if the class is root, get the minimal color
545 if self.mmodule.parent_mclasses(mclass).length == 0 then
546 colorize_elements(self.properties(mclass), color)
547 else
548 # check last color used by parents
549 color = max_color(color, self.mmodule.parent_mclasses(mclass))
550 # check max color used in conflicts
551 if self.class_colorer.conflicts_graph.has_key(mclass) then
552 color = max_color(color, self.class_colorer.conflicts_graph[mclass])
553 end
554 colorize_elements(self.properties(mclass), color)
555 end
556 end
557 end
558
559 # Colorize properties of the crown hierarchy
560 private fun colorize_crown(mclasses: Set[MClass]) do
561 for mclass in mclasses do
562 colorize_elements(self.properties(mclass), max_color(0, self.mmodule.parent_mclasses(mclass)))
563 end
564 end
565
566 # Colorize a collection of mproperties given a starting color
567 private fun colorize_elements(elements: Collection[E], start_color: Int) do
568 for element in elements do
569 if self.coloration_result.has_key(element) then continue
570 self.coloration_result[element] = start_color
571 start_color += 1
572 end
573 end
574
575 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
576 var max_color = min_color
577
578 for mclass in mclasses do
579 for mproperty in self.properties(mclass) do
580 var color = min_color
581 if self.coloration_result.has_key(mproperty) then
582 color = self.coloration_result[mproperty]
583 if color >= max_color then max_color = color + 1
584 end
585 end
586 end
587 return max_color
588 end
589
590 # Filter properties
591 private fun properties(mclass: MClass): Set[E] do
592 var properties = new HashSet[E]
593 for mprop in self.mmodule.properties(mclass) do
594 if mprop isa E then properties.add(mprop)
595 end
596 return properties
597 end
598 end
599
600 # Colorer for type resolution table
601 class ResolutionColorer
602
603 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
604
605 init do end
606
607 fun colorize(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
608 self.build_conflicts_graph(elements)
609 self.colorize_elements(elements)
610 return coloration_result
611 end
612
613 # Colorize a collection of elements
614 fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
615 var min_color = 0
616 for mclasstype, mclasstypes in elements do
617 for element in mclasstypes do
618 if self.coloration_result.has_key(element) then continue
619 var color = min_color
620 while not self.is_color_free(element, color) do
621 color += 1
622 end
623 coloration_result[element] = color
624 color = min_color
625 end
626 end
627 end
628
629 # Check if a related element to the element already use the color
630 private fun is_color_free(element: MType, color: Int): Bool do
631 if conflicts_graph.has_key(element) then
632 for st in conflicts_graph[element] do
633 if coloration_result.has_key(st) and coloration_result[st] == color then return false
634 end
635 end
636 return true
637 end
638
639 # look for unanchored types generated by the same type
640 private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
641 for mclasstype, mtypes in elements do
642 for mtype in mtypes do
643 for otype in mtypes do
644 if otype == mtype then continue
645 self.add_conflict(mtype, otype)
646 end
647 end
648 end
649 end
650
651 private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
652
653 private fun add_conflict(mtype: MType, otype: MType) do
654 if mtype == otype then return
655 if not self.conflicts_graph.has_key(mtype) then self.conflicts_graph[mtype] = new HashSet[MType]
656 self.conflicts_graph[mtype].add(otype)
657 if not self.conflicts_graph.has_key(otype) then self.conflicts_graph[otype] = new HashSet[MType]
658 self.conflicts_graph[otype].add(mtype)
659 end
660 end
661
662 # Perfect hashers
663
664 # Abstract Perfect Hashing
665 private abstract class AbstractHasher[E: Object]
666
667 var operator: PHOperator
668
669 init(operator: PHOperator) do self.operator = operator
670
671 fun compute_masks(elements: Set[E], ids: Map[E, Int]): Map[E, Int] do
672 var masks = new HashMap[E, Int]
673 for element in elements do
674 var supers = new HashSet[E]
675 supers.add_all(self.super_elements(element, elements))
676 supers.add(element)
677 masks[element] = compute_mask(supers, ids)
678 end
679 return masks
680 end
681
682 fun compute_mask(supers: Set[E], ids: Map[E, Int]): Int do
683 var mask = 0
684 loop
685 var used = new List[Int]
686 for sup in supers do
687 var res = operator.op(mask, ids[sup])
688 if used.has(res) then
689 break
690 else
691 used.add(res)
692 end
693 end
694 if used.length == supers.length then break
695 mask += 1
696 end
697 return mask
698 end
699
700 fun compute_hashes(elements: Set[E], ids: Map[E, Int], masks: Map[E, Int]): Map[E, Map[E, Int]] do
701 var hashes = new HashMap[E, Map[E, Int]]
702 for element in elements do
703 var supers = new HashSet[E]
704 supers.add_all(self.super_elements(element, elements))
705 supers.add(element)
706 var inhashes = new HashMap[E, Int]
707 var mask = masks[element]
708 for sup in supers do
709 inhashes[sup] = operator.op(mask, ids[sup])
710 end
711 hashes[element] = inhashes
712 end
713 return hashes
714 end
715
716 fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
717 end
718
719 # Abstract operator used for perfect hashing
720 abstract class PHOperator
721 fun op(mask: Int, id:Int): Int is abstract
722 end
723
724 # Hashing using modulo (MOD) operator
725 # slower but compact
726 class PHModOperator
727 super PHOperator
728 init do end
729 redef fun op(mask, id) do return mask % id
730 end
731
732 # Hashing using binary and (AND) operator
733 # faster but sparse
734 class PHAndOperator
735 super PHOperator
736 init do end
737 redef fun op(mask, id) do return mask.bin_and(id)
738 end
739
740 # MType Perfect Hashing
741 private class MTypeHasher
742 super AbstractHasher[MType]
743
744 var mmodule: MModule
745
746 init(mmodule: MModule, operator: PHOperator) do
747 super(operator)
748 self.mmodule = mmodule
749 end
750
751 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
752 end
753
754 # MClass Perfect Hashing
755 private class MClassHasher
756 super AbstractHasher[MClass]
757
758 private var mmodule: MModule
759
760 init(mmodule: MModule, operator: PHOperator) do
761 super(operator)
762 self.mmodule = mmodule
763 end
764
765 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
766 end
767
768 # Resolution tables Perfect Hashing (PH)
769 private class ResolutionHasher
770
771 var operator: PHOperator
772
773 init(operator: PHOperator) do self.operator = operator
774
775 fun compute_masks(elements: Map[MClassType, Set[MType]], ids: Map[MType, Int]): Map[MClassType, Int] do
776 var masks = new HashMap[MClassType, Int]
777 for mclasstype, mtypes in elements do
778 masks[mclasstype] = compute_mask(mtypes, ids)
779 end
780 return masks
781 end
782
783 private fun compute_mask(mtypes: Set[MType], ids: Map[MType, Int]): Int do
784 var mask = 0
785 loop
786 var used = new List[Int]
787 for mtype in mtypes do
788 var res = operator.op(mask, ids[mtype])
789 if used.has(res) then
790 break
791 else
792 used.add(res)
793 end
794 end
795 if used.length == mtypes.length then break
796 mask += 1
797 end
798 return mask
799 end
800
801 fun compute_hashes(elements: Map[MClassType, Set[MType]], ids: Map[MType, Int], masks: Map[MClassType, Int]): Map[MClassType, Map[MType, Int]] do
802 var hashes = new HashMap[MClassType, Map[MType, Int]]
803 for mclasstype, mtypes in elements do
804 var mask = masks[mclasstype]
805 var inhashes = new HashMap[MType, Int]
806 for mtype in mtypes do
807 inhashes[mtype] = operator.op(mask, ids[mtype])
808 end
809 hashes[mclasstype] = inhashes
810 end
811 return hashes
812 end
813 end
814
815 # Utils
816
817 redef class HashSet[E]
818 init from(elements: Collection[E]) do
819 init
820 self.add_all(elements)
821 end
822 end
823
824 redef class Array[E]
825 init from(elements: Collection[E]) do
826 init
827 self.add_all(elements)
828 end
829
830 # Return a new Array with the elements only contened in 'self' and not in 'o'
831 fun -(o: Array[E]): Array[E] do
832 var res = new Array[E]
833 for e in self do if not o.has(e) then res.add(e)
834 return res
835 end
836 end
837
838 redef class MModule
839
840 # Return a linearization of a set of mtypes
841 private fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do
842 var lin = new Array[MType].from(mtypes)
843 var sorter = new TypeSorter(self)
844 sorter.sort(lin)
845 return lin
846 end
847
848 # Return a reverse linearization of a set of mtypes
849 private fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do
850 var lin = new Array[MType].from(mtypes)
851 var sorter = new ReverseTypeSorter(self)
852 sorter.sort(lin)
853 return lin
854 end
855
856 # Return super types of a `mtype` in `self`
857 private fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
858 if not self.super_mtypes_cache.has_key(mtype) then
859 var supers = new HashSet[MType]
860 for otype in mtypes do
861 if otype == mtype then continue
862 if mtype.is_subtype(self, null, otype) then
863 supers.add(otype)
864 end
865 end
866 self.super_mtypes_cache[mtype] = supers
867 end
868 return self.super_mtypes_cache[mtype]
869 end
870
871 private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
872
873 # Return all sub mtypes (directs and indirects) of a `mtype` in `self`
874 private fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
875 if not self.sub_mtypes_cache.has_key(mtype) then
876 var subs = new HashSet[MType]
877 for otype in mtypes do
878 if otype == mtype then continue
879 if otype.is_subtype(self, null, mtype) then
880 subs.add(otype)
881 end
882 end
883 self.sub_mtypes_cache[mtype] = subs
884 end
885 return self.sub_mtypes_cache[mtype]
886 end
887
888 private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
889
890 # Return a linearization of a set of mclasses
891 private fun linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
892 var lin = new Array[MClass].from(mclasses)
893 var sorter = new ClassSorter(self)
894 sorter.sort(lin)
895 return lin
896 end
897
898 # Return a reverse linearization of a set of mtypes
899 private fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
900 var lin = new Array[MClass].from(mclasses)
901 var sorter = new ReverseClassSorter(self)
902 sorter.sort(lin)
903 return lin
904 end
905
906 # Return all super mclasses (directs and indirects) of a `mclass` in `self`
907 private fun super_mclasses(mclass: MClass): Set[MClass] do
908 if not self.super_mclasses_cache.has_key(mclass) then
909 var supers = new HashSet[MClass]
910 if self.flatten_mclass_hierarchy.has(mclass) then
911 for sup in self.flatten_mclass_hierarchy[mclass].greaters do
912 if sup == mclass then continue
913 supers.add(sup)
914 end
915 end
916 self.super_mclasses_cache[mclass] = supers
917 end
918 return self.super_mclasses_cache[mclass]
919 end
920
921 private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
922
923 # Return all parents of a `mclass` in `self`
924 private fun parent_mclasses(mclass: MClass): Set[MClass] do
925 if not self.parent_mclasses_cache.has_key(mclass) then
926 var parents = new HashSet[MClass]
927 if self.flatten_mclass_hierarchy.has(mclass) then
928 for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do
929 if sup == mclass then continue
930 parents.add(sup)
931 end
932 end
933 self.parent_mclasses_cache[mclass] = parents
934 end
935 return self.parent_mclasses_cache[mclass]
936 end
937
938 private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
939
940 # Return all sub mclasses (directs and indirects) of a `mclass` in `self`
941 private fun sub_mclasses(mclass: MClass): Set[MClass] do
942 if not self.sub_mclasses_cache.has_key(mclass) then
943 var subs = new HashSet[MClass]
944 if self.flatten_mclass_hierarchy.has(mclass) then
945 for sub in self.flatten_mclass_hierarchy[mclass].smallers do
946 if sub == mclass then continue
947 subs.add(sub)
948 end
949 end
950 self.sub_mclasses_cache[mclass] = subs
951 end
952 return self.sub_mclasses_cache[mclass]
953 end
954
955 private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
956
957 # All 'mproperties' associated to all 'mclassdefs' of `mclass`
958 private fun properties(mclass: MClass): Set[MProperty] do
959 if not self.properties_cache.has_key(mclass) then
960 var properties = new HashSet[MProperty]
961 var parents = self.super_mclasses(mclass)
962 for parent in parents do
963 properties.add_all(self.properties(parent))
964 end
965
966 for mclassdef in mclass.mclassdefs do
967 for mpropdef in mclassdef.mpropdefs do
968 properties.add(mpropdef.mproperty)
969 end
970 end
971 self.properties_cache[mclass] = properties
972 end
973 return properties_cache[mclass]
974 end
975
976 private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
977 end
978
979 # A sorter for linearize list of types
980 class TypeSorter
981 super AbstractSorter[MType]
982
983 private var mmodule: MModule
984
985 init(mmodule: MModule) do self.mmodule = mmodule
986
987 redef fun compare(a, b) do
988 if a == b then
989 return 0
990 else if a.is_subtype(self.mmodule, null, b) then
991 return -1
992 end
993 return 1
994 end
995 end
996
997 # A sorter for reverse linearization
998 class ReverseTypeSorter
999 super TypeSorter
1000
1001 init(mmodule: MModule) do end
1002
1003 redef fun compare(a, b) do
1004 if a == b then
1005 return 0
1006 else if a.is_subtype(self.mmodule, null, b) then
1007 return 1
1008 end
1009 return -1
1010 end
1011 end
1012
1013 # A sorter for linearize list of classes
1014 private class ClassSorter
1015 super AbstractSorter[MClass]
1016
1017 var mmodule: MModule
1018
1019 redef fun compare(a, b) do
1020 if a == b then
1021 return 0
1022 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1023 return -1
1024 end
1025 return 1
1026 end
1027 end
1028
1029 # A sorter for reverse linearization
1030 private class ReverseClassSorter
1031 super AbstractSorter[MClass]
1032
1033 var mmodule: MModule
1034
1035 redef fun compare(a, b) do
1036 if a == b then
1037 return 0
1038 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1039 return 1
1040 end
1041 return -1
1042 end
1043 end