withUnsafeBytes + Generic type behavior - swift

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.

Related

Storing Generic Objects in a Heterogeneous Array and retrieving object parameter as the correct type

Ahoy everyone,
I have recently been trying to implement a Node based graph system that passes data between nodes using plugs. Similar to many of the 3D applications like houdini and maya.
I have written a similar system before using Python, and wanted to try this with Swift as my first learning excersise. Boy did I jump into the deep end on this one.
I am stuck now with Swifts Arrays, as I would like to store a list of Generic plugs.
Each plug can have its own value type float, int, color, string, Vector Matrix.
I have read up about Type Erasers and opaque types, but still cant seem to get my values our of a list in a way that I can perform some arithmetic on them.
All and any help that might put me in the direction would be greatly appreciated :D
import Foundation
import MetalKit
protocol genericPlug {
associatedtype T
func GetValue() -> T
}
class Plug<T>:genericPlug{
var _value:T?
var value:T {
get{GetValue()}
set(val){
value = val
}
}
func GetValue() -> T{
return _value!
}
init(_ newValue:T){
_value=newValue
}
}
class Node{
var plugs:[genericPlug] = []
init(){
var p1 = Plug<Int>(0)
var p2 = Plug(vector2(1.2, 3.1))
var p3 = Plug([0.0, 3.1, 0.6, 1])
plugs.append(p1)
plugs.append(p2)
plugs.append(p3)
}
func execute(){
// will access the plugs in the array and perform some sort of calculations on them.
plugs[0].value + 1 // should equal 1
plugs[1].value.x + 0.8 // should have x=2.0 y=3.1
plugs[2].value[1] - 0.1 // should equal 3.0
}
}
Thanks everyone
Use a generic something to extract what you need. Your options are methods and subscripts.
protocol PlugValue {
init()
}
extension Int: PlugValue { }
extension Float: PlugValue { }
extension Double: PlugValue { }
extension SIMD3: PlugValue where Scalar == Int32 { }
struct Plug<Value: PlugValue> {
var value: Value
init(_ value: Value) {
self.value = value
}
}
protocol AnyPlug {
var anyValue: PlugValue { get }
}
extension AnyPlug {
subscript<Value: PlugValue>(type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
func callAsFunction<Value: PlugValue>(_ type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
}
extension Plug: AnyPlug {
var anyValue: PlugValue { value }
}
let plugs: [AnyPlug] = [
Plug(1),
Plug(2.3 as Float),
Plug(4.5),
Plug([6, 7, 8] as SIMD3)
]
plugs[0][Int.self] // 1
plugs[1][Double.self] // 0
plugs[1][] as Float // 2.3
let double: Double = plugs[2]() // 4.5
plugs[3](SIMD3.self).y // 7
With the array of protocols, do you have to down cast them into their Plug when retrieving them every time?
Essentially. This is true of all heterogenous sequences. Here are your options:
extension Array: PlugValue where Element: PlugValue { }
let plug: AnyPlug = Plug([0.1, 1.1, 2.1])
(plug as? Plug<[Double]>)?.value[1]
(plug.anyValue as? [Double])?[1]
extension Plug {
enum Error: Swift.Error {
case typeMismatch
}
}
extension AnyPlug {
func callAsFunction<Value: PlugValue, Return>(_ closure: (Value) -> Return) throws {
guard let value = anyValue as? Value
else { throw Plug<Value>.Error.typeMismatch }
closure(value)
}
}
try plug { (doubles: [Double]) in doubles[1] } // 1.1
try plug { ($0 as [Double])[1] } // 1.1
try plug { $0 as Int } // <Swift.Int>.Error.typeMismatch
I managed to find a solution that worked for my needs.
I am still looking at finding a better way to handle getting the data and their correct type.
import Foundation
import MetalKit
// Creating the PlugType Enum
enum PlugType{
case Integer(Int?)
case Float_(Float?)
case Double_(Double?)
case Vector3(simd_int3)
// default types
static func IntegerType() -> PlugType{ return PlugType.Integer(nil)}
static func FloatType() -> PlugType{ return PlugType.Float_(nil)}
static func DoubleType() -> PlugType{ return PlugType.Double_(nil)}
}
// Implements a way to retrieve the correct value type
extension PlugType{
var IntegerValue: Int{
switch self{
case .Integer(let value):
return value ?? 0
default:
return 0
}
}
var FloatValue: Float{
switch self
{
case .Float_(let value):
return value ?? 0
default:
return 0
}
}
var DoubleValue: Double{
switch self
{
case .Double_(let value):
return value ?? 0
default:
return 0
}
}
}
// Get the string representation of the PlugType
extension PlugType {
var typeName: String{
switch self {
case .Integer: return "Integer"
case .Float_: return "Float"
case .Double_: return "Double"
case .Vector3: return "Vector3"
}
}
var swiftType: Any.Type {
switch self {
case .Integer: return Int.self
case .Float_: return Float.self
case .Double_: return Double.self
case .Vector3: return simd_int3.self
}
}
}
class Plug{
var _value:PlugType?
var type:String? { get{ return _value?.typeName } }
init(_ newValue:PlugType){
_value = newValue
}
func geee<T>(_ input:T) -> T{
switch type {
case "Integer":
return getVal(_value!.IntegerValue) as! T
case "Double":
return getVal(_value!.DoubleValue) as! T
default:
return 0 as! T
}
}
func getVal(_ val:Int) -> Int {
return val
}
func getVal(_ val:Float) -> Float {
return val
}
func getVal(_ val:Double) -> Double {
return val
}
}
var plugs:[Plug] = []
var p1 = Plug(PlugType.Integer(2))

Swift 5: Why Range<String.Index>.Bound.utf16Offset calculates offsets even if empty string provided as argument

In Swift 4 I had a function to dump Range to debugger output defined as below:
extension Range where Bound == String.Index {
public func dump() -> String {
return "[\(lowerBound.encodedOffset)..<\(upperBound.encodedOffset)] (\(length))"
}
public var length: Int {
return upperBound.encodedOffset - lowerBound.encodedOffset
}
}
Since in Swift 5 encodedOffset is deprecated I changed implementation as below:
extension Range where Bound == String.Index {
public func dump(string: String) -> String {
let lower = lowerBound.utf16Offset(in: string)
let upper = upperBound.utf16Offset(in: string)
let result = "[\(lower)..<\(upper)] (\(upper - lower))"
return result
}
}
Test working as expected after implementation update:
class RangeTests: LogicTestCase {
func test_dump() {
let string = "Hello!"
let range = string.range(of: "ello")
Assert.equals(range?.dump(string: string), "[1..<5] (4)")
}
}
But function dump works correctly even if empty string is passed:
class RangeTests: LogicTestCase {
func test_dump() {
let string = "Hello!"
let range = string.range(of: "ello")
Assert.equals(range?.dump(string: ""), "[1..<5] (4)")
}
}
Shouldn't, for instance, call to lowerBound.utf16Offset(in: "") throw exception because we passing empty string, while range itself not empty?
UPDATE 1:
With the trick, with lowerBound.utf16Offset(in: "") mentioned above, the following two versions of sample index shifting function works identically:
extension String.Index {
// Deprecated due `encodedOffset`
public func shifting(by offset: Int) -> String.Index {
return String.Index(encodedOffset: encodedOffset + offset)
}
// Possible Swift 5 replacement to achieve index manipulation
// without reference to string.
public func shifting(by offset: Int) -> String.Index {
let newOffset = utf16Offset(in: "") + offset
let referenceString = String(repeating: " ", count: newOffset)
let result = String.Index(utf16Offset: newOffset, in: referenceString)
return result
}
}

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)

How to work generic with ranges?

My intention is the following:
My first function:
public func substringsOfLength(_ length: Int, inRange range: CountableClosedRange) -> Array<String>
{
...
}
And my second:
public func substringsOfLength(_ length: Int, inRange range: CountableRange) -> Array<String>
{
...
}
How can I realize both of them in one function? I know that Ranges are structures, so I can't use generalization paradigm. And I know too, that CountableRanges conform to RandomAccessCollection protocol and the bounds of them to Comparable, _Strideable and SignedInteger (Bound.Stride). Consequently, I search for a generic solution, right?
So I tried something like that:
public func substringsOfLength<T: RandomAccessCollection>(_ length: Int, inRange range: T) -> Array<String>
{
...
}
I know that here are the other protocols missing, but I don't know how to concretize the bounds with them.
I will try a little bit different and more "Swifty" approach ...
import Foundation
let str = "1234 567 890 1 23456"
extension String {
subscript(bounds: CountableClosedRange<Int>) -> String {
get {
return self[self.index(self.startIndex, offsetBy: bounds.lowerBound)...self.index(str.startIndex, offsetBy: bounds.upperBound)]
}
}
subscript(bounds: CountableRange<Int>) -> String {
get {
return self[bounds.lowerBound...bounds.upperBound]
}
}
var count: Int {
get {
return self.characters.count
}
}
func substrings(separatedBy: CharacterSet, isIncluded: (String) -> Bool)->[String] {
return self.components(separatedBy: separatedBy).filter(isIncluded)
}
}
let a0 = str[2..<14].components(separatedBy: .whitespacesAndNewlines).filter {
$0.count == 3
}
let a1 = str[2...13].substrings(separatedBy: .whitespacesAndNewlines) {
$0.count == 3
}
prints
["567", "890"] ["567", "890"]
Very soon the String will be the collection of characters and life will be easier ... (then just remove a part of your code)
As you can see, the function substrings is almost redundant and probably is better to remove it.

Swift: Function returning an Array of IntegerType

I would like to create a function that takes an NSData parameter, and, depending on what it reads from the NSData it returns an Array<Int8>, Array<Int16>, Array<Int32>, or Array<Int64>.
Basically, I need to return an array of IntegerType, with the specific subtype being determined at runtime.
I am stuck at the signature declaration of the function. (The inside would just be a simple switch, that would create the specific array type and return it).
The following very basic test does not compile
class Test {
func test(data:NSData) -> Array<IntegerType> {
return [1, 2, 3]
}
}
EDIT
It seems to be currently not possible, not because of having to return an array of a protocol type, but because the IntegerType protocol uses Self. Here is an interesting related question
IntegerType is a protocol, so the following should work:
class Test {
func test(data:NSData) -> Array<T: IntegerType> {
[1, 2, 3]
}
}
You can use enum with associated values for that:
enum IntArray {
case Int8([Swift.Int8])
case Int16([Swift.Int16])
case Int32([Swift.Int32])
case Int64([Swift.Int64])
}
class Test {
func test(data:NSData) -> IntArray {
return IntArray.Int8([1, 2, 3]);
}
}
on user side:
let obj = Test()
let array = obj.test(dat)
switch array {
case .Int8(let ary):
// here, ary is [Int8]
...
case .Int16(let ary):
// here, ary is [Int16]
...
case .Int32(let ary):
// here, ary is [Int32]
...
case .Int64(let ary):
// here, ary is [Int64]
...
}
As others have said in the comments, this won't work if you are trying to determine the function's return type at runtime. Swift generics only work at compile time, so changing the return type based off of what's in an NSData won't work.
If you can determine the return type at compile time, then you can use a generic function declaration like so:
func test<T: IntegerType>(data: NSData) -> Array<T> {
return [1, 2, 3]
}
Note: If you don't specify the type explicitly in your function somehow, then you'll need to define the variable the value returned from the function is assigned to. Like so:
var int8Array: Array<Int8> = test(NSData())
Since none of the generic based solutions are working, why don't you try returning [Any] and just check the return type as follows:-
func test(data:NSData) -> [Any]
{
var value1:Int8 = 1
var value2:Int8 = 2
return [value1,value2]
}
var x = test(NSData())
for xin in x
{
var intxin = xin as? Int8
if intxin != nil
{
println(intxin!)
}
}
The way I solved my problem was by defining the following protocol:
protocol IntegerArrayProtocol {
init(rawData: NSData!, length: Int)
func count() -> Int
subscript(index:Int) -> Int { get }
}
This deals with all the operations I need to perform on the array:
Read it from raw memory
Count how many elements it has
Access its elements by index, always returning Ints, regardless of the underlying integer
type
Then, I created a parameterized class that implements the protocol:
final class IntegerArray<T: ConvertibleToInteger>: IntegerArrayProtocol {
let arr: [T]
init(rawData: NSData!, length: Int){
//create array and allocate memory for all elements
arr = Array<T>(count: length, repeatedValue: T.zero())
// read it from the NSData source
// ....
}
func count() -> Int{
return arr.count
}
subscript(index:Int) -> Int {
get {
return arr[index].asInt()
}
}
}
The parameter types T should be able to convert themselves to Int, and should have a zero value (used when I initialize the array). For that, I created the ConvertibleToInteger protocol, which is used above to restrict the possible Ts:
protocol ConvertibleToInteger {
class func zero() -> Self
func asInt() -> Int
}
Then, I extended every type that I would like to create arrays of:
extension Int8: ConvertibleToInteger{
static func zero() -> Int8{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int16: ConvertibleToInteger{
static func zero() -> Int16{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int32: ConvertibleToInteger{
static func zero() -> Int32{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int64: ConvertibleToInteger{
static func zero() -> Int64{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
Finally, to read an array from NSData, I created the following function:
func readArray(rawData: NSData, length: Int): IntegerArrayProtocol? {
qBytes = // read from NSData how many bytes each element is
switch(qBytes){
case 1:
return IntegerArray<Int8>(rawData: rawData, length: length)
case 2:
return IntegerArray<Int16>(rawData: rawData, length: length)
case 3 ... 4:
return IntegerArray<Int32>(rawData: rawData, length: length)
case 5 ... 8:
return IntegerArray<Int64>(rawData: rawData, length: length)
default:
return nil
}
}