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