Skip to content

Commit 5b1f0c6

Browse files
authored
add setters to complete implementations of MutableCollection (#1925)
- for `CircularBuffer` and `MarkedCircularBuffer`. - with tests.
1 parent 74b3a8d commit 5b1f0c6

File tree

6 files changed

+61
-14
lines changed

6 files changed

+61
-14
lines changed

Sources/NIO/MarkedCircularBuffer.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ extension MarkedCircularBuffer: Collection, MutableCollection {
161161
get {
162162
return self._buffer[bounds]
163163
}
164+
set {
165+
var index = bounds.lowerBound
166+
var iterator = newValue.makeIterator()
167+
while let newElement = iterator.next(), index != bounds.upperBound {
168+
self._buffer[index] = newElement
169+
formIndex(after: &index)
170+
}
171+
precondition(iterator.next() == nil && index == bounds.upperBound)
172+
}
164173
}
165174
}
166175

Sources/NIOCore/CircularBuffer.swift

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -227,14 +227,6 @@ extension CircularBuffer: Collection, MutableCollection {
227227
// MARK: RandomAccessCollection implementation
228228
extension CircularBuffer: RandomAccessCollection {
229229
/// Returns the index offset by `distance` from `index`.
230-
@inlinable
231-
public func index(_ i: Index, offsetBy distance: Int) -> Index {
232-
return .init(backingIndex: (i.backingIndex &+ distance) & self.mask,
233-
backingCount: self.count,
234-
backingIndexOfHead: self.headBackingIndex)
235-
}
236-
237-
/// Returns an index that is the specified distance from the given index.
238230
///
239231
/// The following example obtains an index advanced four positions from a
240232
/// string's starting index and then prints the character at that position.
@@ -261,15 +253,30 @@ extension CircularBuffer: RandomAccessCollection {
261253
/// - Complexity: O(1) if the collection conforms to
262254
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the absolute
263255
/// value of `distance`.
256+
@inlinable
257+
public func index(_ i: Index, offsetBy distance: Int) -> Index {
258+
return .init(backingIndex: (i.backingIndex &+ distance) & self.mask,
259+
backingCount: self.count,
260+
backingIndexOfHead: self.headBackingIndex)
261+
}
262+
264263
@inlinable
265264
public subscript(bounds: Range<Index>) -> SubSequence {
266-
precondition(self.distance(from: self.startIndex, to: bounds.lowerBound) >= 0)
267-
precondition(self.distance(from: bounds.upperBound, to: self.endIndex) >= 0)
265+
get {
266+
precondition(self.distance(from: self.startIndex, to: bounds.lowerBound) >= 0)
267+
precondition(self.distance(from: bounds.upperBound, to: self.endIndex) >= 0)
268268

269-
var newRing = self
270-
newRing.headBackingIndex = bounds.lowerBound.backingIndex
271-
newRing.tailBackingIndex = bounds.upperBound.backingIndex
272-
return newRing
269+
var newRing = self
270+
newRing.headBackingIndex = bounds.lowerBound.backingIndex
271+
newRing.tailBackingIndex = bounds.upperBound.backingIndex
272+
return newRing
273+
}
274+
set {
275+
precondition(self.distance(from: self.startIndex, to: bounds.lowerBound) >= 0)
276+
precondition(self.distance(from: bounds.upperBound, to: self.endIndex) >= 0)
277+
278+
self.replaceSubrange(bounds, with: newValue)
279+
}
273280
}
274281
}
275282

Tests/NIOTests/CircularBufferTests+XCTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ extension CircularBufferTests {
4242
("testReplaceSubrangeWithSubrangeLargerThanTargetRange", testReplaceSubrangeWithSubrangeLargerThanTargetRange),
4343
("testReplaceSubrangeSameSize", testReplaceSubrangeSameSize),
4444
("testReplaceSubrangeReplaceBufferWithEmptyArray", testReplaceSubrangeReplaceBufferWithEmptyArray),
45+
("testRangeSubscriptExpanding", testRangeSubscriptExpanding),
4546
("testWeCanDistinguishBetweenEmptyAndFull", testWeCanDistinguishBetweenEmptyAndFull),
4647
("testExpandZeroBasedRingWorks", testExpandZeroBasedRingWorks),
4748
("testExpandNonZeroBasedRingWorks", testExpandNonZeroBasedRingWorks),

Tests/NIOTests/CircularBufferTests.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,23 @@ class CircularBufferTests: XCTestCase {
325325
XCTAssertTrue(ring.isEmpty)
326326
}
327327

328+
func testRangeSubscriptExpanding() {
329+
var ring = CircularBuffer<Int>(initialCapacity: 4)
330+
for idx in 0..<5 {
331+
ring.prepend(idx)
332+
}
333+
XCTAssertEqual(5, ring.count)
334+
335+
let index = ring.firstIndex(of: 1)!
336+
let originalCount = ring.count
337+
XCTAssertEqual(ring[index..<ring.endIndex].count, 2)
338+
ring[index..<ring.endIndex] = [10,11,12,13,14,15,16,17,18,19]
339+
XCTAssertTrue(ring.testOnly_verifyInvariantsForNonSlices())
340+
XCTAssertEqual(originalCount + 8, ring.count)
341+
XCTAssertEqual(4, ring.first)
342+
XCTAssertEqual(19, ring.last)
343+
}
344+
328345
func testWeCanDistinguishBetweenEmptyAndFull() {
329346
var ring = CircularBuffer<Int>(initialCapacity: 4)
330347
XCTAssertTrue(ring.isEmpty)

Tests/NIOTests/MarkedCircularBufferTests+XCTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extension MarkedCircularBufferTests {
3535
("testFirst", testFirst),
3636
("testCount", testCount),
3737
("testSubscript", testSubscript),
38+
("testRangeSubscript", testRangeSubscript),
3839
("testIsEmpty", testIsEmpty),
3940
("testPopFirst", testPopFirst),
4041
]

Tests/NIOTests/MarkedCircularBufferTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,18 @@ class MarkedCircularBufferTests: XCTestCase {
117117
XCTAssertEqual(buf[buf.index(buf.startIndex, offsetBy: 3)], 4)
118118
}
119119

120+
func testRangeSubscript() throws {
121+
var buf = MarkedCircularBuffer<Int>(initialCapacity: 4)
122+
for i in 1...4 {
123+
buf.append(i)
124+
}
125+
let range = buf.startIndex..<buf.index(buf.startIndex, offsetBy: 2)
126+
XCTAssertEqual(buf[range].count, 2)
127+
buf[range] = [0,1]
128+
XCTAssertEqual(buf.firstIndex(of: 2), nil)
129+
XCTAssertEqual(buf.count, 4)
130+
}
131+
120132
func testIsEmpty() throws {
121133
var buf = MarkedCircularBuffer<Int>(initialCapacity: 4)
122134
for i in 1...4 {

0 commit comments

Comments
 (0)