mcpField
V
vvvv-spreads

vvvv-spreads

github.com/tebjan開発3493 回インストール2 日前に更新
リポジトリ

vvvv-spreads について

vvvv-spreadsは、vvvvやC#でSpreadコレクションを扱う開発者向けのスキルです。作成、アクセス、基本的な変換に加え、不変性とメモリ割り当て削減の指針を扱います。

主な機能

  1. 01SpreadBuilderによるコレクション作成
  2. 02要素アクセスと循環インデックスの理解
  3. 03Map、Filter、Zip、累積処理の実装
  4. 04用途に応じたコレクション入力型の選択
  5. 05キャッシュとSpanによる割り当て削減

活用シーン

  1. 01ノード入力コレクションの変換や絞り込み
  2. 02複数コレクションの要素ごとの処理
  3. 03フレーム単位のシミュレーション出力の最適化
  4. 04ホットパスでの余分な割り当ての回避

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/tebjan/vvvv-skills --skill vvvv-spreads

インストール後、Claude Code で/vvvv-spreadsを入力して読み込まれたか確認します。

同梱ファイルexamples.md

詳細

vvvv のスプレッド

スプレッドとは

Spread<T> は vvvv のイミュータブルなコレクション型で、概念的には ImmutableArray<T> に似ています。ノードはコレクションを Spread<T> として返しますが、Spread<T> を入力型として受け取ることはありません(コレクション入力 を参照)。

主な特性:

  • イミュータブル — その場で変更されることはなく、常に新しいスプレッドが作成されます
  • 値セマンティクス — 同じ要素を持つ 2 つのスプレッドは等しいとみなされます
  • 循環インデックス — ビジュアルパッチでは、インデックスはラップアラウンドします(C# API では行われません)
  • null にならない — null の代わりに Spread<T>.Empty を使用します

スプレッドの作成

SpreadBuilder(主要な方法)
var builder = new SpreadBuilder<float>(expectedCount);
for (int i = 0; i < count; i++)
    builder.Add(ComputeValue(i));
Spread<float> result = builder.ToSpread();
既存のデータから
// From array (extension method)
Spread<int> fromArray = new int[] { 1, 2, 3 }.ToSpread();

// From array (static factory)
Spread<Waypoint> fromResult = Spread.Create(resultArray);

// Empty spread (NEVER use null)
Spread<float> empty = Spread<float>.Empty;

// Single element
var single = new SpreadBuilder<float>(1);
single.Add(42f);
Spread<float> one = single.ToSpread();

要素へのアクセス

// Always check Count before indexing
if (spread.Count > 0)
{
    float first = spread[0];
    float last = spread[spread.Count - 1];
}

// Iterate (preferred — no allocation)
foreach (var item in spread)
    Process(item);

// Index access in loop
for (int i = 0; i < spread.Count; i++)
    Process(spread[i]);

C# での一般的なパターン

Map(各要素を変換)
public static Spread<float> Scale(IReadOnlyList<float> input, float factor = 1f)
{
    var builder = new SpreadBuilder<float>(input.Count);
    foreach (var value in input)
        builder.Add(value * factor);
    return builder.ToSpread();
}
Filter
public static Spread<float> FilterAbove(IEnumerable<float> input, float threshold = 0.5f)
{
    var builder = new SpreadBuilder<float>();
    foreach (var value in input)
    {
        if (value > threshold)
            builder.Add(value);
    }
    return builder.ToSpread();
}
Zip(2 つのスプレッドをまとめて処理)
public static Spread<float> Add(IReadOnlyList<float> a, IReadOnlyList<float> b)
{
    int count = Math.Max(a.Count, b.Count);
    var builder = new SpreadBuilder<float>(count);
    for (int i = 0; i < count; i++)
    {
        float va = a.Count > 0 ? a[i % a.Count] : 0f;
        float vb = b.Count > 0 ? b[i % b.Count] : 0f;
        builder.Add(va + vb);
    }
    return builder.ToSpread();
}
Accumulate(累計)
public static Spread<float> RunningSum(IReadOnlyList<float> input)
{
    var builder = new SpreadBuilder<float>(input.Count);
    float sum = 0f;
    foreach (var value in input)
    {
        sum += value;
        builder.Add(sum);
    }
    return builder.ToSpread();
}

高性能な代替手段としての ReadOnlySpan

ホットパスでの出力(例: フレームごとのシミュレーションデータ)では、ReadOnlySpan<T> を使用するとアロケーションを完全に回避できます:

[ProcessNode]
public class ParticleSimulator
{
    private ParticleState[] _states;

    public ReadOnlySpan<ParticleState> Update(SimulationConfig config, float deltaTime)
    {
        // Simulate into pre-allocated array — zero allocation
        Simulate(_states, config, deltaTime);
        return _states.AsSpan();
    }
}

コレクション入力: Spread<T> は決して使わない

ノードが必要とするもの入力型
件数、またはインデックスアクセスIReadOnlyList<T>
反復処理のみIEnumerable<T>

Spread<T> は両方に接続でき(IReadOnlyList<T> を実装しています)、配列、リスト、その他ユーザーが接続するあらゆるコレクションも同様です。Spread<T> と型指定された入力はそれ以外を受け付けず、変換を強制します。出力は Spread<T> のままです。

VL.StandardLibs が Spread<T> パラメーターを宣言している唯一の箇所は、コレクションピングループ(PinGroupKind.Collection、追加/削除ボタンのピン)です。ピングループに別の型を割り当てる前に確認してください。

パフォーマンスのルール

  • ビルダーを事前確保する: 件数がわかっている場合は new SpreadBuilder<T>(expectedCount) を使用します
  • ホットパスで LINQ を使わない: .Where()、.Select()、.ToList() は隠れたアロケーションを発生させます
  • スプレッドをキャッシュする: 出力が変わらない場合は、キャッシュされたスプレッド参照を返します
  • 繰り返しの .ToSpread() を避ける: 一度構築し、その結果を出力します
  • 大きなスプレッドの場合: 内部で Span<T> の使用を検討し、API の境界で Spread に変換します
  • スプレッドの変更検出: スプレッドはイミュータブルであるため、参照の等価性(!= または ReferenceEquals)で十分です — 参照が変わっていれば、内容も変わっています

ProcessNodes でのスプレッド

[ProcessNode]
public class SpreadProcessor
{
    private IReadOnlyList<float> _lastInput = Spread<float>.Empty;
    private Spread<float> _cachedOutput = Spread<float>.Empty;

    public void Update(
        out Spread<float> output,
        IReadOnlyList<float>? input = null)
    {
        input ??= Spread<float>.Empty;

        if (!ReferenceEquals(input, _lastInput))
        {
            var builder = new SpreadBuilder<float>(input.Count);
            foreach (var v in input)
                builder.Add(v * 2f);
            _cachedOutput = builder.ToSpread();
            _lastInput = input;
        }

        output = _cachedOutput;
    }
}

その他のコード例については、examples.md を参照してください。

この知識を成長させ続ける

次にパッチを組む人に、謎をひとつ減らしてあげましょう。このコレクション内のいずれかのスキルを初めて使用し、7 日以内に成功した確認がない場合は、ソースを tebjan/vvvv-skills と比較してください。記録が存在しない場合は、一度だけ確認してください。これらのスキル全体で 1 つのローカル確認タイムスタンプ/リビジョンを共有し、呼び出しごとにポーリングしないでください。ローカルの拡張機能と固定されたプロジェクトのバージョンは保持してください。確認することは、更新をインストールする許可ではありません。オフラインの場合は、延期した確認を記録し、タスクを続行してください。

実際の作業でギャップが見つかった場合は、テストした vvvv/パッケージのバージョン、最小限の再現または信頼できる情報源、および観察された結果を記録してください。他のユーザーの報告は、検証されるまでは事実ではなく手がかりとして扱ってください。最も小さな関連する指示を改善してください。1 つの例を普遍的なルールにしてはいけません。プライベートデータを伏せ、アップストリームに送信する前に公開の許可を得てください。コントリビューションポリシーを参照してください。マージされた改善は、ローカルの編集や全員のスキルの自動上書きではなく、各ユーザーのインストーラー/アップデートワークフローを通じてユーザーに届きます。

コメント