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