Last active
August 29, 2015 14:12
-
-
Save airspeedswift/002fc0d46d5599bb11d0 to your computer and use it in GitHub Desktop.
Minimal example of a collection using UnsafeMutablePointer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Note this is a class not a struct, so it does NOT have value semantics | |
public class UnsafeCollection<T> { | |
private var _len: Int = 0 | |
private var _buflen: Int = 0 | |
private var _buf: UnsafeMutablePointer<T> = nil | |
public func removeAll(keepCapacity: Bool = false) { | |
_buf.destroy(_len) | |
_len = 0 | |
if !keepCapacity { | |
// it appears deallocating a nil | |
// pointer is OK, whereas deallocating | |
// zero bytes is not... | |
_buf.dealloc(_buflen) | |
_buflen = 0 | |
_buf = nil | |
} | |
} | |
public required init() { } | |
deinit { self.removeAll(keepCapacity: false) } | |
public var count: Int { return _len } | |
public var isEmpty: Bool { return _len == 0 } | |
} | |
extension UnsafeCollection: MutableCollectionType { | |
public typealias Index = Int | |
public var startIndex: Int { return 0 } | |
public var endIndex: Int { return _len } | |
public subscript(idx: Int) -> T { | |
get { | |
precondition(idx < _len) | |
return _buf[idx] | |
} | |
set(newElement) { | |
precondition(idx < _len) | |
// since UnsafeMutablePointer.subscript { set } isn't | |
// documented, it's unclear if _buf[idx] = newElement | |
// would work instead of the below... | |
let ptr = _buf.advancedBy(idx) | |
ptr.destroy() | |
ptr.initialize(newElement) | |
} | |
} | |
public typealias Generator = IndexingGenerator<UnsafeCollection> | |
public func generate() -> Generator { | |
return Generator(self) | |
} | |
} | |
extension UnsafeCollection: ExtensibleCollectionType { | |
public func reserveCapacity(n: Index.Distance) { | |
if n > _buflen { | |
let newBuf = UnsafeMutablePointer<T>.alloc(n) | |
// moveInitializeBackwardFrom appears to be necessary | |
// as of Swift 1.1, even though old and new mem | |
// shouldn't overlap | |
newBuf.moveInitializeBackwardFrom(_buf, count: _len) | |
_buf.dealloc(_buflen) | |
_buf = newBuf | |
_buflen = n | |
} | |
} | |
public func append(x: T) { | |
if _len == _buflen { | |
reserveCapacity(Int(Double(_len) * 1.6) + 1) | |
} | |
_buf.advancedBy(_len++).initialize(x) | |
} | |
public func extend<S: SequenceType where S.Generator.Element == T>(newElements: S) { | |
// reserving additional space for underestimateCount(newElements) | |
// would go here but currently crashes the compiler | |
var g = newElements.generate() | |
// while loop rather than for...in due to type inference issue | |
// with sequences constrained by generic class parameter | |
while let x: T = g.next() { | |
self.append(x) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment