From d9efe90751c24da266dfae3d0bb4f97e4531e5d7 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Wed, 12 Aug 2015 20:51:47 +0200 Subject: [PATCH] Performance improvements and cleanup for queue. --- RxSwift/RxSwift/DataStructures/Queue.swift | 34 ++++++++++++--------- RxTests/RxSwiftTests/Tests/QueueTests.swift | 12 ++++++++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/RxSwift/RxSwift/DataStructures/Queue.swift b/RxSwift/RxSwift/DataStructures/Queue.swift index 97964239..ba592649 100644 --- a/RxSwift/RxSwift/DataStructures/Queue.swift +++ b/RxSwift/RxSwift/DataStructures/Queue.swift @@ -23,11 +23,10 @@ public struct Queue: SequenceType { initialCapacity = capacity version = 0 - storage = [] _count = 0 pushNextIndex = 0 - - resizeTo(capacity) + + storage = [T?](count: capacity, repeatedValue: nil) } private var dequeueIndex: Int { @@ -56,19 +55,20 @@ public struct Queue: SequenceType { } mutating private func resizeTo(size: Int) { - var newStorage: [T?] = [] - newStorage.reserveCapacity(size) + var newStorage = [T?](count: size, repeatedValue: nil) var count = _count - for var i = 0; i < count; ++i { - // does swift array have some more efficient methods of copying? - newStorage.append(dequeue()) - } + let dequeueIndex = self.dequeueIndex + let spaceToEndOfQueue = self.storage.count - dequeueIndex - while newStorage.count < size { - newStorage.append(nil) - } + // first batch is from dequeue index to end of array + let countElementsInFirstBatch = min(count, spaceToEndOfQueue) + // second batch is wrapped from start of array to end of queue + let numberOfElementsInSecondBatch = count - countElementsInFirstBatch + + newStorage[0 ..< countElementsInFirstBatch] = self.storage[dequeueIndex ..< (dequeueIndex + countElementsInFirstBatch)] + newStorage[countElementsInFirstBatch ..< (countElementsInFirstBatch + numberOfElementsInSecondBatch)] = self.storage[0 ..< numberOfElementsInSecondBatch] _count = count pushNextIndex = count @@ -92,11 +92,11 @@ public struct Queue: SequenceType { } } - public mutating func dequeue() -> T { + private mutating func dequeueElementOnly() -> T { version++ contract(count > 0) - + let index = dequeueIndex let value = storage[index]! @@ -104,6 +104,12 @@ public struct Queue: SequenceType { _count = _count - 1 + return value + } + + public mutating func dequeue() -> T { + let value = dequeueElementOnly() + let downsizeLimit = storage.count / (resizeFactor * resizeFactor) if _count < downsizeLimit && downsizeLimit >= initialCapacity { resizeTo(storage.count / resizeFactor) diff --git a/RxTests/RxSwiftTests/Tests/QueueTests.swift b/RxTests/RxSwiftTests/Tests/QueueTests.swift index 8a835340..89d9a67f 100644 --- a/RxTests/RxSwiftTests/Tests/QueueTests.swift +++ b/RxTests/RxSwiftTests/Tests/QueueTests.swift @@ -47,4 +47,16 @@ extension QueueTest { XCTAssertEqual(queue.count, 200 - i - 1) } } + + func testComplexity() { + var queue: Queue = Queue(capacity: 2) + + XCTAssertEqual(queue.count, 0) + + for var i = 0; i < 200000; ++i { + queue.enqueue(i) + } + + XCTAssertEqual(Array(0 ..< 200000), Array(queue)) + } } \ No newline at end of file