Sequence协议
Sequence
协议是集合类型结构中的基础,是一系列相同类型的值的集合,并且提供对这些值的迭代能力。Sequence
协议提供了许多强大的功能,遵循该协议的类型都可以直接使用这些功能。
迭代一个
Sequence
最常见的方式就是for...in
循环
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>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>):
alloc_global @main.numbers : [Swift.Int] // id: %2
%3 = global_addr @main.numbers : [Swift.Int] : $*Array // users: %30, %28
%4 = integer_literal $Builtin.Word, 4 // user: %6
// function_ref _allocateUninitializedArray(_:)
%5 = function_ref @Swift._allocateUninitializedArray(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %6
%6 = apply %5(%4) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // users: %8, %7
%7 = tuple_extract %6 : $(Array, Builtin.RawPointer), 0 // user: %28
%8 = tuple_extract %6 : $(Array, 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 // id: %28
%29 = alloc_stack $IndexingIterator>, var, name "$num$generator" // users: %35, %49, %48, %40
%30 = load %3 : $*Array // users: %33, %31
retain_value %30 : $Array // id: %31
%32 = alloc_stack $Array // users: %33, %35, %37
store %30 to %32 : $*Array // id: %33
// function_ref Collection<>.makeIterator()
%34 = function_ref @(extension in Swift):Swift.Collection< where A.Iterator == Swift.IndexingIterator>.makeIterator() -> Swift.IndexingIterator : $@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>(%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 // id: %37
br bb1 // id: %38
bb1: // Preds: bb3 bb0
%39 = alloc_stack $Optional // users: %45, %42, %46
%40 = begin_access [modify] [static] %29 : $*IndexingIterator> // 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>(%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> // id: %44
%45 = load %39 : $*Optional // user: %47
dealloc_stack %39 : $*Optional // id: %46
switch_enum %45 : $Optional, case #Optional.some!enumelt: bb3, case #Optional.none!enumelt: bb2 // id: %47
main
函数:
%29
:创建IndexingIterator
迭代器> %34
:当遍历元素时,调用Collection
协议中的makeIterator()
方法,创建了一个IndexingIterator
bb1
函数:
%41
:通过IndexingIterator.next()
方法来不断拿到元素所以平常写的
for...in
是不存在的,它仅是一个语法糖
源码分析
打开
Collection.swift
文件
public struct IndexingIterator {
@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
public typealias SubSequence = AnySequence
@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
:每次通过创建迭代器来访问序列中的元素所以每次使用
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
__consuming func _copyContents(
initializing ptr: UnsafeMutableBufferPointer
) -> (Iterator,UnsafeMutableBufferPointer.Index)
func withContiguousStorageIfAvailable(
_ body: (UnsafeBufferPointer) throws -> R
) rethrows -> R?
}
Element
:关联类型Iterator
:遵循IteratorProtocol
协议,并且有一个限制条件,Iterator
和Sequence
里面的Element
类型必须相同makeIterator
:用来创建迭代器,返回一个Iterator
Sequence
类似一个车间,而Iterator
类似一条条流水线对于
Sequence
协议来说,表达的既可以是一个有限的集合,也可以是一个无限的集合,它只需要提供集合中的元素,和如何访问这些元素的接口即可
案例
遵循
Sequence
和IteratorProtocol
协议,创建一个可遍历的结构体
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
需要创建一个迭代器,用来遍历当前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
override __consuming func makeIterator() -> Iterator
associatedtype SubSequence: Collection = Slice
where SubSequence.Index == Index,
Element == SubSequence.Element,
SubSequence.SubSequence == SubSequence
@_borrowed
subscript(position: Index) -> Element { get }
subscript(bounds: Range) -> SubSequence { get }
associatedtype Indices: Collection = DefaultIndices
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)
func _failEarlyRangeCheck(_ index: Index, bounds: ClosedRange)
func _failEarlyRangeCheck(_ range: Range, bounds: Range)
func index(after i: Index) -> Index
func formIndex(after i: inout Index)
}
Collection
协议建立在Sequence
协议上,除了从Sequence
中继承了全部方法以外,还默认实现了很多不同的方法和协议
通过环形缓冲区的结构,来了解一下
Collection
协议的实现案例1
为什么要有环形缓冲区?
例如数组,它是一个连续的线性存储空间。
假设数组内存放了
B
、C
、D
、E
、F
等元素,此时要将元素A
插入到数组Index
为0
的位置,这时需要将数组内已有元素全部向后移动一个位置,再将元素A
插入。如果删除
Index
为0
的元素,数组内的其他元素都要向前移动一个位置,以此来保证后续通过下标访问元素的正确性。所以数组存储的元素越多,它的运行效率就越低下。这时可以设计一个环形缓冲区结构来改善效率问题。
环形缓冲区的结构,应该具有首位相连的特性。
首先定义一个
head
指针表示头结点,再定义一个tail
指针表示尾结点。
head
指向当前读取元素的索引位置,而tail
指向下一个将要插入元素的空位置。假设数组内存放了一个元素
A
,此时head
指向Index
为0
的位置,tail
指向Index
为1
的位置。当读取元素时,将
head
移动到指定索引位置。当环形缓冲区所存储的元素满了,这时
tail
应该指向头部,也就是Index
为0
的位置。此时再插入元素
X
,应该插入到Index
为0
的位置,覆盖之前的元素A
。而tail
应该指向下一个Index
为1
的位置。对于
head
的指向也是同理,读取到结尾处,自动指向头部,读取Index
为0
的位置,如此循环往复。
通过代码设计一个环形缓冲区结构
struct RingBuffer{
var _buffer: ContiguousArray
var headIndex: Int = 0
var tailIndex: Int = 0
init(_ count: Int) {
_buffer = ContiguousArray.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
:读取元素的方法上述代码,其实就是一个简单的环形缓冲区,具备了初步的功能,但存在以下几个问题:
- 模运算的开销是非常大的?能否替换掉
- 当前需要频繁移动
tailIndex
- 如何判断环形缓冲区已满?使用
headIndex==tailIndex
可以吗?- 删除一个元素的逻辑是什么
如图所示,
tail
指针其实指向的永远都是当前空闲的节点,如果此时删除index==4
的元素,逻辑是什么?
- 定位到
index==4
的位置,将value
设置为nil
- 如果仅这样处理,后续再插入元素,会被插入到
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)
做按位与运算- 如果可以让当前环形缓冲的大小是
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(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{
var _buffer: ContiguousArray
var headIndex: Int = 0
var tailIndex: Int = 0
var mask: Int{
return _buffer.count - 1
}
init(_ count: Int) {
let tmp = count.nextPowerOf2()
_buffer = ContiguousArray(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
}
}
一个具备初步基础的环形缓冲区,还有一些功能缺陷亟待解决:
- 无法通过下标访问元素,只能从头读取
- 不具备遍历特性
- 无法删除元素
案例3
遵循
Collection
协议,让环形缓冲区具备集合的特性官方文档,提供了必要实现的属性和方法:
- 定义
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.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
个元素- 循环
append
写入1-10
个元素- 通过
for...in
读取元素
当遵循
Collection
协议实现必要属性和方法后,RingBuffer
已经具备了集合特性,很多方法可以直接使用
print("集合是否为空:\(buf.isEmpty)")
print("获取集合第一个元素:\(buf.first!)")
print("读取指定下标元素:\(buf[3])")
//输出以下结果
//集合是否为空:false
//获取集合第一个元素:1
//读取指定下标元素:4
案例4
遵循
RangeReplaceableCollection
协议,让环形缓冲区具备删除元素的功能
首先对
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
循环判断nextIndex
是否等于tailIndex
- 如果不等,使用集合的
swapAt
方法,将nextIndex
的元素和currentIndex
的nil
进行交换- 更新
currentIndex
为nextIndex
- 继续通过
indexAdvanced
方法获取nextIndex
- 循环往复直到
nextIndex
等于tailIndex
为止- 最后将
tailIndex
指向-1
案例5
RangeReplaceableCollection
协议还提供很多方法
例如
init
方法,有两个限制条件:(_ elements:)
S
必须遵循Sequence
协议Self.Element
必须和S.Element
类型相等当遵循
RangeReplaceableCollection
协议,并实现init
方法,我们可以通过字面量方式创建(_ elements:)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
方法由系统自动实现了,打开(_ elements:)RangeReplaceableCollection.swift
文件
@inlinable
public init(_ elements: S) where S.Element == Element {
self.init()
append(contentsOf: elements)
}
- 先调用了
self.init
方法- 然后将
elements
直接append
到当前创建的集合中
完整代码
extension FixedWidthInteger {
@inlinable
func nextPowerOf2() -> Self {
guard self != 0 else {
return 1
}
return 1 << (Self.bitWidth - (self - 1).leadingZeroBitCount)
}
}
struct RingBuffer{
var _buffer: ContiguousArray
var headIndex: Int = 0
var tailIndex: Int = 0
var mask: Int{
return _buffer.count - 1
}
init(_ count: Int) {
let tmp = count.nextPowerOf2()
_buffer = ContiguousArray(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)
}
}