1 module epsilon.soag.hash;
2 
3 import runtime;
4 import SOAG = epsilon.soag.soag;
5 
6 class HashEntry
7 {
8     SOAG.Instruction Instr;
9 }
10 
11 HashEntry[] HashTab;
12 int MaxHashTabIndex;
13 int V4711;
14 int V711;
15 
16 /**
17  * SEM: leert die Hash-Tabelle
18  */
19 void Reset() @nogc nothrow @safe
20 {
21     for (int i = 0; i < MaxHashTabIndex; ++i)
22         HashTab[i] = null;
23 }
24 
25 /**
26  * IN:  maximale Anzahl an Affixparametern in einer Regel
27  * OUT: -
28  * SEM: reserviert Speicher für die Hash-Tabelle und setzt die max. Hash-Adresse
29  */
30 void Init(int MaxAffInRule) @safe
31 in (MaxAffInRule > 0)
32 {
33     import std.conv : to;
34     import std.math : log2;
35 
36     int Exp;
37     int i;
38     // Exp = SHORT(ENTIER(Math.ln(MaxAffInRule) / Math.ln(2)) + 1);
39     Exp = log2(MaxAffInRule).to!int + 1;
40     MaxHashTabIndex = 2;
41     for (i = 2; i <= Exp; ++i)
42         MaxHashTabIndex = MaxHashTabIndex * 2;
43     HashTab = new HashEntry[MaxHashTabIndex];
44     Reset;
45 }
46 
47 /**
48  * IN:  Instruktion aus der Visit-Sequenz, kein NIL !
49  * OUT: Index in der Hash-Tabelle
50  * SEM: Ermittlung Indexes in der Hash-Tabelle
51  */
52 int HashIndex(ref SOAG.Instruction I) @safe
53 {
54     import std.conv : to;
55 
56     int Index;
57     int Index0;
58     int Try;
59     bool found;
60 
61     /**
62      * Fehler im Compiler: kann keine Integerkonstanten > 128 in Multiplikationen verarbeiten
63      * IN:  Instruktion
64      * OUT: -
65      * SEM: Realisierung der Hash-Funktion
66      */
67     int HashFun(ref SOAG.Instruction I)
68     {
69         import std.conv : to;
70 
71         int Index;
72 
73         if (auto visit = cast(SOAG.Visit) I)
74             Index = 100 + V4711 * visit.SymOcc + V711 * visit.VisitNo;
75         else if (auto leave = cast(SOAG.Leave) I)
76             Index = 200 + V4711 * leave.VisitNo;
77         else if (auto call = cast(SOAG.Call) I)
78             Index = 300 + V4711 * call.SymOcc;
79         else
80             Index = 0;
81         return MOD(Index, MaxHashTabIndex).to!int;
82     }
83 
84     Try = 0;
85     Index0 = HashFun(I);
86     Index = Index0;
87     if (HashTab[Index] is null)
88     {
89         found = true;
90     }
91     else
92     {
93         found = SOAG.isEqual(I, HashTab[Index].Instr);
94     }
95     while (!found)
96     {
97         ++Try;
98         Index = MOD(Index0 - Try * (DIV(Index0, 2) * 2 + 1), MaxHashTabIndex).to!int;
99         if (HashTab[Index] is null)
100         {
101             found = true;
102         }
103         else
104         {
105             found = SOAG.isEqual(I, HashTab[Index].Instr);
106         }
107     }
108     return Index;
109 }
110 
111 /**
112  * IN:  Instruktion aus der Visit-Sequenz
113  * OUT: boolscher Wert
114  * SEM: Test, ob die Instruktion schon in der Hash-Tabelle enthalten ist
115  */
116 bool IsIn(SOAG.Instruction I) @safe
117 {
118     if (I is null)
119         return true;
120 
121     const Index = HashIndex(I);
122 
123     return HashTab[Index] !is null;
124 }
125 
126 /**
127  * IN:  Instruktion der Visit-Sequenz
128  * OUT: -
129  * SEM: fügt die Instruktion in die Hash-Tabelle ein
130  */
131 void Enter(SOAG.Instruction I) @safe
132 {
133     if (I !is null)
134     {
135         int Index = HashIndex(I);
136         HashEntry Entry = new HashEntry;
137 
138         Entry.Instr = I;
139         HashTab[Index] = Entry;
140     }
141 }
142 
143 static this() @nogc nothrow @safe
144 {
145     V4711 = 4711;
146     V711 = 711;
147 }