- Revamp whole DB to Display flow - Filter Pipeline, arbitrary filtering and sorting - Binary tree arrays for faster lookup & manipulation - DB: introducing custom functions - DB scheme: split req into heap & cache - cache written by GlassVPN only - heap written by Main App only - Introducing DB separation: DBCore, DBCommon, DBAppOnly - Introducing DB data sources: TestDataSource, GroupedDomainDataSource, RecordingsDB, DomainFilter - Background sync: Move entries from cache to heap and notify all observers - GlassVPN: Binary tree filter lookup - GlassVPN: Reusing prepared statement
78 lines
2.6 KiB
Swift
78 lines
2.6 KiB
Swift
import Foundation
|
|
|
|
//extension Collection {
|
|
// subscript(ifExist i: Index?) -> Iterator.Element? {
|
|
// guard let i = i else { return nil }
|
|
// return indices.contains(i) ? self[i] : nil
|
|
// }
|
|
//}
|
|
|
|
extension Range where Bound == Int {
|
|
@inline(__always) func arr() -> [Bound] { self.map { $0 } }
|
|
}
|
|
|
|
|
|
// MARK: - Sorted Array
|
|
|
|
extension Array {
|
|
typealias CompareFn = (Element, Element) -> Bool
|
|
|
|
/// Binary tree search operation.
|
|
/// - Warning: Array must be sorted already.
|
|
/// - Parameter mustExist: Determine whether to return low index or `nil` if element is missing.
|
|
/// - Returns: Index or `nil` (only if `mustExist = true` and element does not exist).
|
|
/// - Complexity: O(log *n*), where *n* is the length of the array.
|
|
func binTreeIndex(of element: Element, compare fn: CompareFn, mustExist: Bool = false) -> Int? {
|
|
var lo = 0, hi = self.count - 1
|
|
while lo <= hi {
|
|
let mid = (lo + hi)/2
|
|
if fn(self[mid], element) {
|
|
lo = mid + 1
|
|
} else if fn(element, self[mid]) {
|
|
hi = mid - 1
|
|
} else {
|
|
return mid
|
|
}
|
|
}
|
|
return mustExist ? nil : lo // not found, would be inserted at position lo
|
|
}
|
|
|
|
/// Binary tree insert operation
|
|
/// - Warning: Array must be sorted already.
|
|
/// - Returns: Index at which `elem` was inserted
|
|
/// - Complexity: O(log *n*), where *n* is the length of the array.
|
|
@discardableResult mutating func binTreeInsert(_ elem: Element, compare fn: CompareFn) -> Int {
|
|
let newIndex = binTreeIndex(of: elem, compare: fn)!
|
|
insert(elem, at: newIndex)
|
|
return newIndex
|
|
}
|
|
|
|
/// Binary tree remove operation
|
|
/// - Warning: Array must be sorted already.
|
|
/// - Returns: Index of removed `elem` or `nil` if it does not exist
|
|
/// - Complexity: O(log *n*), where *n* is the length of the array.
|
|
@discardableResult mutating func binTreeRemove(_ elem: Element, compare fn: CompareFn) -> Int? {
|
|
if let i = binTreeIndex(of: elem, compare: fn, mustExist: true) {
|
|
remove(at: i)
|
|
return i
|
|
}
|
|
return nil
|
|
}
|
|
|
|
/// Sorted synchronous comparison between elements
|
|
/// - Parameter sortedSubset: Must be a strict subset of the sorted array.
|
|
/// - Returns: List of elements that are **not** present in `sortedSubset`.
|
|
/// - Complexity: O(*m*+*n*), where *n* is the length of the array and *m* the length of the `sortedSubset`.
|
|
/// If indices are found earlier, *n* may be significantly less (on average: `n/2`)
|
|
func difference(toSubset sortedSubset: [Element], compare fn: CompareFn) -> [Element] {
|
|
var result: [Element] = []
|
|
var iter = makeIterator()
|
|
for rhs in sortedSubset {
|
|
while let lhs = iter.next(), fn(lhs, rhs) {
|
|
result.append(lhs)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
}
|