Skip to content

Instantly share code, notes, and snippets.

@dduan
Last active February 28, 2016 04:13
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 dduan/fcd33a09fae4640fc83c to your computer and use it in GitHub Desktop.
Save dduan/fcd33a09fae4640fc83c to your computer and use it in GitHub Desktop.
D-like slicing syntax tailored for Swift.
// this is almost good, if only Swift allows specifying precedence for pre/postfix operators.
struct Dollar {}
let $ = Dollar()
struct BInt: IntegerLiteralConvertible {
let bool: Bool
let int: UInt
func relativeTo(total: Int) -> Int {
return bool ? total - Int(int) : Int(int)
}
init(_ b: Bool, _ n: UInt) {
bool = b
int = n
}
init(integerLiteral value: Int) {
bool = false
int = UInt(value)
}
}
func -(h: Dollar, d: UInt) -> BInt { return BInt(true, d) }
typealias IncompleteRange = (BInt?, BInt?)
prefix operator ..< {}
prefix func ..<(end: BInt) -> IncompleteRange {
return (nil, end)
}
postfix operator ..< {}
postfix func ..<(start: BInt) -> IncompleteRange {
return (start, nil)
}
prefix operator ... {}
prefix func ...(end: BInt) -> IncompleteRange {
return (nil, BInt(end.bool, end.int+1))
}
postfix operator ... {}
postfix func ...(start: BInt) -> IncompleteRange {
return (start, nil)
}
func ..<(start: BInt, end: BInt) -> IncompleteRange {
return (start, end)
}
func ...(start: BInt, end: BInt) -> IncompleteRange {
return (start, BInt(end.bool, end.int+1))
}
internal func normalize(range: IncompleteRange, total: Int) -> (Int, Int) {
var actualStart = range.0 == nil ? 0 : range.0!.relativeTo(total)
var actualEnd = range.1 == nil ? total : range.1!.relativeTo(total)
actualStart = actualStart < 0 ? total + actualStart : actualStart
actualEnd = actualEnd < 0 ? total + actualEnd : actualEnd
return (actualStart, actualEnd)
}
extension CollectionType {
subscript(halfRange: IncompleteRange) -> Self.SubSequence {
let (safeStart, safeEnd) = normalize(
halfRange,
total: self.count as! Int
)
let safeStartIndex = startIndex.advancedBy(
safeStart as! Self.Index.Distance)
let safeEndIndex = startIndex.advancedBy(
safeEnd as! Self.Index.Distance)
return self[safeStartIndex..<safeEndIndex]
}
}
let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// all of these expression results in [6, 7, 8, 9]
s[6...]
s[($-4)...]
s[6..<s.count]
s[6..<$-0]
s[$-4...9]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment