What's wrong
ContiguousMap.GetKeysSpan() and GetValuesSpan() (Containers/ContiguousMap.cs:590-630) allocate new TKey[Count] / new TValue[Count] and copy every entry on each call, then return a span over that fresh array. Their remarks say they provide "direct access to the keys from the contiguous memory, enabling high-performance operations", and the return type (ReadOnlySpan<T>) reinforces that it's a view — so callers have no signal it's an O(n) allocation.
Failure scenario
for (int i = 0; i < map.Count; i++) { var k = map.GetKeysSpan()[i]; ... }
is O(n²) time and allocates n arrays: 40k entries took ~2.2 s in a Release probe. Containers.Benchmarks/ContiguousMapBenchmarks.cs:216 benchmarks this copy as if it were a span access.
Suggested fix
Entries are stored as Entry { Key, Value } structs, so a keys-only span can't exist without a copy. Pick one:
- Replace with non-allocating
CopyKeysTo(Span<TKey>) / CopyValuesTo(Span<TValue>) (and/or ToKeysArray()), obsoleting the *Span names; or
- Keep the methods but make the allocation explicit in the name/remarks, and point callers at
AsReadOnlySpan() (which is genuinely zero-copy) for indexed access to Entry.Key/Entry.Value.
Distinct from #78 (writable AsSpan).
What's wrong
ContiguousMap.GetKeysSpan()andGetValuesSpan()(Containers/ContiguousMap.cs:590-630) allocatenew TKey[Count]/new TValue[Count]and copy every entry on each call, then return a span over that fresh array. Their remarks say they provide "direct access to the keys from the contiguous memory, enabling high-performance operations", and the return type (ReadOnlySpan<T>) reinforces that it's a view — so callers have no signal it's an O(n) allocation.Failure scenario
is O(n²) time and allocates n arrays: 40k entries took ~2.2 s in a Release probe.
Containers.Benchmarks/ContiguousMapBenchmarks.cs:216benchmarks this copy as if it were a span access.Suggested fix
Entries are stored as
Entry { Key, Value }structs, so a keys-only span can't exist without a copy. Pick one:CopyKeysTo(Span<TKey>)/CopyValuesTo(Span<TValue>)(and/orToKeysArray()), obsoleting the*Spannames; orAsReadOnlySpan()(which is genuinely zero-copy) for indexed access toEntry.Key/Entry.Value.Distinct from #78 (writable
AsSpan).