// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CSharp.RuntimeBinder.Syntax; namespace Microsoft.CSharp.RuntimeBinder.Semantics { internal readonly struct KeyPair : IEquatable> { private readonly Key1 _pKey1; private readonly Key2 _pKey2; public KeyPair(Key1 pKey1, Key2 pKey2) { _pKey1 = pKey1; _pKey2 = pKey2; } public bool Equals(KeyPair other) { return EqualityComparer.Default.Equals(_pKey1, other._pKey1) && EqualityComparer.Default.Equals(_pKey2, other._pKey2); } #if DEBUG [ExcludeFromCodeCoverage] // Typed overload should always be the method called. #endif public override bool Equals(object obj) { Debug.Fail("Sub-optimal overload called. Check if this can be avoided."); if (!(obj is KeyPair)) return false; return Equals((KeyPair)obj); } public override int GetHashCode() { int hash = _pKey1 == null ? 0 : _pKey1.GetHashCode(); return (hash << 5) - hash + (_pKey2 == null ? 0 : _pKey2.GetHashCode()); } } internal sealed class TypeTable { // Two way hashes private readonly Dictionary>, AggregateType> _aggregateTable; private readonly Dictionary, ArrayType> _pArrayTable; private readonly Dictionary, ParameterModifierType> _pParameterModifierTable; // One way hashes private readonly Dictionary _pPointerTable; private readonly Dictionary _pNullableTable; public TypeTable() { _aggregateTable = new Dictionary>, AggregateType>(); _pArrayTable = new Dictionary, ArrayType>(); _pParameterModifierTable = new Dictionary, ParameterModifierType>(); _pPointerTable = new Dictionary(); _pNullableTable = new Dictionary(); } private static KeyPair MakeKey(TKey1 key1, TKey2 key2) => new KeyPair(key1, key2); public AggregateType LookupAggregate(AggregateSymbol aggregate, AggregateType outer, TypeArray args) { _aggregateTable.TryGetValue(MakeKey(aggregate, MakeKey(outer, args)), out AggregateType result); return result; } public void InsertAggregate( AggregateSymbol aggregate, AggregateType outer, TypeArray args, AggregateType pAggregate) { Debug.Assert(LookupAggregate(aggregate, outer, args) == null); _aggregateTable.Add(MakeKey(aggregate, MakeKey(outer, args)), pAggregate); } public ArrayType LookupArray(Name pName, CType pElementType) { var key = new KeyPair(pElementType, pName); ArrayType result; if (_pArrayTable.TryGetValue(key, out result)) { return result; } return null; } public void InsertArray(Name pName, CType pElementType, ArrayType pArray) { Debug.Assert(LookupArray(pName, pElementType) == null); _pArrayTable.Add(new KeyPair(pElementType, pName), pArray); } public ParameterModifierType LookupParameterModifier(Name pName, CType pElementType) { var key = new KeyPair(pElementType, pName); ParameterModifierType result; if (_pParameterModifierTable.TryGetValue(key, out result)) { return result; } return null; } public void InsertParameterModifier( Name pName, CType pElementType, ParameterModifierType pParameterModifier) { Debug.Assert(LookupParameterModifier(pName, pElementType) == null); _pParameterModifierTable.Add(new KeyPair(pElementType, pName), pParameterModifier); } public PointerType LookupPointer(CType pElementType) { PointerType result; if (_pPointerTable.TryGetValue(pElementType, out result)) { return result; } return null; } public void InsertPointer(CType pElementType, PointerType pPointer) { _pPointerTable.Add(pElementType, pPointer); } public NullableType LookupNullable(CType pUnderlyingType) { NullableType result; if (_pNullableTable.TryGetValue(pUnderlyingType, out result)) { return result; } return null; } public void InsertNullable(CType pUnderlyingType, NullableType pNullable) { _pNullableTable.Add(pUnderlyingType, pNullable); } } }