summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling
diff options
context:
space:
mode:
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling')
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs200
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs.meta12
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs211
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs.meta7
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs131
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs.meta7
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs88
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs.meta7
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs98
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs.meta7
10 files changed, 768 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();
+ }
+ }
+ }
+}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs.meta
new file mode 100644
index 0000000..25e0d39
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 787a564bf2d894ee09284b775074864c
+timeCreated: 1470483941
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs
new file mode 100644
index 0000000..22ff246
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs
@@ -0,0 +1,211 @@
+#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 List Pool.
+ /// Handy class for pooling lists of type T.
+ ///
+ /// Usage:
+ /// - Claim a new list using <code> List<SomeClass> foo = ListPool<SomeClass>.Claim (); </code>
+ /// - Use it and do stuff with it
+ /// - Release it with <code> ListPool<SomeClass>.Release (foo); </code>
+ ///
+ /// You do not need to clear the list before releasing it.
+ /// After you have released a list, you should never use it again, if you do use it, you will
+ /// mess things up quite badly in the worst case.
+ ///
+ /// Since: Version 3.2
+ /// See: Pathfinding.Util.StackPool
+ /// </summary>
+ public static class ListPool<T> {
+ /// <summary>Internal pool</summary>
+ static readonly List<List<T> > pool = new List<List<T> >();
+
+#if !ASTAR_NO_POOLING
+ static readonly List<List<T> > largePool = new List<List<T> >();
+ static readonly HashSet<List<T> > inPool = new HashSet<List<T> >();
+#endif
+
+ /// <summary>
+ /// When requesting a list with a specified capacity, search max this many lists in the pool before giving up.
+ /// Must be greater or equal to one.
+ /// </summary>
+ const int MaxCapacitySearchLength = 8;
+ const int LargeThreshold = 5000;
+ const int MaxLargePoolSize = 8;
+
+ /// <summary>
+ /// Claim a list.
+ /// Returns a pooled list if any are in the pool.
+ /// Otherwise it creates a new one.
+ /// After usage, this list should be released using the Release function (though not strictly necessary).
+ /// </summary>
+ public static List<T> Claim () {
+#if ASTAR_NO_POOLING
+ return new List<T>();
+#else
+ lock (pool) {
+ if (pool.Count > 0) {
+ List<T> ls = pool[pool.Count-1];
+ pool.RemoveAt(pool.Count-1);
+ inPool.Remove(ls);
+ return ls;
+ }
+
+ return new List<T>();
+ }
+#endif
+ }
+
+ static int FindCandidate (List<List<T> > pool, int capacity) {
+ // Loop through the last MaxCapacitySearchLength items
+ // and check if any item has a capacity greater or equal to the one that
+ // is desired. If so return it.
+ // Otherwise take the largest one or if there are no lists in the pool
+ // then allocate a new one with the desired capacity
+ List<T> list = null;
+ int listIndex = -1;
+
+ for (int i = 0; i < pool.Count && i < MaxCapacitySearchLength; i++) {
+ // ith last item
+ var candidate = pool[pool.Count-1-i];
+
+ // Find the largest list that is not too large (arbitrary decision to try to prevent some memory bloat if the list was not just a temporary list).
+ if ((list == null || candidate.Capacity > list.Capacity) && candidate.Capacity < capacity*16) {
+ list = candidate;
+ listIndex = pool.Count-1-i;
+
+ if (list.Capacity >= capacity) {
+ return listIndex;
+ }
+ }
+ }
+
+ return listIndex;
+ }
+
+ /// <summary>
+ /// Claim a list with minimum capacity
+ /// Returns a pooled list if any are in the pool.
+ /// Otherwise it creates a new one.
+ /// After usage, this list should be released using the Release function (though not strictly necessary).
+ /// A subset of the pool will be searched for a list with a high enough capacity and one will be returned
+ /// if possible, otherwise the list with the largest capacity found will be returned.
+ /// </summary>
+ public static List<T> Claim (int capacity) {
+#if ASTAR_NO_POOLING
+ return new List<T>(capacity);
+#else
+ lock (pool) {
+ var currentPool = pool;
+ var listIndex = FindCandidate(pool, capacity);
+
+ if (capacity > LargeThreshold) {
+ var largeListIndex = FindCandidate(largePool, capacity);
+ if (largeListIndex != -1) {
+ currentPool = largePool;
+ listIndex = largeListIndex;
+ }
+ }
+
+ if (listIndex == -1) {
+ return new List<T>(capacity);
+ } else {
+ var list = currentPool[listIndex];
+ // Swap current item and last item to enable a more efficient removal
+ inPool.Remove(list);
+ currentPool[listIndex] = currentPool[currentPool.Count-1];
+ currentPool.RemoveAt(currentPool.Count-1);
+ return list;
+ }
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Makes sure the pool contains at least count pooled items with capacity size.
+ /// This is good if you want to do all allocations at start.
+ /// </summary>
+ public static void Warmup (int count, int size) {
+ lock (pool) {
+ var tmp = new List<T>[count];
+ for (int i = 0; i < count; i++) tmp[i] = Claim(size);
+ for (int i = 0; i < count; i++) Release(tmp[i]);
+ }
+ }
+
+
+ /// <summary>
+ /// Releases a list and sets the variable to null.
+ /// After the list has been released it should not be used anymore.
+ ///
+ /// Throws: System.InvalidOperationException
+ /// Releasing a list when it has already been released will cause an exception to be thrown.
+ ///
+ /// See: <see cref="Claim"/>
+ /// </summary>
+ public static void Release (ref List<T> list) {
+ Release(list);
+ list = null;
+ }
+
+ /// <summary>
+ /// Releases a list.
+ /// After the list has been released it should not be used anymore.
+ ///
+ /// Throws: System.InvalidOperationException
+ /// Releasing a list when it has already been released will cause an exception to be thrown.
+ ///
+ /// See: <see cref="Claim"/>
+ /// </summary>
+ public static void Release (List<T> list) {
+#if !ASTAR_NO_POOLING
+ list.ClearFast();
+
+ lock (pool) {
+#if !ASTAR_OPTIMIZE_POOLING
+ if (!inPool.Add(list)) {
+ throw new InvalidOperationException("You are trying to pool a list twice. Please make sure that you only pool it once.");
+ }
+#endif
+ if (list.Capacity > LargeThreshold) {
+ largePool.Add(list);
+
+ // Remove the list which was used the longest time ago from the pool if it
+ // exceeds the maximum size as it probably just contributes to memory bloat
+ if (largePool.Count > MaxLargePoolSize) {
+ largePool.RemoveAt(0);
+ }
+ } else {
+ pool.Add(list);
+ }
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Clears the pool for lists of this type.
+ /// This is an O(n) operation, where n is the number of pooled lists.
+ /// </summary>
+ public static void Clear () {
+ lock (pool) {
+#if !ASTAR_OPTIMIZE_POOLING && !ASTAR_NO_POOLING
+ inPool.Clear();
+#endif
+ pool.Clear();
+ }
+ }
+
+ /// <summary>Number of lists of this type in the pool</summary>
+ public static int GetSize () {
+ // No lock required since int writes are atomic
+ return pool.Count;
+ }
+ }
+}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs.meta
new file mode 100644
index 0000000..92e0b9c
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2b76b7593907b44d9a6ef1b186fee0a7
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs
new file mode 100644
index 0000000..262830c
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs
@@ -0,0 +1,131 @@
+#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 {
+ public interface IAstarPooledObject {
+ void OnEnterPool();
+ }
+
+ /// <summary>
+ /// Lightweight object Pool for IAstarPooledObject.
+ /// Handy class for pooling objects of type T which implements the IAstarPooledObject interface.
+ ///
+ /// Usage:
+ /// - Claim a new object using <code> SomeClass foo = ObjectPool<SomeClass>.Claim (); </code>
+ /// - Use it and do stuff with it
+ /// - Release it with <code> ObjectPool<SomeClass>.Release (foo); </code>
+ ///
+ /// After you have released a object, you should never use it again.
+ ///
+ /// Since: Version 3.2
+ /// Version: Since 3.7.6 this class is thread safe
+ /// See: Pathfinding.Util.ListPool
+ /// See: ObjectPoolSimple
+ /// </summary>
+ public static class ObjectPool<T> where T : class, IAstarPooledObject, new(){
+ public static T Claim () {
+ return ObjectPoolSimple<T>.Claim();
+ }
+
+ public static void Release (ref T obj) {
+ obj.OnEnterPool();
+ ObjectPoolSimple<T>.Release(ref obj);
+ }
+ }
+
+ /// <summary>
+ /// Lightweight object Pool.
+ /// Handy class for pooling objects of type T.
+ ///
+ /// Usage:
+ /// - Claim a new object using <code> SomeClass foo = ObjectPool<SomeClass>.Claim (); </code>
+ /// - Use it and do stuff with it
+ /// - Release it with <code> ObjectPool<SomeClass>.Release (foo); </code>
+ ///
+ /// After you have released a object, you should never use it again.
+ ///
+ /// Since: Version 3.2
+ /// Version: Since 3.7.6 this class is thread safe
+ /// See: Pathfinding.Util.ListPool
+ /// See: ObjectPool
+ /// </summary>
+ public static class ObjectPoolSimple<T> where T : class, new(){
+ /// <summary>Internal pool</summary>
+ static List<T> pool = new List<T>();
+
+#if !ASTAR_NO_POOLING
+ static readonly HashSet<T> inPool = new HashSet<T>();
+#endif
+
+ /// <summary>
+ /// Claim a object.
+ /// Returns a pooled object if any are in the pool.
+ /// Otherwise it creates a new one.
+ /// After usage, this object should be released using the Release function (though not strictly necessary).
+ /// </summary>
+ public static T Claim () {
+#if ASTAR_NO_POOLING
+ return new T();
+#else
+ lock (pool) {
+ if (pool.Count > 0) {
+ T ls = pool[pool.Count-1];
+ pool.RemoveAt(pool.Count-1);
+ inPool.Remove(ls);
+ return ls;
+ } else {
+ return new T();
+ }
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Releases an object.
+ /// After the object has been released it should not be used anymore.
+ /// The variable will be set to null to prevent silly mistakes.
+ ///
+ /// Throws: System.InvalidOperationException
+ /// Releasing an object when it has already been released will cause an exception to be thrown.
+ /// However enabling ASTAR_OPTIMIZE_POOLING will prevent this check.
+ ///
+ /// See: Claim
+ /// </summary>
+ public static void Release (ref T obj) {
+#if !ASTAR_NO_POOLING
+ lock (pool) {
+#if !ASTAR_OPTIMIZE_POOLING
+ if (!inPool.Add(obj)) {
+ throw new InvalidOperationException("You are trying to pool an object twice. Please make sure that you only pool it once.");
+ }
+#endif
+ pool.Add(obj);
+ }
+#endif
+ obj = null;
+ }
+
+ /// <summary>
+ /// Clears the pool for objects of this type.
+ /// This is an O(n) operation, where n is the number of pooled objects.
+ /// </summary>
+ public static void Clear () {
+ lock (pool) {
+#if !ASTAR_OPTIMIZE_POOLING && !ASTAR_NO_POOLING
+ inPool.Clear();
+#endif
+ pool.Clear();
+ }
+ }
+
+ /// <summary>Number of objects of this type in the pool</summary>
+ public static int GetSize () {
+ return pool.Count;
+ }
+ }
+}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs.meta
new file mode 100644
index 0000000..6240b52
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 10837c5b030bd47a2a0e6e213fea0868
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs
new file mode 100644
index 0000000..9fa75d1
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs
@@ -0,0 +1,88 @@
+//#define ASTAR_NO_POOLING // Disable pooling for some reason. Maybe for debugging or just for measuring the difference.
+using System;
+using System.Collections.Generic;
+
+namespace Pathfinding {
+ /// <summary>Pools path objects to reduce load on the garbage collector</summary>
+ public static class PathPool {
+ static readonly Dictionary<Type, Stack<Path> > pool = new Dictionary<Type, Stack<Path> >();
+ static readonly Dictionary<Type, int> totalCreated = new Dictionary<Type, int>();
+
+ /// <summary>
+ /// Adds a path to the pool.
+ /// This function should not be used directly. Instead use the Path.Claim and Path.Release functions.
+ /// </summary>
+ public static void Pool (Path path) {
+#if !ASTAR_NO_POOLING
+ lock (pool) {
+ if (((IPathInternals)path).Pooled) {
+ throw new System.ArgumentException("The path is already pooled.");
+ }
+
+ Stack<Path> poolStack;
+ if (!pool.TryGetValue(path.GetType(), out poolStack)) {
+ poolStack = new Stack<Path>();
+ pool[path.GetType()] = poolStack;
+ }
+
+ ((IPathInternals)path).Pooled = true;
+ ((IPathInternals)path).OnEnterPool();
+ poolStack.Push(path);
+ }
+#endif
+ }
+
+ /// <summary>Total created instances of paths of the specified type</summary>
+ public static int GetTotalCreated (Type type) {
+ int created;
+
+ if (totalCreated.TryGetValue(type, out created)) {
+ return created;
+ } else {
+ return 0;
+ }
+ }
+
+ /// <summary>Number of pooled instances of a path of the specified type</summary>
+ public static int GetSize (Type type) {
+ Stack<Path> poolStack;
+
+ if (pool.TryGetValue(type, out poolStack)) {
+ return poolStack.Count;
+ } else {
+ return 0;
+ }
+ }
+
+ /// <summary>Get a path from the pool or create a new one if the pool is empty</summary>
+ public static T GetPath<T>() where T : Path, new() {
+#if ASTAR_NO_POOLING
+ T result = new T();
+ ((IPathInternals)result).Reset();
+ return result;
+#else
+ lock (pool) {
+ T result;
+ Stack<Path> poolStack;
+ if (pool.TryGetValue(typeof(T), out poolStack) && poolStack.Count > 0) {
+ // Guaranteed to have the correct type
+ result = poolStack.Pop() as T;
+ } else {
+ result = new T();
+
+ // Make sure an entry for the path type exists
+ if (!totalCreated.ContainsKey(typeof(T))) {
+ totalCreated[typeof(T)] = 0;
+ }
+
+ totalCreated[typeof(T)]++;
+ }
+
+ ((IPathInternals)result).Pooled = false;
+ ((IPathInternals)result).Reset();
+ return result;
+ }
+#endif
+ }
+ }
+}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs.meta
new file mode 100644
index 0000000..9ff4458
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: cefe1014ab62848a89016fb97b1f8f7b
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs
new file mode 100644
index 0000000..daf7a53
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs
@@ -0,0 +1,98 @@
+//#define ASTAR_NO_POOLING //@SHOWINEDITOR Disable pooling for some reason. Could be debugging or just for measuring the difference.
+
+using System.Collections.Generic;
+
+namespace Pathfinding.Util {
+ /// <summary>
+ /// Lightweight Stack Pool.
+ /// Handy class for pooling stacks of type T.
+ ///
+ /// Usage:
+ /// - Claim a new stack using <code> Stack<SomeClass> foo = StackPool<SomeClass>.Claim (); </code>
+ /// - Use it and do stuff with it
+ /// - Release it with <code> StackPool<SomeClass>.Release (foo); </code>
+ ///
+ /// You do not need to clear the stack before releasing it.
+ /// After you have released a stack, you should never use it again.
+ ///
+ /// Warning: This class is not thread safe
+ ///
+ /// Since: Version 3.2
+ /// See: Pathfinding.Util.ListPool
+ /// </summary>
+ public static class StackPool<T> {
+ /// <summary>Internal pool</summary>
+ static readonly List<Stack<T> > pool;
+
+ /// <summary>Static constructor</summary>
+ static StackPool () {
+ pool = new List<Stack<T> >();
+ }
+
+ /// <summary>
+ /// Claim a stack.
+ /// Returns a pooled stack if any are in the pool.
+ /// Otherwise it creates a new one.
+ /// After usage, this stack should be released using the Release function (though not strictly necessary).
+ /// </summary>
+ public static Stack<T> Claim () {
+#if ASTAR_NO_POOLING
+ return new Stack<T>();
+#else
+ lock (pool) {
+ if (pool.Count > 0) {
+ Stack<T> ls = pool[pool.Count-1];
+ pool.RemoveAt(pool.Count-1);
+ return ls;
+ }
+ }
+
+ return new Stack<T>();
+#endif
+ }
+
+ /// <summary>
+ /// Makes sure the pool contains at least count pooled items.
+ /// This is good if you want to do all allocations at start.
+ /// </summary>
+ public static void Warmup (int count) {
+ var tmp = new Stack<T>[count];
+
+ for (int i = 0; i < count; i++) tmp[i] = Claim();
+ for (int i = 0; i < count; i++) Release(tmp[i]);
+ }
+
+ /// <summary>
+ /// Releases a stack.
+ /// After the stack has been released it should not be used anymore.
+ /// Releasing a stack twice will cause an error.
+ /// </summary>
+ public static void Release (Stack<T> stack) {
+#if !ASTAR_NO_POOLING
+ stack.Clear();
+
+ lock (pool) {
+ for (int i = 0; i < pool.Count; i++)
+ if (pool[i] == stack) UnityEngine.Debug.LogError("The Stack is released even though it is inside the pool");
+
+ pool.Add(stack);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Clears all pooled stacks of this type.
+ /// This is an O(n) operation, where n is the number of pooled stacks
+ /// </summary>
+ public static void Clear () {
+ lock (pool) {
+ pool.Clear();
+ }
+ }
+
+ /// <summary>Number of stacks of this type in the pool</summary>
+ public static int GetSize () {
+ return pool.Count;
+ }
+ }
+}
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs.meta
new file mode 100644
index 0000000..1c8a3b5
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: de467bbbb1ff84668ae8262caad00941
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}