You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

152 lines
4.0 KiB

//
// Queue.swift
// Platform
//
// Created by Krunoslav Zaher on 3/21/15.
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
/**
Data structure that represents queue.
Complexity of `enqueue`, `dequeue` is O(1) when number of operations is
averaged over N operations.
Complexity of `peek` is O(1).
*/
struct Queue<T>: Sequence {
/// Type of generator.
typealias Generator = AnyIterator<T>
private let _resizeFactor = 2
private var _storage: ContiguousArray<T?>
private var _count = 0
private var _pushNextIndex = 0
private let _initialCapacity: Int
/**
Creates new queue.
- parameter capacity: Capacity of newly created queue.
*/
init(capacity: Int) {
_initialCapacity = capacity
_storage = ContiguousArray<T?>(repeating: nil, count: capacity)
}
private var dequeueIndex: Int {
let index = _pushNextIndex - count
return index < 0 ? index + _storage.count : index
}
/// - returns: Is queue empty.
var isEmpty: Bool {
return count == 0
}
/// - returns: Number of elements inside queue.
var count: Int {
return _count
}
/// - returns: Element in front of a list of elements to `dequeue`.
func peek() -> T {
precondition(count > 0)
return _storage[dequeueIndex]!
}
mutating private func resizeTo(_ size: Int) {
var newStorage = ContiguousArray<T?>(repeating: nil, count: size)
let count = _count
let dequeueIndex = self.dequeueIndex
let spaceToEndOfQueue = _storage.count - dequeueIndex
// first batch is from dequeue index to end of array
let countElementsInFirstBatch = Swift.min(count, spaceToEndOfQueue)
// second batch is wrapped from start of array to end of queue
let numberOfElementsInSecondBatch = count - countElementsInFirstBatch
newStorage[0 ..< countElementsInFirstBatch] = _storage[dequeueIndex ..< (dequeueIndex + countElementsInFirstBatch)]
newStorage[countElementsInFirstBatch ..< (countElementsInFirstBatch + numberOfElementsInSecondBatch)] = _storage[0 ..< numberOfElementsInSecondBatch]
_count = count
_pushNextIndex = count
_storage = newStorage
}
/// Enqueues `element`.
///
/// - parameter element: Element to enqueue.
mutating func enqueue(_ element: T) {
if count == _storage.count {
resizeTo(Swift.max(_storage.count, 1) * _resizeFactor)
}
_storage[_pushNextIndex] = element
_pushNextIndex += 1
_count += 1
if _pushNextIndex >= _storage.count {
_pushNextIndex -= _storage.count
}
}
private mutating func dequeueElementOnly() -> T {
precondition(count > 0)
let index = dequeueIndex
defer {
_storage[index] = nil
_count -= 1
}
return _storage[index]!
}
/// Dequeues element or throws an exception in case queue is empty.
///
/// - returns: Dequeued element.
mutating func dequeue() -> T? {
if self.count == 0 {
return nil
}
defer {
let downsizeLimit = _storage.count / (_resizeFactor * _resizeFactor)
if _count < downsizeLimit && downsizeLimit >= _initialCapacity {
resizeTo(_storage.count / _resizeFactor)
}
}
return dequeueElementOnly()
}
/// - returns: Generator of contained elements.
func makeIterator() -> AnyIterator<T> {
var i = dequeueIndex
var count = _count
return AnyIterator {
if count == 0 {
return nil
}
defer {
count -= 1
i += 1
}
if i >= self._storage.count {
i -= self._storage.count
}
return self._storage[i]
}
}
}