VR4Medical/ICI/Library/PackageCache/com.unity.xr.interaction.toolkit@42ef3600567b/Runtime/Utilities/SmallRegistrationList.cs
2025-07-29 13:45:50 +03:00

184 lines
6.0 KiB
C#

using System;
using System.Collections.Generic;
namespace UnityEngine.XR.Interaction.Toolkit.Utilities
{
/// <summary>
/// <inheritdoc />
/// </summary>
/// <typeparam name="T"><inheritdoc /></typeparam>
/// <remarks>
/// <inheritdoc />
/// <para>
/// This is a variation of <see cref="RegistrationList{T}"/> that can be used when changes in registration
/// is done infrequently. This class is also smaller in size since it does not have <see cref="HashSet{T}"/> fields
/// which are more useful when the number of registered items is large and when registration changes happens
/// more frequently.
/// </para>
/// </remarks>
/// <seealso cref="RegistrationList{T}"/>
class SmallRegistrationList<T> : BaseRegistrationList<T>
{
bool m_BufferChanges = true;
/// <summary>
/// Whether this list should buffer changes, the default value is <see langword="true"/>.
/// Assign a <see langword="false"/> value to make all changes take effect immediately. This is useful when
/// changes should be buffered only when the list is being processed.
/// </summary>
/// <remarks>
/// When assign a value, and if needed, this property automatically calls <see cref="Flush"/> to guarantee the
/// order of buffered changes.
/// </remarks>
public bool bufferChanges
{
get => m_BufferChanges;
set
{
if (m_BufferChanges && value == false)
{
m_BufferChanges = false;
Flush();
}
else
{
m_BufferChanges = value;
}
}
}
/// <inheritdoc />
public override bool IsRegistered(T item) => (bufferedAddCount > 0 && m_BufferedAdd.Contains(item)) ||
(registeredSnapshot.Count > 0 && registeredSnapshot.Contains(item) && IsStillRegistered(item));
/// <inheritdoc />
public override bool IsStillRegistered(T item) => bufferedRemoveCount == 0 || !m_BufferedRemove.Contains(item);
/// <inheritdoc />
public override bool Register(T item)
{
if (!bufferChanges)
{
if (registeredSnapshot.Contains(item))
return false;
registeredSnapshot.Add(item);
return true;
}
if (bufferedAddCount > 0 && m_BufferedAdd.Contains(item))
return false;
var snapshotContainsItem = registeredSnapshot.Contains(item);
if ((bufferedRemoveCount > 0 && RemoveFromBufferedRemove(item)) || !snapshotContainsItem)
{
if (!snapshotContainsItem)
AddToBufferedAdd(item);
return true;
}
return false;
}
/// <inheritdoc />
public override bool Unregister(T item)
{
if (!bufferChanges)
return registeredSnapshot.Remove(item);
if (bufferedRemoveCount > 0 && m_BufferedRemove.Contains(item))
return false;
if (bufferedAddCount > 0 && RemoveFromBufferedAdd(item))
return true;
if (registeredSnapshot.Contains(item))
{
AddToBufferedRemove(item);
return true;
}
return false;
}
/// <inheritdoc />
public override void Flush()
{
// This method is called multiple times each frame,
// so additional explicit Count checks are done for
// performance.
if (bufferedRemoveCount > 0)
{
foreach (var item in m_BufferedRemove)
{
registeredSnapshot.Remove(item);
}
ClearBufferedRemove();
}
if (bufferedAddCount > 0)
{
foreach (var item in m_BufferedAdd)
{
if (!registeredSnapshot.Contains(item))
{
registeredSnapshot.Add(item);
}
}
ClearBufferedAdd();
}
}
/// <inheritdoc />
public override void GetRegisteredItems(List<T> results)
{
if (results == null)
throw new ArgumentNullException(nameof(results));
results.Clear();
EnsureCapacity(results, flushedCount);
foreach (var item in registeredSnapshot)
{
if (bufferedRemoveCount > 0 && m_BufferedRemove.Contains(item))
continue;
results.Add(item);
}
if (bufferedAddCount > 0)
results.AddRange(m_BufferedAdd);
}
/// <inheritdoc />
public override T GetRegisteredItemAt(int index)
{
if (index < 0 || index >= flushedCount)
throw new ArgumentOutOfRangeException(nameof(index), "Index was out of range. Must be non-negative and less than the size of the registration collection.");
if (bufferedRemoveCount == 0 && bufferedAddCount == 0)
return registeredSnapshot[index];
if (index >= registeredSnapshot.Count - bufferedRemoveCount)
return m_BufferedAdd[index - (registeredSnapshot.Count - bufferedRemoveCount)];
var effectiveIndex = 0;
foreach (var item in registeredSnapshot)
{
if (bufferedRemoveCount > 0 && m_BufferedRemove.Contains(item))
continue;
if (effectiveIndex == index)
return registeredSnapshot[index];
++effectiveIndex;
}
// Unreachable code
throw new ArgumentOutOfRangeException(nameof(index), "Index was out of range. Must be non-negative and less than the size of the registration collection.");
}
}
}