TM-SGNL-iOS/SignalServiceKit/Util/ReverseDispatchQueue.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

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()
}
}
}