Skip to content

Instantly share code, notes, and snippets.

@airspeedswift
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save airspeedswift/002fc0d46d5599bb11d0 to your computer and use it in GitHub Desktop.
Save airspeedswift/002fc0d46d5599bb11d0 to your computer and use it in GitHub Desktop.
Minimal example of a collection using UnsafeMutablePointer
// 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