Bag.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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 an 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? = nil
  32. var _value0: T? = nil
  33. // then fill "array dictionary"
  34. var _pairs = ContiguousArray<Entry>()
  35. // last is sparse dictionary
  36. var _dictionary: [BagKey : T]? = nil
  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. if _dictionary == nil {
  64. _dictionary = [:]
  65. }
  66. _dictionary![key] = element
  67. return key
  68. }
  69. /// - returns: Number of elements in bag.
  70. var count: Int {
  71. let dictionaryCount: Int = _dictionary?.count ?? 0
  72. return (_value0 != nil ? 1 : 0) + _pairs.count + dictionaryCount
  73. }
  74. /// Removes all elements from bag and clears capacity.
  75. mutating func removeAll() {
  76. _key0 = nil
  77. _value0 = nil
  78. _pairs.removeAll(keepingCapacity: false)
  79. _dictionary?.removeAll(keepingCapacity: false)
  80. }
  81. /**
  82. Removes element with a specific `key` from bag.
  83. - parameter key: Key that identifies element to remove from bag.
  84. - returns: Element that bag contained, or nil in case element was already removed.
  85. */
  86. mutating func removeKey(_ key: BagKey) -> T? {
  87. if _key0 == key {
  88. _key0 = nil
  89. let value = _value0!
  90. _value0 = nil
  91. return value
  92. }
  93. if let existingObject = _dictionary?.removeValue(forKey: key) {
  94. return existingObject
  95. }
  96. for i in 0 ..< _pairs.count {
  97. if _pairs[i].key == key {
  98. let value = _pairs[i].value
  99. _pairs.remove(at: i)
  100. return value
  101. }
  102. }
  103. return nil
  104. }
  105. }
  106. extension Bag {
  107. /// A textual representation of `self`, suitable for debugging.
  108. var debugDescription : String {
  109. return "\(self.count) elements in Bag"
  110. }
  111. }
  112. extension Bag {
  113. /// Enumerates elements inside the bag.
  114. ///
  115. /// - parameter action: Enumeration closure.
  116. func forEach(_ action: (T) -> Void) {
  117. if _onlyFastPath {
  118. if let value0 = _value0 {
  119. action(value0)
  120. }
  121. return
  122. }
  123. let value0 = _value0
  124. let dictionary = _dictionary
  125. if let value0 = value0 {
  126. action(value0)
  127. }
  128. for i in 0 ..< _pairs.count {
  129. action(_pairs[i].value)
  130. }
  131. if dictionary?.count ?? 0 > 0 {
  132. for element in dictionary!.values {
  133. action(element)
  134. }
  135. }
  136. }
  137. }
  138. extension BagKey: Hashable {
  139. var hashValue: Int {
  140. return rawValue.hashValue
  141. }
  142. }
  143. func ==(lhs: BagKey, rhs: BagKey) -> Bool {
  144. return lhs.rawValue == rhs.rawValue
  145. }