See https://github.com/JuliaLang/julia/issues/6219#issuecomment-38117402
On Wednesday, March 25, 2015 at 9:58:46 AM UTC-4, Sebastian Good wrote:
>
> The benefit of the semantics of the two argument pointer function is that
> it preserves intuitive pointer arithmetic. As a new (yet happy!) Julia
> programmer, I certainly don’t know what the deprecation implications of
> changing pointer arithmetic are (vast, sadly, I imagine), but their
> behavior certainly violated my “principle of least astonishment” when I
> found they worked by bytes, not by Ts. That is, instead of
> base/pointer.jl:64 (and friends) looking like
>
> +(x::Ptr, y::Integer) = oftype(x, (UInt(x) + (y % UInt) % UInt))
>
> I would expect them to look like
>
> +{T}(x::Ptr{T}, y::Integer) = oftype(x, (UInt(x) + *sizeof(T)**(y % UInt)
> % UInt))
>
> To more closely follow the principle of pointer arithmetic long ago
> established by C. The type specialization would make these just as fast.
> For this to work with arrays safely, you’d have to guarantee that dense
> arrays had no padding between elements. Since C requires this to the be the
> case, it seems we’re on safe ground?
>
> On March 25, 2015 at 9:07:40 AM, Stefan Karpinski ([email protected]
> <javascript:>) wrote:
>
> Given the performance difference and the different behavior, I'm tempted
> to just deprecate the two-argument form of pointer.
>
> On Wed, Mar 25, 2015 at 12:53 PM, Sebastian Good <
> [email protected] <javascript:>> wrote:
>
>> I guess what I find most confusing is that there would be a difference,
>> since adding 1 to a pointer only adds one byte, not one element size.
>>
>> > p1 = pointer(zeros(UInt64));
>> Ptr{UInt64} @0x000000010b28c360
>> > p1 + 1
>> Ptr{UInt64} @0x000000010b28c361
>>
>> I would have expected the latter to end in 68. the two argument pointer
>> function gets this “right”.
>>
>> > a=zeros(UInt64);
>> > pointer(a,1)
>> Ptr{Int64} @0x000000010b9c72e0
>> > pointer(a,2)
>> Ptr{Int64} @0x000000010b9c72e8
>>
>> I can see arguments multiple ways, but when I’m given a strongly typed
>> pointer (Ptr{T}), I would expect it to participate in arithmetic in
>> increments of sizeof(T).
>>
>> On March 25, 2015 at 6:36:37 AM, Stefan Karpinski ([email protected]
>> <javascript:>) wrote:
>>
>> That does seem to be the issue. It's tricky to fix since you can't
>> evaluate sizeof(Ptr) unless the condition is true.
>>
>> On Tue, Mar 24, 2015 at 7:13 PM, Stefan Karpinski <[email protected]
>> <javascript:>> wrote:
>>
>>> There's a branch in eltype, which is probably causing this difference.
>>>
>>> On Tue, Mar 24, 2015 at 7:00 PM, Sebastian Good <
>>> [email protected] <javascript:>> wrote:
>>>
>>>> Yep, that’s done it. The only difference I can see in the code I
>>>> wrote before and this code is that previously I had
>>>>
>>>> convert(Ptr{T}, pointer(raw, byte_number))
>>>>
>>>> whereas here we have
>>>>
>>>> convert(Ptr{T}, pointer(raw) + byte_number - 1)
>>>>
>>>> The former construction seems to emit a call to a Julia-intrinsic
>>>> function, while the latter executes the more expected simple machine
>>>> loads.
>>>> Is there a subtle difference between the two calls to pointer?
>>>>
>>>> Thanks all for your help!
>>>>
>>>> On March 24, 2015 at 12:19:00 PM, Matt Bauman ([email protected]
>>>> <javascript:>) wrote:
>>>>
>>>> (The key is to ensure that the method gets specialized for different
>>>> types with the parametric `::Type{T}` in the signature instead of
>>>> `T::DataType`).
>>>>
>>>> On Tuesday, March 24, 2015 at 12:10:59 PM UTC-4, Stefan Karpinski
>>>> wrote:
>>>>>
>>>>> This seems like it works fine to me (on both 0.3 and 0.4):
>>>>>
>>>>> immutable Test
>>>>> x::Float32
>>>>> y::Int64
>>>>> z::Int8
>>>>> end
>>>>>
>>>>> julia> a = [Test(1,2,3)]
>>>>> 1-element Array{Test,1}:
>>>>> Test(1.0f0,2,3)
>>>>>
>>>>> julia> b = copy(reinterpret(UInt8, a))
>>>>> 24-element Array{UInt8,1}:
>>>>> 0x00
>>>>> 0x00
>>>>> 0x80
>>>>> 0x3f
>>>>> 0x03
>>>>> 0x00
>>>>> 0x00
>>>>> 0x00
>>>>> 0x02
>>>>> 0x00
>>>>> 0x00
>>>>> 0x00
>>>>> 0x00
>>>>> 0x00
>>>>> 0x00
>>>>> 0x00
>>>>> 0x03
>>>>> 0xe0
>>>>> 0x82
>>>>> 0x10
>>>>> 0x01
>>>>> 0x00
>>>>> 0x00
>>>>> 0x00
>>>>>
>>>>> julia> prim_read{T}(::Type{T}, data::Array{Uint8,1}, offset::Int) =
>>>>> unsafe_load(convert(Ptr{T}, pointer(data) + offset))
>>>>> prim_read (generic function with 1 method)
>>>>>
>>>>> julia> prim_read(Test, b, 0)
>>>>> Test(1.0f0,2,3)
>>>>>
>>>>> julia> @code_native prim_read(Test, b, 0)
>>>>> .section __TEXT,__text,regular,pure_instructions
>>>>> Filename: none
>>>>> Source line: 1
>>>>> push RBP
>>>>> mov RBP, RSP
>>>>> Source line: 1
>>>>> mov RCX, QWORD PTR [RSI + 8]
>>>>> vmovss XMM0, DWORD PTR [RCX + RDX]
>>>>> mov RAX, QWORD PTR [RCX + RDX + 8]
>>>>> mov DL, BYTE PTR [RCX + RDX + 16]
>>>>> pop RBP
>>>>> ret
>>>>>
>>>>>
>>>>> On Tue, Mar 24, 2015 at 5:04 PM, Simon Danisch <[email protected]>
>>>>> wrote:
>>>>>
>>>>>> There is a high chance that I simply don't understand llvmcall well
>>>>>> enough, though ;)
>>>>>>
>>>>>> Am Montag, 23. März 2015 20:20:09 UTC+1 schrieb Sebastian Good:
>>>>>>>
>>>>>>> I'm trying to read some binary formatted data. In C, I would define
>>>>>>> an appropriately padded struct and cast away. Is is possible to do
>>>>>>> something similar in Julia, though for only one value at a time?
>>>>>>> Philosophically, I'd like to approximate the following, for some simple
>>>>>>> bittypes T (Int32, Float32, etc.)
>>>>>>>
>>>>>>> T read<T>(char* data, size_t offset) { return *(T*)(data + offset); }
>>>>>>>
>>>>>>> The transliteration of this brain-dead approach results in the
>>>>>>> following, which seems to allocate a boxed Pointer object on every
>>>>>>> invocation. The pointer function comes with ample warnings about how it
>>>>>>> shouldn't be used, and I imagine that it's not polite to the garbage
>>>>>>> collector.
>>>>>>>
>>>>>>> prim_read{T}(::Type{T}, data::AbstractArray{Uint8, 1}, byte_number)
>>>>>>> = unsafe_load(convert(Ptr{T}, pointer(data, byte_number)))
>>>>>>>
>>>>>>> I can reinterpret the whole array, but this will involve a division
>>>>>>> of the offset to calculate the new offset relative to the reinterpreted
>>>>>>> array, and it allocates an array object.
>>>>>>>
>>>>>>> Is there a better way to simply read the machine word at a
>>>>>>> particular offset in a byte array? I would think it should inline to a
>>>>>>> single assembly instruction if done right.
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>
>>
>