Last active
September 17, 2022 17:05
-
-
Save chigirits/32a1259f788a5c4d1892335be245823b to your computer and use it in GitHub Desktop.
Udon用 C++のstd::vectorみたいな自動拡張配列
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UdonSharp; | |
using UnityEngine; | |
/// Objectクラスの値を格納可能な可変長配列 | |
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] | |
public class FlexArray_Object : UdonSharpBehaviour | |
{ | |
/// <summary>初期サイズ</summary> | |
int initialSize = 4; | |
/// <summary> | |
/// 線形に拡張する単位 | |
/// (このサイズに達するまでは倍々で、これ以降はこの値ごとに線形に拡張) | |
/// </summary> | |
int linearStepSize = 1024; | |
/// <summary> | |
/// 格納されている値の配列 | |
/// (実際の長さよりも長い場合があり、Lengthはキャパシティを表します) | |
/// </summary> | |
Object[] values = new Object[4]; | |
/// <summary>実際の配列長(values の有効部分の長さ)</summary> | |
int actualSize = 0; | |
/// <summary>実際の配列長を返します。</summary> | |
/// <returns>配列長</returns> | |
public int Size() | |
{ | |
return actualSize; | |
} | |
/// <summary> | |
/// 配列のキャパシティを返します。 | |
/// この長さを超えるまではメモリの再確保や複製処理が起こらず、高速にアクセスできます。 | |
/// </summary> | |
/// <returns>配列のキャパシティ</returns> | |
public int Capacity() | |
{ | |
return values.Length; | |
} | |
/// <summary>i番目の配列要素を返します。</summary> | |
/// <param name="i">配列内の位置</param> | |
/// <returns>i番目の配列要素</returns> | |
public Object Get(int i) | |
{ | |
return values[i]; | |
} | |
/// <summary>i番目の配列要素を設定します。</summary> | |
/// <param name="i">配列内の位置</param> | |
/// <param name="o">設定する値</param> | |
public void Set(int i, Object o) | |
{ | |
values[i] = o; | |
} | |
/// <summary>配列の最後に要素を追加します。</summary> | |
/// <param name="o">追加する値</param> | |
public void Push(Object o) | |
{ | |
Allocate(++actualSize); | |
values[actualSize - 1] = o; | |
} | |
/// <summary>配列の最後の要素を取り除き、その値を返します。</summary> | |
/// <returns>取り除かれた値</returns> | |
public Object Pop() | |
{ | |
return values[--actualSize]; | |
} | |
/// <summary>指定した値に等しい最初の配列要素の位置を返します。</summary> | |
/// <param name="o">検索する値</param> | |
/// <returns>配列要素の位置(見つからなかったときは -1)</returns> | |
public int IndexOf(Object o) | |
{ | |
if (o == null) return -1; | |
for (var i=0; i<actualSize; i++) if (values[i] == o) return i; | |
return -1; | |
} | |
/// <summary>指定した値が配列に含まれないときに限り、配列の最後に要素を追加します。</summary> | |
/// <param name="o">追加する値</param> | |
/// <returns>配列要素が追加された位置</returns> | |
public int PushExclusive(Object o) | |
{ | |
int i = IndexOf(o); | |
if (0 <= i) return i; | |
Push(o); | |
return actualSize - 1; | |
} | |
/// <summary>指定した位置の配列要素を取り除き、そこから末尾までの全要素を先頭方向に詰めます。</summary> | |
/// <param name="i">配列内の位置</param> | |
/// <returns>取り除かれた値</returns> | |
public Object RemoveAt(int i) | |
{ | |
if (i < 0) return null; | |
var o = values[i]; | |
actualSize--; | |
for (; i<actualSize; i++) values[i] = values[i+1]; | |
return o; | |
} | |
/// <summary>指定した値に等しい最初の配列要素を取り除き、そこから末尾までの全要素を先頭方向に詰めます。</summary> | |
/// <param name="o">取り除く値</param> | |
/// <returns>取り除いた要素の位置(見つからなかったときは -1)</returns> | |
public int Remove(Object o) | |
{ | |
var i = IndexOf(o); | |
RemoveAt(i); | |
return i; | |
} | |
/// <summary>他の配列の全要素を末尾に連結します。</summary> | |
/// <param name="another">連結する配列</param> | |
public void Concat(FlexArray_Object another) | |
{ | |
var n = another.Size(); | |
Allocate(actualSize + n); | |
for (var i=0; i<n; i++) values[actualSize+i] = another.Get(i); | |
actualSize += n; | |
} | |
/// <summary>空配列にリセットします。</summary> | |
public void Clear() | |
{ | |
values = new Object[initialSize]; | |
actualSize = 0; | |
} | |
/// <summary>キャパシティに関する設定を変更し、空配列にリセットします。</summary> | |
/// <param name="initialSize">初期サイズ</param> | |
/// <param name="linearStepSize">線形に拡張する単位</param> | |
public void Initialize(int initialSize, int linearStepSize) | |
{ | |
this.initialSize = initialSize; | |
this.linearStepSize = linearStepSize; | |
Clear(); | |
} | |
/// <summary>指定した長さまでキャパシティを拡張し、即座にメモリを確保します。</summary> | |
/// <param name="n">キャパシティ</param> | |
/// <returns>現在のキャパシティの方が大きい場合は何もしません。 | |
public void Allocate(int n) | |
{ | |
var l = values.Length; | |
if (n <= l) return; | |
while (l < n) | |
{ | |
if (linearStepSize <= l) | |
l += linearStepSize; | |
else | |
l *= 2; | |
} | |
var newList = new Object[l]; | |
for (var i=0; i<values.Length; i++) newList[i] = values[i]; | |
values = newList; | |
} | |
/// <summary> | |
/// 現在の配列長に必要な最小限のキャパシティまで縮小し、不要なメモリを解放します。 | |
/// 現在のキャパシティの方が小さい場合は何もしません。 | |
/// </summary> | |
public void Minimize() | |
{ | |
var l = initialSize; | |
while (l < actualSize) | |
{ | |
if (linearStepSize <= l) | |
l += linearStepSize; | |
else | |
l *= 2; | |
} | |
if (values.Length <= l) return; | |
var newList = new Object[l]; | |
for (var i=0; i<l; i++) newList[i] = values[i]; | |
values = newList; | |
} | |
/// <summary> | |
/// UdonSharpBehaviour にキャスト可能な全要素に対し、指定したメッセージを送信します。 | |
/// 指定した名前のメソッドが呼ばれます。 | |
/// </summary> | |
/// <param name="message">メッセージ(メソッド名)</param> | |
public void SendCustomEventToAll(string message) | |
{ | |
for (var i=0; i<actualSize; i++) | |
{ | |
var o = (UdonSharpBehaviour)values[i]; | |
if (o != null) o.SendCustomEvent(message); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
使う側で
[SerializeField] public FlexArray_Object listeners;
みたくpublicメンバを定義FlexArray_Object
をつけた空オブジェクトを使う側の子に作成して、そのメンバにDnDして参照設定みたくして使えます(VRCInstantiateしてもいいと思いますたぶん)