WeakSet.swift 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. //
  2. // WeakSet.swift
  3. // LoopKit
  4. //
  5. // Created by Michael Pangburn
  6. // Copyright © 2019 LoopKit Authors. All rights reserved.
  7. //
  8. import Foundation
  9. public struct Weak<Value> {
  10. // Rather than constrain `Value` to `AnyObject`, we store the value privately as `AnyObject`.
  11. // This allows us to hold weak references to class-constrained protocol types,
  12. // which as types do not themselves conform to `AnyObject`.
  13. private weak var _value: AnyObject?
  14. public var value: Value? {
  15. return _value as? Value
  16. }
  17. public init(_ value: Value) {
  18. // All Swift values are implicitly convertible to `AnyObject`,
  19. // so this runtime check is the tradeoff for supporting class-constrained protocol types.
  20. precondition(Mirror(reflecting: value).displayStyle == .class, "Weak references can only be held of class types.")
  21. _value = value as AnyObject
  22. }
  23. }
  24. /// A set that holds weak references to its members.
  25. ///
  26. /// `Element` must be a class or class-constrained protocol type.
  27. public struct WeakSet<Element> {
  28. private var storage: [ObjectIdentifier: Weak<Element>]
  29. public init<S: Sequence>(_ sequence: S) where S.Element == Element {
  30. let keysAndValues = sequence.map { (key: ObjectIdentifier($0 as AnyObject), value: Weak($0)) }
  31. storage = Dictionary(keysAndValues, uniquingKeysWith: { $1 })
  32. }
  33. public mutating func cleanupDeallocatedElements() {
  34. for (id, element) in storage where element.value == nil {
  35. storage.removeValue(forKey: id)
  36. }
  37. }
  38. }
  39. extension WeakSet: SetAlgebra {
  40. public init() {
  41. storage = [:]
  42. }
  43. public var isEmpty: Bool {
  44. return storage.values.allSatisfy { $0.value == nil }
  45. }
  46. public func contains(_ member: Element) -> Bool {
  47. let id = ObjectIdentifier(member as AnyObject)
  48. return storage[id] != nil
  49. }
  50. @discardableResult
  51. public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) {
  52. let id = ObjectIdentifier(newMember as AnyObject)
  53. if let existingMember = storage[id]?.value {
  54. return (inserted: false, memberAfterInsert: existingMember)
  55. } else {
  56. storage[id] = Weak(newMember)
  57. return (inserted: true, memberAfterInsert: newMember)
  58. }
  59. }
  60. @discardableResult
  61. public mutating func update(with newMember: Element) -> Element? {
  62. let id = ObjectIdentifier(newMember as AnyObject)
  63. let previousMember = storage.removeValue(forKey: id)
  64. storage[id] = Weak(newMember)
  65. return previousMember?.value
  66. }
  67. @discardableResult
  68. public mutating func remove(_ member: Element) -> Element? {
  69. let id = ObjectIdentifier(member as AnyObject)
  70. return storage.removeValue(forKey: id)?.value
  71. }
  72. public mutating func formUnion(_ other: WeakSet<Element>) {
  73. for (id, element) in other.storage where storage[id] == nil {
  74. // Ignore deallocated elements
  75. if element.value != nil {
  76. storage[id] = element
  77. }
  78. }
  79. }
  80. public func union(_ other: WeakSet<Element>) -> WeakSet<Element> {
  81. var result = self
  82. result.formUnion(other)
  83. return result
  84. }
  85. public mutating func formIntersection(_ other: WeakSet<Element>) {
  86. for id in storage.keys where other.storage[id] == nil {
  87. storage.removeValue(forKey: id)
  88. }
  89. }
  90. public func intersection(_ other: WeakSet<Element>) -> WeakSet<Element> {
  91. var result = self
  92. result.formIntersection(other)
  93. return result
  94. }
  95. public mutating func formSymmetricDifference(_ other: WeakSet<Element>) {
  96. for (id, element) in other.storage {
  97. if storage[id] == nil {
  98. // Ignore deallocated elements
  99. if element.value != nil {
  100. storage[id] = element
  101. }
  102. } else {
  103. storage.removeValue(forKey: id)
  104. }
  105. }
  106. }
  107. public func symmetricDifference(_ other: WeakSet<Element>) -> WeakSet<Element> {
  108. var result = self
  109. result.formSymmetricDifference(other)
  110. return result
  111. }
  112. }
  113. extension WeakSet: Sequence {
  114. public struct Iterator: IteratorProtocol {
  115. private var base: Dictionary<ObjectIdentifier, Weak<Element>>.Iterator
  116. fileprivate init(_ base: Dictionary<ObjectIdentifier, Weak<Element>>.Iterator) {
  117. self.base = base
  118. }
  119. public mutating func next() -> Element? {
  120. while let element = base.next()?.value {
  121. if let value = element.value {
  122. return value
  123. }
  124. }
  125. return nil
  126. }
  127. }
  128. public func makeIterator() -> Iterator {
  129. return Iterator(storage.makeIterator())
  130. }
  131. }
  132. extension WeakSet: Equatable {
  133. public static func == (lhs: WeakSet, rhs: WeakSet) -> Bool {
  134. return lhs.identifiers() == rhs.identifiers()
  135. }
  136. private func identifiers() -> Set<ObjectIdentifier> {
  137. let ids = storage.compactMap { (id, element) -> ObjectIdentifier? in
  138. // Ignore deallocated elements
  139. guard element.value != nil else {
  140. return nil
  141. }
  142. return id
  143. }
  144. return Set(ids)
  145. }
  146. }
  147. extension WeakSet: ExpressibleByArrayLiteral {
  148. public init(arrayLiteral elements: Element...) {
  149. self.init(elements)
  150. }
  151. }