1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Diagnostics.CodeAnalysis;
9 using Microsoft.CSharp.RuntimeBinder.Syntax;
10 
11 namespace Microsoft.CSharp.RuntimeBinder.Semantics
12 {
13     internal readonly struct KeyPair<Key1, Key2> : IEquatable<KeyPair<Key1, Key2>>
14     {
15         private readonly Key1 _pKey1;
16         private readonly Key2 _pKey2;
17 
KeyPairMicrosoft.CSharp.RuntimeBinder.Semantics.KeyPair18         public KeyPair(Key1 pKey1, Key2 pKey2)
19         {
20             _pKey1 = pKey1;
21             _pKey2 = pKey2;
22         }
23 
EqualsMicrosoft.CSharp.RuntimeBinder.Semantics.KeyPair24         public bool Equals(KeyPair<Key1, Key2> other)
25         {
26             return EqualityComparer<Key1>.Default.Equals(_pKey1, other._pKey1)
27                 && EqualityComparer<Key2>.Default.Equals(_pKey2, other._pKey2);
28         }
29 
30 #if  DEBUG
31         [ExcludeFromCodeCoverage] // Typed overload should always be the method called.
32 #endif
EqualsMicrosoft.CSharp.RuntimeBinder.Semantics.KeyPair33         public override bool Equals(object obj)
34         {
35             Debug.Fail("Sub-optimal overload called. Check if this can be avoided.");
36             if (!(obj is KeyPair<Key1, Key2>)) return false;
37             return Equals((KeyPair<Key1, Key2>)obj);
38         }
39 
GetHashCodeMicrosoft.CSharp.RuntimeBinder.Semantics.KeyPair40         public override int GetHashCode()
41         {
42             int hash = _pKey1 == null ? 0 : _pKey1.GetHashCode();
43             return (hash << 5) - hash + (_pKey2 == null ? 0 : _pKey2.GetHashCode());
44         }
45     }
46 
47     internal sealed class TypeTable
48     {
49         // Two way hashes
50         private readonly Dictionary<KeyPair<AggregateSymbol, KeyPair<AggregateType, TypeArray>>, AggregateType> _aggregateTable;
51         private readonly Dictionary<KeyPair<CType, Name>, ArrayType> _pArrayTable;
52         private readonly Dictionary<KeyPair<CType, Name>, ParameterModifierType> _pParameterModifierTable;
53 
54         // One way hashes
55         private readonly Dictionary<CType, PointerType> _pPointerTable;
56         private readonly Dictionary<CType, NullableType> _pNullableTable;
57 
TypeTable()58         public TypeTable()
59         {
60             _aggregateTable = new Dictionary<KeyPair<AggregateSymbol, KeyPair<AggregateType, TypeArray>>, AggregateType>();
61             _pArrayTable = new Dictionary<KeyPair<CType, Name>, ArrayType>();
62             _pParameterModifierTable = new Dictionary<KeyPair<CType, Name>, ParameterModifierType>();
63             _pPointerTable = new Dictionary<CType, PointerType>();
64             _pNullableTable = new Dictionary<CType, NullableType>();
65         }
66 
MakeKey(TKey1 key1, TKey2 key2)67         private static KeyPair<TKey1, TKey2> MakeKey<TKey1, TKey2>(TKey1 key1, TKey2 key2) =>
68             new KeyPair<TKey1, TKey2>(key1, key2);
69 
LookupAggregate(AggregateSymbol aggregate, AggregateType outer, TypeArray args)70         public AggregateType LookupAggregate(AggregateSymbol aggregate, AggregateType outer, TypeArray args)
71         {
72             _aggregateTable.TryGetValue(MakeKey(aggregate, MakeKey(outer, args)), out AggregateType result);
73             return result;
74         }
75 
InsertAggregate( AggregateSymbol aggregate, AggregateType outer, TypeArray args, AggregateType pAggregate)76         public void InsertAggregate(
77             AggregateSymbol aggregate, AggregateType outer, TypeArray args, AggregateType pAggregate)
78         {
79             Debug.Assert(LookupAggregate(aggregate, outer, args) == null);
80             _aggregateTable.Add(MakeKey(aggregate, MakeKey(outer, args)), pAggregate);
81         }
82 
LookupArray(Name pName, CType pElementType)83         public ArrayType LookupArray(Name pName, CType pElementType)
84         {
85             var key = new KeyPair<CType, Name>(pElementType, pName);
86             ArrayType result;
87             if (_pArrayTable.TryGetValue(key, out result))
88             {
89                 return result;
90             }
91             return null;
92         }
93 
InsertArray(Name pName, CType pElementType, ArrayType pArray)94         public void InsertArray(Name pName, CType pElementType, ArrayType pArray)
95         {
96             Debug.Assert(LookupArray(pName, pElementType) == null);
97             _pArrayTable.Add(new KeyPair<CType, Name>(pElementType, pName), pArray);
98         }
99 
LookupParameterModifier(Name pName, CType pElementType)100         public ParameterModifierType LookupParameterModifier(Name pName, CType pElementType)
101         {
102             var key = new KeyPair<CType, Name>(pElementType, pName);
103             ParameterModifierType result;
104             if (_pParameterModifierTable.TryGetValue(key, out result))
105             {
106                 return result;
107             }
108             return null;
109         }
110 
InsertParameterModifier( Name pName, CType pElementType, ParameterModifierType pParameterModifier)111         public void InsertParameterModifier(
112                 Name pName,
113                 CType pElementType,
114                 ParameterModifierType pParameterModifier)
115         {
116             Debug.Assert(LookupParameterModifier(pName, pElementType) == null);
117             _pParameterModifierTable.Add(new KeyPair<CType, Name>(pElementType, pName), pParameterModifier);
118         }
119 
LookupPointer(CType pElementType)120         public PointerType LookupPointer(CType pElementType)
121         {
122             PointerType result;
123             if (_pPointerTable.TryGetValue(pElementType, out result))
124             {
125                 return result;
126             }
127             return null;
128         }
129 
InsertPointer(CType pElementType, PointerType pPointer)130         public void InsertPointer(CType pElementType, PointerType pPointer)
131         {
132             _pPointerTable.Add(pElementType, pPointer);
133         }
134 
LookupNullable(CType pUnderlyingType)135         public NullableType LookupNullable(CType pUnderlyingType)
136         {
137             NullableType result;
138             if (_pNullableTable.TryGetValue(pUnderlyingType, out result))
139             {
140                 return result;
141             }
142             return null;
143         }
144 
InsertNullable(CType pUnderlyingType, NullableType pNullable)145         public void InsertNullable(CType pUnderlyingType, NullableType pNullable)
146         {
147             _pNullableTable.Add(pUnderlyingType, pNullable);
148         }
149     }
150 }
151