To this and your other method about the real library code; right now the
PNG library doesn’t use buffer methods (since they don’t exist yet) and
pixels are plain-old-data so i’m not using the memory state API there
anyway (the original proposal didn’t even have anything to do with those
APIs actually). However I did take a few minutes to write a quick queue
implementation
<https://gist.github.com/kelvin13/0860334278aeab5c1cbaefbefb050268#file-dequeue-swift>
in Swift which does not make any assumptions about the Element type. I then
rewrote it using the hypothetical buffer API I proposed, and then the
hypothetical buffer API using subscript notation.
*These are the relevant function calls using the current API (the rest of
the code has been stripped out)*
newBuffer:UnsafeMutablePointer<Element> =
UnsafeMutablePointer<Element>.allocate(capacity:
newCapacity)
newBuffer .moveInitialize( from: buffer + self.zero,
count:
self.capacity - self.zero)
(newBuffer + self.zero).moveInitialize( from: buffer,
count: self.zero)
buffer.deallocate(capacity: self.capacity)
(self.buffer! + self.bufferPosition(of: self.count)).initialize(to:
data)
let dequeued:Element = (self.buffer! + self.zero).move()
*These are the function calls using the SE 184 API *
newBuffer:UnsafeMutableBufferPointer<Element> =
UnsafeMutableBufferPointer<Element>.allocate(capacity:
newCapacity)
newBuffer.moveInitialize(at: 0, from:
self.buffer[self.zero... ])
newBuffer.moveInitialize(at: self.zero, from: self.buffer[0 ..<
self.zero])
self.buffer.deallocate()
(self.buffer.baseAddress! + self.bufferPosition(of:
self.count)).initialize(to: data)
let dequeued:Element = (self.buffer! + self.zero).move()
*And with the proposed subscript notation*
newBuffer:UnsafeMutableBufferPointer<Element> =
UnsafeMutableBufferPointer<Element>.allocate(capacity:
newCapacity)
newBuffer[0... ].moveInitialize(from:
self.buffer[self.zero... ])
newBuffer[self.zero ... self.zero << 1].moveInitialize(from:
self.buffer[0 ..< self.zero])
self.buffer.deallocate()
(self.buffer.baseAddress! + self.bufferPosition(of:
self.count)).initialize(to: data)
let dequeued:Element = (self.buffer! + self.zero).move()
I took out the rebasing calls since apparently we’re bringing slices into
the scope of this proposal.
···
On Fri, Sep 29, 2017 at 6:17 PM, Andrew Trick <atrick@apple.com> wrote:
On Sep 29, 2017, at 4:03 PM, Taylor Swift <kelvin13ma@gmail.com> wrote:
On Sep 29, 2017, at 5:56 PM, Dave Abrahams <dabrahams@apple.com> wrote:
On Sep 29, 2017, at 3:48 PM, Taylor Swift <kelvin13ma@gmail.com> wrote:
On Fri, Sep 29, 2017 at 4:13 PM, Andrew Trick <atrick@apple.com> wrote:
On Sep 29, 2017, at 1:23 PM, Taylor Swift <kelvin13ma@gmail.com> wrote:
Instead of
buf.intialize(at: i, from: source)
We want to force a more obvious idiom:
buf[i..<n].intialize(from: source)
The problem with subscript notation is we currently get the n argument
from the source argument. So what would really have to be written is
buf[i ..< i + source.count].initialize(from: source)
which is a lot more ugly and redundant. One option could be to decouple
the count parameter from the length of the source buffer, but that opens up
the whole can of worms in which length do we use? What happens if n - i is
less than or longer than source.count? If we enforce the precondition
that source.count == n - i, then this syntax seems horribly redundant.
Sorry, a better analogy would have been:
buf[i...].intialize(from: source)
Whether you specify the slice’s end point depends on whether you want to
completely initialize that slice or whether you’re just filling up as much
of the buffer as you can. It also depends on whether `source` is also a
buffer (of known size) or some arbitrary Sequence.
Otherwise, point taken.
-Andy
After thinking about this more, one-sided ranges might provide just the
expressivity we need. What if:
buf[offset...].initialize(from: source) // initializes source.count
elements from source starting from offset
buf[offset ..< endIndex].initialize(from: source) // initializes up to
source.count elements from source starting from offset
The one sided one does not give a full initialization guarantee. The two
sided one guarantees the entire segment is initialized.
In every other context, x[i...] is equivalent to x[i..<x.endIndex]
I don't think breaking that precedent is a good idea.
For move operations, the one sided one will fully deinitialize the source
buffer while the two sided one will only deinitialize endIndex - offset
elements.
—
-Dave
well since people want to use subscript notation so much we need some way
of expressing case 1. writing both bounds in the subscript seems to imply a
full initialization (and thus partial movement) guarantee.
Presumably, in your use case, you’re working directly with buffers on both
sides (please point us to the real code). With the slicing approach, that
would be done as follows:
bufA[i ..< i + bufB.count].initialize(from: bufB)
That will enforce full initialization of the slice:
precondition(self.count == source.count).
Your point stands that it is redundant. That point will need to be weighed
against other points, which I think should be discussed in another thread.
-Andy