Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTracking issue for ptr::offset_from #41079
Comments
Mark-Simulacrum
added
B-unstable
T-libs
labels
Jun 20, 2017
This comment has been minimized.
This comment has been minimized.
|
I wonder whether this should have the The |
This comment has been minimized.
This comment has been minimized.
|
It seems suspicious at best to calculate the offset between two unrelated pointers... I agree with @scottmcm |
Mark-Simulacrum
added
the
C-tracking-issue
label
Jul 22, 2017
This comment has been minimized.
This comment has been minimized.
|
@pornel made the point that this should be |
This comment has been minimized.
This comment has been minimized.
|
Also, I find it unfortunate that this forces handling the ZST case even if you know the pointer type and know that it doesn't point to a zero-sized type. Could we use traits to provide a method that only exists for non-zero-sized types, and then returns |
This comment has been minimized.
This comment has been minimized.
|
I like @scottmcm's suggestion to have an unsafe I suggest omitting the [0] For example, |
This comment has been minimized.
This comment has been minimized.
iitalics
commented
Jan 4, 2018
|
I think that returning |
This comment has been minimized.
This comment has been minimized.
|
Renaming to I don’t really understand the @Amanieu since you added this, what do you think? |
This comment has been minimized.
This comment has been minimized.
|
I have no objection to renaming it to The
The current implementation rounds towards zero, however I am considering going with the UB route instead. Note that this situation can only happen if one of the pointers is misaligned, so we could just require that both pointers be properly aligned for their type. |
This comment has been minimized.
This comment has been minimized.
Can’t it also happen with aligned pointers, if |
This comment has been minimized.
This comment has been minimized.
|
That's a good point, I'm not sure why I thought of alignment there. You are correct. |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin That's a good point. C manages to avoid that issue, because in C it's undefined behavior if the pointers aren't both pointing to elements of the same array (6.5.6p9). I don't know whether Rust's |
This comment has been minimized.
This comment has been minimized.
|
@sunfishcode it seems... incredibly suspect to allow |
This comment has been minimized.
This comment has been minimized.
|
I started on a PR for this at #49297; feedback and suggestions appreciated. |
This comment has been minimized.
This comment has been minimized.
|
Amanieu and sunfishcode commented that doing As such, should this API change form to something where it can be |
This comment has been minimized.
This comment has been minimized.
|
Keep in mind that LLVM IR generated by Clang is just a I considered the name |
bors
added a commit
that referenced
this issue
Mar 26, 2018
This comment has been minimized.
This comment has been minimized.
|
In Nightly this is the tracking issue for three different inherent methods of both pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized {…}
pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized {…}
pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized {…}(Note: the The libs team discussed this and it wasn’t clear from this tracking issue or the implementation PR what is the motivation for this feature. @Amanieu Could you comment on what situations this would be used in, why it should be in the standard library, and why three different methods are needed? |
This comment has been minimized.
This comment has been minimized.
|
My understanding is that These methods are useful when converting between slices and raw pointers, which can happen when building data structures or with FFI. |
This comment has been minimized.
This comment has been minimized.
|
If this is a replacement, should |
This comment has been minimized.
This comment has been minimized.
|
I'll make a PR for that and to move vec&slice to offset_from. (Unless it should be deprecated for a bit first? I don't remember what the rules are for nightly things...) |
scottmcm
referenced this issue
Apr 1, 2018
Merged
Deprecate offset_to; switch core&alloc to using offset_from instead #49551
This comment has been minimized.
This comment has been minimized.
|
PR up at #41079 That did reinforce my feeling that |
bors
added a commit
that referenced
this issue
Apr 12, 2018
This comment has been minimized.
This comment has been minimized.
ghost
commented
Aug 20, 2018
|
I tried using the offset_from() method on a pointer today. I like the name and API; it seemed rather intuitive. The only issue I have is that the implementations of offset_from() and wrapping_offset_from() use assert!() rather than debug_assert!(). The result is that offset_from() is a bit slower than it could be when debug = false. Is there a reason to prefer assert!()? |
This comment has been minimized.
This comment has been minimized.
|
@dtrebbien The assert is on the size of the type, which is a compile-time constant, so I would expect it to always get optimized out. Are you seeing otherwise? |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Aug 20, 2018
|
It looks like I am seeing a slight difference, but I am not entirely sure. I am currently working on a piece of code where offset_from() would be used rather frequently. When I run my benchmark using: let all_code_units_ptr = all_code_units.as_ptr();
//...
let code_unit_index = unsafe { iter.as_slice().as_ptr().offset_from(all_code_units_ptr) } as usize - 1;
//...
let end_code_unit_index = unsafe { slice.as_ptr().offset_from(all_code_units_ptr) } as usize - 1;.. then my benchmark numbers are: bench: 6,136,818 ns/iter (+/- 344,438) = 751 MB/s bench: 6,156,946 ns/iter (+/- 349,123) = 748 MB/s bench: 6,140,547 ns/iter (+/- 298,704) = 750 MB/s bench: 6,135,250 ns/iter (+/- 248,410) = 751 MB/s bench: 6,141,995 ns/iter (+/- 228,005) = 750 MB/s When I use this "inlined" version instead: let all_code_units_ptr_as_usize = all_code_units.as_ptr() as usize;
//...
let code_unit_index = unsafe { intrinsics::exact_div(iter.as_slice().as_ptr() as usize - all_code_units_ptr_as_usize, mem::size_of::<CodeUnitT>()) } - 1;
//...
let end_code_unit_index = unsafe { intrinsics::exact_div(slice.as_ptr() as usize - all_code_units_ptr_as_usize, mem::size_of::<CodeUnitT>()) } - 1;.. then my benchmark numbers are: bench: 6,120,998 ns/iter (+/- 205,285) = 753 MB/s bench: 6,108,348 ns/iter (+/- 198,379) = 754 MB/s bench: 6,109,708 ns/iter (+/- 223,981) = 754 MB/s bench: 6,113,860 ns/iter (+/- 230,122) = 754 MB/s bench: 6,123,206 ns/iter (+/- 221,520) = 752 MB/s Here, |
This comment has been minimized.
This comment has been minimized.
|
Now that I'm not on my phone, I tried this out explicitly in playground. pub unsafe fn demo(x: *const u8, y: *const u8) -> isize {
x.offset_from(y)
}; playground::demo
; Function Attrs: norecurse nounwind readnone uwtable
define i64 @_ZN10playground4demo17h3547ff97a5dad82dE(i8* %x, i8* %y) unnamed_addr #0 {
start:
%0 = ptrtoint i8* %x to i64
%1 = ptrtoint i8* %y to i64
%2 = sub i64 %0, %1
ret i64 %2
}Which, as expected, has no sign of the assert. So while there may be some other issue here, it's more complex than just the Do you have a bench you can share? Are you building with incremental? With LTO? With multiple codegen units? Do you see something different with a locally-built nightly without the |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Aug 21, 2018
|
Thanks for looking into this. I can see that you are right; there isn't an effect of debug_assert!() vs. assert!(). There must be something else at play. My benchmark is not public at the moment, but I am working to try to clean up everything so that I can eventually publish it. |
Amanieu
changed the title
Tracking issue for ptr::offset_to
Tracking issue for ptr::offset_from
Oct 23, 2018
This comment has been minimized.
This comment has been minimized.
|
Here are my thoughts on the remaining issues:
|
Amanieu commentedApr 5, 2017
•
edited by scottmcm
PR: #40943
Adds an
offset_tomethod to calculate the distance between two raw pointers.List o' stuff:
offset_fromand make unsafe (withwrapping_offset_fromfor the safe one) #41079 (comment) -- done in #49297offset_fromabort instead of panic on ZSTs?usize(like how isize-takingoffsetis more conveniently done with usize-takingaddthese days)