Skip to content

Instantly share code, notes, and snippets.

@JadenGeller
Last active March 11, 2024 05:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JadenGeller/66585051f8de54d9f2a3df1acfd87c32 to your computer and use it in GitHub Desktop.
Save JadenGeller/66585051f8de54d9f2a3df1acfd87c32 to your computer and use it in GitHub Desktop.
PinnedCollection & ReindexedCollection
struct PinnedCollection<Base: RandomAccessCollection, Index: Strideable>: RandomAccessCollection where Index.Stride == Int {
var reindexedBase: ReindexedCollection<Base, Index>
@inlinable @inline(__always)
var startIndex: Index {
reindexedBase.startIndex
}
@inlinable @inline(__always)
var endIndex: Index {
reindexedBase.endIndex
}
@inlinable @inline(__always)
subscript(position: Index) -> Base.Element {
reindexedBase[position]
}
@inlinable @inline(__always)
func index(_ i: Index, offsetBy distance: Int) -> Index {
reindexedBase.index(i, offsetBy: distance)
}
@inlinable @inline(__always)
func distance(from start: Index, to end: Index) -> Int {
reindexedBase.distance(from: start, to: end)
}
}
extension PinnedCollection: MutableCollection where Base: MutableCollection {
@inlinable @inline(__always)
subscript(position: Index) -> Base.Element {
get { reindexedBase[position] }
set { reindexedBase[position] = newValue }
}
}
extension PinnedCollection where ReindexedCollection<Base, Index>: RangeReplaceableCollection {
@inlinable @inline(__always)
init() {
reindexedBase = .init()
}
@inlinable @inline(__always)
mutating func prepend(_ newElement: Base.Element) {
reindexedBase.formIndex(before: &reindexedBase.startIndex)
reindexedBase.insert(newElement, at: reindexedBase.startIndex)
}
@inlinable @inline(__always)
mutating func prepend(contentsOf newElements: some Collection<Base.Element>) {
reindexedBase.formIndex(&reindexedBase.startIndex, offsetBy: -newElements.count)
reindexedBase.insert(contentsOf: newElements, at: reindexedBase.startIndex)
}
@inlinable @inline(__always)
mutating func append(_ newElement: Base.Element) {
reindexedBase.append(newElement)
}
@inlinable @inline(__always)
mutating func append(contentsOf newElements: some Sequence<Base.Element>) {
reindexedBase.append(contentsOf: newElements)
}
@inlinable @inline(__always)
mutating func removeFirst() -> Base.Element {
reindexedBase.formIndex(after: &reindexedBase.startIndex)
return reindexedBase.removeFirst()
}
@inlinable @inline(__always)
mutating func removeFirst(_ k: Int) {
reindexedBase.formIndex(&reindexedBase.startIndex, offsetBy: k)
return reindexedBase.removeFirst(k)
}
@inlinable @inline(__always)
mutating func removeLast() -> Base.Element {
reindexedBase.removeLast()
}
@inlinable @inline(__always)
mutating func removeLast(_ k: Int) {
reindexedBase.removeLast(k)
}
}
extension ReindexedCollection where Index: Strideable, Index.Stride == Int {
func pinningIndices() -> PinnedCollection<Base, Index> {
.init(reindexedBase: self)
}
}
extension RandomAccessCollection where Index: Strideable, Index.Stride == Int {
func pinningIndices() -> PinnedCollection<Self, Index> {
reindex(from: startIndex).pinningIndices()
}
}
struct ReindexedCollection<Base: RandomAccessCollection, Index: Strideable>: RandomAccessCollection where Index.Stride == Int {
var base: Base
var startIndex: Index
@inlinable @inline(__always)
var endIndex: Index {
startIndex.advanced(by: base.count)
}
@inlinable @inline(__always)
internal func baseIndex(for position: Index) -> Base.Index {
base.index(base.startIndex, offsetBy: distance(from: startIndex, to: position))
}
@inlinable @inline(__always)
subscript(position: Index) -> Base.Element {
base[baseIndex(for: position)]
}
@inlinable @inline(__always)
func index(_ i: Index, offsetBy distance: Int) -> Index {
i.advanced(by: distance)
}
@inlinable @inline(__always)
func distance(from start: Index, to end: Index) -> Int {
start.distance(to: end)
}
}
extension ReindexedCollection: MutableCollection where Base: MutableCollection {
@inlinable @inline(__always)
subscript(position: Index) -> Base.Element {
get { base[baseIndex(for: position)] }
set { base[baseIndex(for: position)] = newValue }
}
}
extension ReindexedCollection: RangeReplaceableCollection where Base: RangeReplaceableCollection {
@inlinable @inline(__always)
init(startIndex: Index) {
self.init(base: .init(), startIndex: startIndex)
}
@inlinable @inline(__always)
init() {
fatalError("must call init(startIndex:)")
}
@inlinable @inline(__always)
mutating func replaceSubrange(_ subrange: Range<Index>, with newElements: some Collection<Base.Element>) {
base.replaceSubrange(baseIndex(for: subrange.lowerBound)..<baseIndex(for: subrange.upperBound), with: newElements)
}
}
extension RandomAccessCollection {
func reindex<NewIndex: Strideable>(from startIndex: NewIndex) -> ReindexedCollection<Self, NewIndex> where NewIndex.Stride == Int {
.init(base: self, startIndex: startIndex)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment