Skip to content

Add method for computing the difference of two unsigned integers in a signed  #117476

@davidzeng0

Description

@davidzeng0
fn overflowing_difference_signed(a: unsigned, b: unsigned) -> (signed, bool);

This is useful in the case of

async fn seek(&mut self, seek: SeekFrom) -> Result<u64> {
  match seek {
    SeekFrom::Current(pos) => self.seek_relative(pos).await,
    SeekFrom::End(pos) => ...
    SeekFrom::Start(pos: u64) => {
      if !self.stream_position_fast() {
        return self.seek_inner(seek).await;
      }

      let stream_pos: u64 = self.stream_position().await?;
 
      /* want to make sure pos - stream_pos can fit in an i64 without overflow */
      /* stream_pos = u64::MAX, pos = 0, seek_relative = -1: wrong */
      self.seek_relative(pos.wrapping_sub(stream_pos) as i64).await
    }
  }
}

This is better than casting u64s to u128s and doing try_into i64 as u128s cannot be upgraded to u256s

GCC and Clang have this feature via

__builtin_sub_overflow(a, b, &output)

which generates the following code: https://godbolt.org/z/E64GnaEz6

This can be implemented in rust with sub_check2: https://godbolt.org/z/dxrP4d9vT
which has zero branches for optimal performance

sub_large: 1.029584449 ns / rep
sub_check: 1.436846155 ns / rep
sub_check2: 1.02297698 ns / rep

CPU: AMD R7 5800X

New code:

let (pos: i64, overflow: bool) = pos.overflowing_difference_signed(stream_pos);

if overflow {
  self.seek_inner(seek).await
} else {
  self.seek_relative(pos)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions