com.wallstop-studios.unity-helpers 2.0.0-rc80.3 → 2.0.0-rc80.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,142 +12,60 @@ namespace WallstopStudios.UnityHelpers.Core.Extension
12
12
  public static class EnumNameCache<T>
13
13
  where T : struct, Enum
14
14
  {
15
- private const int MaxDenseRange = 1024;
16
-
17
- private static readonly bool UseDensePacking;
18
- private static readonly int Min;
19
- private static readonly string[] DenseNames;
20
- private static readonly Dictionary<int, string> SparseNames;
15
+ private static readonly Dictionary<T, string> Names;
21
16
 
22
17
  static EnumNameCache()
23
18
  {
24
- T[] values = Enum.GetValues(typeof(T)).Cast<T>().ToArray();
25
- int[] intValues = values.Select(v => Unsafe.As<T, int>(ref v)).ToArray();
26
- int min = intValues.Min();
27
- int max = intValues.Max();
28
- int range = max - min + 1;
29
-
30
- if (range <= MaxDenseRange)
31
- {
32
- UseDensePacking = true;
33
- Min = min;
34
- DenseNames = new string[range];
35
-
36
- for (int i = 0; i < values.Length; i++)
37
- {
38
- int key = intValues[i] - min;
39
- T value = values[i];
40
- DenseNames[key] = value.ToString("G");
41
- }
42
- }
43
- else
19
+ T[] values = Enum.GetValues(typeof(T)).OfType<T>().ToArray();
20
+ Names = new Dictionary<T, string>(values.Length);
21
+ for (int i = 0; i < values.Length; i++)
44
22
  {
45
- UseDensePacking = false;
46
- SparseNames = new Dictionary<int, string>();
47
- for (int i = 0; i < values.Length; i++)
48
- {
49
- int key = Unsafe.As<T, int>(ref values[i]);
50
- T value = values[i];
51
- string name = value.ToString("G");
52
- SparseNames.TryAdd(key, name);
53
- }
23
+ T value = values[i];
24
+ string name = value.ToString("G");
25
+ Names.TryAdd(value, name);
54
26
  }
55
27
  }
56
28
 
57
29
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
58
30
  public static string ToCachedName(T value)
59
31
  {
60
- int key = Unsafe.As<T, int>(ref value);
61
- if (UseDensePacking)
32
+ if (Names.TryGetValue(value, out string name))
62
33
  {
63
- int idx = key - Min;
64
- if ((uint)idx < (uint)DenseNames!.Length)
65
- {
66
- return DenseNames[idx];
67
- }
68
- }
69
- else
70
- {
71
- if (SparseNames!.TryGetValue(key, out string name))
72
- {
73
- return name;
74
- }
34
+ return name;
75
35
  }
76
36
 
77
- return value.ToString();
37
+ return value.ToString("G");
78
38
  }
79
39
  }
80
40
 
81
41
  public static class EnumDisplayNameCache<T>
82
42
  where T : struct, Enum
83
43
  {
84
- private const int MaxDenseRange = 1024;
85
-
86
- private static readonly bool UseDensePacking;
87
- private static readonly int Min;
88
- private static readonly string[] DenseNames;
89
- private static readonly Dictionary<int, string> SparseNames;
44
+ private static readonly Dictionary<T, string> Names;
90
45
 
91
46
  static EnumDisplayNameCache()
92
47
  {
93
48
  Type type = typeof(T);
94
49
  FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Static);
95
- T[] values = fields.Select(f => (T)f.GetValue(null)).ToArray();
96
- int[] intValues = values.Select(v => Unsafe.As<T, int>(ref v)).ToArray();
97
- int min = intValues.Min();
98
- int max = intValues.Max();
99
- int range = max - min + 1;
50
+ Names = new Dictionary<T, string>(fields.Length);
100
51
 
101
- if (range <= MaxDenseRange)
52
+ for (int i = 0; i < fields.Length; i++)
102
53
  {
103
- UseDensePacking = true;
104
- Min = min;
105
- DenseNames = new string[range];
106
-
107
- for (int i = 0; i < fields.Length; i++)
108
- {
109
- int key = intValues[i] - min;
110
- FieldInfo field = fields[i];
111
- string name = field.IsAttributeDefined(out EnumDisplayNameAttribute displayName)
112
- ? displayName.DisplayName
113
- : field.Name;
114
- DenseNames[key] = name;
115
- }
116
- }
117
- else
118
- {
119
- UseDensePacking = false;
120
- SparseNames = new Dictionary<int, string>(fields.Length);
121
- for (int i = 0; i < fields.Length; i++)
122
- {
123
- int key = Unsafe.As<T, int>(ref values[i]);
124
- FieldInfo field = fields[i];
125
- string name = field.IsAttributeDefined(out EnumDisplayNameAttribute displayName)
126
- ? displayName.DisplayName
127
- : field.Name;
128
- SparseNames.TryAdd(key, name);
129
- }
54
+ FieldInfo field = fields[i];
55
+ string name = field.IsAttributeDefined(out EnumDisplayNameAttribute displayName)
56
+ ? displayName.DisplayName
57
+ : field.Name;
58
+ T value = (T)field.GetValue(null);
59
+ Names.TryAdd(value, name);
130
60
  }
131
61
  }
132
62
 
133
63
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
134
64
  public static string ToDisplayName(T value)
135
65
  {
136
- int key = Unsafe.As<T, int>(ref value);
137
- if (UseDensePacking)
66
+ if (Names.TryGetValue(value, out string name))
138
67
  {
139
- int idx = key - Min;
140
- if ((uint)idx < (uint)DenseNames!.Length)
141
- {
142
- return DenseNames[idx];
143
- }
144
- }
145
- else
146
- {
147
- if (SparseNames!.TryGetValue(key, out string name))
148
- {
149
- return name;
150
- }
68
+ return name;
151
69
  }
152
70
 
153
71
  return value.ToString();
@@ -160,9 +78,15 @@ namespace WallstopStudios.UnityHelpers.Core.Extension
160
78
  public static bool HasFlagNoAlloc<T>(this T value, T flag)
161
79
  where T : unmanaged, Enum
162
80
  {
163
- ulong valueUnderlying = GetUInt64(value);
164
- ulong flagUnderlying = GetUInt64(flag);
165
- return (valueUnderlying & flagUnderlying) == flagUnderlying;
81
+ ulong? valueUnderlying = GetUInt64(value);
82
+ ulong? flagUnderlying = GetUInt64(flag);
83
+ if (valueUnderlying == null || flagUnderlying == null)
84
+ {
85
+ // Fallback for unsupported enum sizes
86
+ return value.HasFlag(flag);
87
+ }
88
+
89
+ return (valueUnderlying.Value & flagUnderlying.Value) == flagUnderlying.Value;
166
90
  }
167
91
 
168
92
  public static string ToDisplayName<T>(this T value)
@@ -190,23 +114,24 @@ namespace WallstopStudios.UnityHelpers.Core.Extension
190
114
  }
191
115
 
192
116
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
193
- private static unsafe ulong GetUInt64<T>(T value)
117
+ private static ulong? GetUInt64<T>(T value)
194
118
  where T : unmanaged
195
119
  {
196
- /*
197
- Works because T is constrained to unmanaged, so it's safe to reinterpret
198
- All enums are value types and have a fixed size
199
- */
200
- return sizeof(T) switch
120
+ try
201
121
  {
202
- 1 => *(byte*)&value,
203
- 2 => *(ushort*)&value,
204
- 4 => *(uint*)&value,
205
- 8 => *(ulong*)&value,
206
- _ => throw new ArgumentException(
207
- $"Unsupported enum size: {sizeof(T)} for type {typeof(T)}"
208
- ),
209
- };
122
+ return Unsafe.SizeOf<T>() switch
123
+ {
124
+ 1 => Unsafe.As<T, byte>(ref value),
125
+ 2 => Unsafe.As<T, ushort>(ref value),
126
+ 4 => Unsafe.As<T, uint>(ref value),
127
+ 8 => Unsafe.As<T, ulong>(ref value),
128
+ _ => null,
129
+ };
130
+ }
131
+ catch
132
+ {
133
+ return null;
134
+ }
210
135
  }
211
136
  }
212
137
  }
@@ -56,7 +56,7 @@ namespace WallstopStudios.UnityHelpers.Core.Helper
56
56
  {
57
57
  if (ObjectsByTag.TryGetValue(tag, out Object value))
58
58
  {
59
- if (value != null && value is T typed)
59
+ if (value is T typed && typed != null)
60
60
  {
61
61
  return typed;
62
62
  }
@@ -166,7 +166,7 @@ namespace WallstopStudios.UnityHelpers.Core.Helper
166
166
  for (int i = 0; i < transform.childCount; ++i)
167
167
  {
168
168
  Transform child = transform.GetChild(i);
169
- EnableRecursively<T>(child, enabled, exclude);
169
+ EnableRecursively(child, enabled, exclude);
170
170
  }
171
171
  }
172
172
 
@@ -188,10 +188,14 @@ namespace WallstopStudios.UnityHelpers.Core.Helper
188
188
  behavior.enabled = enabled;
189
189
  }
190
190
 
191
- Transform transform = component as Transform ?? component.transform;
191
+ Transform transform = component as Transform;
192
192
  if (transform == null)
193
193
  {
194
- return;
194
+ transform = component.transform;
195
+ if (transform == null)
196
+ {
197
+ return;
198
+ }
195
199
  }
196
200
 
197
201
  for (int i = 0; i < transform.childCount; ++i)
@@ -280,7 +284,7 @@ namespace WallstopStudios.UnityHelpers.Core.Helper
280
284
  }
281
285
 
282
286
  public static void DestroyAllChildrenGameObjectsImmediately(this GameObject gameObject) =>
283
- InternalDestroyAllChildrenGameObjects(gameObject, Object.DestroyImmediate);
287
+ InternalDestroyAllChildrenGameObjects(gameObject, go => Object.DestroyImmediate(go));
284
288
 
285
289
  public static void PlayDestroyAllChildrenGameObjects(this GameObject gameObject) =>
286
290
  InternalDestroyAllChildrenGameObjects(gameObject, go => go.Destroy());
@@ -301,9 +305,17 @@ namespace WallstopStudios.UnityHelpers.Core.Helper
301
305
 
302
306
  public static bool IsPrefab(this GameObject gameObject)
303
307
  {
308
+ if (gameObject == null)
309
+ {
310
+ return false;
311
+ }
312
+
304
313
  Scene scene = gameObject.scene;
305
314
  #if UNITY_EDITOR
306
- if (scene.rootCount == 1 && string.Equals(scene.name, gameObject.name))
315
+ if (
316
+ scene.rootCount == 1
317
+ && string.Equals(scene.name, gameObject.name, StringComparison.Ordinal)
318
+ )
307
319
  {
308
320
  return true;
309
321
  }
@@ -321,6 +333,11 @@ namespace WallstopStudios.UnityHelpers.Core.Helper
321
333
 
322
334
  public static bool IsPrefab(this Component component)
323
335
  {
336
+ if (component == null)
337
+ {
338
+ return false;
339
+ }
340
+
324
341
  return IsPrefab(component.gameObject);
325
342
  }
326
343
 
@@ -2,6 +2,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Extensions
2
2
  {
3
3
  using NUnit.Framework;
4
4
  using UnityEngine.TestTools.Constraints;
5
+ using WallstopStudios.UnityHelpers.Core.Attributes;
5
6
  using WallstopStudios.UnityHelpers.Core.Extension;
6
7
  using Is = NUnit.Framework.Is;
7
8
 
@@ -26,8 +27,14 @@ namespace WallstopStudios.UnityHelpers.Tests.Extensions
26
27
  private enum SmallTestEnum : short
27
28
  {
28
29
  None = 0,
30
+
31
+ [EnumDisplayName("TestFirst")]
29
32
  First = 1 << 0,
33
+
34
+ [EnumDisplayName("TestSecond")]
30
35
  Second = 1 << 1,
36
+
37
+ [EnumDisplayName("TestThird")]
31
38
  Third = 1 << 2,
32
39
  }
33
40
 
@@ -39,6 +46,24 @@ namespace WallstopStudios.UnityHelpers.Tests.Extensions
39
46
  Third = 1 << 2,
40
47
  }
41
48
 
49
+ [Test]
50
+ public void DisplayName()
51
+ {
52
+ Assert.AreEqual("None", SmallTestEnum.None.ToDisplayName());
53
+ Assert.AreEqual("TestFirst", SmallTestEnum.First.ToDisplayName());
54
+ Assert.AreEqual("TestSecond", SmallTestEnum.Second.ToDisplayName());
55
+ Assert.AreEqual("TestThird", SmallTestEnum.Third.ToDisplayName());
56
+ }
57
+
58
+ [Test]
59
+ public void CachedName()
60
+ {
61
+ Assert.AreEqual("None", SmallTestEnum.None.ToCachedName());
62
+ Assert.AreEqual("First", SmallTestEnum.First.ToCachedName());
63
+ Assert.AreEqual("Second", SmallTestEnum.Second.ToCachedName());
64
+ Assert.AreEqual("Third", SmallTestEnum.Third.ToCachedName());
65
+ }
66
+
42
67
  [Test]
43
68
  public void HasFlagNoAlloc()
44
69
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.wallstop-studios.unity-helpers",
3
- "version": "2.0.0-rc80.3",
3
+ "version": "2.0.0-rc80.5",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},
@@ -54,6 +54,8 @@
54
54
 
55
55
 
56
56
 
57
+
58
+
57
59
 
58
60
 
59
61