nitg-s: introduced class table layouts
[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 TypeLayout
23 # Unic ids or each Mtype
24 var ids: Map[MType, Int] = new HashMap[MType, Int]
25 # Fixed positions of each MType in all tables
26 var pos: Map[MType, Int] = new HashMap[MType, Int]
27 end
28
29 class PHTypeLayout
30 super TypeLayout
31 # Masks used by hash function
32 var masks: Map[MType, Int] = new HashMap[MType, Int]
33 # Positions of each MType for each tables
34 var hashes: Map[MType, Map[MType, Int]] = new HashMap[MType, Map[MType, Int]]
35 end
36
37 class ClassLayout
38 # Unic ids or each MClass
39 var ids: Map[MClass, Int] = new HashMap[MClass, Int]
40 # Fixed positions of each MClass in all tables
41 var pos: Map[MClass, Int] = new HashMap[MClass, Int]
42 end
43
44 class PHClassLayout
45 super ClassLayout
46 # Masks used by hash function
47 var masks: Map[MClass, Int] = new HashMap[MClass, Int]
48 # Positions of each MClass for each tables
49 var hashes: Map[MClass, Map[MClass, Int]] = new HashMap[MClass, Map[MClass, Int]]
50 end
51
52 # Builders
53
54 abstract class TypeLayoutBuilder
55
56 type LAYOUT: TypeLayout
57
58 private var mmodule: MModule
59 init(mmodule: MModule) do self.mmodule = mmodule
60
61 # Compute mtypes ids and position
62 fun build_layout(mtypes: Set[MType]): LAYOUT is abstract
63
64 # Give each MType a unic id using a descending linearization of the `mtypes` set
65 private fun compute_ids(mtypes: Set[MType]): Map[MType, Int] do
66 var ids = new HashMap[MType, Int]
67 var lin = self.mmodule.reverse_linearize_mtypes(mtypes)
68 for mtype in lin do
69 ids[mtype] = ids.length
70 end
71 return ids
72 end
73 end
74
75 # Layout builder for MType using Binary Matrix (BM)
76 class BMTypeLayoutBuilder
77 super TypeLayoutBuilder
78
79 init(mmodule: MModule) do super
80
81 # Compute mtypes ids and position using BM
82 redef fun build_layout(mtypes: Set[MType]): TypeLayout do
83 var result = new TypeLayout
84 result.ids = self.compute_ids(mtypes)
85 result.pos = result.ids
86 return result
87 end
88 end
89
90 # Layout builder for MType using Coloring (CL)
91 class CLTypeLayoutBuilder
92 super TypeLayoutBuilder
93
94 private var colorer: MTypeColorer
95
96 init(mmodule: MModule) do
97 super
98 self.colorer = new MTypeColorer(mmodule)
99 end
100
101 # Compute mtypes ids and position using BM
102 redef fun build_layout(mtypes) do
103 var result = new TypeLayout
104 result.ids = self.compute_ids(mtypes)
105 result.pos = self.colorer.colorize(mtypes)
106 return result
107 end
108 end
109
110 # Layout builder for MType using Perfect Hashing (PH)
111 class PHTypeLayoutBuilder
112 super TypeLayoutBuilder
113
114 redef type LAYOUT: PHTypeLayout
115
116 private var hasher: MTypeHasher
117
118 init(mmodule: MModule, operator: PHOperator) do
119 super
120 self.hasher = new MTypeHasher(mmodule, operator)
121 end
122
123 # Compute mtypes ids and position using BM
124 redef fun build_layout(mtypes) do
125 var result = new PHTypeLayout
126 result.ids = self.compute_ids(mtypes)
127 result.masks = self.hasher.compute_masks(mtypes, result.ids)
128 result.hashes = self.hasher.compute_hashes(mtypes, result.ids, result.masks)
129 return result
130 end
131
132 # Ids start from 1 instead of 0
133 redef fun compute_ids(mtypes) do
134 var ids = new HashMap[MType, Int]
135 var lin = self.mmodule.reverse_linearize_mtypes(mtypes)
136 for mtype in lin do
137 ids[mtype] = ids.length + 1
138 end
139 return ids
140 end
141 end
142
143 abstract class ClassLayoutBuilder
144
145 type LAYOUT: ClassLayout
146
147 private var mmodule: MModule
148 init(mmodule: MModule) do self.mmodule = mmodule
149
150 # Compute mclasses ids and position
151 fun build_layout(mclasses: Set[MClass]): LAYOUT is abstract
152
153 # Give each MClass a unic id using a descending linearization of the `mclasses` set
154 private fun compute_ids(mclasses: Set[MClass]): Map[MClass, Int] do
155 var ids = new HashMap[MClass, Int]
156 var lin = self.mmodule.reverse_linearize_mclasses(mclasses)
157 for mclass in lin do
158 ids[mclass] = ids.length
159 end
160 return ids
161 end
162 end
163
164 # Layout builder for MClass using Binary Matrix (BM)
165 class BMClassLayoutBuilder
166 super ClassLayoutBuilder
167
168 init(mmodule: MModule) do super
169
170 # Compute mclasses ids and position using BM
171 redef fun build_layout(mclasses: Set[MClass]): LAYOUT do
172 var result = new ClassLayout
173 result.ids = self.compute_ids(mclasses)
174 result.pos = result.ids
175 return result
176 end
177 end
178
179 # Layout builder for MClass using Coloring (CL)
180 class CLClassLayoutBuilder
181 super ClassLayoutBuilder
182
183 private var colorer: MClassColorer
184
185 init(mmodule: MModule) do
186 super
187 self.colorer = new MClassColorer(mmodule)
188 end
189
190 # Compute mclasses ids and position using BM
191 redef fun build_layout(mclasses) do
192 var result = new ClassLayout
193 result.ids = self.compute_ids(mclasses)
194 result.pos = self.colorer.colorize(mclasses)
195 return result
196 end
197 end
198
199 # Layout builder for MClass using Perfect Hashing (PH)
200 class PHClassLayoutBuilder
201 super ClassLayoutBuilder
202
203 redef type LAYOUT: PHClassLayout
204
205 private var hasher: MClassHasher
206
207 init(mmodule: MModule, operator: PHOperator) do
208 super
209 self.hasher = new MClassHasher(mmodule, operator)
210 end
211
212 # Compute mclasses ids and position using BM
213 redef fun build_layout(mclasses) do
214 var result = new PHClassLayout
215 result.ids = self.compute_ids(mclasses)
216 result.masks = self.hasher.compute_masks(mclasses, result.ids)
217 result.hashes = self.hasher.compute_hashes(mclasses, result.ids, result.masks)
218 return result
219 end
220
221 # Ids start from 1 instead of 0
222 redef fun compute_ids(mclasses) do
223 var ids = new HashMap[MClass, Int]
224 var lin = self.mmodule.reverse_linearize_mclasses(mclasses)
225 for mclass in lin do
226 ids[mclass] = ids.length + 1
227 end
228 return ids
229 end
230 end
231
232 # Colorers
233
234 abstract class AbstractColorer[E: Object]
235
236 private var core: Set[E] = new HashSet[E]
237 private var crown: Set[E] = new HashSet[E]
238 private var border: Set[E] = new HashSet[E]
239
240 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
241
242 init do end
243
244 fun colorize(elements: Set[E]): Map[E, Int] do
245 tag_elements(elements)
246 build_conflicts_graph(elements)
247 colorize_elements(core)
248 colorize_elements(border)
249 colorize_elements(crown)
250 return coloration_result
251 end
252
253 # Colorize a collection of elements
254 private fun colorize_elements(elements: Set[E]) do
255 var min_color = 0
256
257 var lin = reverse_linearize(elements)
258 for element in lin do
259 var color = min_color
260 while not self.is_color_free(element, elements, color) do
261 color += 1
262 end
263 coloration_result[element] = color
264 color = min_color
265 end
266 end
267
268 # Check if a related element to the element already use the color
269 private fun is_color_free(element: E, elements: Set[E], color: Int): Bool do
270 if conflicts_graph.has_key(element) then
271 for st in conflicts_graph[element] do
272 if coloration_result.has_key(st) and coloration_result[st] == color then return false
273 end
274 end
275 for st in self.super_elements(element, elements) do
276 if coloration_result.has_key(st) and coloration_result[st] == color then return false
277 end
278 return true
279 end
280
281 # Tag elements as core, crown or border
282 private fun tag_elements(elements: Set[E]) do
283 for element in elements do
284 # Check if sub elements are all in single inheritance
285 var all_subelements_si = true
286 for subelem in self.sub_elements(element, elements) do
287 if self.is_element_mi(subelem, elements) then
288 all_subelements_si = false
289 break
290 end
291 end
292
293 # Tag as core, crown or border
294 if self.is_element_mi(element, elements) then
295 core.add_all(self.super_elements(element, elements))
296 core.add(element)
297 if all_subelements_si then
298 border.add(element)
299 end
300 else if not all_subelements_si then
301 core.add_all(self.super_elements(element, elements))
302 core.add(element)
303 else
304 crown.add(element)
305 end
306 end
307 end
308
309 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
310 private fun build_conflicts_graph(elements: Set[E]) do
311 self.conflicts_graph = new HashMap[E, HashSet[E]]
312 var core = reverse_linearize(self.core)
313 for t in core do
314 for i in self.linear_extension(t, elements) do
315 if t == i then continue
316
317 var lin_i = self.linear_extension(i, elements)
318
319 for j in self.linear_extension(t, elements) do
320 if i == j or j == t then continue
321 var lin_j = self.linear_extension(j, elements)
322
323 var d_ij = lin_i - lin_j
324 var d_ji = lin_j - lin_i
325
326 for ed1 in d_ij do
327 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
328 # add ed1 x ed2 to conflicts graph
329 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
330 end
331 for ed1 in d_ij do
332 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
333 # add ed1 x ed2 to conflicts graph
334 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
335 end
336 end
337 end
338 end
339 end
340
341 private var conflicts_graph: nullable HashMap[E, Set[E]]
342
343 # cache for linear_extensions
344 private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
345
346 # Return a linear_extension of super_elements of the element
347 private fun linear_extension(element: E, elements: Set[E]): Array[E] do
348 if not self.linear_extensions_cache.has_key(element) then
349 var supers = new HashSet[E]
350 supers.add(element)
351 supers.add_all(self.super_elements(element, elements))
352 self.linear_extensions_cache[element] = self.linearize(supers)
353 end
354 return self.linear_extensions_cache[element]
355 end
356
357 private fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
358 private fun sub_elements(element: E, elements: Set[E]): Set[E] is abstract
359 private fun is_element_mi(element: E, elements: Set[E]): Bool is abstract
360 private fun linearize(elements: Set[E]): Array[E] is abstract
361 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
362 end
363
364 # MType coloring
365 private class MTypeColorer
366 super AbstractColorer[MType]
367
368 var mmodule: MModule
369
370 init(mmodule: MModule) do self.mmodule = mmodule
371
372 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
373 redef fun is_element_mi(element, elements) do return self.super_elements(element, elements).length > 1
374 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mtypes(element, elements)
375 redef fun linearize(elements) do return self.mmodule.linearize_mtypes(elements)
376 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
377 end
378
379 # MClass coloring
380 private class MClassColorer
381 super AbstractColorer[MClass]
382
383 private var mmodule: MModule
384
385 init(mmodule: MModule) do self.mmodule = mmodule
386
387 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
388 fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
389 redef fun is_element_mi(element, elements) do return self.parent_elements(element).length > 1
390 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mclasses(element)
391 redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
392 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
393 end
394
395 # Perfect hashers
396
397 # Abstract Perfect Hashing
398 private abstract class AbstractHasher[E: Object]
399
400 var operator: PHOperator
401
402 init(operator: PHOperator) do self.operator = operator
403
404 fun compute_masks(elements: Set[E], ids: Map[E, Int]): Map[E, Int] do
405 var masks = new HashMap[E, Int]
406 for element in elements do
407 var supers = new HashSet[E]
408 supers.add_all(self.super_elements(element, elements))
409 supers.add(element)
410 masks[element] = compute_mask(supers, ids)
411 end
412 return masks
413 end
414
415 fun compute_mask(supers: Set[E], ids: Map[E, Int]): Int do
416 var mask = 0
417 loop
418 var used = new List[Int]
419 for sup in supers do
420 var res = operator.op(mask, ids[sup])
421 if used.has(res) then
422 break
423 else
424 used.add(res)
425 end
426 end
427 if used.length == supers.length then break
428 mask += 1
429 end
430 return mask
431 end
432
433 fun compute_hashes(elements: Set[E], ids: Map[E, Int], masks: Map[E, Int]): Map[E, Map[E, Int]] do
434 var hashes = new HashMap[E, Map[E, Int]]
435 for element in elements do
436 var supers = new HashSet[E]
437 supers.add_all(self.super_elements(element, elements))
438 supers.add(element)
439 var inhashes = new HashMap[E, Int]
440 var mask = masks[element]
441 for sup in supers do
442 inhashes[sup] = operator.op(mask, ids[sup])
443 end
444 hashes[element] = inhashes
445 end
446 return hashes
447 end
448
449 fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
450 end
451
452 # Abstract operator used for perfect hashing
453 abstract class PHOperator
454 fun op(mask: Int, id:Int): Int is abstract
455 end
456
457 # Hashing using modulo (MOD) operator
458 # slower but compact
459 class PHModOperator
460 super PHOperator
461 init do end
462 redef fun op(mask, id) do return mask % id
463 end
464
465 # Hashing using binary and (AND) operator
466 # faster but sparse
467 class PHAndOperator
468 super PHOperator
469 init do end
470 redef fun op(mask, id) do return mask.bin_and(id)
471 end
472
473 # MType Perfect Hashing
474 private class MTypeHasher
475 super AbstractHasher[MType]
476
477 var mmodule: MModule
478
479 init(mmodule: MModule, operator: PHOperator) do
480 super(operator)
481 self.mmodule = mmodule
482 end
483
484 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
485 end
486
487 # MClass Perfect Hashing
488 private class MClassHasher
489 super AbstractHasher[MClass]
490
491 private var mmodule: MModule
492
493 init(mmodule: MModule, operator: PHOperator) do
494 super(operator)
495 self.mmodule = mmodule
496 end
497
498 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
499 end
500
501 # MClass coloring
502 class ClassColoring
503 super AbstractColorer[MClass]
504
505 type T: MClass
506
507 private var mmodule: MModule
508
509 # caches
510 private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
511 private var parent_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
512 private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
513
514 init(mainmodule: MModule) do self.mmodule = mainmodule
515
516 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
517 fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
518 redef fun is_element_mi(element, elements) do return self.parent_elements(element).length > 1
519 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mclasses(element)
520 redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
521 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
522 end
523
524 # incremental coloring (very naive)
525 class NaiveClassColoring
526 super ClassColoring
527
528 init(mainmodule: MModule) do
529 super(mainmodule)
530 end
531
532 # naive coloring that use incremental coloring
533 redef fun colorize_elements(elements) do
534 for e in elements do
535 self.coloration_result[e] = self.coloration_result.length
536 end
537 end
538 end
539
540 abstract class ClassPerfectHashing
541 super ClassColoring
542
543 init(mainmodule: MModule) do
544 super(mainmodule)
545 end
546
547 fun compute_masks(elements: Set[T], ids: Map[T, Int]): Map[T, Int] do
548 for e in elements do
549 # Create super type list
550 var supers = new HashSet[T]
551 supers.add_all(self.super_elements(e, elements))
552 supers.add(e)
553 # Compute the hashing 'mask'
554 self.coloration_result[e] = compute_mask(supers, ids)
555 end
556 return self.coloration_result
557 end
558
559 private fun compute_mask(mtypes: Set[T], ids: Map[T, Int]): Int do
560 var mask = 0
561 loop
562 var used = new List[Int]
563 for sup in mtypes do
564 var res = op(mask, ids[sup])
565 if used.has(res) then
566 break
567 else
568 used.add(res)
569 end
570 end
571 if used.length == mtypes.length then break
572 mask += 1
573 end
574 return mask
575 end
576
577 private fun op(mask: Int, id:Int): Int is abstract
578 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
579 end
580
581 class ClassModPerfectHashing
582 super ClassPerfectHashing
583 init(mainmodule: MModule) do
584 super(mainmodule)
585 end
586 redef fun op(mask, id) do return mask % id
587 end
588
589 class ClassAndPerfectHashing
590 super ClassPerfectHashing
591 init(mainmodule: MModule) do
592 super(mainmodule)
593 end
594 redef fun op(mask, id) do return mask.bin_and(id)
595 end
596
597 # MProperty coloring
598 class PropertyColoring
599
600 type MPROP: MProperty
601 type MPROPDEF: MPropDef
602
603 private var class_coloring: ClassColoring
604 private var coloration_result: Map[MPROP, Int] = new HashMap[MPROP, Int]
605
606 init(class_coloring: ClassColoring) do
607 self.class_coloring = class_coloring
608 end
609
610 fun colorize: Map[MPROP, Int] do
611 colorize_core_properties
612 colorize_crown_properties
613 return self.coloration_result
614 end
615
616 fun build_property_tables: Map[MClass, Array[nullable MPROPDEF]] do
617 var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
618 var mclasses = self.class_coloring.coloration_result.keys
619 for mclass in mclasses do
620 var table = new Array[nullable MPROPDEF]
621 # first, fill table from parents by reverse linearization order
622 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
623 var lin = self.class_coloring.reverse_linearize(parents)
624 for parent in lin do
625 for mproperty in self.properties(parent) do
626 var color = self.coloration_result[mproperty]
627 if table.length <= color then
628 for i in [table.length .. color[ do
629 table[i] = null
630 end
631 end
632 for mpropdef in mproperty.mpropdefs do
633 if mpropdef.mclassdef.mclass == parent then
634 table[color] = mpropdef
635 end
636 end
637 end
638 end
639
640 # then override with local properties
641 for mproperty in self.properties(mclass) do
642 var color = self.coloration_result[mproperty]
643 if table.length <= color then
644 for i in [table.length .. color[ do
645 table[i] = null
646 end
647 end
648 for mpropdef in mproperty.mpropdefs do
649 if mpropdef.mclassdef.mclass == mclass then
650 table[color] = mpropdef
651 end
652 end
653 end
654 tables[mclass] = table
655 end
656 return tables
657 end
658
659 # Colorize properties of the core hierarchy
660 private fun colorize_core_properties do
661 var mclasses = self.class_coloring.core
662 var min_color = 0
663
664 for mclass in mclasses do
665 var color = min_color
666
667 # if the class is root, get the minimal color
668 if self.class_coloring.parent_elements(mclass).length == 0 then
669 colorize_elements(self.properties(mclass), color)
670 else
671 # check last color used by parents
672 color = max_color(color, self.class_coloring.parent_elements(mclass))
673 # check max color used in conflicts
674 if self.class_coloring.conflicts_graph.has_key(mclass) then
675 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
676 end
677
678 # colorize
679 colorize_elements(self.properties(mclass), color)
680 end
681 end
682 end
683
684 # Colorize properties of the crown hierarchy
685 private fun colorize_crown_properties do
686 for mclass in self.class_coloring.crown do
687 colorize_elements(self.properties(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
688 end
689 end
690
691 # Colorize a collection of properties given a starting color
692 private fun colorize_elements(elements: Collection[MPROP], start_color: Int) do
693 for element in elements do
694 if self.coloration_result.has_key(element) then continue
695 self.coloration_result[element] = start_color
696 start_color += 1
697 end
698 end
699
700 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
701 var max_color = min_color
702
703 for mclass in mclasses do
704 for mproperty in self.properties(mclass) do
705 var color = min_color
706 if self.coloration_result.has_key(mproperty) then
707 color = self.coloration_result[mproperty]
708 if color >= max_color then max_color = color + 1
709 end
710 end
711 end
712 return max_color
713 end
714
715 # properties cache
716 private var properties_cache: Map[MClass, Set[MPROP]] = new HashMap[MClass, Set[MPROP]]
717
718 # All 'mproperties' associated to all 'mclassdefs' of the class
719 private fun properties(mclass: MClass): Set[MPROP] do
720 if not self.properties_cache.has_key(mclass) then
721 var properties = new HashSet[MPROP]
722 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
723 for parent in parents do
724 properties.add_all(self.properties(parent))
725 end
726
727 for mclassdef in mclass.mclassdefs do
728 for mpropdef in mclassdef.mpropdefs do
729 var mproperty = mpropdef.mproperty
730 if mproperty isa MPROP then
731 properties.add(mproperty)
732 end
733 end
734 end
735 self.properties_cache[mclass] = properties
736 end
737 return properties_cache[mclass]
738 end
739 end
740
741 # MMethod coloring
742 class MethodColoring
743 super PropertyColoring
744
745 redef type MPROP: MMethod
746 redef type MPROPDEF: MMethodDef
747 init(class_coloring: ClassColoring) do end
748 end
749
750 # MAttribute coloring
751 class AttributeColoring
752 super PropertyColoring
753
754 redef type MPROP: MAttribute
755 redef type MPROPDEF: MAttributeDef
756 init(class_coloring: ClassColoring) do end
757 end
758
759 # MVirtualTypeProp coloring
760 class VTColoring
761 super PropertyColoring
762
763 redef type MPROP: MVirtualTypeProp
764 redef type MPROPDEF: MVirtualTypeDef
765 init(class_coloring: ClassColoring) do end
766 end
767
768 class NaiveVTColoring
769 super VTColoring
770
771 init(class_coloring: ClassColoring) do end
772
773 redef fun colorize: Map[MPROP, Int] do
774 var mclasses = new HashSet[MClass]
775 mclasses.add_all(self.class_coloring.core)
776 mclasses.add_all(self.class_coloring.crown)
777 var min_color = 0
778
779 for mclass in mclasses do
780 min_color = max_color(min_color, mclasses)
781 colorize_elements(self.properties(mclass), min_color)
782 end
783 return self.coloration_result
784 end
785 end
786
787 abstract class VTPerfectHashing
788 super VTColoring
789
790 private var masks: Map[MClass, Int] = new HashMap[MClass, Int]
791
792 init(class_coloring: ClassColoring) do end
793
794 redef fun colorize: Map[MPROP, Int] do
795 var mclasses = new HashSet[MClass]
796 mclasses.add_all(self.class_coloring.core)
797 mclasses.add_all(self.class_coloring.crown)
798 for mclass in mclasses do
799 var vts = self.properties(mclass)
800 for vt in vts do
801 if coloration_result.has_key(vt) then continue
802 coloration_result[vt] = coloration_result.length + 1
803 end
804 end
805 return self.coloration_result
806 end
807
808 fun compute_masks: Map[MClass, Int] do
809 var mclasses = new HashSet[MClass]
810 mclasses.add_all(self.class_coloring.core)
811 mclasses.add_all(self.class_coloring.crown)
812 for mclass in mclasses do
813 self.masks[mclass] = compute_mask(self.properties(mclass))
814 end
815 return self.masks
816 end
817
818 private fun compute_mask(vts: Set[MPROP]): Int do
819 var mask = 0
820 loop
821 var used = new List[Int]
822 for vt in vts do
823 var res = op(mask, self.coloration_result[vt])
824 if used.has(res) then
825 break
826 else
827 used.add(res)
828 end
829 end
830 if used.length == vts.length then break
831 mask += 1
832 end
833 return mask
834 end
835
836 redef fun build_property_tables do
837 var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
838
839 for mclass in self.class_coloring.coloration_result.keys do
840 var table = new Array[nullable MPROPDEF]
841 # first, fill table from parents by reverse linearization order
842 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
843 var lin = self.class_coloring.reverse_linearize(parents)
844 for parent in lin do
845 for mproperty in self.properties(parent) do
846 var color = phash(self.coloration_result[mproperty], masks[mclass])
847 if table.length <= color then
848 for i in [table.length .. color[ do
849 table[i] = null
850 end
851 end
852 for mpropdef in mproperty.mpropdefs do
853 if mpropdef.mclassdef.mclass == parent then
854 table[color] = mpropdef
855 end
856 end
857 end
858 end
859
860 # then override with local properties
861 for mproperty in self.properties(mclass) do
862 var color = phash(self.coloration_result[mproperty], masks[mclass])
863 if table.length <= color then
864 for i in [table.length .. color[ do
865 table[i] = null
866 end
867 end
868 for mpropdef in mproperty.mpropdefs do
869 if mpropdef.mclassdef.mclass == mclass then
870 table[color] = mpropdef
871 end
872 end
873 end
874 tables[mclass] = table
875 end
876 return tables
877 end
878
879 private fun op(mask: Int, id:Int): Int is abstract
880 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
881
882 end
883
884 class VTModPerfectHashing
885 super VTPerfectHashing
886 init(class_coloring: ClassColoring) do end
887 redef fun op(mask, id) do return mask % id
888 end
889
890 class VTAndPerfectHashing
891 super VTPerfectHashing
892 init(class_coloring: ClassColoring) do end
893 redef fun op(mask, id) do return mask.bin_and(id)
894 end
895
896 # MParameterType coloring
897 class FTColoring
898 private var class_coloring: ClassColoring
899 private var coloration_result: Map[MParameterType, Int] = new HashMap[MParameterType, Int]
900
901 init(class_coloring: ClassColoring) do
902 self.class_coloring = class_coloring
903 end
904
905 fun colorize: Map[MParameterType, Int] do
906 colorize_core_properties
907 colorize_crown_properties
908 return self.coloration_result
909 end
910
911 # Colorize properties of the core hierarchy
912 private fun colorize_core_properties do
913 var mclasses = self.class_coloring.core
914 var min_color = 0
915
916 for mclass in mclasses do
917 var color = min_color
918
919 # if the class is root, get the minimal color
920 if self.class_coloring.parent_elements(mclass).length == 0 then
921 colorize_elements(self.fts(mclass), color)
922 else
923 # check last color used by parents
924 color = max_color(color, self.class_coloring.parent_elements(mclass))
925 # check max color used in conflicts
926 if self.class_coloring.conflicts_graph.has_key(mclass) then
927 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
928 end
929 # colorize
930 colorize_elements(self.fts(mclass), color)
931 end
932 end
933 end
934
935 # Colorize properties of the crown hierarchy
936 private fun colorize_crown_properties do
937 for mclass in self.class_coloring.crown do
938 colorize_elements(self.fts(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
939 end
940 end
941
942 # Colorize a collection of properties given a starting color
943 private fun colorize_elements(elements: Collection[MParameterType], start_color: Int) do
944 for element in elements do
945 if self.coloration_result.has_key(element) then continue
946 self.coloration_result[element] = start_color
947 start_color += 1
948 end
949 end
950
951 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
952 var max_color = min_color
953
954 for mclass in mclasses do
955 for ft in self.fts(mclass) do
956 var color = min_color
957 if self.coloration_result.has_key(ft) then
958 color = self.coloration_result[ft]
959 if color >= max_color then max_color = color + 1
960 end
961 end
962 end
963 return max_color
964 end
965
966 # fts cache
967 private var fts_cache: Map[MClass, Set[MParameterType]] = new HashMap[MClass, Set[MParameterType]]
968
969 private fun fts(mclass: MClass): Set[MParameterType] do
970 if not self.fts_cache.has_key(mclass) then
971 var fts = new HashSet[MParameterType]
972 var mclass_type = mclass.mclass_type
973 if mclass_type isa MGenericType then
974 for ft in mclass_type.arguments do
975 fts.add(ft.as(MParameterType))
976 end
977 end
978 self.fts_cache[mclass] = fts
979 end
980 return fts_cache[mclass]
981 end
982
983 fun build_ft_tables: Map[MClass, Array[nullable MParameterType]] do
984 var tables = new HashMap[MClass, Array[nullable MParameterType]]
985
986 for mclass in self.class_coloring.coloration_result.keys do
987 var table = new Array[nullable MParameterType]
988
989 # first, fill table from parents
990 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
991 for parent in parents do
992 for ft in self.fts(parent) do
993 var color = self.coloration_result[ft]
994 if table.length <= color then
995 for i in [table.length .. color[ do
996 table[i] = null
997 end
998 end
999 table[color] = ft
1000 end
1001 end
1002
1003 # then override with local properties
1004 for ft in self.fts(mclass) do
1005 var color = self.coloration_result[ft]
1006 if table.length <= color then
1007 for i in [table.length .. color[ do
1008 table[i] = null
1009 end
1010 end
1011 table[color] = ft
1012 end
1013 tables[mclass] = table
1014 end
1015 return tables
1016 end
1017 end
1018
1019 class NaiveFTColoring
1020 super FTColoring
1021
1022 init(class_coloring: ClassColoring) do end
1023
1024 redef fun colorize: Map[MParameterType, Int] do
1025 var mclasses = new HashSet[MClass]
1026 mclasses.add_all(self.class_coloring.core)
1027 mclasses.add_all(self.class_coloring.crown)
1028 var min_color = 0
1029
1030 for mclass in mclasses do
1031 min_color = max_color(min_color, mclasses)
1032 colorize_elements(self.fts(mclass), min_color)
1033 end
1034 return self.coloration_result
1035 end
1036 end
1037
1038 abstract class FTPerfectHashing
1039 super FTColoring
1040
1041 private var masks: Map[MClass, Int] = new HashMap[MClass, Int]
1042
1043 init(class_coloring: ClassColoring) do end
1044
1045 redef fun colorize: Map[MParameterType, Int] do
1046 var mclasses = new HashSet[MClass]
1047 mclasses.add_all(self.class_coloring.core)
1048 mclasses.add_all(self.class_coloring.crown)
1049 for mclass in mclasses do
1050 for ft in self.fts(mclass) do
1051 if coloration_result.has_key(ft) then continue
1052 coloration_result[ft] = coloration_result.length + 1
1053 end
1054 end
1055 return self.coloration_result
1056 end
1057
1058 fun compute_masks: Map[MClass, Int] do
1059 var mclasses = new HashSet[MClass]
1060 mclasses.add_all(self.class_coloring.core)
1061 mclasses.add_all(self.class_coloring.crown)
1062 for mclass in mclasses do
1063 var fts = new HashSet[MParameterType]
1064 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
1065 for parent in parents do
1066 fts.add_all(self.fts(parent))
1067 end
1068 fts.add_all(self.fts(mclass))
1069 self.masks[mclass] = compute_mask(fts)
1070 end
1071 return self.masks
1072 end
1073
1074 private fun compute_mask(fts: Set[MParameterType]): Int do
1075 var mask = 0
1076 loop
1077 var used = new List[Int]
1078 for ft in fts do
1079 var res = op(mask, self.coloration_result[ft])
1080 if used.has(res) then
1081 break
1082 else
1083 used.add(res)
1084 end
1085 end
1086 if used.length == fts.length then break
1087 mask += 1
1088 end
1089 return mask
1090 end
1091
1092 redef fun build_ft_tables do
1093 var tables = new HashMap[MClass, Array[nullable MParameterType]]
1094
1095 for mclass in self.class_coloring.coloration_result.keys do
1096 var table = new Array[nullable MParameterType]
1097
1098 # first, fill table from parents
1099 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
1100 for parent in parents do
1101 for ft in self.fts(parent) do
1102 var color = phash(self.coloration_result[ft], masks[mclass])
1103 if table.length <= color then
1104 for i in [table.length .. color[ do
1105 table[i] = null
1106 end
1107 end
1108 table[color] = ft
1109 end
1110 end
1111
1112 # then override with local properties
1113 for ft in self.fts(mclass) do
1114 var color = phash(self.coloration_result[ft], masks[mclass])
1115 if table.length <= color then
1116 for i in [table.length .. color[ do
1117 table[i] = null
1118 end
1119 end
1120 table[color] = ft
1121 end
1122 tables[mclass] = table
1123 end
1124 return tables
1125 end
1126
1127 private fun op(mask: Int, id:Int): Int is abstract
1128 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
1129 end
1130
1131 class FTModPerfectHashing
1132 super FTPerfectHashing
1133 init(class_coloring: ClassColoring) do end
1134 redef fun op(mask, id) do return mask % id
1135 end
1136
1137 class FTAndPerfectHashing
1138 super FTPerfectHashing
1139 init(class_coloring: ClassColoring) do end
1140 redef fun op(mask, id) do return mask.bin_and(id)
1141 end
1142
1143 # Live Entries coloring
1144 class LiveEntryColoring
1145
1146 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
1147 private var conflicts_graph_cache: nullable HashMap[MType, Set[MType]]
1148 var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
1149
1150 init do end
1151
1152 fun colorize(elements: Collection[MType]): Map[MType, Int] do
1153 # compute conflicts
1154 build_conflicts_graph(elements)
1155
1156 # colorize graph
1157 colorize_elements(elements)
1158
1159 return coloration_result
1160 end
1161
1162 # Build type tables
1163 fun build_livetype_tables(mtypes: Set[MType]): Map[MClass, Array[nullable Object]] do
1164 var livetypes_tables = new HashMap[MClass, Array[nullable Object]]
1165 self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
1166
1167 for mtype in mtypes do
1168 if mtype isa MGenericType then
1169 var table: Array[nullable Object]
1170 var sizes: Array[Int]
1171 if livetypes_tables.has_key(mtype.mclass) then
1172 table = livetypes_tables[mtype.mclass]
1173 else
1174 table = new Array[nullable Object]
1175 livetypes_tables[mtype.mclass] = table
1176 end
1177 if livetypes_tables_sizes.has_key(mtype.mclass) then
1178 sizes = livetypes_tables_sizes[mtype.mclass]
1179 else
1180 sizes = new Array[Int]
1181 livetypes_tables_sizes[mtype.mclass] = sizes
1182 end
1183 build_livetype_table(mtype, 0, table, sizes)
1184 end
1185 end
1186
1187 return livetypes_tables
1188 end
1189
1190 # Build live gentype table recursively
1191 private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do
1192 var ft = mtype.arguments[current_rank]
1193 if not self.coloration_result.has_key(ft) then return
1194 var color = self.coloration_result[ft]
1195
1196 if current_rank >= sizes.length then
1197 sizes[current_rank] = color + 1
1198 else if color >= sizes[current_rank] then
1199 sizes[current_rank] = color + 1
1200 end
1201
1202 if color > table.length then
1203 for i in [table.length .. color[ do table[i] = null
1204 end
1205
1206 if current_rank == mtype.arguments.length - 1 then
1207 table[color] = mtype
1208 else
1209 var ft_table: Array[nullable Object]
1210 if color < table.length and table[color] != null then
1211 ft_table = table[color].as(Array[nullable Object])
1212 else
1213 ft_table = new Array[nullable Object]
1214 end
1215 table[color] = ft_table
1216 build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
1217 end
1218 end
1219
1220 # Colorize a collection of elements
1221 fun colorize_elements(elements: Collection[MType]) do
1222 var min_color = 0
1223
1224 for element in elements do
1225 var color = min_color
1226 while not self.is_color_free(element, color) do
1227 color += 1
1228 end
1229 coloration_result[element] = color
1230 color = min_color
1231 end
1232 end
1233
1234 # Check if a related element to the element already use the color
1235 private fun is_color_free(element: MType, color: Int): Bool do
1236 if conflicts_graph.has_key(element) then
1237 for st in conflicts_graph[element] do
1238 if coloration_result.has_key(st) and coloration_result[st] == color then return false
1239 end
1240 end
1241 return true
1242 end
1243
1244 # look for types in the same generic signatures
1245 private fun build_conflicts_graph(elements: Collection[MType]) do
1246 # regroup types by classes
1247 var genclasses = new HashMap[MClass, Set[MType]]
1248 for e in elements do
1249 if e isa MGenericType then
1250 if not genclasses.has_key(e.mclass) then
1251 genclasses[e.mclass] = new HashSet[MType]
1252 end
1253 genclasses[e.mclass].add(e)
1254 end
1255 end
1256
1257 # for each class
1258 self.conflicts_graph_cache = new HashMap[MType, Set[MType]]
1259 for mclass, mtypes in genclasses do
1260 # for each rank
1261 for rank in [0..mclass.arity[ do
1262 # for each live type
1263 for mtype in mtypes do
1264 var mclasstype: MClassType
1265 if mtype isa MNullableType then
1266 mclasstype = mtype.mtype.as(MClassType)
1267 else
1268 mclasstype = mtype.as(MClassType)
1269 end
1270 var ft = mclasstype.arguments[rank]
1271 for otype in mtypes do
1272 if mtype == otype then continue
1273 var oclasstype: MClassType
1274 if otype isa MNullableType then
1275 oclasstype = otype.mtype.as(MClassType)
1276 else
1277 oclasstype = otype.as(MClassType)
1278 end
1279 var oft = oclasstype.arguments[rank]
1280 self.add_conflict(ft, oft)
1281 end
1282 end
1283 end
1284 end
1285 end
1286
1287 private fun add_conflict(mtype: MType, otype: MType) do
1288 if mtype == otype then return
1289 if not self.conflicts_graph_cache.has_key(mtype) then self.conflicts_graph_cache[mtype] = new HashSet[MType]
1290 self.conflicts_graph_cache[mtype].add(otype)
1291 if not self.conflicts_graph_cache.has_key(otype) then self.conflicts_graph_cache[otype] = new HashSet[MType]
1292 self.conflicts_graph_cache[otype].add(mtype)
1293 end
1294 private fun conflicts_graph: Map[MType, Set[MType]] do return conflicts_graph_cache.as(not null)
1295 end
1296
1297 class NaiveLiveEntryColoring
1298 super LiveEntryColoring
1299
1300 init do end
1301
1302 redef fun colorize_elements(elements: Collection[MType]) do
1303 var color = 0
1304 for element in elements do
1305 coloration_result[element] = color
1306 color += 1
1307 end
1308 end
1309 end
1310
1311 # live unanchored coloring
1312 class UnanchoredTypeColoring
1313
1314 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
1315 private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1316
1317 init do end
1318
1319 fun colorize(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
1320 build_conflicts_graph(elements)
1321 colorize_elements(elements)
1322 return coloration_result
1323 end
1324
1325 fun build_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
1326 var tables = new HashMap[MClassType, Array[nullable MType]]
1327
1328 for mclasstype, mtypes in elements do
1329 var table = new Array[nullable MType]
1330 for mtype in mtypes do
1331 var color = self.coloration_result[mtype]
1332 if table.length <= color then
1333 for i in [table.length .. color[ do
1334 table[i] = null
1335 end
1336 end
1337 table[color] = mtype
1338 end
1339 tables[mclasstype] = table
1340 end
1341 return tables
1342 end
1343
1344 # Colorize a collection of elements
1345 fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
1346 var min_color = 0
1347 for mclasstype, mclasstypes in elements do
1348 for element in mclasstypes do
1349 if self.coloration_result.has_key(element) then continue
1350 var color = min_color
1351 while not self.is_color_free(element, color) do
1352 color += 1
1353 end
1354 coloration_result[element] = color
1355 color = min_color
1356 end
1357 end
1358 end
1359
1360 # Check if a related element to the element already use the color
1361 private fun is_color_free(element: MType, color: Int): Bool do
1362 if conflicts_graph.has_key(element) then
1363 for st in conflicts_graph[element] do
1364 if coloration_result.has_key(st) and coloration_result[st] == color then return false
1365 end
1366 end
1367 return true
1368 end
1369
1370 # look for unanchored types generated by the same type
1371 private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
1372 for mclasstype, mtypes in elements do
1373 for mtype in mtypes do
1374 for otype in mtypes do
1375 if otype == mtype then continue
1376 self.add_conflict(mtype, otype)
1377 end
1378 end
1379 end
1380 end
1381
1382 private fun add_conflict(mtype: MType, otype: MType) do
1383 if mtype == otype then return
1384 if not self.conflicts_graph.has_key(mtype) then self.conflicts_graph[mtype] = new HashSet[MType]
1385 self.conflicts_graph[mtype].add(otype)
1386 if not self.conflicts_graph.has_key(otype) then self.conflicts_graph[otype] = new HashSet[MType]
1387 self.conflicts_graph[otype].add(mtype)
1388 end
1389 end
1390
1391 class NaiveUnanchoredTypeColoring
1392 super UnanchoredTypeColoring
1393
1394 init do end
1395
1396 redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
1397 var color = 0
1398 for mclasstype, mclasstypes in elements do
1399 for element in mclasstypes do
1400 coloration_result[element] = color
1401 color += 1
1402 end
1403 end
1404 end
1405 end
1406
1407 abstract class UnanchoredTypePerfectHashing
1408 super NaiveUnanchoredTypeColoring
1409
1410 private var masks: Map[MClassType, Int] = new HashMap[MClassType, Int]
1411
1412 init do end
1413
1414 redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
1415 var color = 1
1416 for mclasstype, mclasstypes in elements do
1417 for element in mclasstypes do
1418 coloration_result[element] = color
1419 color += 1
1420 end
1421 end
1422 end
1423
1424 fun compute_masks(elements: Map[MClassType, Set[MType]]): Map[MClassType, Int] do
1425 for mclasstype, mtypes in elements do
1426 self.masks[mclasstype] = compute_mask(mtypes)
1427 end
1428 return self.masks
1429 end
1430
1431 private fun compute_mask(mtypes: Set[MType]): Int do
1432 var mask = 0
1433 loop
1434 var used = new List[Int]
1435 for mtype in mtypes do
1436 var res = op(mask, self.coloration_result[mtype])
1437 if used.has(res) then
1438 break
1439 else
1440 used.add(res)
1441 end
1442 end
1443 if used.length == mtypes.length then break
1444 mask += 1
1445 end
1446 return mask
1447 end
1448
1449 redef fun build_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
1450 var tables = new HashMap[MClassType, Array[nullable MType]]
1451
1452 for mclasstype, mtypes in elements do
1453 var table = new Array[nullable MType]
1454 for mtype in mtypes do
1455 var color = phash(self.coloration_result[mtype], masks[mclasstype])
1456 if table.length <= color then
1457 for i in [table.length .. color[ do
1458 table[i] = null
1459 end
1460 end
1461 table[color] = mtype
1462 end
1463 tables[mclasstype] = table
1464 end
1465 return tables
1466 end
1467
1468 private fun op(mask: Int, id:Int): Int is abstract
1469 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
1470 end
1471
1472 class UnanchoredTypeModPerfectHashing
1473 super UnanchoredTypePerfectHashing
1474 init do end
1475 redef fun op(mask, id) do return mask % id
1476 end
1477
1478 class UnanchoredTypeAndPerfectHashing
1479 super UnanchoredTypePerfectHashing
1480 init do end
1481 redef fun op(mask, id) do return mask.bin_and(id)
1482 end
1483
1484
1485 # Utils
1486
1487 redef class HashSet[E]
1488 init from(elements: Collection[E]) do
1489 init
1490 self.add_all(elements)
1491 end
1492 end
1493
1494 redef class Array[E]
1495 init from(elements: Collection[E]) do
1496 init
1497 self.add_all(elements)
1498 end
1499
1500 # Return a new Array with the elements only contened in 'self' and not in 'o'
1501 fun -(o: Array[E]): Array[E] do
1502 var res = new Array[E]
1503 for e in self do if not o.has(e) then res.add(e)
1504 return res
1505 end
1506 end
1507
1508 redef class MModule
1509
1510 # Return a linearization of a set of mtypes
1511 private fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do
1512 var lin = new Array[MType].from(mtypes)
1513 var sorter = new TypeSorter(self)
1514 sorter.sort(lin)
1515 return lin
1516 end
1517
1518 # Return a reverse linearization of a set of mtypes
1519 private fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do
1520 var lin = new Array[MType].from(mtypes)
1521 var sorter = new ReverseTypeSorter(self)
1522 sorter.sort(lin)
1523 return lin
1524 end
1525
1526 # Return super types of a `mtype` in `self`
1527 private fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
1528 if not self.super_mtypes_cache.has_key(mtype) then
1529 var supers = new HashSet[MType]
1530 for otype in mtypes do
1531 if otype == mtype then continue
1532 if mtype.is_subtype(self, null, otype) then
1533 supers.add(otype)
1534 end
1535 end
1536 self.super_mtypes_cache[mtype] = supers
1537 end
1538 return self.super_mtypes_cache[mtype]
1539 end
1540
1541 private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1542
1543 # Return all sub mtypes (directs and indirects) of a `mtype` in `self`
1544 private fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
1545 if not self.sub_mtypes_cache.has_key(mtype) then
1546 var subs = new HashSet[MType]
1547 for otype in mtypes do
1548 if otype == mtype then continue
1549 if otype.is_subtype(self, null, mtype) then
1550 subs.add(otype)
1551 end
1552 end
1553 self.sub_mtypes_cache[mtype] = subs
1554 end
1555 return self.sub_mtypes_cache[mtype]
1556 end
1557
1558 private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1559
1560 # Return a linearization of a set of mclasses
1561 private fun linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
1562 var lin = new Array[MClass].from(mclasses)
1563 var sorter = new ClassSorter(self)
1564 sorter.sort(lin)
1565 return lin
1566 end
1567
1568 # Return a reverse linearization of a set of mtypes
1569 private fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
1570 var lin = new Array[MClass].from(mclasses)
1571 var sorter = new ReverseClassSorter(self)
1572 sorter.sort(lin)
1573 return lin
1574 end
1575
1576 # Return all super mclasses (directs and indirects) of a `mclass` in `self`
1577 private fun super_mclasses(mclass: MClass): Set[MClass] do
1578 if not self.super_mclasses_cache.has_key(mclass) then
1579 var supers = new HashSet[MClass]
1580 if self.flatten_mclass_hierarchy.has(mclass) then
1581 for sup in self.flatten_mclass_hierarchy[mclass].greaters do
1582 if sup == mclass then continue
1583 supers.add(sup)
1584 end
1585 end
1586 self.super_mclasses_cache[mclass] = supers
1587 end
1588 return self.super_mclasses_cache[mclass]
1589 end
1590
1591 private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1592
1593 # Return all parents of a `mclass` in `self`
1594 private fun parent_mclasses(mclass: MClass): Set[MClass] do
1595 if not self.parent_mclasses_cache.has_key(mclass) then
1596 var parents = new HashSet[MClass]
1597 if self.flatten_mclass_hierarchy.has(mclass) then
1598 for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do
1599 if sup == mclass then continue
1600 parents.add(sup)
1601 end
1602 end
1603 self.parent_mclasses_cache[mclass] = parents
1604 end
1605 return self.parent_mclasses_cache[mclass]
1606 end
1607
1608 private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1609
1610 # Return all sub mclasses (directs and indirects) of a `mclass` in `self`
1611 private fun sub_mclasses(mclass: MClass): Set[MClass] do
1612 if not self.sub_mclasses_cache.has_key(mclass) then
1613 var subs = new HashSet[MClass]
1614 if self.flatten_mclass_hierarchy.has(mclass) then
1615 for sub in self.flatten_mclass_hierarchy[mclass].smallers do
1616 if sub == mclass then continue
1617 subs.add(sub)
1618 end
1619 end
1620 self.sub_mclasses_cache[mclass] = subs
1621 end
1622 return self.sub_mclasses_cache[mclass]
1623 end
1624
1625 private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1626
1627 # All 'mproperties' associated to all 'mclassdefs' of `mclass`
1628 private fun properties(mclass: MClass): Set[MProperty] do
1629 if not self.properties_cache.has_key(mclass) then
1630 var properties = new HashSet[MProperty]
1631 var parents = self.super_mclasses(mclass)
1632 for parent in parents do
1633 properties.add_all(self.properties(parent))
1634 end
1635
1636 for mclassdef in mclass.mclassdefs do
1637 for mpropdef in mclassdef.mpropdefs do
1638 properties.add(mpropdef.mproperty)
1639 end
1640 end
1641 self.properties_cache[mclass] = properties
1642 end
1643 return properties_cache[mclass]
1644 end
1645
1646 private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
1647 end
1648
1649 # A sorter for linearize list of types
1650 class TypeSorter
1651 super AbstractSorter[MType]
1652
1653 private var mmodule: MModule
1654
1655 init(mmodule: MModule) do self.mmodule = mmodule
1656
1657 redef fun compare(a, b) do
1658 if a == b then
1659 return 0
1660 else if a.is_subtype(self.mmodule, null, b) then
1661 return -1
1662 end
1663 return 1
1664 end
1665 end
1666
1667 # A sorter for reverse linearization
1668 class ReverseTypeSorter
1669 super TypeSorter
1670
1671 init(mmodule: MModule) do end
1672
1673 redef fun compare(a, b) do
1674 if a == b then
1675 return 0
1676 else if a.is_subtype(self.mmodule, null, b) then
1677 return 1
1678 end
1679 return -1
1680 end
1681 end
1682
1683 # A sorter for linearize list of classes
1684 private class ClassSorter
1685 super AbstractSorter[MClass]
1686
1687 var mmodule: MModule
1688
1689 redef fun compare(a, b) do
1690 if a == b then
1691 return 0
1692 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1693 return -1
1694 end
1695 return 1
1696 end
1697 end
1698
1699 # A sorter for reverse linearization
1700 private class ReverseClassSorter
1701 super AbstractSorter[MClass]
1702
1703 var mmodule: MModule
1704
1705 redef fun compare(a, b) do
1706 if a == b then
1707 return 0
1708 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1709 return 1
1710 end
1711 return -1
1712 end
1713 end