<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"><<a href="mailto:johannesweiss@apple.com" target="_blank">johannesweiss@apple.com</a>></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>
> On 9 Nov 2017, at 12:30 am, Kelvin Ma <<a href="mailto:kelvin13ma@gmail.com">kelvin13ma@gmail.com</a>> wrote:<br>
><br>
> 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>
><br>
> 0 1 2 3 4 5 6<br>
> [ precision:UInt8 | height:UInt16 | width:UInt16 | Nf:UInt8 | ... ]<br>
><br>
> 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>
><br>
> 1 - bind the entire buffer to UInt8.self, and then do buffer[1] << UInt8.bitWidth | buffer[2]. probably most straightforward, but doesn’t generalize well at all to larger Int types.<br>
><br>
> 2 - copy MemoryLayout<UInt16>.size bytes from offset 1 into the beginning of a new raw buffer, aligned to MemoryLayout<UInt16>.<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>
><br>
</span>> 3 - use withUnsafeMutablePointer(to:_:<wbr>) on a local variable of type UInt16, cast it to a raw pointer, and copy MemoryLayout<UInt16>.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'd need a fancier type system to express 'this is an uninitialised value on the stack that can only be read after it has been written to'. Sure you could use a local Int16? but that'd come with some overhead.<br>
<br>
With endianness I still think you can use that function below and you'll get it super efficient. The compiler will (likely) inline that whole function anyway.<br>
<br>
What's the problem with the local temporary variable? You'd need that in C too. Maybe can you post the C code that you'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<T: FixedWidthInteger>(_ pointer: UnsafeRawBufferPointer, index: Int, endianness: Endianness = .big) -> T {<br>
<span class="gmail-"> precondition(index >= 0)<br>
precondition(index <= pointer.count - MemoryLayout<T>.size)<br>
<br>
var value = T()<br>
withUnsafeMutableBytes(of: &value) { valuePtr in<br>
valuePtr.copyBytes(from: UnsafeRawBufferPointer(start: pointer.baseAddress!.advanced(<wbr>by: index),<br>
count: MemoryLayout<T>.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<I>(from buffer:UnsafeRawBufferPointer, atByteOffset offset:Int)<br> -> I where I:FixedWidthInteger<br>{<br> var i = I()<br> withUnsafeMutablePointer(to: &i)<br> {<br> UnsafeMutableRawPointer($0).copyBytes(from: buffer.baseAddress! + offset,<br> count: MemoryLayout<I>.size)<br> }<br><br> return I(bigEndian: i)<br>}</span></div><div><br></div><div><br></div></div></div></div>