When writing a wrapper function to perform an FFT operation in Swift, I arrived at two different ways of passing a Swift array into Accelerate functions that take C array pointers. The first uses .withUnsafePointerToElements():
func fft(var inputArray:[Double]) -> [Double] {
var fftMagnitudes = [Double](count:inputArray.count, repeatedValue:0.0)
inputArray.withUnsafePointerToElements {(inputArrayPointer: UnsafePointer<Double>) -> () in
var zeroArray = [Double](count:inputArray.count, repeatedValue:0.0)
zeroArray.withUnsafePointerToElements { (zeroArrayPointer: UnsafePointer<Double>) -> () in
var splitComplexInput = DSPDoubleSplitComplex(realp: inputArrayPointer, imagp: zeroArrayPointer)
vDSP_fft_zipD(fft_weights, &splitComplexInput, 1, vDSP_Length(log2(CDouble(inputArray.count))), FFTDirection(FFT_FORWARD));
vDSP_zvmagsD(&splitComplexInput, 1, &fftMagnitudes, 1, vDSP_Length(inputArray.count));
}
}
return sqrt(fftMagnitudes)
}
and the second merely passes the Swift arrays in using &:
func fft(var inputArray:[Double]) -> [Double] {
var fftMagnitudes = [Double](count:inputArray.count, repeatedValue:0.0)
var zeroArray = [Double](count:inputArray.count, repeatedValue:0.0)
var splitComplexInput = DSPDoubleSplitComplex(realp: &inputArray, imagp: &zeroArray)
vDSP_fft_zipD(fft_weights, &splitComplexInput, 1, vDSP_Length(log2(CDouble(inputArray.count))), FFTDirection(FFT_FORWARD));
vDSP_zvmagsD(&splitComplexInput, 1, &fftMagnitudes, 1, vDSP_Length(inputArray.count));
return sqrt(fftMagnitudes)
}
Both appear to operate in the same manner, with the latter being cleaner and shorter. However, I'm not sure if the second way of doing this opens me up to the local inputArray copy and the zeroArray array being deallocated via ARC after their last usage (like what happens here), leaving a dangling pointer to an array that no longer exists.
It seems that .withUnsafePointerToElements() has to serve some purpose, but I can't quite figure out what it is. Is it required to guarantee the lifetime of the backing arrays in the above, or am I safe simply using & to pass these arrays into C functions?
I believe you do need to extend the lifetimes. I originally wrote my FFT code like your second example, but I've grown to believe this is unsafe. The problem is that the docs only seem to promise that a & reference will protect you from destruction until the end of the function call. So zeroArray in this case would be protected until the end of the DSPDoubleSplitComplex line. Since DSPDoubleSplitComplex just holds UnsafePointer, I don't see any reason to believe that can extend the life of zeroArray. (I assume the same applies to inputArray.)
I'm doing it a little differently that I think reads a little better:
// Generate a split complex vector from the real data
var realp = [Double](count:Int(fftLength), repeatedValue:0.0)
var imagp = realp
withExtendedLifetime(realp) { () -> () in
withExtendedLifetime(imagp) {
var splitComplex = DSPDoubleSplitComplex(realp:&realp, imagp:&imagp)
ctozD(ConstUnsafePointer(signal), 2, &splitComplex, 1, fftLength)
// Take the fft
fft_zripD(fftsetup, &splitComplex, 1, log2N, FFTDirection(kFFTDirection_Forward))
... rest of fft
}
}
I'm avoiding the extra pointer variable by using withExtendedLiftetime. I then can just use &realp and &imagp directly. The one required () -> () in can be eliminated this way if you like:
func withExtendedLifetime<T>(x: T, f: () -> () ) {
return Swift.withExtendedLifetime(x, f)
}
...
withExtendedLifetime(realp) {
withExtendedLifetime(imagp) {
var splitComplex = DSPDoubleSplitComplex(realp:&realp, imagp:&imagp)
ctozD(ConstUnsafePointer(signal), 2, &splitComplex, 1, fftLength)
...
Totally off-topic, but I notice you pass the real component in directly without calling ctozD. I thought Data Packing for Real FFTs indicates that you need to reorganize before calling fft_*. Your math is generally better than mine, so I may be missing something here. My full version is https://gist.github.com/rnapier/399676bd389c270e7b66
Related
Task
I am attempting to implement the Gated-GAN architecture using Swift for TensorFlow. In the generator of the Gated-GAN, there are k convolutional blocks (the "Gated-Transformer"), each of which take in a copy of the encoded image. The output of this layer is a single, weighted sum of the outputs of each convolutional block.
In the future, I would like to be able to increase k after a model has already been trained (and, say, fine-tune the k+1th transformer). As such, I don't want to hard-code k into the architecture.
Gated-Transformer diagram (I don't have enough reputation to post the picture directly)
Minimal Working Example
It would be very convenient to write something like this:
struct GatedTransformer: Layer {
// Normally the blocks in the transformer are residual blocks, but
// for simplicity I'll just use Conv2D here.
var convBlocks: [Conv2D<Float>]
/// Custom differentiable input (needed since the layer has two inputs).
struct GatedTransformerInput: Differentiable {
var image: Tensor<Float> // shape=[batch_size, height, width, channel]
var classDistributions: Tensor<Float> // shape=[class_count]
#differentiable
public init(image: Tensor<Float>, classDistributions: Tensor<Float>) {
self.image = image
self.classDistributions = classDistributions
}
}
public init(_ classCount: Int) {
precondition(classCount > 0)
// Some example parameters for Conv2D.
convBlocks = [Conv2D](repeating: Conv2D(filterShape: (3, 3, 128, 128), strides: (1, 1)), count: classCount)
}
var classCount: Int { get { return convBlocks.count } }
#differentiable
func callAsFunction(_ input: GatedTransformerInput) -> Tensor<Float> {
precondition(input.classDistributions.shape.dimensions.last! == self.classCount)
// <problematic_code id=0>
var imageArray: [Tensor<Float>] = [Tensor<Float>](repeating: input.image, count: self.classCount)
for i in 0..<self.classCount {
imageArray[i] = convBlocks[i](input.image).expandingShape(at: 1)
}
let result: Tensor<Float> = Tensor<Float>(concatenating: imageArray, alongAxis: 1)
// </problematic_code>
// Concatenate Tensors, multiply by class distributions, then sum along 'class' axis.
let highRankFactors: Tensor<Float> = input.classDistributions.expandingShape(at: [2, 3, 4])
let broadcastedFactors: Tensor<Float> = highRankFactors.broadcasted(to: result.shape)
return (broadcastedFactors * result).sum(squeezingAxes: 1)
}
}
However, this fails with the compiler error:
cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?
var imageArray: [Tensor<Float>] = [Tensor<Float>](repeating: input.image, count: self.classCount)
^
Alternate Approaches
Build a concatenated Tensor as we go along.
This approach fails because the re-assignment to result is not differentiable. A similar approach could be to use the Tensor += operator, although this does not compile either (Tensor.+= is not implemented as a #differentiable function, according to the official API).
// <problematic_code id=1>
var result: Tensor<Float> = convBlocks[0](input.image).expandingShape(at: 1)
for i in 0..<self.classCount {
let nextResult: Tensor<Float> = convBlocks[i](input.image).expandingShape(at: 1)
result = result.concatenated(with: nextResult, alongAxis: 1)
}
// </problematic_code>
Append to a new Array.
This fails because Array.append is not differentiable.
// <problematic_code id=2>
var imageArray: [Tensor<Float>] = []
for i in 0..<self.classCount {
imageArray.append(convBlocks[i](input.image).expandingShape(at: 1))
}
let result: Tensor<Float> = Tensor<Float>(concatenating: imageArray, alongAxis: 1)
// </problematic_code>
Make GatedTransformerInput a differentiable type.
I'm assuming there is a way to get this to work. However, this would involve conforming GatedTransformerInput to VectorProtocol, which feels like more work than necessary.
Define custom derivative for callAsFunction(...).
This could be another possible approach. However, to compute the derivative, I need to the intermediate array of Tensors. These values are not visible to an outside function, which can only see the input and output of callAsFunction(...)
Summarized Question
Is there a way to leverage Swift's already existing Differentiable types to implement the Gated-Transformer for an arbitrary (and possibly variable) k?
If not, how should I design a new Differentiable type that would allow me to do the above?
Answer
Your minimal working example is very close to doing what you want, and you can fix it with a small adjustment.
The compiler error
cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?
var imageArray: [Tensor<Float>] = [Tensor<Float>](repeating: input.image, count: self.classCount)
^
is happening because the compiler is trying to determine how this use of self.classCount contributes to the gradient. It fails while trying to do this because self.classCount is not differentiable (because it's a non-differentiable integer type).
In this case, you don't actually want uses of self.classCount to contribute to the gradient, so you can make the compiler happy by writing withoutDerivative(at: self).classCount. This tells the compiler to ignore how that particular use of self contributes to the gradient, even though the compiler is differentiating with respect to self.
Alternate Approaches
Some of your alternate approaches can also work.
Concatenated tensor
Use withoutDerivative(at: self).classCount in the for loop bound.
Note 1: The compiler diagnostic for this one could be improved. It's very unclear.
Note 2: I'm not sure why withoutDerivative(at: self).classCount isn't necessary in the for loop bound in the first example.
Using Tensor +=
Tensor += not differentiable because Swift AD currently (as of 2019-11-05) doesn't support differentiating mutating functions like +=. However, you should be able to differentiate functions that use result = result + foo instead of result += foo.
Custom derivative of callAsFunction(_:)
When you define custom derivatives, you specify "VJP" functions that return the original result and a "pullback" closure that calculates the derivative. The "pullback" closure can capture intermediate values from the original result calculation. e.g.
func vjpCallAsFunction(_ input: GatedTransformerInput) -> (Tensor<Float>, ...) {
...
var imageArray = ...
...
func pullback(...) -> ... {
...
<use imageArray>
...
}
return (result, pullback)
}
Of course, this causes unfortunate code duplication between callAsFunction and its VJP. So it's best to use automatically-calculated derivatives when that is possible.
I know that swift will optimize to copy on write for arrays but will it do this for all structs? For example:
struct Point {
var x:Float = 0
}
var p1 = Point()
var p2 = p1 //p1 and p2 share the same data under the hood
p2.x += 1 //p2 now has its own copy of the data
Array is implemented with copy-on-write behaviour – you'll get it regardless of any compiler optimisations (although of course, optimisations can decrease the number of cases where a copy needs to happen).
At a basic level, Array is just a structure that holds a reference to a heap-allocated buffer containing the elements – therefore multiple Array instances can reference the same buffer. When you come to mutate a given array instance, the implementation will check if the buffer is uniquely referenced, and if so, mutate it directly. Otherwise, the array will perform a copy of the underlying buffer in order to preserve value semantics.
However, with your Point structure – you're not implementing copy-on-write at a language level. Of course, as #Alexander says, this doesn't stop the compiler from performing all sorts of optimisations to minimise the cost of copying whole structures about. These optimisations needn't follow the exact behaviour of copy-on-write though – the compiler is simply free to do whatever it wishes, as long as the program runs according to the language specification.
In your specific example, both p1 and p2 are global, therefore the compiler needs to make them distinct instances, as other .swift files in the same module have access to them (although this could potentially be optimised away with whole-module optimisation). However, the compiler still doesn't need to copy the instances – it can just evaluate the floating-point addition at compile-time and initialise one of the globals with 0.0, and the other with 1.0.
And if they were local variables in a function, for example:
struct Point {
var x: Float = 0
}
func foo() {
var p1 = Point()
var p2 = p1
p2.x += 1
print(p2.x)
}
foo()
The compiler doesn't even have to create two Point instances to begin with – it can just create a single floating-point local variable initialised to 1.0, and print that.
Regarding passing value types as function arguments, for large enough types and (in the case of structures) functions that utilise enough of their properties, the compiler can pass them by reference rather than copying. The callee can then make a copy of them only if needed, such as when needing to work with a mutable copy.
In other cases where structures are passed by value, it's also possible for the compiler to specialise functions in order to only copy across the properties that the function needs.
For the following code:
struct Point {
var x: Float = 0
var y: Float = 1
}
func foo(p: Point) {
print(p.x)
}
var p1 = Point()
foo(p: p1)
Assuming foo(p:) isn't inlined by the compiler (it will in this example, but once its implementation reaches a certain size, the compiler won't think it worth it) – the compiler can specialise the function as:
func foo(px: Float) {
print(px)
}
foo(px: 0)
It only passes the value of Point's x property into the function, thereby saving the cost of copying the y property.
So the compiler will do whatever it can in order to reduce the copying of value types. But with so many various optimisations in different circumstances, you cannot simply boil the optimised behaviour of arbitrary value types down to just copy-on-write.
Swift Copy On Write(COW)
Make a copy only when it is necessary(e.g. when we change/write).
By default Value Type[About] does not support COW(Copy on Write) mechanism. But some of system structures like Collections(Array, Dictionary, Set) support it
Print address
// Print memory address
func address(_ object: UnsafeRawPointer) -> String {
let address = Int(bitPattern: object)
return NSString(format: "%p", address) as String
}
Value type default behaviour
struct A {
var value: Int = 0
}
//Default behavior(COW is not used)
var a1 = A()
var a2 = a1
//different addresses
print(address(&a1)) //0x7ffee48f24a8
print(address(&a2)) //0x7ffee48f24a0
//COW for a2 is not used
a2.value = 1
print(address(&a2)) //0x7ffee48f24a0
Value type with COW (Collection)
//collection(COW is realized)
var collection1 = [A()]
var collection2 = collection1
//same addresses
print(address(&collection1)) //0x600000c2c0e0
print(address(&collection2)) //0x600000c2c0e0
//COW for collection2 is used
collection2.append(A())
print(address(&collection2)) //0x600000c2c440
Use COW semantics for large values to minimise copying data every time. There are two common ways:
use a wrapper with value type which support COW.
use a wrapper which has a reference to heap where we can save large data. The point is:
we are able to create multiple copies of lite wrapper which will be pointed to the same large data in a heap
when we try to modify(write) a new reference with a copy of large data will be created - COW in action. AnyObject.isKnownUniquelyReferenced() which can say if there is a
single reference to this object
struct Box<T> {
fileprivate var ref: Ref<T>
init(value: T) {
self.ref = Ref(value: value)
}
var value: T {
get {
return ref.value
}
set {
//it is true when there is only one(single) reference to this object
//that is why it is safe to update,
//if not - new reference to heap is created with a copy of value
if (isKnownUniquelyReferenced(&self.ref)) {
self.ref.value = newValue
} else {
self.ref = Ref(value: newValue)
}
}
}
final class Ref<T> {
var value: T
init(value: T) {
self.value = value
}
}
}
let value = 0
var box1 = Box(value: value)
var box2 = box1
//same addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000ac2490
box2.value = 1
print(box1.value) //0
print(box2.value) //1
//COW in action
//different addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000a9dd30
I was surprised by the following playground I created after seeing some unexpected behavior in my code:
import Foundation
let bytes:[UInt8] = [20, 30, 40, 50, 60, 70]
var stream = bytes.generate()
func consumeTwo(var stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(stream) // This prints 20 and 30
print(stream.next()) // This prints 20!? I expected 40!
I had thought that marking the stream argument as var to the consumeTwo() function, the stream state/position would be shared/updated as it moved from function to function. But that appears to not be the case.
Does this mean I need to make that an inout? And pass with the ampersand? When does one use the var if that's the case?
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
+1 for archaic English in the question title. :)
When you use var in a function signature, you create a local copy of that value. It's the same as if you did this:
func consumeTwo(stream: IndexingGenerator<[UInt8]>) {
var localStream = stream
print(localStream.next())
print(localStream.next())
}
When the parameter is a reference type (i.e. a class), the duplicate "value" is a duplicate reference to the same object. But the thing you get from Array.generate() is a value type, so your local copy is a separate iterator with separate state.
Does this mean I need to make that an inout? And pass with the ampersand?
Yes — for your simple example, inout (and pass with &) is a simple and idiomatic way to do this:
func consumeTwo(inout stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(&stream) // This prints 20 and 30
print(stream.next()) // This prints 40
Remember: when you want to modify a value type inside a function and later see those modifications outside the function, use inout. And the & goes with it, so that it's clear both inside the function and at the call site that this behavior is happening.
When does one use the var if that's the case?
Use var for parameters only when you want to make a copy that's local to the function invocation. Admittedly, the use cases for this are few. Here's a contrived (and completely unnecessary) one:
func bananify(var strings: [String]) {
for i in 1.stride(to: strings.count, by: 2) {
strings[i] = "banana"
}
print(strings.joinWithSeparator(" "))
}
let words = ["foo", "bar", "bas", "zap", "asdf"]
bananify(words) // "foo banana bas banana asdf\n"
If you find this confusing, you're not the only one. For this reason, removing the ability to use var for parameters is a planned change for Swift 3.
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
As user3441734 notes, you can indeed create and use a reference-type iterator instead. Or you can write a reference type that holds and manages an iterator. For your hypothetical case of sharing a stream among several subsystems of a program, this is probably a good approach — representing a shared resource is one of the canonical cases for using reference types.
you wrote "It makes me wish that Generators were objects instead of structs."
there is no trouble define some generator as reference type ...
class G: AnyGenerator<Int> {
var i = 0
override func next() -> Int? {
return i++
}
}
let g = G()
func foo(gen: G)->Void {
print(gen.next())
print(gen.next())
}
foo(g)
print(g.next())
/*
Optional(0)
Optional(1)
Optional(2)
*/
I'm working with a C API from Swift and for one of the methods that I need to call I need to give a
UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
More Info:
Swift Interface:
public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t
Original C:
presage_error_code_t presage_predict(presage_t prsg, char*** result);
Generally, if a function takes a UnsafePointer<T> parameter
then you can pass a variable of type T as in "inout" parameter with &. In your case, T is
UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
which is the Swift mapping of char **. So you can call the C function
as
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }
From the documentation and sample code of the Presage library I
understand that this allocates an array of strings and assigns the
address of this array to the variable pointed to by prediction.
To avoid a memory leak, these strings have to be released eventually
with
presage_free_string_array(prediction)
To demonstrate that this actually works, I have taken the first
part of the demo code at presage_c_demo.c and translated it
to Swift:
// Duplicate the C strings to avoid premature deallocation:
let past = strdup("did you not sa")
let future = strdup("")
func get_past_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(past)
}
func get_future_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(future)
}
var prsg = presage_t()
presage_new(get_past_stream, nil, get_future_stream, nil, &prsg)
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK {
for var i = 0; prediction[i] != nil; i++ {
// Convert C string to Swift `String`:
let pred = String.fromCString(prediction[i])!
print ("prediction[\(i)]: \(pred)")
}
presage_free_string_array(prediction)
}
free(past)
free(future)
This actually worked and produced the output
prediction[0]: say
prediction[1]: said
prediction[2]: savages
prediction[3]: saw
prediction[4]: sat
prediction[5]: same
There may be a better way but this runs in playground and defines a value r with the type you want:
func ptrFromAddress<T>(p:UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
{
return p
}
var myInt:Int8 = 0
var p = ptrFromAddress(&myInt)
var q = ptrFromAddress(&p)
var r = ptrFromAddress(&q)
What's the point of defining ptrFromAddress, which seems like it does nothing? My thinking is that the section of the Swift interop book which discusses mutable pointers shows many ways to initialize them by passing some expression as an argument (like &x), but does not seem to show corresponding ways where you simply call UnsafeMutablePointer's initializer. So let's define a no-op function just to use those special initialization methods based on argument-passing
Update:
While I believe the method above is correct, it was pointed out by #alisoftware in another forum that this seems to be a safer and more idiomatic way to do the same thing:
var myInt: Int8 = 0
withUnsafeMutablePointer(&myInt) { (var p) in
withUnsafeMutablePointer(&p) { (var pp) in
withUnsafeMutablePointer(&pp) { (var ppp) in
// Do stuff with ppp which is a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
}
}
}
It's more idiomatic because you're using the function withUnsafeMutablePointer which is supplied by the Swift standard library, rather than defining your own helper. It's safer because you are guaranteed that the UnsafeMutablePointer is only alive during the extent of the call to the closure (so long as the closure itself does not store the pointer).
I'm doing some performance testing of Swift vs Objective-C.
I created a Mac OS hybrid Swift/Objective-C project that creates large arrays of prime numbers using either Swift or Objective-C.
It's got a decent UI and shows the results in a clear display. You can check out the project on Github if you're interested. It's called SwiftPerformanceBenchmark.
The Objective-C code uses a malloc'ed C array of ints, and the Swift code uses an Array object.
The Objective C code is therefore a lot faster.
I've read about creating an Array-like wrapper around a buffer of bytes using code like this:
let size = 10000
var ptr = UnsafePointer<Int>malloc(size)
var bytes = UnsafeBufferPointer<Int>(start: ptr, count: data.length)
I'd like to modify my sample program so I can switch between my Array<Int> storage and using an UnsafeBufferPointer<Int> at runtime with a checkbox in the UI.
Thus I need a base type for my primes array that will hold either an Array<Int> or an UnsafeBufferPointer<Int>. I'm still too weak on Swift syntax to figure out how to do this.
For my Array- based code, I'll have to use array.append(value), and for the UnsafeBufferPointer<Int>, which is pre-filled with data, I'll use array[index]. I guess if I have to I could pre-populate my Array object with placeholder values so I could use array[index] syntax in both cases.
Can somebody give me a base type that can hold either an Array<Int> or an UnsafeBufferPointer<Int>, and the type-casts to allocate either type at runtime?
EDIT:
Say, for example, I have the following:
let count = 1000
var swiftArray:[Int]?
let useSwiftArrays = checkbox.isChecked
typealias someType = //A type that lets me use either unsafeArray or swiftArray
var primesArray: someType?
if useSwiftArrays
{
//Create a swift array version
swiftArray [Int](count: count, repeatedValue: 0)
primesArray = someType(swiftArray)
}
else
{
var ptr = UnsafePointer<Int>malloc(count*sizeof(Int))
var unsafeArray = UnsafeBufferPointer<Int>(start: ptr, count: data.length)
primesArray = someType(unsafeArray)
}
if let requiredPrimes = primesArray
{
requiredPrimes[0] = 2
}
#MartinR's suggestion should help get code that can switch between the two. But there's a shortcut you can take to prove whether the performance difference is between Swift arrays and C arrays, and that's to switch the Swift compiler optimization to -Ounchecked. Doing this eliminates the bounds checks on array indices etc that you would be doing manually by using unsafe pointers.
If I download your project from github and do that, I find that the Objective-C version is twice as fast as the Swift version. But... that’s because sizeof(int) is 4, but sizeof(Int) is 8. If you switch the C version to use 8-byte arithmetic as well...
p.s. it works the other way around as well, if I switch the Swift code to use UInt32, it runs at 2x the speed.
OK, it’s not pretty but here is a generic function that will work on any kind of collection, which means you can pass in either an Array, or an UnsafeMutableBufferPointer, which means you can use it on a malloc’d memory range, or using the array’s .withUnsafeMutableBufferPointer.
Unfortunately, some of the necessities of the generic version make it slightly less efficient than the non-generic version when used on an array. But it does show quite a nice performance boost over arrays in -O when used with a buffer:
func storePrimes<C: MutableCollectionType where C.Generator.Element: IntegerType>(inout store: C) {
if isEmpty(store) { return }
var candidate: C.Generator.Element = 3
var primeCount = store.startIndex
store[primeCount++] = 2
var isPrime: Bool
while primeCount != store.endIndex {
isPrime = true
var oldPrimeCount = store.startIndex
for oldPrime in store {
if oldPrimeCount++ == primeCount { break }
if candidate % oldPrime == 0 { isPrime = false; break }
if candidate < oldPrime &* oldPrime { isPrime = true; break }
}
if isPrime { store[primeCount++] = candidate }
candidate = candidate.advancedBy(2)
}
}
let totalCount = 2_000_000
var primes = Array<CInt>(count: totalCount, repeatedValue: 0)
let startTime = CFAbsoluteTimeGetCurrent()
storePrimes(&primes)
// or…
primes.withUnsafeMutableBufferPointer { (inout buffer: UnsafeMutableBufferPointer<CInt>) -> Void in
storePrimes(&buffer)
}
let now = CFAbsoluteTimeGetCurrent()
let totalTime = now - startTime
println("Total time: \(totalTime), per second: \(Double(totalCount)/totalTime)")
I am not 100% sure if I understand your problem correctly, but perhaps
this goes into the direction that you need.
Both Array and UnsafeMutablePointer conform to MutableCollectionType (which requires a subscript getter and setter).
So this function would accept both types:
func foo<T : MutableCollectionType where T.Generator.Element == Int, T.Index == Int>(inout storage : T) {
storage[0] = 1
storage[1] = 2
}
Example with buffer pointer:
let size = 2
var ptr = UnsafeMutablePointer<Int>(malloc(UInt(size * sizeof(Int))))
var buffer = UnsafeMutableBufferPointer<Int>(start: ptr, count: size)
foo(&buffer)
for elem in buffer {
println(elem)
}
Example with array:
var array = [Int](count: 2, repeatedValue: 0)
foo(&array)
for elem in array {
println(elem)
}
For non-mutating functions you can use CollectionType
instead of MutableCollectionType.