Skip to content

[Foundation] add additional conformances and functionality to NSRange #7433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 106 additions & 18 deletions stdlib/public/SDK/Foundation/NSRange.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,121 @@

@_exported import Foundation // Clang module

extension NSRange : Hashable {
public var hashValue: Int {
#if arch(i386) || arch(arm)
return Int(bitPattern: (UInt(bitPattern: location) | (UInt(bitPattern: length) << 16)))
#elseif arch(x86_64) || arch(arm64)
return Int(bitPattern: (UInt(bitPattern: location) | (UInt(bitPattern: length) << 32)))
#endif
}

public static func==(_ lhs: NSRange, _ rhs: NSRange) -> Bool {
return lhs.location == rhs.location && rhs.length == rhs.length
}
}

extension NSRange : CustomStringConvertible, CustomDebugStringConvertible {
public var description: String { return "{\(location), \(length)}" }
public var debugDescription: String { return "{\(location), \(length)}" }
}

extension NSRange {
public init?(_ string: String) {
if string.isEmpty {
// fail early if the string is empty
return nil
}
let scanner = Scanner(string: string)
let digitSet = CharacterSet.decimalDigits
let _ = scanner.scanUpToCharacters(from: digitSet, into: nil)
if scanner.isAtEnd {
// fail early if there are no decimal digits
return nil
}
var location = 0
guard scanner.scanInt(&location) else {
return nil
}
if scanner.isAtEnd {
// return early if there are no more characters after the first int in the string
return nil
}
let _ = scanner.scanUpToCharacters(from: digitSet, into: nil)
if scanner.isAtEnd {
// return early if there are no integer characters after the first int in the string
return nil
}
var length = 0
guard scanner.scanInt(&length) else {
return nil
}

self.location = location
self.length = length
}
}

extension NSRange {
public var lowerBound: Int { return location }

public var upperBound: Int { return location + length }

public func contains(_ index: Int) -> Bool { return (!(index < location) && (index - location) < length) }

public mutating func formUnion(_ other: NSRange) {
self = union(other)
}

public func union(_ other: NSRange) -> NSRange {
let max1 = location + length
let max2 = other.location + other.length
let maxend = (max1 < max2) ? max2 : max1
let minloc = location < other.location ? location : other.location
return NSRange(location: minloc, length: maxend - minloc)
}

public func intersection(_ other: NSRange) -> NSRange? {
let max1 = location + length
let max2 = other.location + other.length
let minend = (max1 < max2) ? max1 : max2
if other.location <= location && location < max2 {
return NSRange(location: location, length: minend - location)
} else if location <= other.location && other.location < max1 {
return NSRange(location: other.location, length: minend - other.location);
}
return nil
}
}


//===----------------------------------------------------------------------===//
// Ranges
//===----------------------------------------------------------------------===//

extension NSRange {
public init(_ x: Range<Int>) {
location = x.lowerBound
length = x.count
}

// FIXME(ABI)#75 (Conditional Conformance): this API should be an extension on Range.
// Can't express it now because the compiler does not support conditional
// extensions with type equality constraints.
public func toRange() -> Range<Int>? {
if location == NSNotFound { return nil }
return location..<(location+length)
}
public init(_ x: Range<Int>) {
location = x.lowerBound
length = x.count
}

// FIXME(ABI)#75 (Conditional Conformance): this API should be an extension on Range.
// Can't express it now because the compiler does not support conditional
// extensions with type equality constraints.
Copy link
Contributor

@karwa karwa Feb 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler does now support extensions with same-type constraints. The FIXME hint here looks wrong: this has nothing to do with conditional conformances.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That comment was not part of the additions here; it just got moved around

public func toRange() -> Range<Int>? {
if location == NSNotFound { return nil }
return location..<(location+length)
}
}

extension NSRange : CustomReflectable {
public var customMirror: Mirror {
return Mirror(self, children: ["location": location, "length": length])
}
public var customMirror: Mirror {
return Mirror(self, children: ["location": location, "length": length])
}
}

extension NSRange : CustomPlaygroundQuickLookable {
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .range(Int64(location), Int64(length))
}
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .range(Int64(location), Int64(length))
}
}
1 change: 0 additions & 1 deletion test/Compatibility/bridging-nsnumber-and-nsvalue.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ extension Equatable {
}
}
extension Hashable { public var hashValue: Int { fatalError("trill hiphy") } }
extension NSRange: Hashable {}
extension CGSize: Hashable {}
extension CGPoint: Hashable {}
extension CGRect: Hashable {}
Expand Down
2 changes: 0 additions & 2 deletions test/Constraints/bridging-nsnumber-and-nsvalue.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ coercionTypes = {
'CGRect',
'CGPoint',
'CGSize',
'NSRange',
],
}
}%
Expand All @@ -41,7 +40,6 @@ extension Equatable {
}
}
extension Hashable { public var hashValue: Int { fatalError("trill hiphy") } }
extension NSRange: Hashable {}
extension CGSize: Hashable {}
extension CGPoint: Hashable {}
extension CGRect: Hashable {}
Expand Down