Files
5.24BuYu/Packages/com.kybernetik.inspector-gadgets/Editor/Other/Data/StaticLazyStack.cs
T
2026-03-10 15:36:10 +08:00

164 lines
6.5 KiB
C#

// Inspector Gadgets // https://kybernetik.com.au/inspector-gadgets // Copyright 2017-2025 Kybernetik //
using System;
using System.Collections.Generic;
using UnityEngine;
namespace InspectorGadgets
{
/// <summary>
/// A static stack that creates new elements as needed but keeps and reuses them instead of actually adding and
/// removing like a regular stack.
/// </summary>
public abstract class StaticLazyStack<T> where T : StaticLazyStack<T>, new()
{
/************************************************************************************************************************/
/// <summary>
/// The elements managed by this class.
/// <para></para>
/// Note that the number of active elements is stored in <see cref="StackHeight"/> rather than the count of
/// this list.
/// </summary>
/// <remarks>
/// Not an actual Stack because that class is in System.dll which is not otherwise needed.
/// </remarks>
protected static readonly List<T> Stack = new List<T>();
/// <summary>
/// The number of elements currently active in the stack.
/// </summary>
public static int StackHeight { get; private set; }
/************************************************************************************************************************/
/// <summary>
/// The maximum number of elements that can be in the stack at a time. Default = 10.
/// </summary>
public static int MaxHeight { get; set; }
static StaticLazyStack()
{
MaxHeight = 10;
}
/************************************************************************************************************************/
/// <summary>
/// Increases the <see cref="StackHeight"/> by 1, ensures that an element exists at the last index and returns it.
/// </summary>
public static T Increment()
{
T item;
if (StackHeight < Stack.Count)
{
item = Stack[StackHeight++];
}
else
{
item = new T();
Stack.Add(item);
StackHeight++;
if (StackHeight > MaxHeight)
Debug.LogWarning($"StaticLazyStack<{typeof(T).Name}>.StackHeight" +
$" has exceeded the specified maximum of {MaxHeight}." +
$" Please ensure that you Remove as many items as you Add and increase the {nameof(MaxHeight)} if necessary.");
}
item.OnIncrement();
return item;
}
/// <summary>Called by <see cref="Increment"/>.</summary>
protected virtual void OnIncrement() { }
/************************************************************************************************************************/
/// <summary>Decreases the <see cref="StackHeight"/> by 1.</summary>
public static void Decrement()
=> StackHeight--;
/************************************************************************************************************************/
/// <summary>Gets the element currently at the top of the stack.</summary>
public static T GetCurrent()
=> StackHeight > 0 ? Stack[StackHeight - 1] : null;
/************************************************************************************************************************/
}
/// <summary>
/// A <see cref="StaticLazyStack{T}"/> which implements <see cref="IDisposable.Dispose"/> to automatically call
/// <see cref="StaticLazyStack{T}.Decrement"/>
/// </summary>
public abstract class DisposableStaticLazyStack<T> : StaticLazyStack<T>, IDisposable where T : StaticLazyStack<T>, new()
{
/************************************************************************************************************************/
/// <summary>
/// Calls <see cref="StaticLazyStack{T}.Decrement"/> and can be overridden.
/// </summary>
public virtual void Dispose()
{
Decrement();
}
/************************************************************************************************************************/
}
/// <summary>
/// A <see cref="DisposableStaticLazyStack{T}"/> that gets and stores a particular <typeparamref name="TValue"/>,
/// sets it to a different value, and then reverts it to the previous value when disposed.
/// </summary>
public abstract class SimpleStaticLazyStack<TStack, TValue> : DisposableStaticLazyStack<TStack>
where TStack : SimpleStaticLazyStack<TStack, TValue>, new()
{
/************************************************************************************************************************/
/// <summary>The <see cref="CurrentValue"/> from before this stack element was activated.</summary>
public TValue PreviousValue { get; private set; }
/// <summary>The <typeparamref name="TValue"/> being controlled by this stack.</summary>
public abstract TValue CurrentValue { get; set; }
/************************************************************************************************************************/
/// <summary>
/// Called by <see cref="StaticLazyStack{T}.Increment"/>.
/// Stores the <see cref="CurrentValue"/> in <see cref="PreviousValue"/>.
/// </summary>
protected override void OnIncrement()
{
base.OnIncrement();
PreviousValue = CurrentValue;
}
/// <summary>
/// Calls <see cref="StaticLazyStack{T}.Decrement"/> and reverts the <see cref="CurrentValue"/> to the
/// <see cref="PreviousValue"/>.
/// </summary>
public override void Dispose()
{
base.Dispose();
CurrentValue = PreviousValue;
}
/************************************************************************************************************************/
/// <summary>
/// Increments the stack, sets the <see cref="CurrentValue"/>, and returns the top element of the stack.
/// </summary>
public static TStack Get(TValue value)
{
var context = Increment();
context.CurrentValue = value;
return context;
}
/************************************************************************************************************************/
}
}