Skip to content

Instantly share code, notes, and snippets.

@Tony-Y
Last active April 25, 2018 14:26
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 Tony-Y/2d9d8960d8e80a45300cca312cb0ec11 to your computer and use it in GitHub Desktop.
Save Tony-Y/2d9d8960d8e80a45300cca312cb0ec11 to your computer and use it in GitHub Desktop.
Swift Stride Operators: (a..<b)%%step and (a...b)%%step
struct StrideIterator<Element : Strideable> {
var element: Element
let step: Element.Stride
}
extension StrideIterator : IteratorProtocol where Element : Strideable {
mutating func next() -> Element? {
guard step != 0 else { return nil }
defer { element = element.advanced(by: step) }
return element
}
}
struct StrideFrom<Element : Strideable> {
var start: Element
var step: Element.Stride
}
extension StrideFrom : Sequence {
typealias Iterator = StrideIterator<Element>
func makeIterator() -> Iterator {
return StrideIterator(element: start, step: step)
}
}
extension StrideFrom {
func stop(before end: Element) -> StrideTo<Element> {
return stride(from: start, to: end, by: step)
}
func stop(on end: Element) -> StrideThrough<Element> {
return stride(from: start, through: end, by: step)
}
}
func stride<Element: Strideable>(from start: Element, by step: Element.Stride) -> StrideFrom<Element> {
return StrideFrom(start: start, step: step)
}
precedencegroup StrideFormationPrecedence {
lowerThan: RangeFormationPrecedence
}
infix operator %%: StrideFormationPrecedence
// Half-open Range Stride
func %% <T: Strideable>(left: Range<T>, right: T.Stride) -> StrideTo<T> {
if right > 0{
return stride(from: left.lowerBound, to: left.upperBound, by: right)
} else {
return stride(from: left.upperBound.advanced(by: -1), to: left.lowerBound.advanced(by: -1), by: right)
}
}
func %% <T: Strideable>(left: CountableRange<T>, right: T.Stride) -> StrideTo<T> {
if right > 0{
return stride(from: left.lowerBound, to: left.upperBound, by: right)
} else {
return stride(from: left.upperBound.advanced(by: -1), to: left.lowerBound.advanced(by: -1), by: right)
}
}
// Closed Range Stride
func %% <T: Strideable>(left: ClosedRange<T>, right: T.Stride) -> StrideThrough<T> {
if right > 0{
return stride(from: left.lowerBound, through: left.upperBound, by: right)
} else {
return stride(from: left.upperBound, through: left.lowerBound, by: right)
}
}
func %% <T: Strideable>(left: CountableClosedRange<T>, right: T.Stride) -> StrideThrough<T> {
if right > 0{
return stride(from: left.lowerBound, through: left.upperBound, by: right)
} else {
return stride(from: left.upperBound, through: left.lowerBound, by: right)
}
}
// Partial Range From Stride
func %% <T: Strideable>(left: CountablePartialRangeFrom<T>, right: T.Stride) -> StrideFrom<T> {
if right > 0{
return stride(from: left.lowerBound, by: right)
} else {
return stride(from: left.lowerBound, by: 0)
}
}
// Partial Range To Stride
func %% <T: Strideable>(left: PartialRangeUpTo<T>, right: T.Stride) -> StrideFrom<T> {
if right > 0{
return stride(from: left.upperBound, by: 0)
} else {
return stride(from: left.upperBound.advanced(by: -1), by: right)
}
}
// Partial Range Through Stride
func %% <T: Strideable>(left: PartialRangeThrough<T>, right: T.Stride) -> StrideFrom<T> {
if right > 0{
return stride(from: left.upperBound, by: 0)
} else {
return stride(from: left.upperBound, by: right)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment