Skip to content

Commit 1fc280c

Browse files
committed
docs(RadixSort): clarify ArgSort aliasing contract
1 parent 3386948 commit 1fc280c

2 files changed

Lines changed: 11 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ All notable changes to Celerity are documented here. This project follows [Keep
2828
### Fixed
2929

3030
- `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`.
31-
- `RadixSort.ArgSort`'s XML docs promised an `ArgumentException` when `indices` shares storage with `keys`, but only the `int`-keyed overload can throw it — the aliasing check is a same-element-type test by design. The doc now says which overload it covers, and why the rest treat a reinterpreted alias as out of contract. Documentation only.
31+
- Corrected `RadixSort.ArgSort` XML documentation: only its `ReadOnlySpan<int>` overload rejects `indices` that shares storage with `keys`. Documentation only.
3232
- 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).
3333

3434
## [2.5.0] - 2026-08-02

src/Celerity.Sorting/RadixSort.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,17 +155,22 @@ public static void SortWithScratch<TValue>(Span<uint> keys, Span<TValue> values,
155155
/// <param name="keys">The keys to rank. Not modified.</param>
156156
/// <param name="indices">Receives <c>keys.Length</c> indices into <paramref name="keys"/>, in ascending key order.</param>
157157
/// <exception cref="ArgumentException">
158-
/// <paramref name="indices"/> is shorter than <paramref name="keys"/>. It is also thrown when
159-
/// <paramref name="indices"/> shares storage with <paramref name="keys"/>, but only on the
160-
/// <see cref="int"/>-keyed overload: the aliasing check is a same-element-type test, and for
161-
/// every other key type an <see cref="int"/> index buffer can be made to overlap the keys only
162-
/// by reinterpreting one buffer as another type, which is out of contract rather than checked.
158+
/// <paramref name="indices"/> is shorter than <paramref name="keys"/>. For
159+
/// <see cref="ArgSort(ReadOnlySpan{int}, Span{int})"/>, it is also thrown when
160+
/// <paramref name="indices"/> shares storage with <paramref name="keys"/>. See remarks for
161+
/// cross-type aliases.
163162
/// </exception>
164163
/// <remarks>
164+
/// Aliasing is checked only by <see cref="ArgSort(ReadOnlySpan{int}, Span{int})"/> because its
165+
/// <paramref name="keys"/> and <paramref name="indices"/> have the same element type. For the
166+
/// other overloads, making their differently typed spans overlap requires reinterpreting one
167+
/// buffer as another type; that is out-of-contract rather than checked.
168+
/// <para>
165169
/// The point of an argsort is to avoid moving a wide payload: rank once, then gather. This form
166170
/// rents three buffers, so a hot loop that already owns its scratch should copy the keys itself
167171
/// and call <see cref="SortWithScratch{TValue}(Span{uint}, Span{TValue}, Span{uint}, Span{TValue})"/> with
168172
/// an identity index array as the payload — that is exactly what this does.
173+
/// </para>
169174
/// </remarks>
170175
public static void ArgSort(ReadOnlySpan<uint> keys, Span<int> indices)
171176
{

0 commit comments

Comments
 (0)