summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2024-05-23 10:08:29 +0800
committerchai <215380520@qq.com>2024-05-23 10:08:29 +0800
commit8722a9920c1f6119bf6e769cba270e63097f8e25 (patch)
tree2eaf9865de7fb1404546de4a4296553d8f68cc3b /Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs
parent3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff)
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs')
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs200
1 files changed, 200 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs
new file mode 100644
index 0000000..f7b6300
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs
@@ -0,0 +1,200 @@
+#if !UNITY_EDITOR
+// Extra optimizations when not running in the editor, but less error checking
+#define ASTAR_OPTIMIZE_POOLING
+#endif
+
+using System;
+using System.Collections.Generic;
+
+namespace Pathfinding.Util {
+ /// <summary>
+ /// Lightweight Array Pool.
+ /// Handy class for pooling arrays of type T.
+ ///
+ /// Usage:
+ /// - Claim a new array using <code> SomeClass[] foo = ArrayPool<SomeClass>.Claim (capacity); </code>
+ /// - Use it and do stuff with it
+ /// - Release it with <code> ArrayPool<SomeClass>.Release (ref foo); </code>
+ ///
+ /// Warning: Arrays returned from the Claim method may contain arbitrary data.
+ /// You cannot rely on it being zeroed out.
+ ///
+ /// After you have released a array, you should never use it again, if you do use it
+ /// your code may modify it at the same time as some other code is using it which
+ /// will likely lead to bad results.
+ ///
+ /// Since: Version 3.8.6
+ /// See: Pathfinding.Util.ListPool
+ /// </summary>
+ public static class ArrayPool<T> {
+#if !ASTAR_NO_POOLING
+ /// <summary>
+ /// Maximum length of an array pooled using ClaimWithExactLength.
+ /// Arrays with lengths longer than this will silently not be pooled.
+ /// </summary>
+ const int MaximumExactArrayLength = 256;
+
+ /// <summary>
+ /// Internal pool.
+ /// The arrays in each bucket have lengths of 2^i
+ /// </summary>
+ static readonly Stack<T[]>[] pool = new Stack<T[]>[31];
+ static readonly Stack<T[]>[] exactPool = new Stack<T[]>[MaximumExactArrayLength+1];
+#if !ASTAR_OPTIMIZE_POOLING
+ static readonly HashSet<T[]> inPool = new HashSet<T[]>();
+#endif
+#endif
+
+ /// <summary>
+ /// Returns an array with at least the specified length.
+ /// Warning: Returned arrays may contain arbitrary data.
+ /// You cannot rely on it being zeroed out.
+ ///
+ /// The returned array will always be a power of two, or zero.
+ /// </summary>
+ public static T[] Claim (int minimumLength) {
+ if (minimumLength <= 0) {
+ return ClaimWithExactLength(0);
+ }
+
+ int bucketIndex = 0;
+ while ((1 << bucketIndex) < minimumLength && bucketIndex < 30) {
+ bucketIndex++;
+ }
+
+ if (bucketIndex == 30)
+ throw new System.ArgumentException("Too high minimum length");
+
+#if !ASTAR_NO_POOLING
+ lock (pool) {
+ if (pool[bucketIndex] == null) {
+ pool[bucketIndex] = new Stack<T[]>();
+ }
+
+ if (pool[bucketIndex].Count > 0) {
+ var array = pool[bucketIndex].Pop();
+#if !ASTAR_OPTIMIZE_POOLING
+ inPool.Remove(array);
+#endif
+ return array;
+ }
+ }
+#endif
+ return new T[1 << bucketIndex];
+ }
+
+ /// <summary>
+ /// Returns an array with the specified length.
+ /// Use with caution as pooling too many arrays with different lengths that
+ /// are rarely being reused will lead to an effective memory leak.
+ ///
+ /// Use <see cref="Claim"/> if you just need an array that is at least as large as some value.
+ ///
+ /// Warning: Returned arrays may contain arbitrary data.
+ /// You cannot rely on it being zeroed out.
+ /// </summary>
+ public static T[] ClaimWithExactLength (int length) {
+#if !ASTAR_NO_POOLING
+ bool isPowerOfTwo = length != 0 && (length & (length - 1)) == 0;
+ if (isPowerOfTwo) {
+ // Will return the correct array length
+ return Claim(length);
+ }
+
+ if (length <= MaximumExactArrayLength) {
+ lock (pool) {
+ Stack<T[]> stack = exactPool[length];
+ if (stack != null && stack.Count > 0) {
+ var array = stack.Pop();
+#if !ASTAR_OPTIMIZE_POOLING
+ inPool.Remove(array);
+#endif
+ return array;
+ }
+ }
+ }
+#endif
+ return new T[length];
+ }
+
+ /// <summary>
+ /// Pool an array.
+ /// If the array was got using the <see cref="ClaimWithExactLength"/> method then the allowNonPowerOfTwo parameter must be set to true.
+ /// The parameter exists to make sure that non power of two arrays are not pooled unintentionally which could lead to memory leaks.
+ /// </summary>
+ public static void Release (ref T[] array, bool allowNonPowerOfTwo = false) {
+ if (array == null) return;
+ if (array.GetType() != typeof(T[])) {
+ throw new System.ArgumentException("Expected array type " + typeof(T[]).Name + " but found " + array.GetType().Name + "\nAre you using the correct generic class?\n");
+ }
+
+#if !ASTAR_NO_POOLING
+ bool isPowerOfTwo = array.Length != 0 && (array.Length & (array.Length - 1)) == 0;
+ if (!isPowerOfTwo && !allowNonPowerOfTwo && array.Length != 0) throw new System.ArgumentException("Length is not a power of 2");
+
+ lock (pool) {
+#if !ASTAR_OPTIMIZE_POOLING
+ if (!inPool.Add(array)) {
+ throw new InvalidOperationException("You are trying to pool an array twice. Please make sure that you only pool it once.");
+ }
+#endif
+ if (isPowerOfTwo) {
+ int bucketIndex = 0;
+ while ((1 << bucketIndex) < array.Length && bucketIndex < 30) {
+ bucketIndex++;
+ }
+
+ if (pool[bucketIndex] == null) {
+ pool[bucketIndex] = new Stack<T[]>();
+ }
+
+ pool[bucketIndex].Push(array);
+ } else if (array.Length <= MaximumExactArrayLength) {
+ Stack<T[]> stack = exactPool[array.Length];
+ if (stack == null) stack = exactPool[array.Length] = new Stack<T[]>();
+ stack.Push(array);
+ }
+ }
+#endif
+ array = null;
+ }
+ }
+
+ /// <summary>Extension methods for List<T></summary>
+ public static class ListExtensions {
+ /// <summary>
+ /// Identical to ToArray but it uses ArrayPool<T> to avoid allocations if possible.
+ ///
+ /// Use with caution as pooling too many arrays with different lengths that
+ /// are rarely being reused will lead to an effective memory leak.
+ /// </summary>
+ public static T[] ToArrayFromPool<T>(this List<T> list) {
+ var arr = ArrayPool<T>.ClaimWithExactLength(list.Count);
+
+ for (int i = 0; i < arr.Length; i++) {
+ arr[i] = list[i];
+ }
+ return arr;
+ }
+
+ /// <summary>
+ /// Clear a list faster than List<T>.Clear.
+ /// It turns out that the List<T>.Clear method will clear all elements in the underlaying array
+ /// not just the ones up to Count. If the list only has a few elements, but the capacity
+ /// is huge, this can cause performance problems. Using the RemoveRange method to remove
+ /// all elements in the list does not have this problem, however it is implemented in a
+ /// stupid way, so it will clear the elements twice (completely unnecessarily) so it will
+ /// only be faster than using the Clear method if the number of elements in the list is
+ /// less than half of the capacity of the list.
+ ///
+ /// Hopefully this method can be removed when Unity upgrades to a newer version of Mono.
+ /// </summary>
+ public static void ClearFast<T>(this List<T> list) {
+ if (list.Count*2 < list.Capacity) {
+ list.RemoveRange(0, list.Count);
+ } else {
+ list.Clear();
+ }
+ }
+ }
+}