Better way to use ArraySlice with Accelerate functions? - arrays

I have some very large arrays that I have to perform millions of computations on. In Objective-C, the arrays would be stored as NSData and I'd abstract them to C arrays to use the Accelerate functions on (sum, add, etc). However, (given the obvious issues with using pointers everywhere) I'd love to make more use of the bounds checking that Swift arrays have built in. Therefore, I could use a nested withUnsafeBufferPointer for working with two arrays.
func mult(_ x: ArraySlice<Double>, _ y: ArraySlice<Double>) -> [Double] {
assert(x.count == y.count)
var results = [Double](repeating:0, count: x.count)
x.withUnsafeBufferPointer({xBuffer in
y.withUnsafeBufferPointer({yBuffer in
vDSP_vmulD([Double](xBuffer), 1, [Double](yBuffer), 1, &results, 1, vDSP_Length(xBuffer.count))
})
})
return results
}
var testArray = [Double]([0,1,2,3,4,5,6,7,8,9,10])
var testArray2 = [Double]([2,2,2,2,2,2,2,2,2,2,2])
let results = mult(testArray[5...10], testArray2[5...10])
print("\(results)")
First, having the recast the pointer as the intended type seems strange, when the compiler already knows how to cast the [Double] itself (the pointer passed inside the block is of type UnsafeBufferPointer<Double>, whereas the vDSP function is expects UnsafePointer<Double> (again, there is no complaint if I passed it the array variable itself)). Second, having to nest the withUnsafeBufferPointer looks strange, although I understand the usage. Finally, if I use ArraySlice<Double> as the input parameter type, then I can't generalize the function to both a Double array and a slice of that array.
Is there a better way to do this?

The recast is indeed a problem, it creates a whole new array. To avoid it you can use the baseAddress property of the UnsafeBuffer (and unwrap it in Swift 3)
The nested withUnsafeBufferPointer are indeed correct and can't be avoided (to my knowledge). The buffer pointer is only valid within the closure.
You can create a protocol for that
All in all, here is your code with these changes:
import Accelerate
protocol ArrayType {
associatedtype Element
var count : Int { get }
func withUnsafeBufferPointer<R>(_ body: #noescape (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R
}
extension Array : ArrayType {}
extension ArraySlice : ArrayType {}
extension ContiguousArray : ArrayType {}
func mult<A : ArrayType where A.Element == Double>(x: A, y: A) -> [Double] {
assert(x.count == y.count)
var result = [Double](repeating: 0, count: x.count)
x.withUnsafeBufferPointer { x in
y.withUnsafeBufferPointer { y in
vDSP_vmulD(x.baseAddress!, 1, y.baseAddress!, 1, &result, 1, vDSP_Length(x.count))
}
}
return result
}
var testArray1 : [Double] = [0,1,2,3,4,5,6,7,8,9,10]
var testArray2 : [Double] = [2,2,2,2,2,2,2,2,2,2,2]
let results = mult(x: testArray1[5...10], y: testArray2[5...10])
print("\(results)")
The forced unwrap will be fine, since the three conforming types won't ever give you a null pointer.

Related

Swift 2.2: cannot convert value of type '[B]' to specified type '[A]'

I'm officially confused why this is not working (there isn't much to explain here):
protocol A {
var value: Int { get set }
}
struct B: A {
var value: Int
}
let array: [B] = [B(value: 10)]
let singleAValue: A = array[0] // extracting works as expected
var protocolArray: [A] = []
protocolArray.append(singleAValue) // we can put the value inside the `protocolArray` without problems
print(protocolArray)
let newProtocolArray: [A] = array // but why does this conversion not work?
The array of the protocol type has a different memory representation than an array of B structs. Because an array of A can contain many different types of objects, the compiler has to create an indirection (a wrapper around the elements in the array) to ensure that they all have the same size.
Since this conversion is potentially costly (if the source array is large), the compiler forces you to make it explicit by mapping over the source array. You can write either this:
let newProtocolArray = array.map { $0 as A }
or this:
let newProtocolArray: [A] = array.map { $0 }
Both are equivalent.

Storing a reference to array in swift

I want to pass an array to an object and store a reference to this array. I want to be able to modify this array within this object and make sure that it's modified everywhere else.
Here is what I am trying to accomplish (how the code doesn't work)
class Foo {
var foo : Array<Int>
init(foo: Array<Int>) {
self.foo = foo
}
func modify() {
foo.append(5)
}
}
var a = [1,2,3,4]
let bar = Foo(a)
bar.modify()
print(a) // My goal is that it will print 1,2,3,4,5
My findings so far
A) The array (by default) are passed strange way. It's a reference until you modify an array length. As soon as you modify a length it will be copied and modified. As result, if I append or delete anything from it in the object it won't be seen outside
B) I can use inout on a function parameter. This will allow me to modify it within this function. However, as soon as I will try to assign it to some object member I am again struck by A)
C) I can wrap an array in some Container class. This probably is the cleanest way. However, I serialize/deserialize these objects and I would rather not put it in Container (because I will have to work around some things for serialization and deserialization and sending it to the server).
Are there anything else? Am I missing some Swift construct which allows me to do that?
You'll have to use an NSArray or NSMutableArray for this because Swift Arrays are value types so any assignment will make a copy.
You could make use of Swifts (very un-swifty) UnsafeMutablePointer.
Since (from your post) the behaviour references to arrays can't really seem be trusted, instead keep an UnsafeMutablePointer companion to the class inner array foo as well as any "external" arrays that you want to be binded to foo, in the sense that they are both just pointers to same address in memory.
class Foo {
var foo : [Int]
var pInner: UnsafeMutablePointer<Int>
init(foo: [Int]) {
pInner = UnsafeMutablePointer(foo)
self.foo = Array(UnsafeBufferPointer(start: pInner, count: foo.count))
}
func modify(inout pOuter: UnsafeMutablePointer<Int>) {
foo.append(5) // <-- foo gets new memory adress
pInner = UnsafeMutablePointer(foo)
pOuter = pInner
}
}
var a = [1,2,3,4] // first alloc in memory
var pOuter: UnsafeMutablePointer<Int> = UnsafeMutablePointer(a)
var bar = Foo(foo: a) // 'bar.foo' now at same address as 'a'
print(bar.foo) // [1,2,3,4]
bar.modify(&pOuter) // -> [1,2,3,4,5]
a = Array(UnsafeBufferPointer(start: pOuter, count: bar.foo.count))
/* Same pointer adress, OK! */
print(bar.pInner)
print(pOuter)
/* Naturally same value (same address in memory) */
print(bar.foo)
print(a)
Pointers can be dangerous though (hence the fitting type name), and, again, very un-swifty. Anyway...
/* When you're done: clear pointers. Usually when using
pointers like these you should take care to .destroy
and .dealloc, but here your pointers are just companions
to an Array property (which has a pointer an reference
counter itself), and the latter will take care of the
objects in memory when it goes out of scope. */
bar.pInner = nil
pOuter = nil
Now, what happens when either a or foo goes out of scope, will it break the variable that are not out of scope, or does Swift contain some clever reference counting that realises a memory address is still in use? I haven't investigated this, but feel free to indulge yourself in that.
From the Swift Programming Language,
Structures are always copied when they are passed around in your code, and do not use reference counting.
If you examine the contents of the array variable, you will see that indeed the append works:
class Foo {
var foo : Array
init(_ foo: Array) {
self.foo = foo
}
func modify() {
foo.append(5)
}
func printFoo() {
print("self.foo: \(foo)")
}
}
let a = [1,2,3,4]
let bar = Foo(a)
bar.modify()
bar.printFoo()
print("a: \(a)")
produces
self.foo: [1, 2, 3, 4, 5]
a: [1, 2, 3, 4]
You have taken a copy of a, not a reference to a.
a is declared a constant hence cannot be modified. If you are planning to modify the contents of a, declare it as a variable. i.e.,
var a = [1,2,3,4]
I haven't tested this but, as you are using a class to wrap the array, I see no reason why the following would not work.
class Foo {
var foo : Array<Int>
init(foo: inout Array<Int>) {
self.foo = foo
}
func modify() {
foo.append(5)
}
}
let a = [1,2,3,4]
let bar = Foo(&a)
bar.modify()
print("a: \(a)") // a: [1,2,3,4,5]

Using generic arrays in swift

This should be pretty simple. I have a data source that always gives me UInt16s. I derive different data sets from this raw data and plot the results. Some of the derived data sets are Floats, some are UInt8s, and some are UInt16s.
I queue the derived data where it is later retrieved by my graphing classes.
Queues are arrays of arrays and look like this: [[UInt16]], [[Float]], or [[UInt8]].
I'm trying to make use of generics, but I get a compiler error when I try to append a generic-typed array to an array that is declared to be [[AnyObject]].
As I'm learning Swift, I keep bumping into this AnyObject / generic problem quite a bit. Any help/insight is appreciated.
class Base: NSObject {
var queue : [[AnyObject]] = Array()
func addtoQueue<T>(dataSet: [T]) {
queue.append(dataSet)
}
func removeFromQueue() -> [AnyObject]? {
return queue.removeAtIndex(0)
}
}
class DataSet1 : Base {
func getSomeData(rawData: [UInt16]) {
var result : [Float] = processRawData(rawData)
addToQueue(result)
}
}
It may be that you don't understand what AnyObject is. It is the protocol type automatically adopted by all classes. But Float, UInt16, and UInt8 are not classes; they are structs.
It may be that you meant [[Any]] as the type of your array. In that case, you don't need a generic. This works:
var queue : [[Any]] = Array()
func addToQueue(dataSet:[Any]) {
queue.append(dataSet)
}
let f = Float(1)
let i1 = UInt8(2)
let i2 = UInt16(3)
addToQueue([f])
addToQueue([i1])
addToQueue([i2])
If you insist on [[AnyObject]], you have two problems:
Your generic is too generic. Not everything in the universe is an AnyObject, so how can the compiler know that this thing will be an AnyObject? Write your generic like this:
func addToQueue<T:AnyObject>(dataSet:[T]) {
queue.append(dataSet)
}
Now the compiler knows that only something conforming to AnyObject will be used when calling this method. At that point, however, it is a little hard to see what your generic is for; you are not using T elsewhere, so just write a normal function:
func addToQueue(dataSet:[AnyObject]) {
queue.append(dataSet)
}
The second problem is that you will still have to convert (as Drew's answer tells you), because there is no automagic bridging between, say, a UIInt16 and an AnyObject. Float is _ObjectiveCBridgeable, but UInt16 and UInt8 are not.
var queue : [[AnyObject]] = Array()
func addToQueue(dataSet:[AnyObject]) {
queue.append(dataSet)
}
let f = Float(1)
let i1 = UInt8(2)
let i2 = UInt16(3)
addToQueue([f])
addToQueue([NSNumber(unsignedChar: i1)])
addToQueue([NSNumber(unsignedShort: i2)])
What you'll need to do is 'box' up the underlying value. You could accomplish this using a protocol which exposed a setter/getter and an enum property of the underlying type that you can 'switch' on. Alternatively, you could see if you can make Foundation's built in NSNumber work for you. It's doing exactly that: boxes up any number of numerical types for you to store and retrieve later on:
var queue : Array<NSNumber> = []
queue.append(NSNumber(int: 1))
queue.append(NSNumber(double: 2.5))
queue.append(NSNumber(float: 3.5))
var types : Array<String> = []
for item in queue{
println("number type: \(item)")
}

Pass Array containing either class or struct

In Swift I declared a function that differs from Array.count only in that if array == nil the function returns 0. This is related to my UITableViewDataSource, but that's not important here. The problem is, if I declare the function as:
class func countOfItemsInArray(array: [AnyObject]?) -> Int
and then try to pass it an array of structs, it declares that the structs in the array do not conform to AnyObject. I understand why that is (I think), but is there a way to make this work with classes and structs, or should I just give in to copy and paste?
Generics are probably better suited to this problem than relying on covariance of [AnyObject]. A version of countElements that worked on an optional array and returned 0 in case of nil could go like this:
func countElements<T>(array: [T]?) -> Int {
return array?.count ?? 0
}
When you call countElements with any kind of array, the placeholder T is replaced with the type of the element contained in the array.
Note, this version overloads the existing countElements with a version that takes an optional. If you call it with a non-optional or any other kind of collection, the Swift version would be called, if you pass in an optional array, this one will be called. It’s debatable whether this is a good practice (I think it’s fine) or a bad one (some may disapprove :).
A version that works on any collection type would be:
func countElements<C: CollectionType>(col: C?) -> C.Index.Distance {
return col.map { countElements($0) } ?? 0
}
If you use Any instead of AnyObject you can pass any type, so also structs:
class func countOfItemsInArray(array: [Any]?) -> Int
This is kind of weird.
I used this function:
func countOfItemsInArray(array: [Any]?) -> Int {
return array != nil ? array!.count : 0
}
Declared two of your Assignment structs and put them in an array:
let structOne = Assignment(name: "1", dueDate: NSDate(), subject: "1")
let structTwo = Assignment(name: "2", dueDate: NSDate(), subject: "2")
let myArray: [Assignment] = [structOne, structTwo]
But here's the interesting part.
When calling println(countOfItemsInArray(myArray)) it gives the error:
<stdin>:27:33: error: 'Assignment' is not identical to 'Any'
println(countOfItemsInArray(myArray))
^
<stdin>:17:26: note: in initialization of parameter 'array'
func countOfItemsInArray(array: [Any]?) -> Int {
^
So I tested if myArray is of type [Any]:
println(myArray is [Any])
to which swift says:
<stdin>:25:17: error: 'Any' is not a subtype of 'Assignment'
println(myArray is [Any])
^
But when I change the type annotation of myArray to [Any] it works:
let myArray: [Any] = [structOne, structTwo]
And when simply handing the literal to the function it works, too:
countOfItemsInArray([structOne, structTwo])
The whole code example can be seen here.

How do I make a exact duplicate copy of an array?

How would I make an exact duplicate of an array?
I am having hard time finding information about duplicating an array in Swift.
I tried using .copy()
var originalArray = [1, 2, 3, 4]
var duplicateArray = originalArray.copy()
Arrays have full value semantics in Swift, so there's no need for anything fancy.
var duplicateArray = originalArray is all you need.
If the contents of your array are a reference type, then yes, this will only copy the pointers to your objects. To perform a deep copy of the contents, you would instead use map and perform a copy of each instance. For Foundation classes that conform to the NSCopying protocol, you can use the copy() method:
let x = [NSMutableArray(), NSMutableArray(), NSMutableArray()]
let y = x
let z = x.map { $0.copy() }
x[0] === y[0] // true
x[0] === z[0] // false
Note that there are pitfalls here that Swift's value semantics are working to protect you from—for example, since NSArray represents an immutable array, its copy method just returns a reference to itself, so the test above would yield unexpected results.
There is a third option to Nate's answer:
let z = x.map { $0 } // different array with same objects
* EDITED * edit starts here
Above is essentially the same as below and actually using the equality operator below will perform better since the array won't be copied unless it is changed (this is by design).
let z = x
Read more here: https://developer.apple.com/swift/blog/?id=10
* EDITED * edit ends here
adding or removing to this array won't affect the original array. However, changing any of the objects' any properties that the array holds would be seen in the original array. Because the objects in the array are not copies (assuming the array hold objects, not primitive numbers).
Nate is correct. If you are working with primitive arrays all you need to do is assign duplicateArray to the originalArray.
For the sake of completeness, if you were working an NSArray object, you would do the following to do a full copy of an NSArray:
var originalArray = [1, 2, 3, 4] as NSArray
var duplicateArray = NSArray(array:originalArray, copyItems: true)
For normal objects what can be done is to implement a protocol that supports copying, and make the object class implements this protocol like this:
protocol Copying {
init(original: Self)
}
extension Copying {
func copy() -> Self {
return Self.init(original: self)
}
}
And then the Array extension for cloning:
extension Array where Element: Copying {
func clone() -> Array {
var copiedArray = Array<Element>()
for element in self {
copiedArray.append(element.copy())
}
return copiedArray
}
}
and that is pretty much it, to view code and a sample check this gist
If you want to copy the items of an array of some class object.
Then you can follow the below code without using NSCopying protocol but you need to have an init method which should take all the parameters that are required for your object.
Here is the code for an example to test on playground.
class ABC {
var a = 0
func myCopy() -> ABC {
return ABC(value: self.a)
}
init(value: Int) {
self.a = value
}
}
var arrayA: [ABC] = [ABC(value: 1)]
var arrayB: [ABC] = arrayA.map { $0.myCopy() }
arrayB.first?.a = 2
print(arrayA.first?.a)//Prints 1
print(arrayB.first?.a)//Prints 2

Resources