[swift-evolution] [Discussion][Expericment] D-like slicing syntax

Daniel Duan daniel at duan.org
Sat Feb 27 22:12:20 CST 2016


Dave Abrahams via swift-evolution <swift-evolution at ...> writes:

> 
> 
> on Sat Feb 20 2016, Daniel Duan <swift-evolution <at> swift.org> wrote:
> 

> Why not just make
> 
>     x[..<$-2]
> 
> work?  You can create unary overloads for ..<

Hi Dave, I took another stab at it today. The code is in the following link as
well as end of this email:
https://gist.github.com/dduan/fcd33a09fae4640fc83c


This implementation is almost good IMO :)


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]




More information about the swift-evolution mailing list