Bag.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. //
  2. // Bag.swift
  3. // Platform
  4. //
  5. // Created by Krunoslav Zaher on 2/28/15.
  6. // Copyright © 2015 Krunoslav Zaher. All rights reserved.
  7. //
  8. import Swift
  9. let arrayDictionaryMaxSize = 30
  10. struct BagKey {
  11. /**
  12. Unique identifier for object added to `Bag`.
  13. It's underlying type is UInt64. If we assume there in an idealized CPU that works at 4GHz,
  14. it would take ~150 years of continuous running time for it to overflow.
  15. */
  16. fileprivate let rawValue: UInt64
  17. }
  18. /**
  19. Data structure that represents a bag of elements typed `T`.
  20. Single element can be stored multiple times.
  21. Time and space complexity of insertion and deletion is O(n).
  22. It is suitable for storing small number of elements.
  23. */
  24. struct Bag<T> : CustomDebugStringConvertible {
  25. /// Type of identifier for inserted elements.
  26. typealias KeyType = BagKey
  27. typealias Entry = (key: BagKey, value: T)
  28. fileprivate var _nextKey: BagKey = BagKey(rawValue: 0)
  29. // data
  30. // first fill inline variables
  31. var _key0: BagKey?
  32. var _value0: T?
  33. // then fill "array dictionary"
  34. var _pairs = ContiguousArray<Entry>()
  35. // last is sparse dictionary
  36. var _dictionary: [BagKey: T]?
  37. var _onlyFastPath = true
  38. /// Creates new empty `Bag`.
  39. init() {
  40. }
  41. /**
  42. Inserts `value` into bag.
  43. - parameter element: Element to insert.
  44. - returns: Key that can be used to remove element from bag.
  45. */
  46. mutating func insert(_ element: T) -> BagKey {
  47. let key = _nextKey
  48. _nextKey = BagKey(rawValue: _nextKey.rawValue &+ 1)
  49. if _key0 == nil {
  50. _key0 = key
  51. _value0 = element
  52. return key
  53. }
  54. _onlyFastPath = false
  55. if _dictionary != nil {
  56. _dictionary![key] = element
  57. return key
  58. }
  59. if _pairs.count < arrayDictionaryMaxSize {
  60. _pairs.append((key: key, value: element))
  61. return key
  62. }
  63. _dictionary = [key: element]
  64. return key
  65. }
  66. /// - returns: Number of elements in bag.
  67. var count: Int {
  68. let dictionaryCount: Int = _dictionary?.count ?? 0
  69. return (_value0 != nil ? 1 : 0) + _pairs.count + dictionaryCount
  70. }
  71. /// Removes all elements from bag and clears capacity.
  72. mutating func removeAll() {
  73. _key0 = nil
  74. _value0 = nil
  75. _pairs.removeAll(keepingCapacity: false)
  76. _dictionary?.removeAll(keepingCapacity: false)
  77. }
  78. /**
  79. Removes element with a specific `key` from bag.
  80. - parameter key: Key that identifies element to remove from bag.
  81. - returns: Element that bag contained, or nil in case element was already removed.
  82. */
  83. mutating func removeKey(_ key: BagKey) -> T? {
  84. if _key0 == key {
  85. _key0 = nil
  86. let value = _value0!
  87. _value0 = nil
  88. return value
  89. }
  90. if let existingObject = _dictionary?.removeValue(forKey: key) {
  91. return existingObject
  92. }
  93. for i in 0 ..< _pairs.count where _pairs[i].key == key {
  94. let value = _pairs[i].value
  95. _pairs.remove(at: i)
  96. return value
  97. }
  98. return nil
  99. }
  100. }
  101. extension Bag {
  102. /// A textual representation of `self`, suitable for debugging.
  103. var debugDescription : String {
  104. return "\(self.count) elements in Bag"
  105. }
  106. }
  107. extension Bag {
  108. /// Enumerates elements inside the bag.
  109. ///
  110. /// - parameter action: Enumeration closure.
  111. func forEach(_ action: (T) -> Void) {
  112. if _onlyFastPath {
  113. if let value0 = _value0 {
  114. action(value0)
  115. }
  116. return
  117. }
  118. let value0 = _value0
  119. let dictionary = _dictionary
  120. if let value0 = value0 {
  121. action(value0)
  122. }
  123. for i in 0 ..< _pairs.count {
  124. action(_pairs[i].value)
  125. }
  126. if dictionary?.count ?? 0 > 0 {
  127. for element in dictionary!.values {
  128. action(element)
  129. }
  130. }
  131. }
  132. }
  133. extension BagKey: Hashable {
  134. #if swift(>=4.2)
  135. func hash(into hasher: inout Hasher) {
  136. hasher.combine(rawValue)
  137. }
  138. #else
  139. var hashValue: Int {
  140. return rawValue.hashValue
  141. }
  142. #endif
  143. }
  144. func ==(lhs: BagKey, rhs: BagKey) -> Bool {
  145. return lhs.rawValue == rhs.rawValue
  146. }