Can I extend multiple integer types at once to be initializable from an array of bytes? - swift

Using Swift 4, is there any way to compress these byte array initializers down? I hate having to create the call in each extension. Wishing there were a way to make this a single init method.
private func fromByteArray<T>(bytes: [UInt8]) -> T where T : UnsignedInteger {
return bytes.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(to: T.self, capacity: 1) {
$0
}
}.pointee
}
extension UInt16 {
init(bytes: [UInt8]) {
self.init(bigEndian: fromByteArray(bytes: bytes))
}
}
extension UInt32 {
init(bytes: [UInt8]) {
self.init(bigEndian: fromByteArray(bytes: bytes))
}
}
extension UInt64 {
init(bytes: [UInt8]) {
self.init(bigEndian: fromByteArray(bytes: bytes))
}
}

I'm going to one-up everybody by giving you one that not only collapses everything into one initializer in one extension, but also takes any sequence of UInt8 (including Data, DispatchData, Array, ContiguousArray, or anything else) and doesn't rely on Foundation and lets you choose your endianness:
extension FixedWidthInteger {
init<Bytes: Sequence>(bytes: Bytes, littleEndian: Bool = false) where Bytes.Element == UInt8 {
var s: Self = 0
let width = Self.bitWidth / 8
for (i, byte) in bytes.enumerated() where i < width {
let shiftAmount = (littleEndian ? i : (width - 1 - i)) * 8
s |= (Self(truncatingIfNeeded: byte) << shiftAmount)
}
self = s
}
}

Related

how to extend Double and Int in Swift with the same function

I want to create an extension for Swift Double, Int, and other numeric types that support the random(in:) function, like so:
extension Double {
// function to generate multiple random numbers of type
static func random(in range: ClosedRange<Self>, count: Int) -> [Self] {
var values = [Self]()
if count > 0 {
for _ in 0..<count {
values.append(Self.random(in: range))
}
}
return values
}
}
How do I do this without creating a separate extension for each type?
You can't really since there is no common protocol involved here but as far as I understand the types that has the method random(in:) can be grouped into types conforming to two protocols so you need only two implementations
// Double & Float
extension BinaryFloatingPoint {
static func random(in range: ClosedRange<Self>, count: Int) -> [Self] where Self.RawSignificand: FixedWidthInteger {
var values = [Self]()
if count > 0 {
for _ in 0..<count {
values.append(Self.random(in: range))
}
}
return values
}
}
// Int & UInt
extension FixedWidthInteger {
static func random(in range: ClosedRange<Self>, count: Int) -> [Self] {
var values = [Self]()
if count > 0 {
for _ in 0..<count {
values.append(Self.random(in: range))
}
}
return values
}
}

withUnsafeBytes + Generic type behavior

I have a function that allows me to read a number (Integer, Double etc) from a binary file using generic types. For example if I expect a Int64, il will read 8 bytes...
// A simple function that read n bytes from a FileHandle and returns
// the data
public func read(chunkSize: Int) -> Data {
return self.handle!.readData(ofLength: chunkSize)
}
// A function that reads the proper amount of bytes specified
// by the return type which in my case would be an integer
public func readNumber<I>() -> I? {
let data: Data = self.read(chunkSize: MemoryLayout<I>.size)
if data.count == 0 {
return nil
}
return data.withUnsafeBytes { $0.pointee }
}
The readNumber randomly returns nil for no reason. Not from the count check but from the last line.
However it perfectly works when I cast to I like so :
return data.withUnsafeBytes { $0.pointee } as I
Why is that ?
EDIT:
I reproduced this using Playgrounds :
class Test {
public func read(chunkSize: Int) -> Data {
return Data(repeating: 1, count: chunkSize)
}
public func readNumber<T>() -> T? {
let data: Data = read(chunkSize: MemoryLayout<T>.size)
if data.count == 0 {
return nil
}
return data.withUnsafeBytes { $0.pointee }
}
public func example() {
let value2: Double = readNumber()!
print(value2)
}
}
let test = Test()
for i in 0..<1000 {
test.example()
}
Seems I need to correct my comment a little. Even when Swift works consistently as programmed, the result may seem randomly changing, when you have some memory issue like accessing out of bounds.
First prepare a magical extension for UnsafePointer:
extension UnsafePointer {
var printingPointee: Pointee {
print(Pointee.self) //<- Check how Swift inferred `Pointee`
return self.pointee
}
}
And modify your EDIT code a little:
class Test {
public func read(chunkSize: Int) -> Data {
return Data(repeating: 1, count: chunkSize)
}
public func readNumber<T>() -> T? {
let data: Data = read(chunkSize: MemoryLayout<T>.size)
if data.count == 0 {
return nil
}
print(T.self) //<- Check how Swift inferred `T`
return data.withUnsafeBytes { $0.printingPointee }
}
public func example() {
let value2: Double = readNumber()!
print(value2)
}
}
let test = Test()
for _ in 0..<1000 {
test.example()
}
Output:
Double
Optional<Double>
7.748604185489348e-304
Double
Optional<Double>
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an
Optional value
How many pairs of Double and Optional<Double> shown would be seemingly random, but the cause of this behavior is quite clear.
In this line return data.withUnsafeBytes { $0.printingPointee }, Swift infers the type of $0 as UnsafePointer<Optional<Double>>.
In the current implementation of Swift, Optional<Double> occupies 9 bytes in memory:
print(MemoryLayout<Optional<Double>>.size) //-> 9
So, $0.pointee accesses 9 bytes starting from the pointer, although the pointer is pointing to the region of 8-byte:
|+0|+1|+2|+3|+4|+5|+6|+7|+8|
+--+--+--+--+--+--+--+--+
01 01 01 01 01 01 01 01 ??
<-taken from the Data->
As you know, the extra 9th (+8) byte cannot be predictable and may seemingly be random, which is an indicator of nil in Optional<Double>.
Exactly the same inference is working in your code. In your readNumber<T>(), the return type is clearly declared as T?, so, in the line return data.withUnsafeBytes { $0.pointee }, it is very natural that Swift infers the type of $0.pointee as Double? aka Optional<Double>.
You know you can control this type inference with adding as T.

How to read bytes of struct in Swift

I am working with a variety of structs in Swift that I need to be able to look at the memory of directly.
How can I look at a struct byte for byte?
For example:
struct AwesomeStructure {
var index: Int32
var id: UInt16
var stuff: UInt8
// etc.
}
The compiler will not allow me to do this:
func scopeOfAwesomeStruct() {
withUnsafePointer(to: &self, { (ptr: UnsafePointer<Int8>) in
})
}
Obviously because withUnsafePointer is a templated function that requires the UnsafePointer to be the same type as self.
So, how can I break down self (my structs) into 8 bit pieces? Yes, I want to be able to look at index in 4, 8-bit pieces, and so-on.
(In this case, I'm trying to port a CRC algorithm from C#, but I have been confounded by this problem for other reasons as well.)
edit/update: Xcode 12.5 • Swift 5.4
extension ContiguousBytes {
func object<T>() -> T { withUnsafeBytes { $0.load(as: T.self) } }
}
extension Data {
func subdata<R: RangeExpression>(in range: R) -> Self where R.Bound == Index {
subdata(in: range.relative(to: self) )
}
func object<T>(at offset: Int) -> T { subdata(in: offset...).object() }
}
extension Numeric {
var data: Data {
var source = self
return Data(bytes: &source, count: MemoryLayout<Self>.size)
}
}
struct AwesomeStructure {
let index: Int32
let id: UInt16
let stuff: UInt8
}
extension AwesomeStructure {
init(data: Data) {
index = data.object()
id = data.object(at: 4)
stuff = data.object(at: 6)
}
var data: Data { index.data + id.data + stuff.data }
}
let awesomeStructure = AwesomeStructure(index: 1, id: 2, stuff: 3)
let data = awesomeStructure.data
print(data) // 7 bytes
let structFromData = AwesomeStructure(data: data)
print(structFromData) // "AwesomeStructure(index: 1, id: 2, stuff: 3)\n"
You can use withUnsafeBytes(_:) directly like this:
mutating func scopeOfAwesomeStruct() {
withUnsafeBytes(of: &self) {rbp in
let ptr = rbp.baseAddress!.assumingMemoryBound(to: UInt8.self)
//...
}
}
As already noted, do not export ptr outside of the closure.
And it is not safe even if you have a function that knows the length of the structure. Swift API stability is not declared yet. Any of the layout details of structs are not guaranteed, including the orders of the properties and how they put paddings. Which may be different than the C# structs and may generate the different result than that of C#.
I (and many other developers) believe and expect that the current layout strategy would not change in the near future, so I would write some code like yours. But I do not think it's safe. Remember Swift is not C.
(Though, it's all the same if you copy the contents of a struct into a Data.)
If you want a strictly exact layout with C, you can write a C struct and import it into your Swift project.
Here's a decent first approximation. The trick is to use Swift.withUnsafeBytes(_:) to get a UnsafeRawBufferPointer, which can then be easily converted to Data using Data.init<SourceType>(buffer: UnsafeMutableBufferPointer<SourceType>).
This causes a copy of the memory, so you don't have to worry about any sort of dangling pointer issues.
import Foundation
struct AwesomeStructure {
let index: Int32 = 0x56
let id: UInt16 = 0x34
let stuff: UInt8 = 0x12
}
func toData<T>(_ input: inout T) -> Data {
var data = withUnsafeBytes(of: &input, Data.init)
let alignment = MemoryLayout<T>.alignment
let remainder = data.count % alignment
if remainder == 0 {
return data
}
else {
let paddingByteCount = alignment - remainder
return data + Data(count: paddingByteCount)
}
}
extension Data {
var prettyString: String {
return self.enumerated()
.lazy
.map { byteNumber, byte in String(format:"/* %02i */ 0x%02X", byteNumber, byte) }
.joined(separator: "\n")
}
}
var x = AwesomeStructure()
let d = toData(&x)
print(d.prettyString)

Is it possible to create a "Positive Number" type in Swift?

Sorry if this is a stupid question but I'm wondering if there's a way in Swift to create a type that exclusively holds numbers that are strictly greater than zero and where the "positiveness" of the values is enforced at compile time.
For example, can I create somehow write code like
func divide(x: PositiveNumber, y: PositiveNumber){
return x / y
}
such that
divide(1, 3)
works but
divide(1, 0)
won't compile?
The closest thing I could come up with was a struct with only one fallible initializer such that the type has either a positive value or is nil:
struct PositiveNumber {
let value: Float
init?(value: Float){
if value > 0 {
self.value = value
} else {
return nil
}
}
}
func / (left: PositiveNumber, right: PositiveNumber) -> Float {
return left.value / right.value
}
func divide(x: PositiveNumber?, y: PositiveNumber?) -> Float? {
if let x = x, y = y {
return x / y
}
return nil
}
let x1 = PositiveNumber(value: 1)
let y1 = PositiveNumber(value: 3)
let x2 = PositiveNumber(value: -1)
let y2 = PositiveNumber(value: 0)
divide(x1, y: y1)! // .333
divide(x2, y: y2)! // runtime error
That's not terrible but we still have to deal with a lot of optional handling/unwrapping. I'm asking this question because I have many places in my code where I need to check that a value is not zero and I'm curious if there's a way to remove that code and let the compiler handle it. The struct-based solution requires pretty much the same amount of code.
Number Type build on Float
This gist is contains a Struct that conforms to pretty much everything Float conforms too. It is just a vanilla copy of Float, change it to your liking.
Have you considered a custom operator?
infix operator /+ { associativity left precedence 150 }
func /+(lhs:Float,rhs:Float) -> Float? {
guard rhs > 0 else {
return nil
}
return lhs / rhs
}
let test = 2 /+ -1 // nil
let test2 = 2 /+ 1 // 2
let test3 = 2 /+ 1 + 2 // warning
It doesn't really matter if you let it return an optional, or an enum value, or different protocols. You will have to handle the return. But this way you get compiler warnings.
Limited Number Type with just an operator to handle divisions:
You could change math altogether and create a PositiveNumber Type that returns NaN when dividing by a value less than Zero.
public struct PositiveFloat {
public var value: Float
/// Create an instance initialized to zero.
public init() {
self.value = 0
}
/// Create an instance initialized to `value`.
public init(_ value: Float) {
self.value = value
}
public init(_ value: PositiveFloat) {
self.value = value.value
}
}
extension Float {
public var positive : PositiveFloat {
return PositiveFloat(self)
}
}
public func /(lhs:Float,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs / rhs.value
} else {
return Float.NaN
}
}
public func /(lhs:PositiveFloat,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs.value / rhs.value
} else {
return Float.NaN
}
}
let testNormal : Float = 10
let testFloat : Float = -5
let test = testFloat / testNormal.positive
if test.isNaN {
// do stuff
}

Map OptionSetType to Array

Given the following:
struct Weekdays: OptionSetType {
let rawValue: Int
init(rawValue: Int) { self.rawValue = rawValue }
static let Monday = Weekdays(rawValue: 1)
static let Tuesday = Weekdays(rawValue: 2)
static let Wednesday = Weekdays(rawValue: 4)
static let Thursday = Weekdays(rawValue: 8)
static let allOptions: [Weekdays] = [.Monday, .Tuesday, .Wednesday, .Thursday]
}
I can convert an array of Ints into a Weekdays object by doing this:
let arr = [1, 4]
let weekdays = arr.reduce(Weekdays()) { $0.union(Weekdays(rawValue: $1)) }
My question is, how do I take a Weekdays object and convert it into an array of Ints?
(Not necessarily better, but a different way to look at it and slightly
more general).
OptionSetType inherits from RawRepresentable and therefore can be
converted from and to the associated raw type, which in your case is
Int.
So the "missing link" is a conversion between the raw value (e.g. 5)
and an integer array of the bitwise components (e.g. [1, 4]).
This can be done with an Int extension method:
extension Int {
init(bitComponents : [Int]) {
self = bitComponents.reduce(0, combine: (+))
}
func bitComponents() -> [Int] {
return (0 ..< 8*sizeof(Int)).map( { 1 << $0 }).filter( { self & $0 != 0 } )
}
}
Then your conversion from an array to a Weekdays object becomes
let arr : [Int] = [1, 4]
let weekdays = Weekdays(rawValue: Int(bitComponents: arr))
print(weekdays)
// app.Weekdays(rawValue: 5)
and the reverse conversion
let array = weekdays.rawValue.bitComponents()
print(array)
// [1, 4]
Advantages:
The explicit definition of allOptions: is not needed.
It can be applied to other option set types (which have Int
as a raw value).
One could also try to define the conversions as a protocol extension,
e.g. of IntegerType, so that the same works with other integer raw types as well. However, this seems to be a bit complicated/ugly
because the left shift operator << is not part of the
IntegerType (or any) protocol.
Update for Swift 3:
extension Int {
init(bitComponents : [Int]) {
self = bitComponents.reduce(0, +)
}
func bitComponents() -> [Int] {
return (0 ..< 8*MemoryLayout<Int>.size).map( { 1 << $0 }).filter( { self & $0 != 0 } )
}
}
Not exactly answering the question, but might be useful to others. Based on Martin's answer I extract back the component objects:
extension FixedWidthInteger {
init(bitComponents : [Self]) {
self = bitComponents.reduce(0, +)
}
var bitComponents : [Self] {
(0 ..< Self.bitWidth).map { 1 << $0 } .filter { self & $0 != 0 }
}
}
extension OptionSet where RawValue: FixedWidthInteger, Self == Self.Element {
var components : [Self] { rawValue.bitComponents.map(Self.init) }
}
As I was writing the question, I figured it out:
let array = Weekdays.allOptions.filter { weekdays.contains($0) }.map { $0.rawValue }
Is there a better way?
You can improve the context of your extension by defining it conditionally on OptionSet.
extension OptionSet where RawValue: UnsignedInteger {
var individualCases: [Self] {
return (0..<(8 * MemoryLayout<RawValue>.size))
.map { bitsToShift in RawValue(1 << bitsToShift) } // Get every possible single-bit flag
.filter { (powerOfTwo: RawValue) -> Bool in rawValue & powerOfTwo != 0 } // filter out only the cases the receiver contains
.map { Self(rawValue: $0) } // create the `OptionSet` (single bit) type
}
}
let weekdays = Weekdays(rawValue: 0b11111)
weekdays.individualCases.map { $0.rawValue } // [1, 2, 4, 8, 16]
A warning: On my 13" 2019 MacBookPro, I had to provide all of the explicit types above to keep the methods type checking under 1500ms in Swift 5.0.
Thanks to MartinR for the inspiration to loop of the memory layout size.
To complete the example, I've updated the weekday type to Swift 5 below, and explicitly used the UInt8 type to make the individualCases more efficient. With UInt, it would loop over the first map and filter 64 times each, with UInt8 it only loops 8 times.
struct Weekdays: OptionSet {
let rawValue: UInt8
static let Monday = Weekdays(rawValue: 1)
static let Tuesday = Weekdays(rawValue: 2)
static let Wednesday = Weekdays(rawValue: 4)
static let Thursday = Weekdays(rawValue: 8)
static let Friday = Weekdays(rawValue: 16)
}