fix(core): Fixes type caching & cleanup (#422)
- [X] Fixes some issues with the type caching - [X] Changes type check default to ignore case - [X] Splits out type caching of insensitive and sensitive lists. This means less stuff to iterate through when checking a type against the string. - [X] Adds an ArrayEnumerator, mostly for reference purposes (copy/paste as needed)
This commit is contained in:
parent
b921c38879
commit
e869c105d0
35 changed files with 253 additions and 96 deletions
|
|
@ -90,35 +90,32 @@ namespace Server
|
|||
return m_TypeCaches[asm] = new TypeCache(asm);
|
||||
}
|
||||
|
||||
private static bool IgnoreCaseTypeComparer(string name, Type type) =>
|
||||
type.FullName.InsensitiveEquals(name) || type.Name.InsensitiveEquals(name);
|
||||
|
||||
private static bool CaseTypeComparer(string name, Type type) =>
|
||||
type.FullName.EqualsOrdinal(name) || type.Name.EqualsOrdinal(name);
|
||||
|
||||
public static Type FindFirstTypeForName(string name, bool ignoreCase = false, Func<string, Type, bool> predicate = null)
|
||||
public static Type FindTypeByFullName(string name, bool ignoreCase = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var types = FindTypesByName(name, ignoreCase);
|
||||
|
||||
if (types.Count == 0)
|
||||
if (ignoreCase)
|
||||
{
|
||||
return null;
|
||||
name = name.ToLower();
|
||||
}
|
||||
|
||||
// Try to find the closest match if there is no predicate.
|
||||
// Check for exact match of the FullName or Name
|
||||
// Then check for case-insensitive match of FullName or Name
|
||||
// Otherwise just return the first entry
|
||||
predicate ??= ignoreCase ? IgnoreCaseTypeComparer : CaseTypeComparer;
|
||||
|
||||
foreach (var type in types)
|
||||
for (var i = 0; i < Assemblies.Length; i++)
|
||||
{
|
||||
if (predicate(name, type))
|
||||
foreach (var type in GetTypeCache(Assemblies[i]).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
if (type.FullName.EqualsOrdinal(name))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var type in GetTypeCache(Core.Assembly).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
if (type.FullName.EqualsOrdinal(name))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
|
@ -127,7 +124,36 @@ namespace Server
|
|||
return null;
|
||||
}
|
||||
|
||||
public static List<Type> FindTypesByName(string name, bool ignoreCase = false)
|
||||
public static Type FindTypeByName(string name, bool ignoreCase = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ignoreCase)
|
||||
{
|
||||
name = name.ToLower();
|
||||
}
|
||||
|
||||
for (var i = 0; i < Assemblies.Length; i++)
|
||||
{
|
||||
foreach (var type in GetTypeCache(Assemblies[i]).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var type in GetTypeCache(Core.Assembly).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Change to IEnumerable using another custom enumerator
|
||||
public static List<Type> FindTypesByFullName(string name, bool ignoreCase = true)
|
||||
{
|
||||
var types = new List<Type>();
|
||||
|
||||
|
|
@ -138,20 +164,49 @@ namespace Server
|
|||
|
||||
for (var i = 0; i < Assemblies.Length; i++)
|
||||
{
|
||||
foreach (var type in GetTypeCache(Assemblies[i])[name])
|
||||
foreach (var type in GetTypeCache(Assemblies[i]).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
if (type.FullName.EqualsOrdinal(name))
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var type in GetTypeCache(Core.Assembly).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
if (type.FullName.EqualsOrdinal(name))
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (types.Count == 0)
|
||||
return types;
|
||||
}
|
||||
|
||||
// TODO: Change to IEnumerable using another custom enumerator
|
||||
public static List<Type> FindTypesByName(string name, bool ignoreCase = true)
|
||||
{
|
||||
var types = new List<Type>();
|
||||
|
||||
if (ignoreCase)
|
||||
{
|
||||
foreach(var type in GetTypeCache(Core.Assembly)[name])
|
||||
name = name.ToLower();
|
||||
}
|
||||
|
||||
for (var i = 0; i < Assemblies.Length; i++)
|
||||
{
|
||||
foreach (var type in GetTypeCache(Assemblies[i]).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var type in GetTypeCache(Core.Assembly).GetEnumerator(name, ignoreCase))
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
|
|
@ -166,52 +221,64 @@ namespace Server
|
|||
|
||||
public class TypeCache
|
||||
{
|
||||
private readonly Dictionary<string, int[]> m_NameMap = new();
|
||||
private readonly Dictionary<string, int[]> _nameMap = new();
|
||||
private readonly Dictionary<string, int[]> _nameMapInsensitive = new();
|
||||
|
||||
public TypeCache(Assembly asm)
|
||||
{
|
||||
Types = asm?.GetTypes() ?? Type.EmptyTypes;
|
||||
|
||||
var nameMap = new Dictionary<string, HashSet<int>>();
|
||||
HashSet<int> refs;
|
||||
Action<int, string> addToRefs = (index, key) =>
|
||||
var nameMapInsensitive = new Dictionary<string, HashSet<int>>();
|
||||
|
||||
void addToRefs(int index, string key, Dictionary<string, HashSet<int>> map)
|
||||
{
|
||||
if (nameMap.TryGetValue(key, out refs))
|
||||
if (key == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (map.TryGetValue(key, out var refs))
|
||||
{
|
||||
refs.Add(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
refs = new HashSet<int> { index };
|
||||
nameMap.Add(key, refs);
|
||||
map.Add(key, refs);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var aliasType = typeof(TypeAliasAttribute);
|
||||
for (var i = 0; i < Types.Length; i++)
|
||||
{
|
||||
var current = Types[i];
|
||||
addToRefs(i, current.Name);
|
||||
addToRefs(i, current.Name.ToLower());
|
||||
addToRefs(i, current.FullName);
|
||||
addToRefs(i, current.FullName?.ToLower());
|
||||
addToRefs(i, current.Name, nameMap);
|
||||
addToRefs(i, current.Name.ToLower(), nameMapInsensitive);
|
||||
addToRefs(i, current.FullName, nameMap);
|
||||
addToRefs(i, current.FullName?.ToLower(), nameMapInsensitive);
|
||||
if (current.GetCustomAttribute(aliasType, false) is TypeAliasAttribute alias)
|
||||
{
|
||||
for (var j = 0; j < alias.Aliases.Length; j++)
|
||||
{
|
||||
addToRefs(i, alias.Aliases[j]);
|
||||
addToRefs(i, alias.Aliases[j].ToLower());
|
||||
addToRefs(i, alias.Aliases[j], nameMap);
|
||||
addToRefs(i, alias.Aliases[j], nameMapInsensitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (key, value) in nameMap)
|
||||
{
|
||||
m_NameMap[key] = value.ToArray();
|
||||
_nameMap[key] = value.ToArray();
|
||||
}
|
||||
|
||||
foreach (var (key, value) in nameMapInsensitive)
|
||||
{
|
||||
_nameMapInsensitive[key] = value.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public Enumerator this[string name] => new(name, this);
|
||||
public Enumerator GetEnumerator(string name, bool ignoreCase) => new(name, this, ignoreCase);
|
||||
|
||||
public Type[] Types { get; }
|
||||
|
||||
|
|
@ -222,10 +289,12 @@ namespace Server
|
|||
private int _index;
|
||||
private Type _current;
|
||||
|
||||
internal Enumerator(string name, TypeCache cache)
|
||||
internal Enumerator(string name, TypeCache cache, bool ignoreCase)
|
||||
{
|
||||
_cache = cache;
|
||||
_values = !cache.m_NameMap.TryGetValue(name, out var values) ? Array.Empty<int>() : values;
|
||||
|
||||
var map = ignoreCase ? _cache._nameMap : _cache._nameMapInsensitive;
|
||||
_values = map.TryGetValue(name, out var values) ? values : Array.Empty<int>();
|
||||
_index = 0;
|
||||
_current = default;
|
||||
}
|
||||
|
|
@ -274,7 +343,7 @@ namespace Server
|
|||
|
||||
public IEnumerator<Type> GetEnumerator() => this;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue