Skip to content

Instantly share code, notes, and snippets.

@josephlord
Created September 9, 2015 22:07
Show Gist options
  • Select an option

  • Save josephlord/40676938db05c693299a to your computer and use it in GitHub Desktop.

Select an option

Save josephlord/40676938db05c693299a to your computer and use it in GitHub Desktop.
As presented at iOSDevUK briefly during the Swift Perfromance talk. See blog.human-friendly.com for details. This is exploratory and example code, not yet performance tested. I plan to blog more about the array type later.
final class Bar {
var i = 0
}
struct Foo {
var i:Int {
get {
return bar.i
}
set {
if !isUniquelyReferencedNonObjC(&bar) {
bar = Bar()
}
bar.i = newValue
}
}
private var bar = Bar()
}
var f = Foo()
isUniquelyReferencedNonObjC(&f.bar)
var f2 = f
isUniquelyReferencedNonObjC(&f.bar)
f.i = 5
isUniquelyReferencedNonObjC(&f.bar)
f.i
f2.i
extension Foo : CustomDebugStringConvertible {
var debugDescription:String {
get {
return "Foo: \(i)"
}
}
}
var x = Foo()
x.i = 4
var y = x
y.i = 5
x
// Slightly more realistic example but more a demo of a simplified array than something worth using in place of normal arrays
private final class FLArrayInternal<Element> : NonObjectiveCBase {
let arrayCount:Int
/**
Only allocates does not initialize
:param: count Array size
*/
private init(count:Int) {
arrayCount = count
buffer = UnsafeMutablePointer.alloc(count)
}
convenience init(count:Int, unsafePointer:UnsafeMutablePointer<Element>) {
self.init(count:count)
buffer.initializeFrom(unsafePointer, count: count)
}
private let buffer:UnsafeMutablePointer<Element>
deinit {
buffer.destroy(arrayCount)
buffer.dealloc(arrayCount)
}
}
struct FLArray<E> {
typealias Element = E
let count:Int
private var internalArray:FLArrayInternal<Element>
}
extension FLArray : ArrayLiteralConvertible {
init(array:[Element]) {
count = array.count
var arr = array
internalArray = arr.withUnsafeMutableBufferPointer { (inout buf:UnsafeMutableBufferPointer<E>) in
return FLArrayInternal<E>(count: array.count, unsafePointer: buf.baseAddress)
}
}
init(count:Int, repeatedValue:Element) {
self.init(uninitializedSize:count)
for i in 0..<count {
internalArray.buffer[i] = repeatedValue
}
}
init(arrayLiteral elements: FLArray.Element...) {
self.init(array:elements)
}
init<C : CollectionType where C.Generator.Element == Element>(collection: C) {
self.init(count: Int(collection.count.toIntMax()), sequence:collection)
}
init<S : SequenceType where S.Generator.Element == Element>(count:Int,sequence: S) {
self.init(uninitializedSize:count)
for (i,e) in sequence.enumerate() {
assert(i < count)
internalArray.buffer[i] = e
}
}
private init(uninitializedSize:Int) {
self.count = uninitializedSize
internalArray = FLArrayInternal(count: uninitializedSize)
}
}
extension FLArray : SequenceType {
typealias Generator = FLArrayGenerator<Element>
func underestimateCount()->Int {
return count
}
func generate()->FLArrayGenerator<Element> {
return FLArrayGenerator(array: self)
}
}
class FLArrayGenerator<Element> : GeneratorType {
private let count:Int
private var index:Int = 0
// Interesting decision point. By keeping the struct we don't update but will cause a copy made by mutations, the generator will remain valid
// We could just take a reference to the underlying internal class and the generator would return current values for array elements
private let array:FLArray<Element>
func next() -> Element? {
guard index < count else { return nil }
return array.internalArray.buffer[index++]
}
init(array:FLArray<Element>) {
self.array = array
count = array.count
}
}
// Mutation
extension FLArray {
private mutating func prepareForMutation() {
if !isUniquelyReferencedNonObjC(&internalArray) {
internalArray = FLArrayInternal<Element>(count: count, unsafePointer: internalArray.buffer)
}
}
subscript(position: Int)->Element {
get {
return internalArray.buffer[position]
}
set {
prepareForMutation()
internalArray.buffer[position] = newValue
}
}
}
extension FLArray {
func map<T>(@noescape transform: (Element) throws -> T) rethrows -> FLArray<T> {
let ret_array = FLArray<T>(uninitializedSize: self.count)
let buffer = ret_array.internalArray.buffer
for (i,v) in enumerate() {
buffer[i] = try transform(v)
}
return ret_array
}
}
/*extension FLArray : CollectionType {
}*/
extension FLArray : CustomDebugStringConvertible {
var debugDescription:String {
let strings:FLArray<String> = self.map { "\($0)" }
return "[" + strings.joinWithSeparator(",") + "]"
}
}
public func testArrayPrint() {
let x:FLArray = [1,2,sizeof(FLArray<Double>),strideof(FLArray<Double>)]
print(x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment