Le mercredi 25 mars 2015 à 07:55 -0700, Matt Bauman a écrit : > See https://github.com/JuliaLang/julia/issues/6219#issuecomment-38117402
This looks like a case where, as discussed for string indexing, writing
something like p + 5bytes could make sense. Then the default behavior
could follow the more natural C convention, yet you'd never have to
write things like p + size/sizeof(T) (to quote Jeff's remark on the
issue).
Regards
> 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]) 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]> 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]) 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]> 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]>
> > > 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])
> > > 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.
> > > >
> > > >
> > > >
> > > >
> > >
> > >
> > >
> > >
> > >
> > >
> >
> >
> >
