blob: 8b0dff8f1465266ef89d339b464a960d3c9218f1 [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
import CoreFoundation
public struct _NSRange {
public var location: Int
public var length: Int
public init() {
location = 0
length = 0
}
public init(location: Int, length: Int) {
self.location = location
self.length = length
}
internal init(_ range: CFRange) {
location = range.location == kCFNotFound ? NSNotFound : range.location
length = range.length
}
}
extension CFRange {
internal init(_ range: NSRange) {
location = range.location == NSNotFound ? kCFNotFound : range.location
length = range.length
}
}
public typealias NSRange = _NSRange
extension NSRange {
public init(_ x: Range<Int>) {
location = x.lowerBound
length = x.count
}
public func toRange() -> Range<Int>? {
if location == NSNotFound { return nil }
return location..<(location+length)
}
internal func toCountableRange() -> CountableRange<Int>? {
if location == NSNotFound { return nil }
return location..<(location+length)
}
}
extension NSRange: NSSpecialValueCoding {
init(bytes: UnsafeRawPointer) {
self.location = bytes.load(as: Int.self)
self.length = bytes.load(fromByteOffset: MemoryLayout<Int>.stride, as: Int.self)
}
init?(coder aDecoder: NSCoder) {
guard aDecoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
if let location = aDecoder.decodeObject(of: NSNumber.self, forKey: "NS.rangeval.location") {
self.location = location.intValue
} else {
self.location = 0
}
if let length = aDecoder.decodeObject(of: NSNumber.self, forKey: "NS.rangeval.length") {
self.length = length.intValue
} else {
self.length = 0
}
}
func encodeWithCoder(_ aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
aCoder.encode(NSNumber(value: self.location), forKey: "NS.rangeval.location")
aCoder.encode(NSNumber(value: self.length), forKey: "NS.rangeval.length")
}
static func objCType() -> String {
#if arch(i386) || arch(arm)
return "{_NSRange=II}"
#elseif arch(x86_64) || arch(arm64) || arch(s390x)
return "{_NSRange=QQ}"
#else
NSUnimplemented()
#endif
}
func getValue(_ value: UnsafeMutableRawPointer) {
value.initializeMemory(as: NSRange.self, to: self)
}
func isEqual(_ aValue: Any) -> Bool {
if let other = aValue as? NSRange {
return other.location == self.location && other.length == self.length
} else {
return false
}
}
var hash: Int {
return self.location &+ self.length
}
var description: String? {
return NSStringFromRange(self)
}
}
public typealias NSRangePointer = UnsafeMutablePointer<NSRange>
public func NSMakeRange(_ loc: Int, _ len: Int) -> NSRange {
return NSRange(location: loc, length: len)
}
public func NSMaxRange(_ range: NSRange) -> Int {
return range.location + range.length
}
public func NSLocationInRange(_ loc: Int, _ range: NSRange) -> Bool {
return !(loc < range.location) && (loc - range.location) < range.length
}
public func NSEqualRanges(_ range1: NSRange, _ range2: NSRange) -> Bool {
return range1.location == range2.location && range1.length == range2.length
}
public func NSUnionRange(_ range1: NSRange, _ range2: NSRange) -> NSRange {
let max1 = range1.location + range1.length
let max2 = range2.location + range2.length
let maxend: Int
if max1 > max2 {
maxend = max1
} else {
maxend = max2
}
let minloc: Int
if range1.location < range2.location {
minloc = range1.location
} else {
minloc = range2.location
}
return NSMakeRange(minloc, maxend - minloc)
}
public func NSIntersectionRange(_ range1: NSRange, _ range2: NSRange) -> NSRange {
let max1 = range1.location + range1.length
let max2 = range2.location + range2.length
let minend: Int
if max1 < max2 {
minend = max1
} else {
minend = max2
}
if range2.location <= range1.location && range1.location < max2 {
return NSMakeRange(range1.location, minend - range1.location)
} else if range1.location <= range2.location && range2.location < max1 {
return NSMakeRange(range2.location, minend - range2.location)
}
return NSMakeRange(0, 0)
}
public func NSStringFromRange(_ range: NSRange) -> String {
return "{\(range.location), \(range.length)}"
}
public func NSRangeFromString(_ aString: String) -> NSRange {
let emptyRange = NSMakeRange(0, 0)
if aString.isEmpty {
// fail early if the string is empty
return emptyRange
}
let scanner = Scanner(string: aString)
let digitSet = CharacterSet.decimalDigits
let _ = scanner.scanUpToCharactersFromSet(digitSet)
if scanner.atEnd {
// fail early if there are no decimal digits
return emptyRange
}
guard let location = scanner.scanInteger() else {
return emptyRange
}
let partialRange = NSMakeRange(location, 0)
if scanner.atEnd {
// return early if there are no more characters after the first int in the string
return partialRange
}
let _ = scanner.scanUpToCharactersFromSet(digitSet)
if scanner.atEnd {
// return early if there are no integer characters after the first int in the string
return partialRange
}
guard let length = scanner.scanInteger() else {
return partialRange
}
return NSMakeRange(location, length)
}
extension NSValue {
public convenience init(range: NSRange) {
self.init()
self._concreteValue = NSSpecialValue(range)
}
public var rangeValue: NSRange {
let specialValue = self._concreteValue as! NSSpecialValue
return specialValue._value as! NSRange
}
}