Skip to content

Instantly share code, notes, and snippets.

@romainmenke
Last active June 23, 2016 16:33
Show Gist options
  • Save romainmenke/dd574ca063ca26c109795515e98e820e to your computer and use it in GitHub Desktop.
Save romainmenke/dd574ca063ca26c109795515e98e820e to your computer and use it in GitHub Desktop.
import Foundation
private class Weak<T : AnyObject> {
private weak var pointer : T?
private init(pointer:T) { self.pointer = pointer }
}
prefix operator § {}
postfix operator § {}
private prefix func §<T : AnyObject>(rhs:T) -> Weak<T> {
return Weak(pointer: rhs)
}
private prefix func §<T>(rhs:Weak<T>) -> T? {
return rhs.pointer
}
private postfix func §<T>(rhs:Weak<T>) -> T? {
return rhs.pointer
}
private func +<T>(lhs:[Weak<T>], rhs:T) -> [Weak<T>] {
var copy = lhs
copy.append(§rhs)
return copy
}
private func +=<T>(inout lhs:[Weak<T>], rhs:T) {
lhs.append(§rhs)
}
public final class WeakCollection<Element : AnyObject> : CollectionType, MutableCollectionType, _DestructorSafeContainer {
/// Always zero, which is the index of the first element when non-empty.
public var startIndex: Int { return 0 }
/// A "past-the-end" element index; the successor of the last valid
/// subscript argument.
public var endIndex: Int { clean(); return pointers.count }
/// Access the `index`th element. Reading is O(1). Writing is
/// O(1) unless `self`'s storage is shared with another live array; O(`count`) if `self` does not wrap a bridged `NSArray`; otherwise the efficiency is unspecified..
public subscript (index: Int) -> Element {
get {
clean()
return pointers[index].pointer!
} set(value) {
clean()
pointers[index] = §value
}
}
public subscript (subRange: Range<Int>) -> ArraySlice<Element> {
get {
clean()
return (pointers.map { $0.pointer! })[subRange]
} set(value) {
clean()
var newPointers = (pointers.map { $0.pointer! })
newPointers[subRange] = value
self.pointers = newPointers.map { §$0 }
}
}
private var pointers : [Weak<Element>] = []
public init() {}
private func clean() {
while let index = (self.pointers.indexOf{ $0.pointer == nil }) {
self.pointers.removeAtIndex(index)
}
}
}
extension WeakCollection : ArrayLiteralConvertible {
/// Create an instance containing `elements`.
public convenience init(arrayLiteral elements: Element...) {
self.init()
var pointers : [Weak<Element>] = []
for element in elements {
pointers += element
}
self.pointers = pointers
}
}
extension WeakCollection {
/// Construct a Array of `count` elements, each initialized to
/// `repeatedValue`.
public convenience init(count: Int, repeatedValue: Element) {
self.init()
for _ in 0..<count {
pointers.append(§repeatedValue)
}
}
/// The number of elements the Array stores.
public var count: Int { clean(); return pointers.count }
/// The number of elements the `Array` can store without reallocation.
public var capacity: Int { clean(); return pointers.count }
/// Reserve enough space to store `minimumCapacity` elements.
///
/// - Postcondition: `capacity >= minimumCapacity` and the array has
/// mutable contiguous storage.
///
/// - Complexity: O(`self.count`).
public func reserveCapacity(minimumCapacity: Int) { clean(); pointers.reserveCapacity(minimumCapacity) }
/// Append `newElement` to the Array.
///
/// - Complexity: Amortized O(1) unless `self`'s storage is shared with another live array; O(`count`) if `self` does not wrap a bridged `NSArray`; otherwise the efficiency is unspecified..
public func append(newElement: Element) { clean(); pointers.append(§newElement) }
/// Append the elements of `newElements` to `self`.
///
/// - Complexity: O(*length of result*).
public func appendContentsOf<S : SequenceType where S.Generator.Element == Element>(newElements: S) {
clean()
for element in newElements {
pointers.append(§element)
}
}
/// Append the elements of `newElements` to `self`.
///
/// - Complexity: O(*length of result*).
public func appendContentsOf<C : CollectionType where C.Generator.Element == Element>(newElements: C) {
clean()
for element in newElements {
pointers.append(§element)
}
}
/// Remove an element from the end of the Array in O(1).
///
/// - Requires: `count > 0`.
public func removeLast() -> Element {
clean()
return pointers.removeLast().pointer!
}
/// Insert `newElement` at index `i`.
///
/// - Requires: `i <= count`.
///
/// - Complexity: O(`self.count`).
public func insert(newElement: Element, atIndex i: Int) {
clean()
pointers.insert(§newElement, atIndex: i)
}
/// Remove and return the element at index `i`.
///
/// Invalidates all indices with respect to `self`.
///
/// - Complexity: O(`self.count`).
public func removeAtIndex(index: Int) -> Element {
clean()
return (§(pointers.removeAtIndex(index)))!
}
/// Remove all elements.
///
/// - Postcondition: `capacity == 0` iff `keepCapacity` is `false`.
///
/// - Complexity: O(`self.count`).
public func removeAll(keepCapacity keepCapacity: Bool = true) {
pointers.removeAll(keepCapacity: keepCapacity)
}
}
extension WeakCollection : CustomStringConvertible, CustomDebugStringConvertible {
/// A textual representation of `self`.
public var description: String { clean(); return (self.map{ $0 }).description }
/// A textual representation of `self`, suitable for debugging.
public var debugDescription: String { clean(); return (self.map{ $0 }).debugDescription }
}
extension WeakCollection {
/// If `!self.isEmpty`, remove the last element and return it, otherwise
/// return `nil`.
///
/// - Complexity: O(`self.count`) if the array is bridged,
/// otherwise O(1).
public func popLast() -> Element? {
clean()
return pointers.popLast()?.pointer
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment