Search code examples
c#.netvectordata-structuresdynamic-arrays

How is (uint) index >= (uint)_size better than index >= _size?


I looked under the hood of List<T> and came across the following piece of code:

public T this[int index] {
        get {
            // Following trick can reduce the range check by one
            if ((uint) index >= (uint)_size) {
                ThrowHelper.ThrowArgumentOutOfRangeException();
            }
            Contract.EndContractBlock();
            return _items[index]; 
        }

        set {
            if ((uint) index >= (uint)_size) {
                ThrowHelper.ThrowArgumentOutOfRangeException();
            }
            Contract.EndContractBlock();
            _items[index] = value;
            _version++;
        }
    }

In both if statements, index and _size (of type Int32) are casted to UInt32, I know it is not because of overflow, because first if has a comment stating otherwise.

Question: What is this concept of casting integer to unsigned-integers other than overflow, and in what specific situation can it be useful to a developer?


Solution

  • The point is to handle both negative numbers and positive numbers in one step.

    If you cast a negative numbers to uint, the result is guaranteed to be larger than than int.MaxValue. So any negative index will fail the (uint) index >= (uint)_size check. If you remove the cast you would need to do two checks: index < 0 || index >= _size. Since the cast is "free" this end up improving performance a bit.

    Note that this will not work in a checked context