Skip to content

Commit d9efe90

Browse files
committed
Performance improvements and cleanup for queue.
1 parent c4b392c commit d9efe90

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

RxSwift/RxSwift/DataStructures/Queue.swift

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ public struct Queue<T>: SequenceType {
2323
initialCapacity = capacity
2424

2525
version = 0
26-
storage = []
2726
_count = 0
2827
pushNextIndex = 0
29-
30-
resizeTo(capacity)
28+
29+
storage = [T?](count: capacity, repeatedValue: nil)
3130
}
3231

3332
private var dequeueIndex: Int {
@@ -56,19 +55,20 @@ public struct Queue<T>: SequenceType {
5655
}
5756

5857
mutating private func resizeTo(size: Int) {
59-
var newStorage: [T?] = []
60-
newStorage.reserveCapacity(size)
58+
var newStorage = [T?](count: size, repeatedValue: nil)
6159

6260
var count = _count
6361

64-
for var i = 0; i < count; ++i {
65-
// does swift array have some more efficient methods of copying?
66-
newStorage.append(dequeue())
67-
}
62+
let dequeueIndex = self.dequeueIndex
63+
let spaceToEndOfQueue = self.storage.count - dequeueIndex
6864

69-
while newStorage.count < size {
70-
newStorage.append(nil)
71-
}
65+
// first batch is from dequeue index to end of array
66+
let countElementsInFirstBatch = min(count, spaceToEndOfQueue)
67+
// second batch is wrapped from start of array to end of queue
68+
let numberOfElementsInSecondBatch = count - countElementsInFirstBatch
69+
70+
newStorage[0 ..< countElementsInFirstBatch] = self.storage[dequeueIndex ..< (dequeueIndex + countElementsInFirstBatch)]
71+
newStorage[countElementsInFirstBatch ..< (countElementsInFirstBatch + numberOfElementsInSecondBatch)] = self.storage[0 ..< numberOfElementsInSecondBatch]
7272

7373
_count = count
7474
pushNextIndex = count
@@ -92,18 +92,24 @@ public struct Queue<T>: SequenceType {
9292
}
9393
}
9494

95-
public mutating func dequeue() -> T {
95+
private mutating func dequeueElementOnly() -> T {
9696
version++
9797

9898
contract(count > 0)
99-
99+
100100
let index = dequeueIndex
101101
let value = storage[index]!
102102

103103
storage[index] = nil
104104

105105
_count = _count - 1
106106

107+
return value
108+
}
109+
110+
public mutating func dequeue() -> T {
111+
let value = dequeueElementOnly()
112+
107113
let downsizeLimit = storage.count / (resizeFactor * resizeFactor)
108114
if _count < downsizeLimit && downsizeLimit >= initialCapacity {
109115
resizeTo(storage.count / resizeFactor)

RxTests/RxSwiftTests/Tests/QueueTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,16 @@ extension QueueTest {
4747
XCTAssertEqual(queue.count, 200 - i - 1)
4848
}
4949
}
50+
51+
func testComplexity() {
52+
var queue: Queue<Int> = Queue(capacity: 2)
53+
54+
XCTAssertEqual(queue.count, 0)
55+
56+
for var i = 0; i < 200000; ++i {
57+
queue.enqueue(i)
58+
}
59+
60+
XCTAssertEqual(Array(0 ..< 200000), Array(queue))
61+
}
5062
}

0 commit comments

Comments
 (0)