From 8722a9920c1f6119bf6e769cba270e63097f8e25 Mon Sep 17 00:00:00 2001 From: chai <215380520@qq.com> Date: Thu, 23 May 2024 10:08:29 +0800 Subject: + astar project --- .../Core/Pooling/ArrayPool.cs | 200 +++++++++++++++++++ .../Core/Pooling/ArrayPool.cs.meta | 12 ++ .../Core/Pooling/ListPool.cs | 211 +++++++++++++++++++++ .../Core/Pooling/ListPool.cs.meta | 7 + .../Core/Pooling/ObjectPool.cs | 131 +++++++++++++ .../Core/Pooling/ObjectPool.cs.meta | 7 + .../Core/Pooling/PathPool.cs | 88 +++++++++ .../Core/Pooling/PathPool.cs.meta | 7 + .../Core/Pooling/StackPool.cs | 98 ++++++++++ .../Core/Pooling/StackPool.cs.meta | 7 + 10 files changed, 768 insertions(+) create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ArrayPool.cs.meta create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ListPool.cs.meta create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/ObjectPool.cs.meta create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/PathPool.cs.meta create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling/StackPool.cs.meta (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pooling') 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 { + /// + /// Lightweight Array Pool. + /// Handy class for pooling arrays of type T. + /// + /// Usage: + /// - Claim a new array using SomeClass[] foo = ArrayPool.Claim (capacity); + /// - Use it and do stuff with it + /// - Release it with ArrayPool.Release (ref foo); + /// + /// 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 + /// + public static class ArrayPool { +#if !ASTAR_NO_POOLING + /// + /// Maximum length of an array pooled using ClaimWithExactLength. + /// Arrays with lengths longer than this will silently not be pooled. + /// + const int MaximumExactArrayLength = 256; + + /// + /// Internal pool. + /// The arrays in each bucket have lengths of 2^i + /// + static readonly Stack[] pool = new Stack[31]; + static readonly Stack[] exactPool = new Stack[MaximumExactArrayLength+1]; +#if !ASTAR_OPTIMIZE_POOLING + static readonly HashSet inPool = new HashSet(); +#endif +#endif + + /// + /// 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. + /// + 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(); + } + + 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]; + } + + /// + /// 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 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. + /// + 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 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]; + } + + /// + /// Pool an array. + /// If the array was got using the 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. + /// + 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(); + } + + pool[bucketIndex].Push(array); + } else if (array.Length <= MaximumExactArrayLength) { + Stack stack = exactPool[array.Length]; + if (stack == null) stack = exactPool[array.Length] = new Stack(); + stack.Push(array); + } + } +#endif + array = null; + } + } + + /// Extension methods for List + public static class ListExtensions { + /// + /// Identical to ToArray but it uses ArrayPool 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. + /// + public static T[] ToArrayFromPool(this List list) { + var arr = ArrayPool.ClaimWithExactLength(list.Count); + + for (int i = 0; i < arr.Length; i++) { + arr[i] = list[i]; + } + return arr; + } + + /// + /// Clear a list faster than List.Clear. + /// It turns out that the List.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. + /// + public static void ClearFast(this List 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 { + /// + /// Lightweight List Pool. + /// Handy class for pooling lists of type T. + /// + /// Usage: + /// - Claim a new list using List foo = ListPool.Claim (); + /// - Use it and do stuff with it + /// - Release it with ListPool.Release (foo); + /// + /// 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 + /// + public static class ListPool { + /// Internal pool + static readonly List > pool = new List >(); + +#if !ASTAR_NO_POOLING + static readonly List > largePool = new List >(); + static readonly HashSet > inPool = new HashSet >(); +#endif + + /// + /// 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. + /// + const int MaxCapacitySearchLength = 8; + const int LargeThreshold = 5000; + const int MaxLargePoolSize = 8; + + /// + /// 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). + /// + public static List Claim () { +#if ASTAR_NO_POOLING + return new List(); +#else + lock (pool) { + if (pool.Count > 0) { + List ls = pool[pool.Count-1]; + pool.RemoveAt(pool.Count-1); + inPool.Remove(ls); + return ls; + } + + return new List(); + } +#endif + } + + static int FindCandidate (List > 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 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; + } + + /// + /// 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. + /// + public static List Claim (int capacity) { +#if ASTAR_NO_POOLING + return new List(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(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 + } + + /// + /// 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. + /// + public static void Warmup (int count, int size) { + lock (pool) { + var tmp = new List[count]; + for (int i = 0; i < count; i++) tmp[i] = Claim(size); + for (int i = 0; i < count; i++) Release(tmp[i]); + } + } + + + /// + /// 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: + /// + public static void Release (ref List list) { + Release(list); + list = null; + } + + /// + /// 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: + /// + public static void Release (List 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 + } + + /// + /// Clears the pool for lists of this type. + /// This is an O(n) operation, where n is the number of pooled lists. + /// + public static void Clear () { + lock (pool) { +#if !ASTAR_OPTIMIZE_POOLING && !ASTAR_NO_POOLING + inPool.Clear(); +#endif + pool.Clear(); + } + } + + /// Number of lists of this type in the pool + 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(); + } + + /// + /// Lightweight object Pool for IAstarPooledObject. + /// Handy class for pooling objects of type T which implements the IAstarPooledObject interface. + /// + /// Usage: + /// - Claim a new object using SomeClass foo = ObjectPool.Claim (); + /// - Use it and do stuff with it + /// - Release it with ObjectPool.Release (foo); + /// + /// 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 + /// + public static class ObjectPool where T : class, IAstarPooledObject, new(){ + public static T Claim () { + return ObjectPoolSimple.Claim(); + } + + public static void Release (ref T obj) { + obj.OnEnterPool(); + ObjectPoolSimple.Release(ref obj); + } + } + + /// + /// Lightweight object Pool. + /// Handy class for pooling objects of type T. + /// + /// Usage: + /// - Claim a new object using SomeClass foo = ObjectPool.Claim (); + /// - Use it and do stuff with it + /// - Release it with ObjectPool.Release (foo); + /// + /// 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 + /// + public static class ObjectPoolSimple where T : class, new(){ + /// Internal pool + static List pool = new List(); + +#if !ASTAR_NO_POOLING + static readonly HashSet inPool = new HashSet(); +#endif + + /// + /// 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). + /// + 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 + } + + /// + /// 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 + /// + 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; + } + + /// + /// Clears the pool for objects of this type. + /// This is an O(n) operation, where n is the number of pooled objects. + /// + public static void Clear () { + lock (pool) { +#if !ASTAR_OPTIMIZE_POOLING && !ASTAR_NO_POOLING + inPool.Clear(); +#endif + pool.Clear(); + } + } + + /// Number of objects of this type in the pool + 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 { + /// Pools path objects to reduce load on the garbage collector + public static class PathPool { + static readonly Dictionary > pool = new Dictionary >(); + static readonly Dictionary totalCreated = new Dictionary(); + + /// + /// Adds a path to the pool. + /// This function should not be used directly. Instead use the Path.Claim and Path.Release functions. + /// + 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 poolStack; + if (!pool.TryGetValue(path.GetType(), out poolStack)) { + poolStack = new Stack(); + pool[path.GetType()] = poolStack; + } + + ((IPathInternals)path).Pooled = true; + ((IPathInternals)path).OnEnterPool(); + poolStack.Push(path); + } +#endif + } + + /// Total created instances of paths of the specified type + public static int GetTotalCreated (Type type) { + int created; + + if (totalCreated.TryGetValue(type, out created)) { + return created; + } else { + return 0; + } + } + + /// Number of pooled instances of a path of the specified type + public static int GetSize (Type type) { + Stack poolStack; + + if (pool.TryGetValue(type, out poolStack)) { + return poolStack.Count; + } else { + return 0; + } + } + + /// Get a path from the pool or create a new one if the pool is empty + public static T GetPath() where T : Path, new() { +#if ASTAR_NO_POOLING + T result = new T(); + ((IPathInternals)result).Reset(); + return result; +#else + lock (pool) { + T result; + Stack 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 { + /// + /// Lightweight Stack Pool. + /// Handy class for pooling stacks of type T. + /// + /// Usage: + /// - Claim a new stack using Stack foo = StackPool.Claim (); + /// - Use it and do stuff with it + /// - Release it with StackPool.Release (foo); + /// + /// 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 + /// + public static class StackPool { + /// Internal pool + static readonly List > pool; + + /// Static constructor + static StackPool () { + pool = new List >(); + } + + /// + /// 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). + /// + public static Stack Claim () { +#if ASTAR_NO_POOLING + return new Stack(); +#else + lock (pool) { + if (pool.Count > 0) { + Stack ls = pool[pool.Count-1]; + pool.RemoveAt(pool.Count-1); + return ls; + } + } + + return new Stack(); +#endif + } + + /// + /// Makes sure the pool contains at least count pooled items. + /// This is good if you want to do all allocations at start. + /// + public static void Warmup (int count) { + var tmp = new Stack[count]; + + for (int i = 0; i < count; i++) tmp[i] = Claim(); + for (int i = 0; i < count; i++) Release(tmp[i]); + } + + /// + /// Releases a stack. + /// After the stack has been released it should not be used anymore. + /// Releasing a stack twice will cause an error. + /// + public static void Release (Stack 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 + } + + /// + /// Clears all pooled stacks of this type. + /// This is an O(n) operation, where n is the number of pooled stacks + /// + public static void Clear () { + lock (pool) { + pool.Clear(); + } + } + + /// Number of stacks of this type in the pool + 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} -- cgit v1.1-26-g67d0