mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-12 22:10:11 -05:00
Merge pull request #1864 from ousttrue/fix/cacheedenum_static_type_caching
素直な static type caching 技法になるように書き直し
This commit is contained in:
@@ -2,26 +2,47 @@
|
||||
|
||||
namespace UniGLTF.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// CachedEnumType<T> に対するインターフェース。
|
||||
/// 非 Generic class
|
||||
/// </summary>
|
||||
public static class CachedEnum
|
||||
{
|
||||
public static T Parse<T>(string name, bool ignoreCase = false) where T : struct, Enum
|
||||
{
|
||||
return CachedEnumType<T>.Parse(name, ignoreCase);
|
||||
if (ignoreCase)
|
||||
{
|
||||
return CachedEnumType<T>.IgnoreCaseMap[name];
|
||||
}
|
||||
else
|
||||
{
|
||||
return CachedEnumType<T>.Map[name];
|
||||
}
|
||||
}
|
||||
|
||||
public static T TryParseOrDefault<T>(string name, bool ignoreCase = false, T defaultValue = default)
|
||||
public static T ParseOrDefault<T>(string name, bool ignoreCase = false, T defaultValue = default)
|
||||
where T : struct, Enum
|
||||
{
|
||||
try
|
||||
{
|
||||
return Parse<T>(name, ignoreCase: ignoreCase);
|
||||
}
|
||||
catch
|
||||
catch (System.Collections.Generic.KeyNotFoundException)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// bool を返して out 変数に結果を返すのが TryXXX なので、Try ではない。
|
||||
/// </summary>
|
||||
[Obsolete("use ParseOrDefault")]
|
||||
public static T TryParseOrDefault<T>(string name, bool ignoreCase = false, T defaultValue = default)
|
||||
where T : struct, Enum
|
||||
{
|
||||
return ParseOrDefault<T>(name, ignoreCase: ignoreCase);
|
||||
}
|
||||
|
||||
public static T[] GetValues<T>() where T : struct, Enum
|
||||
{
|
||||
return CachedEnumType<T>.Values;
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace UniGLTF.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// enum T に対する static type caching 。
|
||||
///
|
||||
/// CachedEnumType<T>.Values
|
||||
/// CachedEnumType<T>.Map
|
||||
/// CachedEnumType<T>.IgnoreCaseMap
|
||||
///
|
||||
/// がスレッドセーフに(キャッシュされた)同じ値を返す。
|
||||
/// </summary>
|
||||
internal static class CachedEnumType<T> where T : struct, Enum
|
||||
{
|
||||
private static readonly Dictionary<string, T> _values = new Dictionary<string, T>();
|
||||
private static readonly Dictionary<string, T> _ignoreCaseValues = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
|
||||
private static T[] _allValues;
|
||||
public static IReadOnlyDictionary<string, T> Map { get; } = CreateStringEnumMap(false);
|
||||
public static IReadOnlyDictionary<string, T> IgnoreCaseMap { get; } = CreateStringEnumMap(true);
|
||||
public static T[] Values { get; } = (T[])Enum.GetValues(typeof(T));
|
||||
|
||||
public static T[] Values
|
||||
private static Dictionary<string, T> CreateStringEnumMap(bool ignoreCase)
|
||||
{
|
||||
get
|
||||
var dict = ignoreCase
|
||||
? new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase)
|
||||
: new Dictionary<string, T>()
|
||||
;
|
||||
|
||||
// ここで Values を使うと
|
||||
// System.TypeInitializationException
|
||||
// が起きる。
|
||||
// static 変数初期化中に別の static 変数を参照すると未初期化がありえるぽい(初期化順?)
|
||||
foreach (T value in Enum.GetValues(typeof(T)))
|
||||
{
|
||||
if (_allValues == null)
|
||||
{
|
||||
_allValues = Enum.GetValues(typeof(T)) as T[];
|
||||
}
|
||||
|
||||
return _allValues;
|
||||
dict.Add(value.ToString(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public static T Parse(string name, bool ignoreCase)
|
||||
{
|
||||
var caches = ignoreCase ? _ignoreCaseValues : _values;
|
||||
|
||||
if (caches.TryGetValue(name, out var ignoreCaseValue))
|
||||
{
|
||||
return ignoreCaseValue;
|
||||
}
|
||||
|
||||
if (Enum.TryParse<T>(name, ignoreCase, out var result))
|
||||
{
|
||||
caches.Add(name, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new ArgumentException(name);
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -12,6 +13,7 @@ namespace UniGLTF
|
||||
{
|
||||
Assert.AreEqual(default(HumanBodyBones), CachedEnum.TryParseOrDefault<HumanBodyBones>("xxx"));
|
||||
Assert.AreEqual(HumanBodyBones.UpperChest, CachedEnum.TryParseOrDefault<HumanBodyBones>("upperchest", true));
|
||||
Assert.AreEqual(CachedEnum.GetValues<HumanBodyBones>().First(x => x == HumanBodyBones.Hips), HumanBodyBones.Hips);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user