5c8184bd63dc41a0bbe2798928301713ae2096b2
[nit.git] / src / layout_builders.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 # Table layout builders
16 module layout_builders
17
18 import abstract_compiler
19
20 # Layouts
21
22 class Layout[E: Object]
23 # 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 PHLayout[HOLDER: Object, E: Object]
30 super Layout[E]
31 # Masks used by hash function
32 var masks: Map[HOLDER, Int] = new HashMap[HOLDER, Int]
33 # Positions of each element for each tables
34 var hashes: Map[HOLDER, Map[E, Int]] = new HashMap[HOLDER, Map[E, Int]]
35 end
36
37 class PropertyLayout[E: Object]
38 # Fixed positions of each element in all tables
39 var pos: Map[E, Int] = new HashMap[E, Int]
40 end
41
42 # Builders
43
44 abstract class TypingLayoutBuilder[E: Object]
45
46 type LAYOUT: Layout[E]
47
48 private var mmodule: MModule
49 init(mmodule: MModule) do self.mmodule = mmodule
50
51 # Compute elements ids and position
52 fun build_layout(elements: Set[E]): LAYOUT is abstract
53
54 # Give each MType a unic id using a descending linearization of the `mtypes` set
55 private fun compute_ids(elements: Set[E]): Map[E, Int] do
56 var ids = new HashMap[E, Int]
57 var lin = self.reverse_linearize(elements)
58 for element in lin do
59 ids[element] = ids.length
60 end
61 return ids
62 end
63
64 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
65 end
66
67 # Layout builder for MType using Binary Matrix (BM)
68 class BMTypeLayoutBuilder
69 super TypingLayoutBuilder[MType]
70
71 init(mmodule: MModule) do super
72
73 # Compute mtypes ids and position using BM
74 redef fun build_layout(mtypes) do
75 var result = new Layout[MType]
76 result.ids = self.compute_ids(mtypes)
77 result.pos = result.ids
78 return result
79 end
80
81 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
82 end
83
84 # Layout builder for MType using Coloring (CL)
85 class CLTypeLayoutBuilder
86 super TypingLayoutBuilder[MType]
87
88 private var colorer: MTypeColorer
89
90 init(mmodule: MModule) do
91 super
92 self.colorer = new MTypeColorer(mmodule)
93 end
94
95 # Compute mtypes ids and position using BM
96 redef fun build_layout(mtypes) do
97 var result = new Layout[MType]
98 result.ids = self.compute_ids(mtypes)
99 result.pos = self.colorer.colorize(mtypes)
100 return result
101 end
102
103 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
104 end
105
106 # Layout builder for MType using Perfect Hashing (PH)
107 class PHTypeLayoutBuilder
108 super TypingLayoutBuilder[MType]
109
110 redef type LAYOUT: PHLayout[MType, MType]
111
112 private var hasher: PerfectHasher[MType, MType]
113
114 init(mmodule: MModule, operator: PHOperator) do
115 super(mmodule)
116 self.hasher = new PerfectHasher[MType, MType](operator)
117 end
118
119 private fun build_conflicts(mtypes: Set[MType]): Map[MType, Set[MType]] do
120 var conflicts = new HashMap[MType, Set[MType]]
121 for mtype in mtypes do
122 var supers = self.mmodule.super_mtypes(mtype, mtypes)
123 supers.add(mtype)
124 conflicts[mtype] = supers
125 end
126 return conflicts
127 end
128
129 # Compute mtypes ids and position using BM
130 redef fun build_layout(mtypes) do
131 var result = new PHLayout[MType, MType]
132 var conflicts = build_conflicts(mtypes)
133 result.ids = self.compute_ids(mtypes)
134 result.masks = self.hasher.compute_masks(conflicts, result.ids)
135 result.hashes = self.hasher.compute_hashes(conflicts, result.ids, result.masks)
136 return result
137 end
138
139 # Ids start from 1 instead of 0
140 redef fun compute_ids(mtypes) do
141 var ids = new HashMap[MType, Int]
142 var lin = self.mmodule.reverse_linearize_mtypes(mtypes)
143 for mtype in lin do
144 ids[mtype] = ids.length + 1
145 end
146 return ids
147 end
148
149 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
150 end
151
152 # Layout builder for MClass using Binary Matrix (BM)
153 class BMClassLayoutBuilder
154 super TypingLayoutBuilder[MClass]
155
156 init(mmodule: MModule) do super
157
158 # Compute mclasses ids and position using BM
159 redef fun build_layout(mclasses) do
160 var result = new Layout[MClass]
161 result.ids = self.compute_ids(mclasses)
162 result.pos = result.ids
163 return result
164 end
165
166 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
167 end
168
169 # Layout builder for MClass using Coloring (CL)
170 class CLClassLayoutBuilder
171 super TypingLayoutBuilder[MClass]
172
173 private var colorer: MClassColorer
174
175 init(mmodule: MModule) do
176 super
177 self.colorer = new MClassColorer(mmodule)
178 end
179
180 # Compute mclasses ids and position using BM
181 redef fun build_layout(mclasses) do
182 var result = new Layout[MClass]
183 result.ids = self.compute_ids(mclasses)
184 result.pos = self.colorer.colorize(mclasses)
185 return result
186 end
187
188 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
189 end
190
191 # Layout builder for MClass using Perfect Hashing (PH)
192 class PHClassLayoutBuilder
193 super TypingLayoutBuilder[MClass]
194
195 redef type LAYOUT: PHLayout[MClass, MClass]
196
197 private var hasher: PerfectHasher[MClass, MClass]
198
199 init(mmodule: MModule, operator: PHOperator) do
200 super(mmodule)
201 self.hasher = new PerfectHasher[MClass, MClass](operator)
202 end
203
204 private fun build_conflicts(mclasses: Set[MClass]): Map[MClass, Set[MClass]] do
205 var conflicts = new HashMap[MClass, Set[MClass]]
206 for mclass in mclasses do
207 var supers = self.mmodule.super_mclasses(mclass)
208 supers.add(mclass)
209 conflicts[mclass] = supers
210 end
211 return conflicts
212 end
213
214 # Compute mclasses ids and position using BM
215 redef fun build_layout(mclasses) do
216 var result = new PHLayout[MClass, MClass]
217 var conflicts = build_conflicts(mclasses)
218 result.ids = self.compute_ids(mclasses)
219 result.masks = self.hasher.compute_masks(conflicts, result.ids)
220 result.hashes = self.hasher.compute_hashes(conflicts, result.ids, result.masks)
221 return result
222 end
223
224 # Ids start from 1 instead of 0
225 redef fun compute_ids(mclasses) do
226 var ids = new HashMap[MClass, Int]
227 var lin = self.mmodule.reverse_linearize_mclasses(mclasses)
228 for mclass in lin do
229 ids[mclass] = ids.length + 1
230 end
231 return ids
232 end
233
234 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
235 end
236
237 abstract class PropertyLayoutBuilder[E: MProperty]
238
239 type LAYOUT: PropertyLayout[E]
240
241 # Compute properties ids and position
242 fun build_layout(mclasses: Set[MClass]): LAYOUT is abstract
243 end
244
245 # Layout builder for MProperty using Coloring (CL)
246 class CLPropertyLayoutBuilder[E: MProperty]
247 super PropertyLayoutBuilder[E]
248
249 private var colorer: MPropertyColorer[E]
250
251 init(colorer: MPropertyColorer[E]) do
252 self.colorer = colorer
253 end
254
255 # Compute mclasses ids and position using BM
256 redef fun build_layout(mclasses) do
257 var result = new PropertyLayout[E]
258 result.pos = self.colorer.colorize(mclasses)
259 return result
260 end
261 end
262
263 # Layout builder for MProperty using Perfect Hashing (PH)
264 # TODO implement this class without sublcassing CL builder
265 class PHPropertyLayoutBuilder[E: MProperty]
266 super CLPropertyLayoutBuilder[E]
267 end
268
269 abstract class ResolutionLayoutBuilder
270
271 type LAYOUT: Layout[MType]
272
273 init do end
274
275 fun build_layout(elements: Map[MClassType, Set[MType]]): LAYOUT is abstract
276
277 fun compute_ids(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
278 var ids = new HashMap[MType, Int]
279 var color = 0
280 for mclasstype, mclasstypes in elements do
281 for element in mclasstypes do
282 if ids.has_key(element) then continue
283 ids[element] = color
284 color += 1
285 end
286 end
287 return ids
288 end
289 end
290
291 # Layout builder for MClass using Binary Matrix (BM)
292 class BMResolutionLayoutBuilder
293 super ResolutionLayoutBuilder
294
295 init do super
296
297 # Compute resolved types position using BM
298 redef fun build_layout(elements) do
299 var result = new Layout[MType]
300 result.ids = self.compute_ids(elements)
301 result.pos = result.ids
302 return result
303 end
304 end
305
306 # Layout builder for resolution tables using Coloring (CL)
307 class CLResolutionLayoutBuilder
308 super ResolutionLayoutBuilder
309
310 private var colorer: ResolutionColorer = new ResolutionColorer
311
312 init do super
313
314 # Compute resolved types colors
315 redef fun build_layout(elements) do
316 var result = new Layout[MType]
317 result.ids = self.compute_ids(elements)
318 result.pos = self.colorer.colorize(elements)
319 return result
320 end
321 end
322
323 # Layout builder for resolution table using Perfect Hashing (PH)
324 class PHResolutionLayoutBuilder
325 super ResolutionLayoutBuilder
326
327 redef type LAYOUT: PHLayout[MClassType, MType]
328
329 private var hasher: PerfectHasher[MClassType, MType]
330
331 init(operator: PHOperator) do self.hasher = new PerfectHasher[MClassType, MType](operator)
332
333 # Compute resolved types masks and hashes
334 redef fun build_layout(elements) do
335 var result = new PHLayout[MClassType, MType]
336 result.ids = self.compute_ids(elements)
337 result.pos = result.ids
338 result.masks = self.hasher.compute_masks(elements, result.ids)
339 result.hashes = self.hasher.compute_hashes(elements, result.ids, result.masks)
340 return result
341 end
342
343 redef fun compute_ids(elements) do
344 var ids = new HashMap[MType, Int]
345 var color = 1
346 for mclasstype, mclasstypes in elements do
347 for element in mclasstypes do
348 if ids.has_key(element) then continue
349 ids[element] = color
350 color += 1
351 end
352 end
353 return ids
354 end
355 end
356
357 # Colorers
358
359 abstract class AbstractColorer[E: Object]
360
361 private var core: Set[E] = new HashSet[E]
362 private var crown: Set[E] = new HashSet[E]
363 private var border: Set[E] = new HashSet[E]
364
365 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
366
367 init do end
368
369 fun colorize(elements: Set[E]): Map[E, Int] do
370 tag_elements(elements)
371 build_conflicts_graph(elements)
372 colorize_elements(core)
373 colorize_elements(border)
374 colorize_elements(crown)
375 return coloration_result
376 end
377
378 # Colorize a collection of elements
379 private fun colorize_elements(elements: Set[E]) do
380 var min_color = 0
381
382 var lin = reverse_linearize(elements)
383 for element in lin do
384 var color = min_color
385 while not self.is_color_free(element, elements, color) do
386 color += 1
387 end
388 coloration_result[element] = color
389 color = min_color
390 end
391 end
392
393 # Check if a related element to the element already use the color
394 private fun is_color_free(element: E, elements: Set[E], color: Int): Bool do
395 if conflicts_graph.has_key(element) then
396 for st in conflicts_graph[element] do
397 if coloration_result.has_key(st) and coloration_result[st] == color then return false
398 end
399 end
400 for st in self.super_elements(element, elements) do
401 if coloration_result.has_key(st) and coloration_result[st] == color then return false
402 end
403 return true
404 end
405
406 # Tag elements as core, crown or border
407 private fun tag_elements(elements: Set[E]) do
408 for element in elements do
409 # Check if sub elements are all in single inheritance
410 var all_subelements_si = true
411 for subelem in self.sub_elements(element, elements) do
412 if self.is_element_mi(subelem, elements) then
413 all_subelements_si = false
414 break
415 end
416 end
417
418 # Tag as core, crown or border
419 if self.is_element_mi(element, elements) then
420 core.add_all(self.super_elements(element, elements))
421 core.add(element)
422 if all_subelements_si then
423 border.add(element)
424 end
425 else if not all_subelements_si then
426 core.add_all(self.super_elements(element, elements))
427 core.add(element)
428 else
429 crown.add(element)
430 end
431 end
432 end
433
434 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
435 private fun build_conflicts_graph(elements: Set[E]) do
436 self.conflicts_graph = new HashMap[E, HashSet[E]]
437 var core = reverse_linearize(self.core)
438 for t in core do
439 for i in self.linear_extension(t, elements) do
440 if t == i then continue
441
442 var lin_i = self.linear_extension(i, elements)
443
444 for j in self.linear_extension(t, elements) do
445 if i == j or j == t then continue
446 var lin_j = self.linear_extension(j, elements)
447
448 var d_ij = lin_i - lin_j
449 var d_ji = lin_j - lin_i
450
451 for ed1 in d_ij do
452 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
453 # add ed1 x ed2 to conflicts graph
454 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
455 end
456 for ed1 in d_ij do
457 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
458 # add ed1 x ed2 to conflicts graph
459 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
460 end
461 end
462 end
463 end
464 end
465
466 private var conflicts_graph: nullable HashMap[E, Set[E]]
467
468 # cache for linear_extensions
469 private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
470
471 # Return a linear_extension of super_elements of the element
472 private fun linear_extension(element: E, elements: Set[E]): Array[E] do
473 if not self.linear_extensions_cache.has_key(element) then
474 var supers = new HashSet[E]
475 supers.add(element)
476 supers.add_all(self.super_elements(element, elements))
477 self.linear_extensions_cache[element] = self.linearize(supers)
478 end
479 return self.linear_extensions_cache[element]
480 end
481
482 private fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
483 private fun sub_elements(element: E, elements: Set[E]): Set[E] is abstract
484 private fun is_element_mi(element: E, elements: Set[E]): Bool is abstract
485 private fun linearize(elements: Set[E]): Array[E] is abstract
486 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
487 end
488
489 # MType coloring
490 private class MTypeColorer
491 super AbstractColorer[MType]
492
493 var mmodule: MModule
494
495 init(mmodule: MModule) do self.mmodule = mmodule
496
497 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
498 redef fun is_element_mi(element, elements) do return self.super_elements(element, elements).length > 1
499 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mtypes(element, elements)
500 redef fun linearize(elements) do return self.mmodule.linearize_mtypes(elements)
501 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
502 end
503
504 # MClass coloring
505 private class MClassColorer
506 super AbstractColorer[MClass]
507
508 private var mmodule: MModule
509
510 init(mmodule: MModule) do self.mmodule = mmodule
511
512 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
513 fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
514 redef fun is_element_mi(element, elements) do return self.parent_elements(element).length > 1
515 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mclasses(element)
516 redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
517 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
518 end
519
520 # MProperty coloring
521 abstract class MPropertyColorer[E: MProperty]
522
523 private var mmodule: MModule
524 private var class_colorer: MClassColorer
525 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
526
527 init(mmodule: MModule) do
528 self.mmodule = mmodule
529 self.class_colorer = new MClassColorer(mmodule)
530 end
531
532 fun colorize(mclasses: Set[MClass]): Map[E, Int] do
533 self.class_colorer.tag_elements(mclasses)
534 self.class_colorer.build_conflicts_graph(mclasses)
535 self.colorize_core(self.class_colorer.core)
536 self.colorize_crown(self.class_colorer.crown)
537 return self.coloration_result
538 end
539
540 # Colorize properties of the core hierarchy
541 private fun colorize_core(mclasses: Set[MClass]) do
542 var min_color = 0
543 for mclass in mclasses do
544 var color = min_color
545
546 # if the class is root, get the minimal color
547 if self.mmodule.parent_mclasses(mclass).length == 0 then
548 colorize_elements(self.properties(mclass), color)
549 else
550 # check last color used by parents
551 color = max_color(color, self.mmodule.parent_mclasses(mclass))
552 # check max color used in conflicts
553 if self.class_colorer.conflicts_graph.has_key(mclass) then
554 color = max_color(color, self.class_colorer.conflicts_graph[mclass])
555 end
556 colorize_elements(self.properties(mclass), color)
557 end
558 end
559 end
560
561 # Colorize properties of the crown hierarchy
562 private fun colorize_crown(mclasses: Set[MClass]) do
563 for mclass in mclasses do
564 colorize_elements(self.properties(mclass), max_color(0, self.mmodule.parent_mclasses(mclass)))
565 end
566 end
567
568 # Colorize a collection of mproperties given a starting color
569 private fun colorize_elements(elements: Collection[E], start_color: Int) do
570 for element in elements do
571 if self.coloration_result.has_key(element) then continue
572 self.coloration_result[element] = start_color
573 start_color += 1
574 end
575 end
576
577 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
578 var max_color = min_color
579
580 for mclass in mclasses do
581 for mproperty in self.properties(mclass) do
582 var color = min_color
583 if self.coloration_result.has_key(mproperty) then
584 color = self.coloration_result[mproperty]
585 if color >= max_color then max_color = color + 1
586 end
587 end
588 end
589 return max_color
590 end
591
592 # Filter properties
593 private fun properties(mclass: MClass): Set[E] is abstract
594 end
595
596 # Coloring for MMethods
597 class MMethodColorer
598 super MPropertyColorer[MMethod]
599
600 init(mmodule: MModule) do super
601
602 redef fun properties(mclass) do
603 var properties = new HashSet[MMethod]
604 for mprop in self.mmodule.properties(mclass) do
605 if mprop isa MMethod then properties.add(mprop)
606 end
607 return properties
608 end
609 end
610
611 # Coloring for MMAttributes
612 class MAttributeColorer
613 super MPropertyColorer[MAttribute]
614
615 init(mmodule: MModule) do super
616
617 redef fun properties(mclass) do
618 var properties = new HashSet[MAttribute]
619 for mprop in self.mmodule.properties(mclass) do
620 if mprop isa MAttribute then properties.add(mprop)
621 end
622 return properties
623 end
624 end
625
626 # Coloring for MVirtualTypeProps
627 class MVirtualTypePropColorer
628 super MPropertyColorer[MVirtualTypeProp]
629
630 init(mmodule: MModule) do super
631
632 redef fun properties(mclass) do
633 var properties = new HashSet[MVirtualTypeProp]
634 for mprop in self.mmodule.properties(mclass) do
635 if mprop isa MVirtualTypeProp then properties.add(mprop)
636 end
637 return properties
638 end
639 end
640
641 # Colorer for type resolution table
642 class ResolutionColorer
643
644 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
645
646 init do end
647
648 fun colorize(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
649 self.build_conflicts_graph(elements)
650 self.colorize_elements(elements)
651 return coloration_result
652 end
653
654 # Colorize a collection of elements
655 fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
656 var min_color = 0
657 for mclasstype, mclasstypes in elements do
658 for element in mclasstypes do
659 if self.coloration_result.has_key(element) then continue
660 var color = min_color
661 while not self.is_color_free(element, color) do
662 color += 1
663 end
664 coloration_result[element] = color
665 color = min_color
666 end
667 end
668 end
669
670 # Check if a related element to the element already use the color
671 private fun is_color_free(element: MType, color: Int): Bool do
672 if conflicts_graph.has_key(element) then
673 for st in conflicts_graph[element] do
674 if coloration_result.has_key(st) and coloration_result[st] == color then return false
675 end
676 end
677 return true
678 end
679
680 # look for unanchored types generated by the same type
681 private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
682 for mclasstype, mtypes in elements do
683 for mtype in mtypes do
684 for otype in mtypes do
685 if otype == mtype then continue
686 self.add_conflict(mtype, otype)
687 end
688 end
689 end
690 end
691
692 private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
693
694 private fun add_conflict(mtype: MType, otype: MType) do
695 if mtype == otype then return
696 if not self.conflicts_graph.has_key(mtype) then self.conflicts_graph[mtype] = new HashSet[MType]
697 self.conflicts_graph[mtype].add(otype)
698 if not self.conflicts_graph.has_key(otype) then self.conflicts_graph[otype] = new HashSet[MType]
699 self.conflicts_graph[otype].add(mtype)
700 end
701 end
702
703 # Perfect Hashing (PH)
704 # T = type of holder
705 # U = type of elements to hash
706 private class PerfectHasher[T: Object, U: Object]
707
708 var operator: PHOperator
709
710 init(operator: PHOperator) do self.operator = operator
711
712 fun compute_masks(conflicts: Map[T, Set[U]], ids: Map[U, Int]): Map[T, Int] do
713 var masks = new HashMap[T, Int]
714 for mclasstype, mtypes in conflicts do
715 masks[mclasstype] = compute_mask(mtypes, ids)
716 end
717 return masks
718 end
719
720 private fun compute_mask(mtypes: Set[U], ids: Map[U, Int]): Int do
721 var mask = 0
722 loop
723 var used = new List[Int]
724 for mtype in mtypes do
725 var res = operator.op(mask, ids[mtype])
726 if used.has(res) then
727 break
728 else
729 used.add(res)
730 end
731 end
732 if used.length == mtypes.length then break
733 mask += 1
734 end
735 return mask
736 end
737
738 fun compute_hashes(elements: Map[T, Set[U]], ids: Map[U, Int], masks: Map[T, Int]): Map[T, Map[U, Int]] do
739 var hashes = new HashMap[T, Map[U, Int]]
740 for mclasstype, mtypes in elements do
741 var mask = masks[mclasstype]
742 var inhashes = new HashMap[U, Int]
743 for mtype in mtypes do
744 inhashes[mtype] = operator.op(mask, ids[mtype])
745 end
746 hashes[mclasstype] = inhashes
747 end
748 return hashes
749 end
750 end
751
752 # Abstract operator used for perfect hashing
753 abstract class PHOperator
754 fun op(mask: Int, id:Int): Int is abstract
755 end
756
757 # Hashing using modulo (MOD) operator
758 # slower but compact
759 class PHModOperator
760 super PHOperator
761 init do end
762 redef fun op(mask, id) do return mask % id
763 end
764
765 # Hashing using binary and (AND) operator
766 # faster but sparse
767 class PHAndOperator
768 super PHOperator
769 init do end
770 redef fun op(mask, id) do return mask.bin_and(id)
771 end