Last active
January 22, 2021 09:04
-
-
Save ctreffs/6c2dd356c77e81af583e474a1cf38edc to your computer and use it in GitHub Desktop.
FIFO Queue in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// A First-in first-out queue (FIFO). | |
/// | |
/// - New elements are added to the end/tail of the queue. | |
/// - Dequeuing pulls elements from the front/head of the queue. | |
public struct Queue<Element> { | |
private var tail: ContiguousArray<Element?> | |
private var head: Int | |
/// Creates a new, empty queue. | |
public init() { | |
head = 0 | |
tail = [] | |
} | |
/// Adds an element to the end of the collection. | |
/// | |
/// O(1) | |
/// - Parameter element: The element to append to the queue. | |
public mutating func enqueue(_ element: Element) { | |
tail.append(element) | |
} | |
/// Removes and returns the first element in the queue. | |
/// | |
/// O(1) on avarage. | |
/// - Returns: The removed element. | |
public mutating func dequeue() -> Element? { | |
guard head < tail.count else { | |
return nil | |
} | |
let element = tail[head] | |
tail[head] = nil | |
head += 1 | |
/// This calculates the percentage of empty spots at the beginning as a ratio of the total array size. | |
/// If more than 25% of the array is unused, we chop off that wasted space. | |
/// However, if the array is small we do not resize it all the time, so there must be at least 2^6 elements in the array before we try to trim it. | |
if tail.count > 64 { | |
let percentage = Double(head)/Double(tail.count) | |
if percentage > 0.25 { | |
tail.removeFirst(head) // O(n) | |
head = 0 | |
} | |
} | |
return element | |
} | |
/// A Boolean value indicating whether the queue is empty. | |
@inline(__always) public var isEmpty: Bool { | |
count == 0 | |
} | |
/// The number of elements in the queue. | |
public var count: Int { | |
return tail.count - head | |
} | |
} | |
extension Queue: Equatable where Element: Equatable { } | |
extension Queue: Decodable where Element: Decodable { } | |
extension Queue: Encodable where Element: Encodable { } | |
extension Queue: IteratorProtocol { | |
public mutating func next() -> Element? { dequeue() } | |
} | |
extension Queue: Sequence { } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I would have loved to use this implementation, but performance was not good in comparison, due to re-allocation overhead: