vvvv-spreads

安装量: 34
排名: #19936

安装

npx skills add https://github.com/tebjan/vvvv-skills --skill vvvv-spreads
vvvv Spreads
What Are Spreads
Spread
is vvvv's immutable collection type, conceptually similar to
ImmutableArray
. It is the primary way to pass collections between nodes.
Key properties:
Immutable
— never modify in place, always create new spreads
Value semantics
— two spreads with same elements are considered equal
Cyclic indexing
— in visual patches, indexing wraps around (not in C# API)
Never null
— use
Spread.Empty
instead of
null
Creating Spreads
SpreadBuilder (Primary Method)
var
builder
=
new
SpreadBuilder
<
float
>
(
expectedCount
)
;
for
(
int
i
=
0
;
i
<
count
;
i
++
)
builder
.
Add
(
ComputeValue
(
i
)
)
;
Spread
<
float
>
result
=
builder
.
ToSpread
(
)
;
From Existing Data
// 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
(
)
;
Accessing Elements
// 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
]
)
;
Common Patterns in C#
Map (Transform Each Element)
public
static
Spread
<
float
>
Scale
(
Spread
<
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
(
Spread
<
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 (Process Two Spreads Together)
public
static
Spread
<
float
>
Add
(
Spread
<
float
>
a
,
Spread
<
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 (Running Total)
public
static
Spread
<
float
>
RunningSum
(
Spread
<
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 as High-Performance Alternative
For hot-path output (e.g., per-frame simulation data),
ReadOnlySpan
avoids allocation entirely:
[
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
(
)
;
}
}
Use
Spread
for infrequent config inputs; use
ReadOnlySpan
for high-frequency frame data.
Performance Rules
Pre-allocate builder
:
new SpreadBuilder(expectedCount)
when count is known
No LINQ in hot paths
:
.Where()
,
.Select()
,
.ToList()
create hidden allocations
Cache spreads
If output doesn't change, return the cached spread reference
Avoid repeated
.ToSpread()
Build once, output the result
For large spreads
Consider
Span
internally, convert to Spread at the API boundary
Spread change detection
Since Spreads are immutable, reference equality ( != or ReferenceEquals ) is sufficient — if the reference changed, the content changed Spreads in ProcessNodes [ ProcessNode ] public class SpreadProcessor { private Spread < float

_lastInput

Spread < float

. Empty ; private Spread < float

_cachedOutput

Spread < float

. Empty ; public void Update ( out Spread < float

output , Spread < float

input

default ) { 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 ; } } For more code examples, see examples.md .

返回排行榜