Rust has strict aliasing rules. But can I work around them if "I know what I'm doing"?
I'm trying to convert to Rust a C function that performs a complicated operation by reading from input buffer and writing to a destination buffer, but it has a clever optimization that allows the input and output buffer to be the same:
foo(src, dst); // result is written to dst
foo(buf, buf); // legal in C, does the operation in-place
For the sake of the question let's say it's something like:
void inplace(char *src, char *dst, int len) {
for(int i=0; i < len-1; i++) {
dst[i] = src[i+1] * 2; // algorithm works even if src == dst
}
}
In safe subset of Rust I'd have to have two nearly copy & pasted versions of the function fn(&mut)
and fn(&, &mut)
.
Is there a way to cheat Rust to get both mutable and immutable reference to the same buffer?
Rust Playground. In general, raw pointers are allowed to alias. You can't mutate something through a raw pointer if it originally came from a &T reference without going through some form of UnsafeCell , though.
Pointer aliasing is a hidden kind of data dependency that can occur in C, C++, or any other language that uses pointers for array addresses in arithmetic operations. Array data identified by pointers in C can overlap, because the C language puts very few restrictions on pointers.
No, you cannot do so in safe Rust. You can use unsafe code to work around aliasing limitations if you wish to but...
but it has a clever optimization that allows the input and output buffer to be the same
what you call an optimization, I call a pessimization.
When the two buffers are guaranteed not to be the same, the optimizer can vectorize your code. It means 4x or 8x less comparisons for the loop, greatly speeding up the execution for larger inputs.
In the absence of aliasing information, however, it must pessimistically assume that the inputs could be aliased and therefore cannot do such optimization. Worse, not knowing how they are aliased, it does not even know whether &dst[i] == &src[i-1]
or &dst[i] == &src[i]
or &dst[i] == &src[i+1]
; it means pre-fetching is out etc...
In safe Rust, however, this information is available. It does force you to write two routines (one for a single input, one for two inputs) but both can be optimized accordingly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With