Skip to content

Commit 8b42b7f

Browse files
L2stephentoub
andauthored
Optimize index bounds check for immutable sorted set and list (#53266)
* Optimize index bounds check for immutable sorted set and list - The bounds check to determine if a given index is >= 0 and < this.Count is only necessary on the first call to ItemRef. - The recursive steps within ItemRef do not need to continuously do this bounds check on these immutable data structures. - Proof: Elimination of index >= 0 bounds check: The first call to ItemRef checks if index >= 0. If we recurse on the left node, the index value does not change. If we recurse on the right node, index > _left._count. Then index - _left._count - 1 >= 0. Elimination of index < this.Count: The first call to ItemRef checks if index < this.Count. Then the given index must lie somewhere in this tree and (**) index < this.Count == left.Count + right.Count + 1. If we recurse on the left node, the index value does not change and a check is already made to determine that index < _left.Count. If we recurse on the right node, then we need to be sure that index - _left.count - 1 < _right.Count. But this is just a rearrangement of (**). * Remove redundant code * Remove redundant assert * Apply suggestions from code review Change from internal to private for unchecked methods. Co-authored-by: Stephen Toub <stoub@microsoft.com> Co-authored-by: Stephen Toub <stoub@microsoft.com>
1 parent 3319fa8 commit 8b42b7f

2 files changed

Lines changed: 15 additions & 4 deletions

File tree

src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,15 +195,20 @@ internal ref readonly T ItemRef(int index)
195195
{
196196
Requires.Range(index >= 0 && index < this.Count, nameof(index));
197197

198+
return ref ItemRefUnchecked(index);
199+
}
200+
201+
private ref readonly T ItemRefUnchecked(int index)
202+
{
198203
Debug.Assert(_left != null && _right != null);
199204
if (index < _left._count)
200205
{
201-
return ref _left.ItemRef(index);
206+
return ref _left.ItemRefUnchecked(index);
202207
}
203208

204209
if (index > _left._count)
205210
{
206-
return ref _right.ItemRef(index - _left._count - 1);
211+
return ref _right.ItemRefUnchecked(index - _left._count - 1);
207212
}
208213

209214
return ref _key;

src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Node.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,16 +260,22 @@ internal T this[int index]
260260
internal ref readonly T ItemRef(int index)
261261
{
262262
Requires.Range(index >= 0 && index < this.Count, nameof(index));
263+
264+
return ref ItemRefUnchecked(index);
265+
}
266+
267+
private ref readonly T ItemRefUnchecked(int index)
268+
{
263269
Debug.Assert(_left != null && _right != null);
264270

265271
if (index < _left._count)
266272
{
267-
return ref _left.ItemRef(index);
273+
return ref _left.ItemRefUnchecked(index);
268274
}
269275

270276
if (index > _left._count)
271277
{
272-
return ref _right.ItemRef(index - _left._count - 1);
278+
return ref _right.ItemRefUnchecked(index - _left._count - 1);
273279
}
274280

275281
return ref _key;

0 commit comments

Comments
 (0)