forked from dotnet/runtimelab
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request dotnet#2867 from dotnet/TypeMetadataCache
added TypeMetadataCache
- Loading branch information
Showing
5 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Swift.Runtime; | ||
|
||
/// <summary> | ||
/// Represents an interface that defines how a cache for TypeMetadata should operate. | ||
/// The implementation of this interface needs to be thread safe. | ||
/// </summary> | ||
public interface ITypeMetadataCache | ||
{ | ||
/// <summary> | ||
/// Returns true if the cache contains an entry for type and sets metadata to the resulting value, | ||
/// otherwise it returns false and metadata will be null. | ||
/// </summary> | ||
/// <param name="type">The type to look up in the cache</param> | ||
/// <param name="metadata">The resulting metadata if found</param> | ||
/// <returns>true if the lookup was successful, false otherwise</returns> | ||
bool TryGet(Type type, [NotNullWhen(true)]out TypeMetadata? metadata); | ||
|
||
/// <summary> | ||
/// Gets the TypeMetadata for the given Type type or if it is not present, | ||
/// adds it to the cache using the given factory to generate the value. | ||
/// </summary> | ||
/// <param name="type">The type to look up in the cache</param> | ||
/// <param name="metadataFactory">a factory to generate the TypeMetadata if not present</param> | ||
/// <returns>The TypeMetadata associated with the give Type type</returns> | ||
TypeMetadata GetOrAdd(Type type, Func<Type, TypeMetadata> metadataFactory); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Swift.Runtime; | ||
|
||
/// <summary> | ||
/// Internal implementation of ITypeMetadataCache | ||
/// </summary> | ||
internal class TypeMetadataCache : ITypeMetadataCache | ||
{ | ||
readonly ConcurrentDictionary<Type, TypeMetadata> cache = new(); | ||
|
||
/// <summary> | ||
/// Constructs an empty cache. | ||
/// </summary> | ||
public TypeMetadataCache() | ||
{ | ||
|
||
} | ||
|
||
/// <summary> | ||
/// Constructs a cache with the supplied initial values. | ||
/// </summary> | ||
/// <param name="initialValues">An enumeration of tuples of Type and TypeMetadata to initialize the cache</param> | ||
public TypeMetadataCache(IEnumerable<(Type, TypeMetadata)> initialValues) | ||
{ | ||
var dictCache = (IDictionary<Type, TypeMetadata>)cache; | ||
foreach (var (key, value) in initialValues) | ||
{ | ||
dictCache.Add(key, value); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Returns true if the cache contains an entry for type and sets metadata to the resulting value, | ||
/// otherwise it returns false and metadata will be null. | ||
/// </summary> | ||
/// <param name="type">The type to look up in the cache</param> | ||
/// <param name="metadata">The resulting metadata if found</param> | ||
/// <returns>true if the lookup was successful, false otherwise</returns> | ||
public bool TryGet(Type type, [NotNullWhen(true)] out TypeMetadata? metadata) | ||
{ | ||
if (cache.TryGetValue(type, out var md)) | ||
{ | ||
metadata = md; | ||
return true; | ||
} | ||
else | ||
{ | ||
metadata = null; | ||
return false; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Gets the TypeMetadata for the given Type type or if it is not present, | ||
/// adds it to the cache using the given factory to generate the value. | ||
/// </summary> | ||
/// <param name="type">The type to look up in the cache</param> | ||
/// <param name="metadataFactory">a factory to generate the TypeMetadata if not present</param> | ||
/// <returns>The TypeMetadata associated with the give Type type</returns> | ||
public TypeMetadata GetOrAdd(Type type, Func<Type, TypeMetadata> metadataFactory) | ||
{ | ||
return cache.GetOrAdd(type, metadataFactory); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
src/Swift.Runtime/tests/TypeMetadataTests/TypeMetadataTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using Xunit; | ||
using Swift.Runtime; | ||
using System.Reflection; | ||
|
||
namespace BindingsGeneration.Tests; | ||
|
||
public class TypeMetadataTests : IClassFixture<TypeMetadataTests.TestFixture> | ||
{ | ||
private readonly TestFixture _fixture; | ||
|
||
public TypeMetadataTests(TestFixture fixture) | ||
{ | ||
_fixture = fixture; | ||
} | ||
|
||
public class TestFixture | ||
{ | ||
static TestFixture() | ||
{ | ||
} | ||
|
||
private static void InitializeResources() | ||
{ | ||
} | ||
} | ||
|
||
static TypeMetadata MakePhonyMetadata(int value) | ||
{ | ||
IntPtr p = new IntPtr(value); | ||
|
||
var t = typeof(TypeMetadata); | ||
var ci = t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, new Type[] { typeof(IntPtr) })!; | ||
|
||
return (TypeMetadata)(ci.Invoke(new object[] { p })); | ||
} | ||
|
||
[Fact] | ||
public static void CacheWorks() | ||
{ | ||
var fakeMeta = MakePhonyMetadata(42); | ||
TypeMetadata.Cache.GetOrAdd(typeof(System.Convert), (t) => | ||
{ | ||
return fakeMeta; | ||
}); | ||
Assert.True(TypeMetadata.Cache.TryGet(typeof(System.Convert), out var result)); | ||
} | ||
|
||
[Fact] | ||
public static void TryGetFail() | ||
{ | ||
var contains = TypeMetadata.Cache.TryGet(typeof(System.EventArgs), out var result); | ||
Assert.False(contains); | ||
} | ||
|
||
[Fact] | ||
public static void TryGetSucceed() | ||
{ | ||
var fakeMeta = MakePhonyMetadata(43); | ||
TypeMetadata.Cache.GetOrAdd(typeof(System.Random), (t) => | ||
{ | ||
return fakeMeta; | ||
}); | ||
var contains = TypeMetadata.Cache.TryGet(typeof(System.Random), out var result); | ||
Assert.True(contains); | ||
} | ||
} |