ShikiSuen
(ShikiSuen)
1
I wrote a Swift Index Revolver (requiring Swift 5.6).
It's not compilable with Swift 5.5, hence my question: how should I rewrite the parameter types?
Swift Index Revolver (requiring Swift 5.6) (github.com)
// (c) 2021 and onwards Shiki Suen (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
import Foundation
extension Collection {
public func revolvedIndex(_ id: Int, clockwise: Bool = true, steps: Int = 1) -> Int {
if id < 0 || steps < 1 { return id }
var result = id
func revolvedIndexByOneStep(_ id: Int, clockwise: Bool = true) -> Int {
let newID = clockwise ? id + 1 : id - 1
if (0..<count).contains(newID) { return newID }
return clockwise ? 0 : count - 1
}
for _ in 0..<steps {
result = revolvedIndexByOneStep(result, clockwise: clockwise)
}
return result
}
}
extension Int {
public mutating func revolveAsIndex(with target: any Collection, clockwise: Bool = true, steps: Int = 1) {
if self < 0 || steps < 1 { return }
self = target.revolvedIndex(self, clockwise: clockwise, steps: steps)
}
}
// MARK: - Tests
let theArray: [Int] = [1,2,3,4]
var currentIndex = 0
for _ in 0..<8 {
currentIndex.revolveAsIndex(with: theArray)
print(currentIndex)
}
print("")
for _ in 0..<8 {
currentIndex.revolveAsIndex(with: theArray, clockwise: false)
print(currentIndex)
}
ShikiSuen
(ShikiSuen)
2
I wonder whether this one is right. Haven't found any bug with it.
Please feel free to let me know if it looks wrong to you.
extension Int {
public mutating func revolveAsIndex<T: Collection>(with target: T, clockwise: Bool = true, steps: Int = 1) {
if self < 0 || steps < 1 { return }
self = target.revolvedIndex(self, clockwise: clockwise, steps: steps)
}
}
1 Like
jeremyp
(Jeremy Pereira)
3
Why wouldn't you use the generic solution for Swift > 5.5?
Also, is this what you really want? Collections don't necessarily have indexes that are Int,nor, even if it is Int does the startIndex have to be 0 or the endIndex have to be count.
1 Like
Martin
(Martin R)
4
(You are probably aware of it:) Collection indices are not necessarily of type Int, and even if they are, the index of the first element need not be zero. What your revolvedIndex() operates on are “offsets” with respect to the startIndex of the collection, not indices into the collection.
The computation can be more efficiently done using the remainder operator %.
2 Likes
ShikiSuen
(ShikiSuen)
6
Maybe I shouldn't use Collection here.
Is Array the basic-enough type in this situation?
P.S.: Thanks for your suggestion regarding computation method.
My math is really bad. I need some time to figure out how % works.
jeremyp
(Jeremy Pereira)
7
It would certainly be easier to start with Arrayif you are just doing something simple as a learning exercise.
1 Like
ShikiSuen
(ShikiSuen)
8
Thanks. Is Array already the most basic type in this scenario?
jeremyp
(Jeremy Pereira)
9
I think it's the easiest to use collection type and its index is of type Int and indices are always in the range 0 ..< self.count, so yes.
Collection is not just a protocol but it is one with associated types, which is why you can't just write revolveAsIndex(with target: Collection ... You can't really avoid generics as soon as you start doing anything interesting with Collection.
1 Like
It's just the "remainder operator". It's not directly useful when you use negative offsets. Instead, you need a "real" modulo function:
public extension BinaryInteger {
func modulo(_ divisor: Self) -> Self {
(self % divisor + divisor) % divisor
}
}
Using that, you can avoid your loops. And you can just use negative numbers instead of the "clockwise" argument.
extension Collection {
public func revolvedIndex(_ index: Index, steps: Int = 1) -> Index {
self.index(
startIndex,
offsetBy:
(distance(from: startIndex, to: index) + steps)
.modulo(count)
)
}
}
extension Comparable {
public mutating func revolveAsIndex<Collection: Swift.Collection>(
with target: Collection,
steps: Int = 1
) where Self == Collection.Index {
self = target.revolvedIndex(self, steps: steps)
}
}
1 Like
ShikiSuen
(ShikiSuen)
11
Thanks for your explanation.
Looks like I can use negative divisor to reverse-revolve.
ShikiSuen
(ShikiSuen)
12
Hi, Jessy,
Sorry for a supplemental question.
Supposing that someone is gonna use your version instead, which license are you going to use? MIT or something else?
Warm Regards,
Shiki