Shallow compare for slices


#1

Is there a shallow compare for slices that returns true if the pointers and lengths match, false otherwise? It would be useful to short-circuit sometimes.

Could be implemented like

impl<T> [T] {
    fn shallow_cmp(&self, other: &[T]) {
        self.len() == other.len() && (self as *const T) == (other as *const T)
    }
}

(this function might not be correct, which is why I’m asking here rather than using it).

Note that I don’t care if sometimes the function says “no” when it should say “yes”, but I do care about the other way round.


#2

That comparison looks fine, but I would prefer as_ptr() instead of as casting. One false case that you may or may not want would be empty slices with different pointers. I suppose it depends on how you’re using this “identity” comparison.


#3

You can use std::ptr::eq on slices:

use std::ptr;

let a = [1, 2, 3, 4];
let b = [1, 2, 3];

// True if the slices have the same address and length:
assert!(ptr::eq(&a[..3], &a[..3]));

// False if the slices have different lengths...
assert!(!ptr::eq(&a[..3], &a[..2]));

// ...or different addresses:
assert!(!ptr::eq(&a[..3], &b[..3]));

(Playground)


#4

I did not know about the std::ptr::eq function. How does it know to compare lengths? Is that compiler magic?


#5

By using pointer comparisons which in turn compare the pointer using some compiler intrinsic magic. (IE. It’s implemented by the compiler)


#6

It seems that equality comparison of pointers also compares the metadata for fat pointers. Slices store their length in the metadata.

See here for evidence that it also compares vtables for dyn Trait:

#[repr(transparent)]
struct A<T>(T);
struct B;

trait Trait {}
impl<T> Trait for A<T> {}
impl Trait for B {}

fn main() {
    let a = A(B);
    
    // Fat pointers don't compare equal
    assert!(!std::ptr::eq(&a as &dyn Trait, &a.0 as &dyn Trait));
    // ...but thin pointers do.
    assert!(std::ptr::eq(
        &a as &dyn Trait as *const dyn Trait as *const u8,
        &a.0 as &dyn Trait as *const dyn Trait as *const u8,
    ));
}