-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathTypeInfo.cs
150 lines (127 loc) · 5.07 KB
/
TypeInfo.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using static Arenas.TypeHandle;
namespace Arenas {
public unsafe class TypeInfo {
public Type Type { get; private set; }
public TypeHandle Handle { get; private set; }
public int Size { get; private set; }
public IArenaMethods ArenaContentsMethods { get; private set; }
public bool IsArenaContents { get { return ArenaContentsMethods != null; } }
private Func<IntPtr, string> toStringFunc;
private Func<IntPtr, int> getHashCodeFunc;
private Func<IntPtr, object> ptrToStructFunc;
internal TypeInfo(Type type, TypeHandle handle, int size, Func<IntPtr, string> toStringFunc, Func<IntPtr, int> getHashCodeFunc, Func<IntPtr, object> ptrToStructFunc) {
Type = type;
Handle = handle;
Size = size;
this.toStringFunc = toStringFunc;
this.getHashCodeFunc = getHashCodeFunc;
this.ptrToStructFunc = ptrToStructFunc;
}
public string ToString(IntPtr instance) {
return toStringFunc(instance);
}
public int GetHashCode(IntPtr instance) {
return getHashCodeFunc(instance);
}
public object PtrToStruct(IntPtr instance) {
return ptrToStructFunc(instance);
}
public bool TryFree(IntPtr instance) {
if (ArenaContentsMethods == null) return false;
ArenaContentsMethods.Free(instance);
return true;
}
public bool TrySetArenaID(IntPtr instance, ArenaID id) {
if (ArenaContentsMethods == null) return false;
ArenaContentsMethods.SetArenaID(instance, id);
return true;
}
public override string ToString() {
return $"TypeInfo({Type})";
}
#region Static
private static Dictionary<TypeHandle, TypeInfo> handleToInfo;
private static object handleLock;
private static Dictionary<Type, TypeInfo> typeToInfo;
private static object typeLock;
static TypeInfo() {
handleToInfo = new Dictionary<TypeHandle, TypeInfo>();
handleLock = new object();
typeToInfo = new Dictionary<Type, TypeInfo>();
typeLock = new object();
}
private static string ToStringFromPtr<T>(IntPtr ptr) where T : unmanaged {
var inst = (T*)ptr;
return inst->ToString();
}
private static int GetHashCodeFromPtr<T>(IntPtr ptr) where T : unmanaged {
var inst = (T*)ptr;
return inst->GetHashCode();
}
private static object CloneFromPtr<T>(IntPtr ptr) where T : unmanaged {
var inst = (T*)ptr;
return *inst;
}
public static TypeInfo GenerateTypeInfo<T>() where T : unmanaged {
Type type = typeof(T);
TypeInfo info;
lock (typeLock) {
if (!typeToInfo.TryGetValue(type, out info)) {
info = new TypeInfo(type, GetTypeHandle(type), sizeof(T),
ToStringFromPtr<T>, GetHashCodeFromPtr<T>, CloneFromPtr<T>);
if (typeof(IArenaContents).IsAssignableFrom(type)) {
var inst = default(T);
if (inst is IArenaContents) {
info.ArenaContentsMethods = ((IArenaContents)inst).ArenaMethods;
}
}
typeToInfo[type] = info;
handleToInfo[GetTypeHandle(typeof(T))] = info;
}
}
return info;
}
public static bool TryGetTypeInfo(TypeHandle handle, out TypeInfo info) {
lock (handleLock) {
if (!handleToInfo.TryGetValue(handle, out info)) {
return false;
}
}
return true;
}
public static TypeInfo GetTypeInfo(TypeHandle handle) {
TypeInfo result;
if (!TryGetTypeInfo(handle, out result)) {
Type type;
if (!TypeHandle.TryGetTypeFromHandle(handle, out type)) {
throw new KeyNotFoundException("No TypeInfo for handle to unknown type");
}
else {
throw new KeyNotFoundException($"No TypeInfo for handle to type {type}");
}
}
return result;
}
public static bool TryGetTypeInfo(Type type, out TypeInfo info) {
lock (typeLock) {
if (!typeToInfo.TryGetValue(type, out info)) {
return false;
}
}
return true;
}
public static TypeInfo GetTypeInfo(Type type) {
TypeInfo result;
if (!TryGetTypeInfo(type, out result)) {
throw new KeyNotFoundException($"No TypeInfo for type {type}");
}
return result;
}
#endregion
}
}