1 #include <cstring>
2 #include <cstdio>
3 #include <algorithm>
4 #include <limits.h>
5
6 #include "typeconv.hpp"
7
8
9 // ------ TypeManager ------
10
TCCMap()11 TCCMap::TCCMap()
12 : nb_records(0)
13 {
14 }
15
hash(const TypePair & key) const16 unsigned int TCCMap::hash(const TypePair &key) const {
17 const int mult = 1000003;
18 int x = 0x345678;
19 x = (x ^ key.first) * mult;
20 x = (x ^ key.second);
21 return x;
22 }
23
insert(const TypePair & key,TypeCompatibleCode val)24 void TCCMap::insert(const TypePair &key, TypeCompatibleCode val) {
25 unsigned int i = hash(key) & (TCCMAP_SIZE - 1);
26 TCCMapBin &bin = records[i];
27 TCCRecord data;
28 data.key = key;
29 data.val = val;
30 for (unsigned int j = 0; j < bin.size(); ++j) {
31 if (bin[j].key == key) {
32 bin[j].val = val;
33 return;
34 }
35 }
36 bin.push_back(data);
37 nb_records++;
38 }
39
find(const TypePair & key) const40 TypeCompatibleCode TCCMap::find(const TypePair &key) const {
41 unsigned int i = hash(key) & (TCCMAP_SIZE - 1);
42 const TCCMapBin &bin = records[i];
43 for (unsigned int j = 0; j < bin.size(); ++j) {
44 if (bin[j].key == key) {
45 return bin[j].val;
46 }
47 }
48 return TCC_FALSE;
49 }
50
51 // ----- Ratings -----
Rating()52 Rating::Rating() : promote(0), safe_convert(0), unsafe_convert(0) { }
53
operator <(const Rating & other) const54 inline bool Rating::operator < (const Rating &other) const {
55 if (unsafe_convert < other.unsafe_convert)
56 return true;
57 else if (unsafe_convert > other.unsafe_convert)
58 return false;
59 if (safe_convert < other.safe_convert)
60 return true;
61 else if (safe_convert > other.safe_convert)
62 return false;
63 return (promote < other.promote);
64 }
65
operator ==(const Rating & other) const66 inline bool Rating::operator == (const Rating &other) const {
67 return promote == other.promote && safe_convert == other.safe_convert &&
68 unsafe_convert == other.unsafe_convert;
69 }
70
71 // ------ TypeManager ------
72
canPromote(Type from,Type to) const73 bool TypeManager::canPromote(Type from, Type to) const {
74 return isCompatible(from, to) == TCC_PROMOTE;
75 }
76
canSafeConvert(Type from,Type to) const77 bool TypeManager::canSafeConvert(Type from, Type to) const {
78 return isCompatible(from, to) == TCC_CONVERT_SAFE;
79 }
80
canUnsafeConvert(Type from,Type to) const81 bool TypeManager::canUnsafeConvert(Type from, Type to) const {
82 return isCompatible(from, to) == TCC_CONVERT_UNSAFE;
83 }
84
addPromotion(Type from,Type to)85 void TypeManager::addPromotion(Type from, Type to) {
86 return addCompatibility(from, to, TCC_PROMOTE);
87 }
88
addUnsafeConversion(Type from,Type to)89 void TypeManager::addUnsafeConversion(Type from, Type to) {
90 return addCompatibility(from, to, TCC_CONVERT_UNSAFE);
91 }
92
addSafeConversion(Type from,Type to)93 void TypeManager::addSafeConversion(Type from, Type to) {
94 return addCompatibility(from, to, TCC_CONVERT_SAFE);
95 }
96
addCompatibility(Type from,Type to,TypeCompatibleCode tcc)97 void TypeManager::addCompatibility(Type from, Type to, TypeCompatibleCode tcc) {
98 TypePair pair(from, to);
99 tccmap.insert(pair, tcc);
100 }
101
isCompatible(Type from,Type to) const102 TypeCompatibleCode TypeManager::isCompatible(Type from, Type to) const {
103 if (from == to)
104 return TCC_EXACT;
105 TypePair pair(from, to);
106 return tccmap.find(pair);
107 }
108
109
selectOverload(const Type sig[],const Type ovsigs[],int & selected,int sigsz,int ovct,bool allow_unsafe,bool exact_match_required) const110 int TypeManager::selectOverload(const Type sig[], const Type ovsigs[],
111 int &selected,
112 int sigsz, int ovct, bool allow_unsafe,
113 bool exact_match_required
114 ) const {
115 int count;
116 if (ovct <= 16) {
117 Rating ratings[16];
118 int candidates[16];
119 count = _selectOverload(sig, ovsigs, selected, sigsz, ovct,
120 allow_unsafe, exact_match_required, ratings,
121 candidates);
122 }
123 else {
124 Rating *ratings = new Rating[ovct];
125 int *candidates = new int[ovct];
126 count = _selectOverload(sig, ovsigs, selected, sigsz, ovct,
127 allow_unsafe, exact_match_required, ratings,
128 candidates);
129 delete [] ratings;
130 delete [] candidates;
131 }
132 return count;
133 }
134
_selectOverload(const Type sig[],const Type ovsigs[],int & selected,int sigsz,int ovct,bool allow_unsafe,bool exact_match_required,Rating ratings[],int candidates[]) const135 int TypeManager::_selectOverload(const Type sig[], const Type ovsigs[],
136 int &selected, int sigsz, int ovct,
137 bool allow_unsafe, bool exact_match_required,
138 Rating ratings[], int candidates[]) const {
139 // Generate rating table
140 // Use a penalize scheme.
141 int nb_candidates = 0;
142
143 for (int i = 0; i < ovct; ++i) {
144 const Type *entry = &ovsigs[i * sigsz];
145 Rating rate;
146
147 for (int j = 0; j < sigsz; ++j) {
148 TypeCompatibleCode tcc = isCompatible(sig[j], entry[j]);
149 if (tcc == TCC_FALSE ||
150 (tcc == TCC_CONVERT_UNSAFE && !allow_unsafe) ||
151 (tcc != TCC_EXACT && exact_match_required)) {
152 // stop the loop early
153 goto _incompatible;
154 }
155 switch(tcc) {
156 case TCC_PROMOTE:
157 rate.promote += 1;
158 break;
159 case TCC_CONVERT_SAFE:
160 rate.safe_convert += 1;
161 break;
162 case TCC_CONVERT_UNSAFE:
163 rate.unsafe_convert += 1;
164 break;
165 default:
166 break;
167 }
168 }
169 ratings[nb_candidates] = rate;
170 candidates[nb_candidates] = i;
171 nb_candidates++;
172 _incompatible:
173 ;
174 }
175
176 // Bail if no match
177 if (nb_candidates == 0)
178 return 0;
179
180 // Find lowest rating
181 Rating best = ratings[0];
182 selected = candidates[0];
183
184 int matchcount = 1;
185 for (int i = 1; i < nb_candidates; ++i) {
186 if (ratings[i] < best) {
187 best = ratings[i];
188 selected = candidates[i];
189 matchcount = 1;
190 }
191 else if (ratings[i] == best) {
192 matchcount += 1;
193 }
194 }
195 return matchcount;
196 }
197
198 // ----- utils -----
199
TCCString(TypeCompatibleCode tcc)200 const char* TCCString(TypeCompatibleCode tcc) {
201 switch(tcc) {
202 case TCC_EXACT:
203 return "exact";
204 case TCC_SUBTYPE:
205 return "subtype";
206 case TCC_PROMOTE:
207 return "promote";
208 case TCC_CONVERT_SAFE:
209 return "safe_convert";
210 case TCC_CONVERT_UNSAFE:
211 return "unsafe_convert";
212 default:
213 return "false";
214 }
215 }
216
217