Browse Source

Testing the interning support

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
20708b6d54
  1. 1
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  2. 166
      ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs
  3. 1
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  4. 40
      ICSharpCode.NRefactory/TypeSystem/AmbiguousType.cs
  5. 18
      ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
  6. 42
      ICSharpCode.NRefactory/TypeSystem/ConstructedType.cs
  7. 4
      ICSharpCode.NRefactory/TypeSystem/DomRegion.cs
  8. 24
      ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs
  9. 4
      ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs
  10. 8
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs
  11. 8
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs
  12. 19
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs
  13. 11
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs
  14. 18
      ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs
  15. 19
      ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs
  16. 23
      ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleConstantValue.cs

1
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -50,6 +50,7 @@ @@ -50,6 +50,7 @@
<Compile Include="FormattingTests\TestTypeLevelIndentation.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeSystem\CecilLoaderTests.cs" />
<Compile Include="TypeSystem\TestInterningProvider.cs" />
<Compile Include="TypeSystem\TypeSystemTests.cs" />
<Compile Include="TypeSystem\TypeSystemTests.TestCase.cs" />
</ItemGroup>

166
ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs

@ -0,0 +1,166 @@ @@ -0,0 +1,166 @@

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.TypeSystem
{
[TestFixture]
public class TestInterningProvider : IInterningProvider
{
sealed class ReferenceComparer : IEqualityComparer<object>
{
public new bool Equals(object a, object b)
{
return ReferenceEquals(a, b);
}
public int GetHashCode(object obj)
{
return RuntimeHelpers.GetHashCode(obj);
}
}
sealed class InterningComparer : IEqualityComparer<ISupportsInterning>
{
public bool Equals(ISupportsInterning x, ISupportsInterning y)
{
return x.EqualsForInterning(y);
}
public int GetHashCode(ISupportsInterning obj)
{
return obj.GetHashCodeForInterning();
}
}
sealed class ListComparer : IEqualityComparer<IEnumerable<object>>
{
public bool Equals(IEnumerable<object> a, IEnumerable<object> b)
{
if (a.GetType() != b.GetType())
return false;
return Enumerable.SequenceEqual(a, b, new ReferenceComparer());
}
public int GetHashCode(IEnumerable<object> obj)
{
int hashCode = obj.GetType().GetHashCode();
unchecked {
foreach (object o in obj) {
hashCode *= 27;
hashCode += RuntimeHelpers.GetHashCode(o);
}
}
return hashCode;
}
}
HashSet<object> uniqueObjectsPreIntern = new HashSet<object>(new ReferenceComparer());
HashSet<object> uniqueObjectsPostIntern = new HashSet<object>(new ReferenceComparer());
Dictionary<object, object> byValueDict = new Dictionary<object, object>();
Dictionary<ISupportsInterning, ISupportsInterning> supportsInternDict = new Dictionary<ISupportsInterning, ISupportsInterning>(new InterningComparer());
Dictionary<IEnumerable<object>, IEnumerable<object>> listDict = new Dictionary<IEnumerable<object>, IEnumerable<object>>(new ListComparer());
public T Intern<T>(T obj) where T : class
{
if (obj == null)
return null;
uniqueObjectsPreIntern.Add(obj);
ISupportsInterning s = obj as ISupportsInterning;
if (s != null) {
s.PrepareForInterning(this);
ISupportsInterning output;
if (supportsInternDict.TryGetValue(s, out output))
obj = (T)output;
else
supportsInternDict.Add(s, s);
} else if (obj is string || obj is IType || obj is bool || obj is int) {
object output;
if (byValueDict.TryGetValue(obj, out output))
obj = (T)output;
else
byValueDict.Add(obj, obj);
}
uniqueObjectsPostIntern.Add(obj);
return obj;
}
public IList<T> InternList<T>(IList<T> list) where T : class
{
if (list == null)
return null;
uniqueObjectsPreIntern.Add(list);
for (int i = 0; i < list.Count; i++) {
T oldItem = list[i];
T newItem = Intern(oldItem);
if (oldItem != newItem) {
if (list.IsReadOnly)
list = new List<T>(list);
list[i] = newItem;
}
}
IEnumerable<object> output;
if (listDict.TryGetValue(list, out output))
list = (IList<T>)output;
else
listDict.Add(list, list);
uniqueObjectsPostIntern.Add(list);
return list;
}
void Run(ITypeDefinition c)
{
foreach (ITypeDefinition n in c.InnerClasses) {
Run(n);
}
Intern(c.Name);
foreach (IProperty p in c.Properties) {
Intern(p.Name);
Intern(p.ReturnType);
InternList(p.Parameters);
InternList(p.Attributes);
}
foreach (IMethod m in c.Methods) {
Intern(m.Name);
Intern(m.ReturnType);
InternList(m.Parameters);
InternList(m.Attributes);
}
foreach (IField f in c.Fields) {
Intern(f.Name);
Intern(f.ReturnType);
Intern(f.ConstantValue);
InternList(f.Attributes);
}
foreach (IEvent e in c.Events) {
Intern(e.Name);
Intern(e.ReturnType);
InternList(e.Attributes);
}
}
[Test]
public void PrintStatistics()
{
foreach (var c in CecilLoaderTests.Mscorlib.GetClasses()) {
Run(c);
}
var stats =
from obj in uniqueObjectsPreIntern
group 1 by obj.GetType() into g
join g2 in (from obj in uniqueObjectsPostIntern group 1 by obj.GetType()) on g.Key equals g2.Key
orderby g.Key.FullName
select new { Type = g.Key, PreCount = g.Count(), PostCount = g2.Count() };
foreach (var element in stats) {
Console.WriteLine(element.Type + ": " + element.PostCount + "/" + element.PreCount);
}
}
}
}

1
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -141,6 +141,7 @@ @@ -141,6 +141,7 @@
<Compile Include="CSharp\Parser\mcs\roottypes.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeSystem\Accessibility.cs" />
<Compile Include="TypeSystem\AmbiguousType.cs" />
<Compile Include="TypeSystem\ArrayType.cs" />
<Compile Include="TypeSystem\ByReferenceType.cs" />
<Compile Include="TypeSystem\CecilLoader.cs" />

40
ICSharpCode.NRefactory/TypeSystem/AmbiguousType.cs

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@

using System;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{
/// <summary>
/// Represents an ambiguous type (same type found in multiple locations).
/// </summary>
public class AmbiguousType : AbstractType
{
readonly string name;
public AmbiguousType(string name)
{
if (name == null)
throw new ArgumentNullException("name");
this.name = name;
}
public override string Name {
get { return name; }
}
public override bool? IsReferenceType {
get { return null; }
}
public override int GetHashCode()
{
return name.GetHashCode() ^ 12661218;
}
public override bool Equals(IType other)
{
AmbiguousType at = other as AmbiguousType;
return at != null && name == at.name;
}
}
}

18
ICSharpCode.NRefactory/TypeSystem/ArrayType.cs

@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
}
public class ArrayTypeReference : ITypeReference
public class ArrayTypeReference : ITypeReference, ISupportsInterning
{
ITypeReference elementType;
int dimensions;
@ -117,5 +117,21 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -117,5 +117,21 @@ namespace ICSharpCode.NRefactory.TypeSystem
else
return new ArrayTypeReference(elementType, dimensions);
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
elementType = provider.Intern(elementType);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ dimensions;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ArrayTypeReference o = other as ArrayTypeReference;
return o != null && elementType == o.elementType && dimensions == o.dimensions;
}
}
}

42
ICSharpCode.NRefactory/TypeSystem/ConstructedType.cs

@ -21,7 +21,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -21,7 +21,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <see cref="GenericReturnType"/>s are replaced with the return types in the
/// type arguments collection.
/// </remarks>
public class ConstructedType : Immutable, IType
public sealed class ConstructedType : Immutable, IType
{
sealed class Substitution : TypeVisitor
{
@ -290,7 +290,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -290,7 +290,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// ConstructedTypeReference is a reference to generic class that specifies the type parameters.
/// Example: List&lt;string&gt;
/// </summary>
public class ConstructedTypeReference : ITypeReference
public sealed class ConstructedTypeReference : ITypeReference, ISupportsInterning
{
public static ITypeReference Create(ITypeReference genericType, IEnumerable<ITypeReference> typeArguments)
{
@ -311,8 +311,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -311,8 +311,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
}
readonly ITypeReference genericType;
readonly ITypeReference[] typeArguments;
ITypeReference genericType;
ITypeReference[] typeArguments;
public ConstructedTypeReference(ITypeReference genericType, IEnumerable<ITypeReference> typeArguments)
{
@ -370,5 +370,39 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -370,5 +370,39 @@ namespace ICSharpCode.NRefactory.TypeSystem
b.Append(']');
return b.ToString();
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
genericType = provider.Intern(genericType);
for (int i = 0; i < typeArguments.Length; i++) {
typeArguments[i] = provider.Intern(typeArguments[i]);
}
}
int ISupportsInterning.GetHashCodeForInterning()
{
int hashCode = genericType.GetHashCode();
unchecked {
foreach (ITypeReference t in typeArguments) {
hashCode *= 27;
hashCode += t.GetHashCode();
}
}
return hashCode;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ConstructedTypeReference o = other as ConstructedTypeReference;
if (o != null && genericType == o.genericType && typeArguments.Length == o.typeArguments.Length) {
for (int i = 0; i < typeArguments.Length; i++) {
if (typeArguments[i] != o.typeArguments[i])
return false;
}
return true;
}
return false;
}
}
}

4
ICSharpCode.NRefactory/TypeSystem/DomRegion.cs

@ -61,8 +61,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -61,8 +61,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
public DomRegion(string fileName, int beginLine, int beginColumn, int endLine, int endColumn)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
this.fileName = fileName;
this.beginLine = beginLine;
this.beginColumn = beginColumn;
@ -72,8 +70,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -72,8 +70,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
public DomRegion(string fileName, int beginLine, int beginColumn)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
this.fileName = fileName;
this.beginLine = beginLine;
this.beginColumn = beginColumn;

24
ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs

@ -10,37 +10,27 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -10,37 +10,27 @@ namespace ICSharpCode.NRefactory.TypeSystem
[ContractClass(typeof(IInterningProviderContract))]
public interface IInterningProvider
{
/// <summary>
/// Intern the specified string.
/// </summary>
string InternString(string s);
/// <summary>
/// Interns the specified object.
/// The object must implement <see cref="ISupportsInterning"/>, otherwise it will be returned without being interned.
/// The object must implement <see cref="ISupportsInterning"/>, or must be of one of the types
/// known to the interning provider to use value equality,
/// otherwise it will be returned without being interned.
/// </summary>
T InternObject<T>(T obj);
T Intern<T>(T obj) where T : class;
IList<T> InternObjectList<T>(IList<T> list);
IList<T> InternList<T>(IList<T> list) where T : class;
}
[ContractClassFor(typeof(IInterningProvider))]
abstract class IInterningProviderContract : IInterningProvider
{
string IInterningProvider.InternString(string s)
{
Contract.Ensures((Contract.Result<string>() == null) == (s == null));
Contract.Ensures(string.IsNullOrEmpty(Contract.Result<string>()) == string.IsNullOrEmpty(s));
return s;
}
T IInterningProvider.InternObject<T>(T obj)
T IInterningProvider.Intern<T>(T obj)
{
Contract.Ensures((Contract.Result<T>() == null) == (obj == null));
return obj;
}
IList<T> IInterningProvider.InternObjectList<T>(IList<T> list)
IList<T> IInterningProvider.InternList<T>(IList<T> list)
{
Contract.Ensures((Contract.Result<IList<T>>() == null) == (list == null));
return list;

4
ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs

@ -11,7 +11,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -11,7 +11,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Interface for DOM objects that support interning.
/// </summary>
[ContractClass(typeof(ISupportsInterningContract))]
public interface ISupportsInterning : IFreezable
public interface ISupportsInterning
{
/// <summary>
/// Interns child objects and strings.
@ -30,7 +30,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -30,7 +30,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
[ContractClassFor(typeof(ISupportsInterning))]
abstract class ISupportsInterningContract : IFreezableContract, ISupportsInterning
abstract class ISupportsInterningContract : ISupportsInterning
{
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{

8
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs

@ -55,6 +55,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -55,6 +55,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
throw new InvalidOperationException("Cannot mutate frozen " + GetType().Name);
}
protected static IList<T> CopyList<T>(IList<T> inputList)
{
if (inputList.Count == 0)
return null;
else
return new List<T>(inputList);
}
protected static IList<T> FreezeList<T>(IList<T> list) where T : IFreezable
{
if (list == null || list.Count == 0)

8
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs

@ -76,14 +76,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -76,14 +76,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.IsStatic = member.IsStatic;
}
protected static IList<T> CopyList<T>(IList<T> inputList)
{
if (inputList.Count == 0)
return null;
else
return new List<T>(inputList);
}
public ITypeDefinition DeclaringTypeDefinition {
get { return declaringTypeDefinition; }
}

19
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary>
/// Default implementation of <see cref="IAttribute"/>.
/// </summary>
public sealed class DefaultAttribute : AbstractFreezable, IAttribute
public sealed class DefaultAttribute : AbstractFreezable, IAttribute, ISupportsInterning
{
DomRegion region;
ITypeReference attributeType;
@ -76,5 +76,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -76,5 +76,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
return "[" + attributeType + "]";
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
attributeType = provider.Intern(attributeType);
positionalArguments = provider.InternList(positionalArguments);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return attributeType.GetHashCode() ^ (positionalArguments != null ? positionalArguments.GetHashCode() : 0) ^ (namedArguments != null ? namedArguments.GetHashCode() : 0);
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
DefaultAttribute a = other as DefaultAttribute;
return a != null && attributeType == a.attributeType && positionalArguments == a.positionalArguments && namedArguments == a.namedArguments;
}
}
}

11
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs

@ -37,7 +37,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -37,7 +37,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
this.name = p.Name;
this.type = p.Type;
this.attributes = p.Attributes;
this.attributes = CopyList(p.Attributes);
this.defaultValue = p.DefaultValue;
this.region = p.Region;
this.IsRef = p.IsRef;
@ -140,11 +140,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -140,11 +140,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
CheckBeforeMutation();
name = provider.InternString(name);
type = provider.InternObject(type);
attributes = provider.InternObjectList(attributes);
defaultValue = provider.InternObject(defaultValue);
name = provider.Intern(name);
type = provider.Intern(type);
attributes = provider.InternList(attributes);
defaultValue = provider.Intern(defaultValue);
}
int ISupportsInterning.GetHashCodeForInterning()

18
ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs

@ -8,7 +8,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -8,7 +8,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary>
/// Type Reference used when the fully qualified type name is known.
/// </summary>
public class GetClassTypeReference : ITypeReference
public sealed class GetClassTypeReference : ITypeReference, ISupportsInterning
{
string fullTypeName;
int typeParameterCount;
@ -35,5 +35,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -35,5 +35,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
else
return fullTypeName + "`" + typeParameterCount;
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
fullTypeName = provider.Intern(fullTypeName);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return fullTypeName.GetHashCode() ^ typeParameterCount;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
GetClassTypeReference o = other as GetClassTypeReference;
return o != null && fullTypeName == o.fullTypeName && typeParameterCount == o.typeParameterCount;
}
}
}

19
ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs

@ -8,7 +8,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -8,7 +8,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary>
/// Type reference used to reference nested types.
/// </summary>
public class NestedTypeReference : ITypeReference
public sealed class NestedTypeReference : ITypeReference, ISupportsInterning
{
ITypeReference baseTypeRef;
string name;
@ -49,5 +49,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -49,5 +49,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
else
return baseTypeRef + "+" + name + "`" + additionalTypeParameterCount;
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
baseTypeRef = provider.Intern(baseTypeRef);
name = provider.Intern(name);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return baseTypeRef.GetHashCode() ^ name.GetHashCode() ^ additionalTypeParameterCount;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
NestedTypeReference o = other as NestedTypeReference;
return o != null && baseTypeRef == o.baseTypeRef && name == o.name && additionalTypeParameterCount == o.additionalTypeParameterCount;
}
}
}

23
ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleConstantValue.cs

@ -8,10 +8,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -8,10 +8,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary>
/// A simple constant value that is independent of the resolve context.
/// </summary>
public sealed class SimpleConstantValue : Immutable, IConstantValue
public sealed class SimpleConstantValue : Immutable, IConstantValue, ISupportsInterning
{
readonly ITypeReference type;
readonly object value;
ITypeReference type;
object value;
public SimpleConstantValue(ITypeReference type, object value)
{
@ -41,5 +41,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -41,5 +41,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
else
return value.ToString();
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
type = provider.Intern(type);
value = provider.Intern(value);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return type.GetHashCode() ^ (value != null ? value.GetHashCode() : 0);
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
SimpleConstantValue scv = other as SimpleConstantValue;
return scv != null && type == scv.type && value == scv.value;
}
}
}

Loading…
Cancel
Save