1
0

feat: update some interface

This commit is contained in:
2026-03-27 16:11:11 +08:00
parent ba53ad1da4
commit 7f4d511715
7 changed files with 143 additions and 85 deletions

View File

@@ -1,64 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BallanceTasEditor.Backend {
/// <summary>
/// 一种提前给定元素个数的的IEnumerable。
/// </summary>
public sealed class CountableEnumerable<T> {
/// <summary>
/// 以直接方式构建。
/// </summary>
/// <param name="enumerable">一个迭代器,其最多只能迭代给定次数。</param>
/// <param name="count">迭代器会迭代的次数。</param>
public CountableEnumerable(IEnumerable<T> enumerable, int count) {
m_Inner = enumerable;
m_Count = count;
}
/// <summary>
/// 从数组便捷构建。
/// </summary>
/// <param name="array">要使用的数组。</param>
public CountableEnumerable(T[] array) {
m_Inner = array;
m_Count = array.Length;
}
private readonly IEnumerable<T> m_Inner;
private readonly int m_Count;
/// <summary>
/// 获取迭代器对象。
/// </summary>
/// <returns>用于迭代的迭代器。</returns>
/// <exception cref="ArgumentException">当迭代器迭代次数与给定次数不匹配时。</exception>
public IEnumerable<T> GetInner() {
int counter = 0;
foreach (var item in m_Inner) {
if (counter >= m_Count) {
throw new ArgumentException("Given IEnumerable<T> is not stopped at given count.");
} else {
yield return item;
++counter;
}
}
if (counter != m_Count) {
throw new ArgumentException("Given IEnumerable<T> is not stopped at given count.");
}
}
/// <summary>
/// 获取该迭代器会迭代的次数。
/// </summary>
/// <returns>迭代器会迭代的次数,用于给使用该结构的方法提前分配必要的空间。</returns>
public int GetCount() {
return m_Count;
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BallanceTasEditor.Backend {
/// <summary>
/// 一种提前给定元素个数的的IEnumerable。
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IExactSizeEnumerable<out T> : IEnumerable<T> {
/// <summary>
/// 该迭代器会返回的元素的个数。
/// </summary>
/// <remarks>
/// 如果迭代器返回的元素个数与该方法给定的个数不同,
/// 则是未定义行为。
/// </remarks>
/// <returns>迭代器会返回的元素的准确个数。大于等于0。</returns>
public int GetCount();
}
/// <summary>
/// 将普通IEnumerable转变为IExactSizeEnumerable的适配器。
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class ExactSizeEnumerableAdapter<T> : IExactSizeEnumerable<T> {
/// <summary>
/// 以迭代器和指定长度构建适配器。
/// </summary>
/// <remarks>
/// 如果迭代器返回的元素个数与该方法给定的个数不同,
/// 则是未定义行为。
/// </remarks>
/// <param name="enumerable">一个迭代器,其最多只能迭代给定次数。</param>
/// <param name="count">迭代器会迭代的次数。</param>
public ExactSizeEnumerableAdapter(IEnumerable<T> enumerable, int count) {
m_Inner = enumerable;
m_Count = count;
}
private readonly IEnumerable<T> m_Inner;
private readonly int m_Count;
public IEnumerator<T> GetEnumerator() {
return m_Inner.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return m_Inner.GetEnumerator();
}
public int GetCount() {
return m_Count;
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace BallanceTasEditor.Backend {
public class TasClipboard {
// Reference: https://stackoverflow.com/questions/22272822/copy-binary-data-to-clipboard
private static readonly string CLIPBOARD_DATA_FORMAT = "BallanceTasEditor.TasFrames";
public static void SetClipboard(IExactSizeEnumerable<TasFrame> frames) {
DataObject data = new DataObject();
var rawFrames = frames.Select((f) => f.ToRaw()).ToArray();
data.SetData(CLIPBOARD_DATA_FORMAT, rawFrames, false);
Clipboard.SetDataObject(data, true);
}
private static RawTasFrame[]? GetClipboardObject() {
DataObject? retrievedData = Clipboard.GetDataObject() as DataObject;
if (retrievedData is null) return null;
if (!retrievedData.GetDataPresent(CLIPBOARD_DATA_FORMAT)) return null;
RawTasFrame[]? rawFrames = retrievedData.GetData(CLIPBOARD_DATA_FORMAT) as RawTasFrame[];
if (rawFrames is null) return null;
return rawFrames;
}
public static bool HasClipboard() {
return GetClipboardObject() is not null;
}
public static EnumerableArray? GetClipboard() {
var rawFrames = GetClipboardObject();
if (rawFrames is null) return null;
return new EnumerableArray(rawFrames);
}
public sealed class EnumerableArray : IExactSizeEnumerable<TasFrame> {
public EnumerableArray(RawTasFrame[] rawFrames) {
m_RawFrames = rawFrames;
}
private RawTasFrame[] m_RawFrames;
public IEnumerator<TasFrame> GetEnumerator() {
return m_RawFrames.Select((f) => new TasFrame(f)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
public int GetCount() {
return m_RawFrames.Length;
}
}
}
}

View File

@@ -11,6 +11,7 @@ namespace BallanceTasEditor.Backend {
/// 原始的TAS帧结构与二进制结构保持一致。
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public struct RawTasFrame {
/// <summary>
/// 该帧的持续时间(以秒为单位)。

View File

@@ -1,10 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BallanceTasEditor.Backend {
internal class TasOperationStack {
}
}

View File

@@ -44,7 +44,7 @@ namespace BallanceTasEditor.Backend {
/// <param name="index">要在前方插入数据的元素的索引。</param>
/// <param name="items">要插入的元素的迭代器。</param>
/// <exception cref="ArgumentOutOfRangeException">给定的索引无效。</exception>
void Insert(int index, CountableEnumerable<TasFrame> items);
void Insert(int index, IExactSizeEnumerable<TasFrame> items);
/// <summary>
/// 从序列中移出给定帧区间的元素。
/// </summary>
@@ -89,7 +89,7 @@ namespace BallanceTasEditor.Backend {
throw new NotImplementedException();
}
public void Insert(int index, CountableEnumerable<TasFrame> items) {
public void Insert(int index, IExactSizeEnumerable<TasFrame> items) {
throw new NotImplementedException();
}
@@ -139,14 +139,14 @@ namespace BallanceTasEditor.Backend {
}
}
public void Insert(int index, CountableEnumerable<TasFrame> items) {
public void Insert(int index, IExactSizeEnumerable<TasFrame> items) {
if (index == m_Container.Count) {
m_Container.AddRange(items.GetInner());
m_Container.AddRange(items);
} else {
if (index > m_Container.Count || index < 0) {
throw new IndexOutOfRangeException("Invalid index for frame.");
} else {
m_Container.InsertRange(index, items.GetInner());
m_Container.InsertRange(index, items);
}
}
}
@@ -272,12 +272,12 @@ namespace BallanceTasEditor.Backend {
}
}
public void Insert(int index, CountableEnumerable<TasFrame> items) {
public void Insert(int index, IExactSizeEnumerable<TasFrame> items) {
if (index >= m_Container.Count || index < 0) {
throw new IndexOutOfRangeException("Invalid index for frame.");
} else {
if (index == m_Container.Count) {
foreach (TasFrame item in items.GetInner()) {
foreach (TasFrame item in items) {
m_Container.AddLast(item);
}
@@ -290,7 +290,7 @@ namespace BallanceTasEditor.Backend {
} else {
MoveToIndex(index);
foreach (TasFrame item in items.GetInner()) {
foreach (TasFrame item in items) {
m_Container.AddBefore(m_Cursor.Node, item);
}
m_Cursor.Index += items.GetCount();

View File

@@ -10,8 +10,8 @@ using System.Threading.Tasks;
namespace BallanceTasEditor.Backend {
public static class TasStorage {
internal const int SIZEOF_F32 = sizeof(float);
internal const int SIZEOF_I32 = sizeof(int);
internal const int SIZEOF_F32 = sizeof(float);
internal const int SIZEOF_U32 = sizeof(uint);
internal const int SIZEOF_RAW_TAS_FRAME = SIZEOF_F32 + SIZEOF_U32;
@@ -70,7 +70,7 @@ namespace BallanceTasEditor.Backend {
var memWrapper = new EnumerableMemoryStream(mem, expectedCount);
seq.Clear();
seq.Insert(0, new CountableEnumerable<TasFrame>(memWrapper, expectedCount));
seq.Insert(0, memWrapper);
mem.Close();
}
@@ -105,7 +105,7 @@ namespace BallanceTasEditor.Backend {
//target.Flush();
}
private class EnumerableMemoryStream : IEnumerable<TasFrame> {
private sealed class EnumerableMemoryStream : IExactSizeEnumerable<TasFrame> {
public EnumerableMemoryStream(MemoryStream mem, int frameCnt) {
m_MemoryStream = mem;
m_FrameCount = frameCnt;
@@ -130,6 +130,9 @@ namespace BallanceTasEditor.Backend {
return GetEnumerator();
}
public int GetCount() {
return m_FrameCount;
}
}
}