1
0

feat: introduce batchly visit in tas sequence

This commit is contained in:
2026-04-01 13:33:30 +08:00
parent 5f10338d33
commit 08734c6ef7
2 changed files with 74 additions and 14 deletions

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
@@ -108,14 +109,13 @@ namespace BallanceTasEditor.Backend {
ArgumentOutOfRangeException.ThrowIfLessThan(m_StartIndex, 0);
// Do backup and set values at the same time
int backupIndex = 0;
var backups = new RawTasFrame[m_EndIndex - m_StartIndex + 1];
// Pre-build key list for fast fetching.
var keys = Enumerable.Range(m_StartKey.ToIndex(), m_EndKey.ToIndex() - m_StartKey.ToIndex() + 1).Select((i) => TasKey.FromIndex(i)).ToArray();
for (int index = m_StartIndex; index <= m_EndIndex; index++) {
// Fetch frame
var frame = seq.Visit(index);
foreach (var frame in seq.BatchlyVisit(m_StartIndex, m_EndIndex)) {
// Do backup
frame.ToRawImplace(ref backups[index - m_StartIndex]);
frame.ToRawImplace(ref backups[backupIndex++]);
// Modify keys
foreach (var key in keys) {
switch (m_Kind) {
@@ -143,8 +143,9 @@ namespace BallanceTasEditor.Backend {
// Index range is checked,
// so we directly restore backup.
for (int index = m_StartIndex; index <= m_EndIndex; index++) {
seq.Visit(index).FromRawImplace(m_FramesBackup[index - m_StartIndex]);
int backupIndex = 0;
foreach (var frame in seq.BatchlyVisit(m_StartIndex, m_EndIndex)) {
frame.FromRawImplace(m_FramesBackup[backupIndex++]);
}
// Clear backups
@@ -197,12 +198,11 @@ namespace BallanceTasEditor.Backend {
ArgumentOutOfRangeException.ThrowIfLessThan(m_StartIndex, 0);
// Do backup and set values at the same time
int backupIndex = 0;
var backups = new float[m_EndIndex - m_StartIndex + 1];
for (int index = m_StartIndex; index <= m_EndIndex; index++) {
// Fetch frame
var frame = seq.Visit(index);
foreach (var frame in seq.BatchlyVisit(m_StartIndex, m_EndIndex)) {
// Do backup
backups[index - m_StartIndex] = frame.GetTimeDelta();
backups[backupIndex++] = frame.GetTimeDelta();
// Modify delta time
frame.SetTimeDelta(m_DeltaTime);
}
@@ -218,8 +218,9 @@ namespace BallanceTasEditor.Backend {
// Index range is checked,
// so we directly restore backup.
for (int index = m_StartIndex; index <= m_EndIndex; index++) {
seq.Visit(index).SetTimeDelta(m_DeltaTimesBackup[index - m_StartIndex]);
int backupIndex = 0;
foreach (var frame in seq.BatchlyVisit(m_StartIndex, m_EndIndex)) {
frame.SetTimeDelta(m_DeltaTimesBackup[backupIndex++]);
}
// Clear backups
@@ -259,9 +260,10 @@ namespace BallanceTasEditor.Backend {
ArgumentOutOfRangeException.ThrowIfLessThan(m_StartIndex, 0);
// Do backups
int backupIndex = 0;
var backups = new RawTasFrame[m_EndIndex - m_StartIndex + 1];
for (int index = m_StartIndex; index <= m_EndIndex; index++) {
seq.Visit(index).ToRawImplace(ref backups[index - m_StartIndex]);
foreach (var frame in seq.BatchlyVisit(m_StartIndex, m_EndIndex)) {
frame.ToRawImplace(ref backups[backupIndex++]);
}
// Do remove
seq.Remove(m_StartIndex, m_EndIndex);

View File

@@ -30,6 +30,21 @@ namespace BallanceTasEditor.Backend {
/// <exception cref="IndexOutOfRangeException">给定的索引无效。</exception>
TasFrame Visit(int index);
/// <summary>
/// 按顺序访问给定索引区间内的帧的值。
/// </summary>
/// <remarks>
/// 实现此函数时需要格外注意以下事项:
/// <para/>
/// 该函数如果可以进行顺序访问优化,则应当优化。
/// 即使用此函数可以获得等于或大于单独一次使用<see cref="Visit(int)"/>函数。
/// <para/>
/// 该函数理论上的复杂度应为O(1)。
/// </remarks>
/// <param name="startIndex">要访问的帧区间的起始索引(包含)。</param>
/// <param name="endIndex">要访问的帧区间的终止索引(包含)</param>
/// <exception cref="IndexOutOfRangeException">给定的索引无效。</exception>
IExactSizeEnumerable<TasFrame> BatchlyVisit(int startIndex, int endIndex);
/// <summary>
/// 在给定的帧索引<b>之前</b>插入给定的项目。
/// </summary>
/// <remarks>
@@ -93,6 +108,10 @@ namespace BallanceTasEditor.Backend {
throw new NotImplementedException();
}
public IExactSizeEnumerable<TasFrame> BatchlyVisit(int startIndex, int endIndex) {
throw new NotImplementedException();
}
public void Insert(int index, IExactSizeEnumerable<TasFrame> items) {
throw new NotImplementedException();
}
@@ -120,6 +139,7 @@ namespace BallanceTasEditor.Backend {
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
/// <summary>
@@ -143,6 +163,21 @@ namespace BallanceTasEditor.Backend {
}
}
private IEnumerable<TasFrame> BatchlyVisitEx(int startIndex, int endIndex) {
if (endIndex < startIndex || startIndex < 0 || endIndex >= m_Container.Count) {
throw new IndexOutOfRangeException("Invalid index for frame.");
}
// Iterate items one by one.
for (int i = startIndex; i <= endIndex; ++i) {
yield return m_Container[i];
}
}
public IExactSizeEnumerable<TasFrame> BatchlyVisit(int startIndex, int endIndex) {
return new ExactSizeEnumerableAdapter<TasFrame>(BatchlyVisitEx(startIndex, endIndex), endIndex - startIndex + 1);
}
public void Insert(int index, IExactSizeEnumerable<TasFrame> items) {
if (index == m_Container.Count) {
m_Container.AddRange(items);
@@ -276,6 +311,29 @@ namespace BallanceTasEditor.Backend {
}
}
private IEnumerable<TasFrame> BatchlyVisitEx(int startIndex, int endIndex) {
if (endIndex < startIndex || startIndex < 0 || endIndex >= m_Container.Count) {
throw new IndexOutOfRangeException("Invalid index for frame.");
}
// We move to start index first.
MoveToIndex(startIndex);
// Then we copy its reference
LinkedListNode<TasFrame>? node = m_Cursor.Node;
// Then compute count
var count = endIndex - startIndex + 1;
// Now we can iterate items one by one.
for (int i = 0; i < count; ++i) {
node = node.Unwrap();
yield return node.Unwrap().Value;
node = node.Next;
}
}
public IExactSizeEnumerable<TasFrame> BatchlyVisit(int startIndex, int endIndex) {
return new ExactSizeEnumerableAdapter<TasFrame>(BatchlyVisitEx(startIndex, endIndex), endIndex - startIndex + 1);
}
public void Insert(int index, IExactSizeEnumerable<TasFrame> items) {
// YYC MARK:
// We must test the equal first, to handle back appending properly.