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.
>>>>>>>     
>>>>>>>   
>>>>>>   
>>>>>       
>>>   
>>     
>

Reply via email to