70 lines
1.9 KiB
Swift
70 lines
1.9 KiB
Swift
//
|
|
// Copyright 2018 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
|
|
// This is intended to be a drop-in replacement for DispatchQueue
|
|
// that processes its queue in reverse order.
|
|
@objc
|
|
public class ReverseDispatchQueue: NSObject {
|
|
|
|
private let label: String
|
|
private let serialQueue: DispatchQueue
|
|
|
|
@objc
|
|
public convenience init(label: String) {
|
|
self.init(label: label, qos: .unspecified, autoreleaseFrequency: .inherit)
|
|
}
|
|
|
|
public init(label: String, qos: DispatchQoS, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency) {
|
|
self.label = label
|
|
serialQueue = DispatchQueue(label: label, qos: qos, autoreleaseFrequency: autoreleaseFrequency)
|
|
|
|
super.init()
|
|
}
|
|
|
|
public typealias WorkBlock = () -> Void
|
|
|
|
private class Item {
|
|
let workBlock: WorkBlock
|
|
let index: UInt64
|
|
|
|
init(workBlock: @escaping WorkBlock, index: UInt64) {
|
|
self.workBlock = workBlock
|
|
self.index = index
|
|
}
|
|
}
|
|
|
|
// These properties should only be accessed on serialQueue.
|
|
private var items = [Item]()
|
|
private var indexCounter: UInt64 = 0
|
|
|
|
@objc
|
|
public func async(workBlock: @escaping WorkBlock) {
|
|
serialQueue.async {
|
|
self.indexCounter += 1
|
|
let index = self.indexCounter
|
|
let item = Item(workBlock: workBlock, index: index )
|
|
self.items.append(item)
|
|
|
|
self.process()
|
|
}
|
|
}
|
|
|
|
private func process() {
|
|
serialQueue.async {
|
|
// Note that we popLast() so that we process
|
|
// the queue in the _reverse_ order from
|
|
// which it was enqueued.
|
|
guard let item = self.items.popLast() else {
|
|
// No enqueued work to do.
|
|
return
|
|
}
|
|
item.workBlock()
|
|
|
|
self.process()
|
|
}
|
|
}
|
|
}
|