Advertisement
Guest User

Untitled

a guest
Jul 19th, 2019
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.65 KB | None | 0 0
  1. /// The result of a binary search.
  2. struct BinarySearchResult<Index> {
  3. /// The index for the searched key.
  4. ///
  5. /// Use this to either insert new values while maintaining the sort order of the collection, or to lookup the value if `isPresent` is true.
  6. var index: Index
  7.  
  8. /// Whether the key was found in the collection.
  9. ///
  10. /// When performing a binary search, even if the value is not found in the collection, an index is returned which can be used to insert a new item at the correct location.
  11. var isPresent: Bool
  12. }
  13.  
  14. extension Collection where Index: BinaryInteger {
  15. /// Search for an index for a given key.
  16. ///
  17. /// Searches through a sorted collection to find the index where the item should be inserted, or already exists.
  18. ///
  19. /// This method assumes that the collection is already sorted by the given key.
  20. func binarySearch<Key: Comparable>(for key: Key, using: (Element) -> Key) -> BinarySearchResult<Index> {
  21. if self.endIndex == self.startIndex {
  22. return BinarySearchResult(index: startIndex, isPresent: false)
  23. }
  24.  
  25. let midIndex = startIndex + (endIndex - startIndex) / Index(exactly: 2)!
  26. let midKey = using(self[midIndex])
  27.  
  28. // Is the search key in the left half?
  29. if midKey > key {
  30. return self[startIndex..<midIndex].binarySearch(for: key, using: using)
  31. // Is the search key in the right half?
  32. } else if midKey < key {
  33. return self[(midIndex + 1)..<endIndex].binarySearch(for: key, using: using)
  34. // If we get here, then we've found the search key!
  35. } else {
  36. return BinarySearchResult(index: midIndex, isPresent: true)
  37. }
  38. }
  39. }
  40.  
  41. extension Collection where Index: BinaryInteger, Element: Comparable {
  42. /// Search for an index for a given element.
  43. ///
  44. /// Searches through a sorted collection to find the index where the item should be inserted, or already exists.
  45. ///
  46. /// This method assumes that the collection is already sorted.
  47. func binarySearch(for key: Element) -> BinarySearchResult<Index> {
  48. return self.binarySearch(for: key, using: { $0 })
  49. }
  50. }
  51.  
  52.  
  53. /// A cache that removes elements once they are no longer used (retained).
  54. class ReferenceCache<Key: Hashable, Value: AnyObject> {
  55. private struct Content {
  56. var hash: Int
  57.  
  58. struct Entry {
  59. var key: Key
  60. var value: Value
  61. }
  62. var entries: [Entry]
  63. }
  64.  
  65. private var content: [Content] = []
  66.  
  67. subscript(key: Key) -> Value? {
  68. get {
  69. let result = content.binarySearch(for: key.hashValue, using: { $0.hash })
  70. guard result.isPresent else { return nil }
  71. return content[result.index].entries.first(where: { $0.key == key })?.value
  72. }
  73. set(newValue) {
  74. let result = content.binarySearch(for: key.hashValue, using: { $0.hash })
  75. let index = result.index
  76.  
  77. if result.isPresent {
  78. if let newValue = newValue {
  79. if let entryIndex = content[index].entries.firstIndex(where: { $0.key == key }) {
  80. content[index].entries[entryIndex].value = newValue
  81. } else {
  82. content[index].entries.append(Content.Entry(key: key, value: newValue))
  83. }
  84. } else {
  85. content[index].entries.removeAll(where: { $0.key == key })
  86. if content[index].entries.isEmpty {
  87. content.remove(at: index)
  88. }
  89. }
  90. } else {
  91. guard let newValue = newValue else { return }
  92. content.insert(Content(hash: key.hashValue, entries: [Content.Entry(key: key, value: newValue)]), at: index)
  93. }
  94. }
  95. }
  96.  
  97. func clean() {
  98. for index in content.indices.reversed() {
  99. for entryIndex in content[index].entries.indices.reversed() {
  100. if isKnownUniquelyReferenced(&self.content[index].entries[entryIndex].value) {
  101. self.content[index].entries.remove(at: entryIndex)
  102.  
  103. if self.content[index].entries.isEmpty {
  104. self.content[index].entries.remove(at: entryIndex)
  105. }
  106. }
  107. }
  108. }
  109. }
  110. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement