Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ All notable changes to Celerity are documented here. This project follows [Keep
### Fixed

- `PartialSort.TopK` now throws `ArgumentException` when its `destination` overlaps its `source`, instead of silently returning a wrong answer and writing to the source it documents as untouched. Disjoint slices of one array are still accepted, matching `RadixSort` and `CountingSort`.
- Corrected `RadixSort.ArgSort` XML documentation: only its `ReadOnlySpan<int>` overload rejects `indices` that shares storage with `keys`. Documentation only.
- Eight documentation links pointed at anchors that do not exist: seven `CeleritySet` / `SwissSet` references in `docs/api/collections.md` and one in `CHANGELOG.md`. GitHub deletes `<`, `>` and `,` from a heading without substituting a separator, so `CeleritySet&lt;T, THasher&gt;` anchors as `#celeritysett-thasher`, not the `#celerityset-t-thasher` everyone writes. Closes [#339](https://github.com/marius-bughiu/Celerity/issues/339).

## [2.5.0] - 2026-08-02
Expand Down
13 changes: 12 additions & 1 deletion src/Celerity.Sorting/RadixSort.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,23 @@ public static void SortWithScratch<TValue>(Span<uint> keys, Span<TValue> values,
/// </summary>
/// <param name="keys">The keys to rank. Not modified.</param>
/// <param name="indices">Receives <c>keys.Length</c> indices into <paramref name="keys"/>, in ascending key order.</param>
/// <exception cref="ArgumentException"><paramref name="indices"/> is shorter than <paramref name="keys"/>, or shares storage with it.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="indices"/> is shorter than <paramref name="keys"/>. For
/// <see cref="ArgSort(ReadOnlySpan{int}, Span{int})"/>, it is also thrown when
/// <paramref name="indices"/> shares storage with <paramref name="keys"/>. See remarks for
/// cross-type aliases.
/// </exception>
Comment thread
marius-bughiu marked this conversation as resolved.
/// <remarks>
/// Aliasing is checked only by <see cref="ArgSort(ReadOnlySpan{int}, Span{int})"/> because its
/// <paramref name="keys"/> and <paramref name="indices"/> have the same element type. For the
/// other overloads, making their differently typed spans overlap requires reinterpreting one
/// buffer as another type; that is out-of-contract rather than checked.
/// <para>
/// The point of an argsort is to avoid moving a wide payload: rank once, then gather. This form
/// rents three buffers, so a hot loop that already owns its scratch should copy the keys itself
/// and call <see cref="SortWithScratch{TValue}(Span{uint}, Span{TValue}, Span{uint}, Span{TValue})"/> with
/// an identity index array as the payload — that is exactly what this does.
/// </para>
/// </remarks>
public static void ArgSort(ReadOnlySpan<uint> keys, Span<int> indices)
{
Expand Down
Loading