Sequence協議
Sequence
協議是集合類型結構中的基礎唱捣,是一系列相同類型的值的集合两蟀,并且提供對這些值的迭代能力。Sequence
協議提供了許多強大的功能震缭,遵循該協議的類型都可以直接使用這些功能垫竞。
迭代一個
Sequence
最常見的方式就是for...in
循環(huán)
let numbers = [2, 4, 6, 8]
for num in numbers {
print(num)
}
分析SIL代碼
將上述代碼生成SIL文件:
swiftc -emit-sil main.swift | xcrun swift-demangle
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
alloc_global @main.numbers : [Swift.Int] // id: %2
%3 = global_addr @main.numbers : [Swift.Int] : $*Array<Int> // users: %30, %28
%4 = integer_literal $Builtin.Word, 4 // user: %6
// function_ref _allocateUninitializedArray<A>(_:)
%5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %6
%6 = apply %5<Int>(%4) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // users: %8, %7
%7 = tuple_extract %6 : $(Array<Int>, Builtin.RawPointer), 0 // user: %28
%8 = tuple_extract %6 : $(Array<Int>, Builtin.RawPointer), 1 // user: %9
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Int // users: %12, %24, %19, %14
%10 = integer_literal $Builtin.Int64, 2 // user: %11
%11 = struct $Int (%10 : $Builtin.Int64) // user: %12
store %11 to %9 : $*Int // id: %12
%13 = integer_literal $Builtin.Word, 1 // user: %14
%14 = index_addr %9 : $*Int, %13 : $Builtin.Word // user: %17
%15 = integer_literal $Builtin.Int64, 4 // user: %16
%16 = struct $Int (%15 : $Builtin.Int64) // user: %17
store %16 to %14 : $*Int // id: %17
%18 = integer_literal $Builtin.Word, 2 // user: %19
%19 = index_addr %9 : $*Int, %18 : $Builtin.Word // user: %22
%20 = integer_literal $Builtin.Int64, 6 // user: %21
%21 = struct $Int (%20 : $Builtin.Int64) // user: %22
store %21 to %19 : $*Int // id: %22
%23 = integer_literal $Builtin.Word, 3 // user: %24
%24 = index_addr %9 : $*Int, %23 : $Builtin.Word // user: %27
%25 = integer_literal $Builtin.Int64, 8 // user: %26
%26 = struct $Int (%25 : $Builtin.Int64) // user: %27
store %26 to %24 : $*Int // id: %27
store %7 to %3 : $*Array<Int> // id: %28
%29 = alloc_stack $IndexingIterator<Array<Int>>, var, name "$num$generator" // users: %35, %49, %48, %40
%30 = load %3 : $*Array<Int> // users: %33, %31
retain_value %30 : $Array<Int> // id: %31
%32 = alloc_stack $Array<Int> // users: %33, %35, %37
store %30 to %32 : $*Array<Int> // id: %33
// function_ref Collection<>.makeIterator()
%34 = function_ref @(extension in Swift):Swift.Collection< where A.Iterator == Swift.IndexingIterator<A>>.makeIterator() -> Swift.IndexingIterator<A> : $@convention(method) <τ_0_0 where τ_0_0 : Collection, τ_0_0.Iterator == IndexingIterator<τ_0_0>> (@in τ_0_0) -> @out IndexingIterator<τ_0_0> // user: %35
%35 = apply %34<Array<Int>>(%29, %32) : $@convention(method) <τ_0_0 where τ_0_0 : Collection, τ_0_0.Iterator == IndexingIterator<τ_0_0>> (@in τ_0_0) -> @out IndexingIterator<τ_0_0>
%36 = tuple ()
dealloc_stack %32 : $*Array<Int> // id: %37
br bb1 // id: %38
bb1: // Preds: bb3 bb0
%39 = alloc_stack $Optional<Int> // users: %45, %42, %46
%40 = begin_access [modify] [static] %29 : $*IndexingIterator<Array<Int>> // users: %42, %44
// function_ref IndexingIterator.next()
%41 = function_ref @Swift.IndexingIterator.next() -> A.Element? : $@convention(method) <τ_0_0 where τ_0_0 : Collection> (@inout IndexingIterator<τ_0_0>) -> @out Optional<τ_0_0.Element> // user: %42
%42 = apply %41<Array<Int>>(%39, %40) : $@convention(method) <τ_0_0 where τ_0_0 : Collection> (@inout IndexingIterator<τ_0_0>) -> @out Optional<τ_0_0.Element>
%43 = tuple ()
end_access %40 : $*IndexingIterator<Array<Int>> // id: %44
%45 = load %39 : $*Optional<Int> // user: %47
dealloc_stack %39 : $*Optional<Int> // id: %46
switch_enum %45 : $Optional<Int>, case #Optional.some!enumelt: bb3, case #Optional.none!enumelt: bb2 // id: %47
main
函數:
%29
:創(chuàng)建IndexingIterator<Array<Int>>
迭代器%34
:當遍歷元素時,調用Collection
協議中的makeIterator()
方法蛀序,創(chuàng)建了一個IndexingIterator
bb1
函數:
%41
:通過IndexingIterator.next()
方法來不斷拿到元素所以平常寫的
for...in
是不存在的欢瞪,它僅是一個語法糖
源碼分析
打開
Collection.swift
文件
public struct IndexingIterator<Elements: Collection> {
@usableFromInline
internal let _elements: Elements
@usableFromInline
internal var _position: Elements.Index
@inlinable
@inline(__always)
/// Creates an iterator over the given collection.
public /// @testable
init(_elements: Elements) {
self._elements = _elements
self._position = _elements.startIndex
}
@inlinable
@inline(__always)
/// Creates an iterator over the given collection.
public /// @testable
init(_elements: Elements, _position: Elements.Index) {
self._elements = _elements
self._position = _position
}
}
extension IndexingIterator: IteratorProtocol, Sequence {
public typealias Element = Elements.Element
public typealias Iterator = IndexingIterator<Elements>
public typealias SubSequence = AnySequence<Element>
@inlinable
@inline(__always)
public mutating func next() -> Elements.Element? {
if _position == _elements.endIndex { return nil }
let element = _elements[_position]
_elements.formIndex(after: &_position)
return element
}
}
IndexingIterator
是一個接收泛型的結構體IndexingIterator
遵循IteratorProtocol
和Sequence
兩個協議
打開
Sequence.swift
文件
IteratorProtocol
:一次提供一個序列值的類型,它和Sequence
協議是息息相關的Sequence
:每次通過創(chuàng)建迭代器來訪問序列中的元素所以每次使用
for..in
的時候徐裸,其實都使用這個集合的迭代器來遍歷當前集合或序列中的元素
找到
IteratorProtocol
協議的定義
public protocol IteratorProtocol {
/// The type of element traversed by the iterator.
associatedtype Element
mutating func next() -> Element?
}
Element
:關聯類型遣鼓,取決于實現該協議的提供者next
:使用mutating
修飾的next
方法,返回一個element
找到
Sequence
協議的定義
public protocol Sequence {
/// A type representing the sequence's elements.
associatedtype Element
/// A type that provides the sequence's iteration interface and
/// encapsulates its iteration state.
associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
__consuming func makeIterator() -> Iterator
var underestimatedCount: Int { get }
func _customContainsEquatableElement(
_ element: Element
) -> Bool?
__consuming func _copyToContiguousArray() -> ContiguousArray<Element>
__consuming func _copyContents(
initializing ptr: UnsafeMutableBufferPointer<Element>
) -> (Iterator,UnsafeMutableBufferPointer<Element>.Index)
func withContiguousStorageIfAvailable<R>(
_ body: (UnsafeBufferPointer<Element>) throws -> R
) rethrows -> R?
}
Element
:關聯類型Iterator
:遵循IteratorProtocol
協議重贺,并且有一個限制條件骑祟,Iterator
和Sequence
里面的Element
類型必須相同makeIterator
:用來創(chuàng)建迭代器,返回一個Iterator
Sequence
類似一個車間气笙,而Iterator
類似一條條流水線對于
Sequence
協議來說次企,表達的既可以是一個有限的集合,也可以是一個無限的集合潜圃,它只需要提供集合中的元素缸棵,和如何訪問這些元素的接口即可
案例
遵循
Sequence
和IteratorProtocol
協議,創(chuàng)建一個可遍歷的結構體
struct LGSequence: Sequence {
typealias Element = Int
var arrayCount: Int
init(_ count: Int) {
self.arrayCount = count
}
func makeIterator() -> LGIterator{
return LGIterator(self)
}
}
struct LGIterator: IteratorProtocol {
typealias Element = Int
let seq: LGSequence
var count = 0
init(_ sequence: LGSequence) {
self.seq = sequence
}
mutating func next() -> Int? {
guard count < self.seq.arrayCount else {
return nil
}
count += 1
return count
}
}
let seq = LGSequence.init(10)
for element in seq{
print(element)
}
//輸出以下內容
//1
//2
//3
//4
//5
//6
//7
//8
//9
//10
LGSequence .arrayCount
:提供一個Int
類型的數據LGSequence.init
:初始化arrayCount
LGSequence.makeIterator
:Sequence
需要創(chuàng)建一個迭代器谭期,用來遍歷當前Sequence
中的元素堵第,每次遍歷只會調用一次LGIterator.init
:提供一個構造方法吧凉,需要傳遞LGSequence
LGIterator.next
,讓當前count
做自增操作踏志,遍歷Sequence
中的元素阀捅。當count
小于LGSequence.arrayCount
進行遍歷,否則返回nil
終止遍歷针余。next
方法在符合遍歷條件的情況下會調用多次由此可見
Sequence
和Iterator
兩者之間的關系
Collection協議
Collection
協議遵循Sequence
協議饲鄙,除線性遍歷以外,集合中的元素也可以通過下標索引的方式被獲取到圆雁。和序列不同忍级,集合類型不能是無限的。
上面提到的
IndexingIterator
結構體摸柄,接收泛型Elements
遵循了Collection
協議颤练,_position: Elements.Index
提供了當前元素的Index
打開
Collection.swift
文件既忆,找到Collection
協議的定義
public protocol Collection: Sequence {
// FIXME: ideally this would be in MigrationSupport.swift, but it needs
// to be on the protocol instead of as an extension
@available(*, deprecated/*, obsoleted: 5.0*/, message: "all index distances are now of type Int")
typealias IndexDistance = Int
// FIXME: Associated type inference requires this.
override associatedtype Element
associatedtype Index: Comparable
var startIndex: Index { get }
var endIndex: Index { get }
associatedtype Iterator = IndexingIterator<Self>
override __consuming func makeIterator() -> Iterator
associatedtype SubSequence: Collection = Slice<Self>
where SubSequence.Index == Index,
Element == SubSequence.Element,
SubSequence.SubSequence == SubSequence
@_borrowed
subscript(position: Index) -> Element { get }
subscript(bounds: Range<Index>) -> SubSequence { get }
associatedtype Indices: Collection = DefaultIndices<Self>
where Indices.Element == Index,
Indices.Index == Index,
Indices.SubSequence == Indices
var indices: Indices { get }
var isEmpty: Bool { get }
var count: Int { get }
func _customIndexOfEquatableElement(_ element: Element) -> Index??
func _customLastIndexOfEquatableElement(_ element: Element) -> Index??
func index(_ i: Index, offsetBy distance: Int) -> Index
func index(
_ i: Index, offsetBy distance: Int, limitedBy limit: Index
) -> Index?
func distance(from start: Index, to end: Index) -> Int
func _failEarlyRangeCheck(_ index: Index, bounds: Range<Index>)
func _failEarlyRangeCheck(_ index: Index, bounds: ClosedRange<Index>)
func _failEarlyRangeCheck(_ range: Range<Index>, bounds: Range<Index>)
func index(after i: Index) -> Index
func formIndex(after i: inout Index)
}
Collection
協議建立在Sequence
協議上驱负,除了從Sequence
中繼承了全部方法以外,還默認實現了很多不同的方法和協議
通過環(huán)形緩沖區(qū)的結構患雇,來了解一下
Collection
協議的實現案例1
為什么要有環(huán)形緩沖區(qū)跃脊?
例如數組,它是一個連續(xù)的線性存儲空間苛吱。
假設數組內存放了
B
酪术、C
、D
翠储、E
绘雁、F
等元素,此時要將元素A
插入到數組Index
為0
的位置援所,這時需要將數組內已有元素全部向后移動一個位置庐舟,再將元素A
插入。如果刪除
Index
為0
的元素住拭,數組內的其他元素都要向前移動一個位置挪略,以此來保證后續(xù)通過下標訪問元素的正確性。所以數組存儲的元素越多滔岳,它的運行效率就越低下杠娱。這時可以設計一個環(huán)形緩沖區(qū)結構來改善效率問題。
環(huán)形緩沖區(qū)的結構谱煤,應該具有首位相連的特性摊求。
首先定義一個
head
指針表示頭結點,再定義一個tail
指針表示尾結點刘离。
head
指向當前讀取元素的索引位置睹簇,而tail
指向下一個將要插入元素的空位置奏赘。假設數組內存放了一個元素
A
,此時head
指向Index
為0
的位置太惠,tail
指向Index
為1
的位置磨淌。當讀取元素時,將
head
移動到指定索引位置凿渊。當環(huán)形緩沖區(qū)所存儲的元素滿了梁只,這時
tail
應該指向頭部,也就是Index
為0
的位置埃脏。此時再插入元素
X
搪锣,應該插入到Index
為0
的位置,覆蓋之前的元素A
彩掐。而tail
應該指向下一個Index
為1
的位置构舟。對于
head
的指向也是同理,讀取到結尾處堵幽,自動指向頭部狗超,讀取Index
為0
的位置,如此循環(huán)往復朴下。
通過代碼設計一個環(huán)形緩沖區(qū)結構
struct RingBuffer<Element>{
var _buffer: ContiguousArray<Element?>
var headIndex: Int = 0
var tailIndex: Int = 0
init(_ count: Int) {
_buffer = ContiguousArray<Element?>.init(repeating: nil, count: count)
}
mutating func append(_ value: Element) {
_buffer[tailIndex % _buffer.count] = value
tailIndex += 1
}
mutating func pop() -> Element? {
let result = _buffer[tailIndex % _buffer.count]
headIndex += 1
return result
}
}
_buffer
:定義為ContiguousArray
類型努咐,ContiguousArray
提供了和Array
完全相同的功能,而Array
的底層也使用了ContiguousArray
結構來存儲數據殴胧。如果我們不需要與OC
交互渗稍,使用ContiguousArray
會更加高效init
:使用ContiguousArray
的init(repeating: nil, count: count)
初始化_buffer
,指定_buffer
的count
大小团滥,全部使用nil
填充append
:存儲元素的方法pop
:讀取元素的方法上述代碼竿屹,其實就是一個簡單的環(huán)形緩沖區(qū),具備了初步的功能灸姊,但存在以下幾個問題:
- 模運算的開銷是非常大的拱燃?能否替換掉
- 當前需要頻繁移動
tailIndex
- 如何判斷環(huán)形緩沖區(qū)已滿?使用
headIndex==tailIndex
可以嗎厨钻?- 刪除一個元素的邏輯是什么
如圖所示扼雏,
tail
指針其實指向的永遠都是當前空閑的節(jié)點,如果此時刪除index==4
的元素夯膀,邏輯是什么诗充?
- 定位到
index==4
的位置,將value
設置為nil
- 如果僅這樣處理诱建,后續(xù)再插入元素蝴蜓,會被插入到
7
的位置,這樣顯然不合理,因為前面仍有空閑位置- 所以應該依次把
5
茎匠、6
的位置向前移動格仲,再將tail
的指向-1
,這樣才能保證tail
指向的是將要填充的空間
模運算替換為位運算
- 在
objc_msgSend
源碼中诵冒,查找緩存時凯肋,通過sel & mask
來計算緩存的index
,此時mask
的取值范圍必須滿足2^n - 1
的條件才能成立- 所以有這么一個表達式:
x % y = x % (y - 1)
汽馋,其中y
的取值為2^n
侮东,一個數對2^n
取模相當于一個數和(2^n - 1)
做按位與運算- 如果可以讓當前環(huán)形緩沖的大小是
2^n
,就可以直接通過與運算的方式來計算index
例如:
2^n
豹芯,此時n
等于3
2^3 = 8
悄雅,轉為二進制1000
,(2^3 - 1)
轉為二進制0111
x/8
相當于x
右移3
位:x >> 3
铁蹈,此時得到的是商宽闲。被移掉的3
位即為余數2^n
轉為二進制,首位是1
握牧,后面跟n
個0
容诬,即:1……n個0
2^n - 1
轉為二進制,首位是0
我碟,后面跟n
個1
放案,即:0……n個1
x/2^n
等同于x
右移n
位:x >> n
- 故此
x & (2^n - 1)
可以得到被移掉的n
位姚建,即為余數
明白上述公式矫俺,假設
_buffer
的容量是2^n
大小,即可使用位運算代替模運算掸冤。在官方源碼中厘托,有這樣一段方法:
extension FixedWidthInteger {
@inlinable
func nextPowerOf2() -> Self {
guard self != 0 else {
return 1
}
return 1 << (Self.bitWidth - (self - 1).leadingZeroBitCount)
}
}
定義
FixedWidthInteger
協議的擴展,實現nextPowerOf2
方法稿湿,找到距一個值最近的2
的n
次方數
Self
:代表當前類型铅匹,當前類型是Int
,Self
代表的就是Int
饺藤。當前類型是Double
包斑,Self
代表的就是Double
。一般用作返回值類型bitWidth
:代表當前類型有多少二進制位涕俗,例如Int
類型有64
個二進制位leadingZeroBitCount
:代表當前值轉為二進制罗丰,有多少前導零。例如Int
類型的8
再姑,二進制1000
萌抵,Int
為64
位,所以它的前導零為60
測試
nextPowerOf2
方法的正確性如果
x
為3
,距離3
最近的2
的n
次方數是多少绍填?
測試結果:距離3
最近的2
的n
次方數是4
如果
x
為5
測試結果:距離5
最近的2
的n
次方數是8
案例2
使用
nextPowerOf2
方法霎桅,讓位運算代替模運算改造
init
方法,將傳入的count
值讨永,找的距它最近的2
的n
次方數滔驶,將其設置為_buffer
的容量大小
init(_ count: Int) {
let tmp = count.nextPowerOf2()
_buffer = ContiguousArray<Element?>(repeating: nil, count: tmp)
}
定義
mask
計算屬性,設置掩碼_buffer.count - 1
var mask: Int{
return _buffer.count - 1
}
定義兩個方法卿闹,用于控制
headIndex
和tailIndex
的指向
mutating func advanceTailIndex(by: Int){
self.tailIndex = (self.tailIndex + by) & self.mask
}
mutating func advanceHeadIndex(by: Int){
self.headIndex = (self.headIndex + by) & self.mask
}
改造存儲元素的
append
方法
mutating func append(_ value : Element){
self._buffer[self.tailIndex] = value
self.advanceTailIndex(by: 1)
if self.headIndex == self.tailIndex {
fatalError("out of bounds")
}
}
改造讀取元素的
pop
方法
mutating func pop() -> Element?{
let result = _buffer[self.headIndex]
self.advanceHeadIndex(by: 1)
return result
}
完整代碼如下:
struct RingBuffer<Element>{
var _buffer: ContiguousArray<Element?>
var headIndex: Int = 0
var tailIndex: Int = 0
var mask: Int{
return _buffer.count - 1
}
init(_ count: Int) {
let tmp = count.nextPowerOf2()
_buffer = ContiguousArray<Element?>(repeating: nil, count: tmp)
}
mutating func advanceTailIndex(by: Int){
self.tailIndex = (self.tailIndex + by) & self.mask
}
mutating func advanceHeadIndex(by: Int){
self.headIndex = (self.headIndex + by) & self.mask
}
mutating func append(_ value : Element){
self._buffer[self.tailIndex] = value
self.advanceTailIndex(by: 1)
if self.headIndex == self.tailIndex {
fatalError("out of bounds")
}
}
mutating func pop() -> Element?{
let result = _buffer[self.headIndex]
self.advanceHeadIndex(by: 1)
return result
}
}
一個具備初步基礎的環(huán)形緩沖區(qū)瓜浸,還有一些功能缺陷亟待解決:
- 無法通過下標訪問元素,只能從頭讀取
- 不具備遍歷特性
- 無法刪除元素
案例3
遵循
Collection
協議比原,讓環(huán)形緩沖區(qū)具備集合的特性官方文檔插佛,提供了必要實現的屬性和方法:
- 定義
startIndex
和endIndex
屬性,表示集合起始和結束位置- 定義一個只讀的下標操作符
- 實現一個
index(after:)
方法量窘,用于在集合中移動索引位置
定義
RingBuffer
擴展雇寇,遵循Collection
協議
extension RingBuffer: Collection{
var startIndex: Int{
return self.headIndex
}
var endIndex: Int{
return self.tailIndex
}
subscript(position: Int) -> Element {
get{
return self._buffer[position]!
}
set{
self._buffer[position] = newValue
}
}
func index(after i: Int) -> Int {
return (i + 1) & self.mask
}
}
- 實現
startIndex
和endIndex
屬性- 實現
subscript(position:)
方法,通過下標讀寫指定位置的元素- 實現
index(after:)
方法蚌铜,移動索引位置
對上述代碼進行測試:
var buf = RingBuffer<Int>.init(9)
for i in 1...10{
buf.append(i)
}
for element in buf{
print(element)
}
//輸出以下結果
//1
//2
//3
//4
//5
//6
//7
//8
//9
//10
- 初始化
init
方法傳入9
锨侯,距離9
最近的2
的n
次方數是16
,實際上_buffer
的容量大小是16
冬殃,最大可存儲15
個元素- 循環(huán)
append
寫入1-10
個元素- 通過
for...in
讀取元素
當遵循
Collection
協議實現必要屬性和方法后囚痴,RingBuffer
已經具備了集合特性,很多方法可以直接使用
print("集合是否為空:\(buf.isEmpty)")
print("獲取集合第一個元素:\(buf.first!)")
print("讀取指定下標元素:\(buf[3])")
//輸出以下結果
//集合是否為空:false
//獲取集合第一個元素:1
//讀取指定下標元素:4
案例4
遵循
RangeReplaceableCollection
協議审葬,讓環(huán)形緩沖區(qū)具備刪除元素的功能
首先對
RingBuffer
結構體深滚,添加indexAdvanced
方法,返回指定位置移動后的index
func indexAdvanced(index: Int, by: Int) -> Int{
return (index + by) & self.mask
}
定義
RingBuffer
擴展涣觉,遵循RangeReplaceableCollection
協議
extension RingBuffer: RangeReplaceableCollection{
init() {
self.init(16)
}
mutating func remove(at position: Int) -> Element {
var currentIndex = position
guard let element = self._buffer[currentIndex] else {
fatalError("not fount element")
}
switch currentIndex {
case self.headIndex:
self.advanceHeadIndex(by: 1)
self._buffer[currentIndex] = nil
default:
self._buffer[currentIndex] = nil
var nextIndex = self.indexAdvanced(index: currentIndex, by: 1)
while nextIndex != self.tailIndex {
self._buffer.swapAt(currentIndex, nextIndex)
currentIndex = nextIndex
nextIndex = self.indexAdvanced(index: currentIndex, by: 1)
}
self.advanceTailIndex(by: -1)
}
return element
}
}
實現
remove
方法如果將要刪除的
currentIndex
位置不存在元素痴荐,輸出錯誤提示如果
currentIndex
等于headIndex
- 將
headIndex
指向+1
- 將
currentIndex
的元素置為nil
如果
currentIndex
不等于headIndex
- 將
currentIndex
的元素置為nil
- 調用
indexAdvanced
方法獲取nextIndex
(下一個位置)- 通過
while
循環(huán)判斷nextIndex
是否等于tailIndex
- 如果不等,使用集合的
swapAt
方法官册,將nextIndex
的元素和currentIndex
的nil
進行交換- 更新
currentIndex
為nextIndex
- 繼續(xù)通過
indexAdvanced
方法獲取nextIndex
- 循環(huán)往復直到
nextIndex
等于tailIndex
為止- 最后將
tailIndex
指向-1
案例5
RangeReplaceableCollection
協議還提供很多方法
例如
init<S>(_ elements:)
方法生兆,有兩個限制條件:
S
必須遵循Sequence
協議Self.Element
必須和S.Element
類型相等當遵循
RangeReplaceableCollection
協議,并實現init<S>(_ elements:)
方法膝宁,我們可以通過字面量方式創(chuàng)建RingBuffer
extension RingBuffer: ExpressibleByArrayLiteral{
typealias ArrayLiteralElement = Element
init(arrayLiteral elements: ArrayLiteralElement...) {
self.init(elements)
}
}
var buf = [1, 2, 3, 4, 5, 6]
for element in buf{
print(element)
}
//輸出以下結果:
//1
//2
//3
//4
//5
//6
通過源碼可以看到
init<S>(_ elements:)
方法由系統自動實現了鸦难,打開RangeReplaceableCollection.swift
文件
@inlinable
public init<S: Sequence>(_ elements: S) where S.Element == Element {
self.init()
append(contentsOf: elements)
}
- 先調用了
self.init
方法- 然后將
elements
直接append
到當前創(chuàng)建的集合中
完整代碼
extension FixedWidthInteger {
@inlinable
func nextPowerOf2() -> Self {
guard self != 0 else {
return 1
}
return 1 << (Self.bitWidth - (self - 1).leadingZeroBitCount)
}
}
struct RingBuffer<Element>{
var _buffer: ContiguousArray<Element?>
var headIndex: Int = 0
var tailIndex: Int = 0
var mask: Int{
return _buffer.count - 1
}
init(_ count: Int) {
let tmp = count.nextPowerOf2()
_buffer = ContiguousArray<Element?>(repeating: nil, count: tmp)
}
mutating func advanceTailIndex(by: Int){
self.tailIndex = (self.tailIndex + by) & self.mask
}
mutating func advanceHeadIndex(by: Int){
self.headIndex = (self.headIndex + by) & self.mask
}
func indexAdvanced(index: Int, by: Int) -> Int{
return (index + by) & self.mask
}
mutating func append(_ value : Element){
self._buffer[self.tailIndex] = value
self.advanceTailIndex(by: 1)
if self.headIndex == self.tailIndex {
fatalError("out of bounds")
}
}
mutating func pop() -> Element?{
let result = _buffer[self.headIndex]
self.advanceHeadIndex(by: 1)
return result
}
}
extension RingBuffer: Collection{
var startIndex: Int{
return self.headIndex
}
var endIndex: Int{
return self.tailIndex
}
subscript(position: Int) -> Element {
get{
return self._buffer[position]!
}
set{
self._buffer[position] = newValue
}
}
func index(after i: Int) -> Int {
return (i + 1) & self.mask
}
}
extension RingBuffer: RangeReplaceableCollection{
init() {
self.init(16)
}
mutating func remove(at position: Int) -> Element {
var currentIndex = position
guard let element = self._buffer[currentIndex] else {
fatalError("not fount element")
}
switch currentIndex {
case self.headIndex:
self.advanceHeadIndex(by: 1)
self._buffer[currentIndex] = nil
default:
self._buffer[currentIndex] = nil
var nextIndex = self.indexAdvanced(index: currentIndex, by: 1)
while nextIndex != self.tailIndex {
self._buffer.swapAt(currentIndex, nextIndex)
currentIndex = nextIndex
nextIndex = self.indexAdvanced(index: currentIndex, by: 1)
}
self.advanceTailIndex(by: -1)
}
return element
}
}
extension RingBuffer: ExpressibleByArrayLiteral{
typealias ArrayLiteralElement = Element
init(arrayLiteral elements: ArrayLiteralElement...) {
self.init(elements)
}
}