<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Nov 9, 2017 at 10:37 AM, Johannes Weiß <span dir="ltr">&lt;<a href="mailto:johannesweiss@apple.com" target="_blank">johannesweiss@apple.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Kelvin,<br>
<span class="gmail-"><br>
&gt; On 9 Nov 2017, at 12:30 am, Kelvin Ma &lt;<a href="mailto:kelvin13ma@gmail.com">kelvin13ma@gmail.com</a>&gt; wrote:<br>
&gt;<br>
&gt; For context, the problem I’m trying to solve is efficiently parsing JPEG chunks. This means reading each chunk of the JPEG from a file into a raw buffer pointer, and then parsing the chunk according to its expected layout. For example, a frame header chunk looks like this:<br>
&gt;<br>
&gt; 0                 1                 2                 3                  4                  5              6<br>
&gt; [ precision:UInt8 |          height:UInt16            |             width:UInt16            |   Nf:UInt8   | ... ]<br>
&gt;<br>
&gt; what I want to do is to be able to load the height and width into something I can pass into UInt16.init(bigEndian:) without failing because of alignment. I’ve thought of several options but none of them seem to be great.<br>
&gt;<br>
&gt; 1 - bind the entire buffer to UInt8.self, and then do buffer[1] &lt;&lt; UInt8.bitWidth | buffer[2]. probably most straightforward, but doesn’t generalize well at all to larger Int types.<br>
&gt;<br>
&gt; 2 - copy MemoryLayout&lt;UInt16&gt;.size bytes from offset 1 into the beginning of a new raw buffer, aligned to MemoryLayout&lt;UInt16&gt;.<wbr>alignment, and do load(fromByteOffset: 0, as: UInt16.self) from that. Seems very inefficient because you have to allocate a new heap buffer copy everything over and then free it just to hold the bytes in the right alignment.<br>
&gt;<br>
</span>&gt; 3 - use withUnsafeMutablePointer(to:_:<wbr>) on a local variable of type UInt16, cast it to a raw pointer, and copy MemoryLayout&lt;UInt16&gt;.sizebytes into it. Like 2 it involves declaring a temporary variable which is annoying, and also, while the default initialization isn’t that big a problem, it’s introducing a meaningless value into the source code and can be problematic for non-integer types. Also, wasn’t Swift supposed to be designed so that Optional is the only thing which has a “default” value; Bool does not default to false and Int does not default to 0. Default constructors are evil.<br>
<br>
I agree. However, that meaningless value would just exist very temporarily in a function. I think you&#39;d need a fancier type system to express &#39;this is an uninitialised value on the stack that can only be read after it has been written to&#39;. Sure you could use a local Int16? but that&#39;d come with some overhead.<br>
<br>
With endianness I still think you can use that function below and you&#39;ll get it super efficient. The compiler will (likely) inline that whole function anyway.<br>
<br>
What&#39;s the problem with the local temporary variable? You&#39;d need that in C too. Maybe can you post the C code that you&#39;d like to write? Then we can work from there and create some Swift code that does the same.<br>
<br>
<br>
enum Endianness {<br>
    case little<br>
    case big<br>
}<br>
<br>
func integerFromBuffer&lt;T: FixedWidthInteger&gt;(_ pointer: UnsafeRawBufferPointer, index: Int, endianness: Endianness = .big) -&gt; T {<br>
<span class="gmail-">    precondition(index &gt;= 0)<br>
    precondition(index &lt;= pointer.count - MemoryLayout&lt;T&gt;.size)<br>
<br>
    var value = T()<br>
    withUnsafeMutableBytes(of: &amp;value) { valuePtr in<br>
        valuePtr.copyBytes(from: UnsafeRawBufferPointer(start: pointer.baseAddress!.advanced(<wbr>by: index),<br>
                                                        count: MemoryLayout&lt;T&gt;.size))<br>
    }<br>
</span>    switch endianness {<br>
        case .little:<br>
            return value.littleEndian /* does nothing on little endian, swaps on big */<br>
        case .big:<br>
            return value.bigEndian /* does nothing on big endian, swaps on little */<br>
    }<br>
}<br>
<span class="gmail-HOEnZb"><font color="#888888"><br>
-- Johannes<br>
</font></span><div class="gmail-HOEnZb"><div class="gmail-h5"><br></div></div></blockquote><div><br></div><div>Is it safe to use UnsafeRawPointer instead?</div><div><br></div><div><span style="font-family:monospace,monospace">func loadBigEndianInt&lt;I&gt;(from buffer:UnsafeRawBufferPointer, atByteOffset offset:Int)<br>    -&gt; I where I:FixedWidthInteger<br>{<br>    var i = I()<br>    withUnsafeMutablePointer(to: &amp;i)<br>    {<br>        UnsafeMutableRawPointer($0).copyBytes(from: buffer.baseAddress! + offset,<br>            count: MemoryLayout&lt;I&gt;.size)<br>    }<br><br>    return I(bigEndian: i)<br>}</span></div><div><br></div><div><br></div></div></div></div>