From a4a2d6aae3a710f62267ccbc26339cbc3b4f1e6d Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Sun, 13 Dec 2015 22:44:52 +0900 Subject: [PATCH 1/5] Optimize `NSRangeToByteRange(start:length:) -> NSRange?` `UTF8Index.distanceTo(_:)` cost depends on actual distance. So, reduce cost by calculating length from start`s index instead of calculating distances of stringStart and stringEnd separately. By applying this, duration of linting [KeychainAccess](https://github.com/kishikawakatsumi/KeychainAccess/) by SwiftLint is reduced from 27sec to 21sec. --- .../String+SourceKitten.swift | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Source/SourceKittenFramework/String+SourceKitten.swift b/Source/SourceKittenFramework/String+SourceKitten.swift index 161bb0e4c..c3319078d 100644 --- a/Source/SourceKittenFramework/String+SourceKitten.swift +++ b/Source/SourceKittenFramework/String+SourceKitten.swift @@ -98,11 +98,17 @@ extension NSString { */ public func NSRangeToByteRange(start start: Int, length: Int) -> NSRange? { let string = self as String - return string.byteOffsetAtIndex(start).flatMap { stringStart in - return string.byteOffsetAtIndex(start + length).map { stringEnd in - return NSRange(location: stringStart, length: stringEnd - stringStart) - } + let startUTF16Index = string.utf16.startIndex.advancedBy(start) + let endUTF16Index = startUTF16Index.advancedBy(length) + + guard let startUTF8Index = startUTF16Index.samePositionIn(string.utf8), + let endUTF8Index = endUTF16Index.samePositionIn(string.utf8) else { + return nil } + + let location = string.utf8.startIndex.distanceTo(startUTF8Index) + let length = startUTF8Index.distanceTo(endUTF8Index) + return NSRange(location: location, length: length) } /** From 034d598a798efea44c2c276a8c576ebe6fe1cdff Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Sun, 13 Dec 2015 22:57:17 +0900 Subject: [PATCH 2/5] Optimize `byteRangeToNSRange(start:length:) -> NSRange?` The cost of `UTF8Index.advancedBy(_:)` depends on actual distance. So, reduce cost by calculating endIndex based on startIndex instead of calculating each of stringStart and stringEnd separately. --- .../String+SourceKitten.swift | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Source/SourceKittenFramework/String+SourceKitten.swift b/Source/SourceKittenFramework/String+SourceKitten.swift index c3319078d..3ef5e9557 100644 --- a/Source/SourceKittenFramework/String+SourceKitten.swift +++ b/Source/SourceKittenFramework/String+SourceKitten.swift @@ -80,11 +80,17 @@ extension NSString { */ public func byteRangeToNSRange(start start: Int, length: Int) -> NSRange? { let string = self as String - return string.indexOfByteOffset(start).flatMap { stringStart in - return string.indexOfByteOffset(start + length).map { stringEnd in - return NSRange(location: stringStart, length: stringEnd - stringStart) - } + let startUTF8Index = string.utf8.startIndex.advancedBy(start) + let endUTF8Index = startUTF8Index.advancedBy(length) + + guard let startUTF16Index = startUTF8Index.samePositionIn(string.utf16), + let endUTF16Index = endUTF8Index.samePositionIn(string.utf16) else { + return nil } + + let location = string.utf16.startIndex.distanceTo(startUTF16Index) + let length = startUTF16Index.distanceTo(endUTF16Index) + return NSRange(location: location, length: length) } /** From 76444d2f1c8859b7d6ca138acb913c119f15cb52 Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Sun, 13 Dec 2015 22:59:34 +0900 Subject: [PATCH 3/5] Remove `indexOfByteOffset(_:)` and `byteOffsetAtIndex(_:)` --- .../String+SourceKitten.swift | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/Source/SourceKittenFramework/String+SourceKitten.swift b/Source/SourceKittenFramework/String+SourceKitten.swift index 3ef5e9557..1a102f4f3 100644 --- a/Source/SourceKittenFramework/String+SourceKitten.swift +++ b/Source/SourceKittenFramework/String+SourceKitten.swift @@ -200,28 +200,6 @@ extension NSString { } extension String { - /** - UTF16 index equivalent to byte offset. - - - parameter offset: Byte offset. - - - returns: UTF16 index, if any. - */ - private func indexOfByteOffset(offset: Int) -> Int? { - return utf8.startIndex.advancedBy(offset).samePositionIn(utf16).map(utf16.startIndex.distanceTo) - } - - /** - Byte offset equivalent to UTF16 index. - - - parameter index: UTF16 index. - - - returns: Byte offset, if any. - */ - private func byteOffsetAtIndex(index: Int) -> Int? { - return utf16.startIndex.advancedBy(index).samePositionIn(utf8).map(utf8.startIndex.distanceTo) - } - /// Returns the `#pragma mark`s in the string. /// Just the content; no leading dashes or leading `#pragma mark`. public func pragmaMarks(filename: String, excludeRanges: [NSRange], limitRange: NSRange?) -> [SourceDeclaration] { From 63161b30127e6c1cd1c5d936933c3e8345b93575 Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Sun, 13 Dec 2015 23:06:42 +0900 Subject: [PATCH 4/5] Add entry to CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3333f42e..981012210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## Master + +##### Enhancements + +* Optimize `NSRange` operation. + [Norio Nomura](https://github.com/norio-nomura) + [#120](https://github.com/jpsim/SourceKitten/pull/120) + ## 0.7.0 ##### Breaking From 229c9911878977219c2686da81e9591e10eb668e Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Mon, 14 Dec 2015 09:41:32 +0900 Subject: [PATCH 5/5] Apply reviews --- CHANGELOG.md | 2 +- .../String+SourceKitten.swift | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 981012210..cbbb98408 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * Optimize `NSRange` operation. [Norio Nomura](https://github.com/norio-nomura) - [#120](https://github.com/jpsim/SourceKitten/pull/120) + [#119](https://github.com/jpsim/SourceKitten/issues/119) ## 0.7.0 diff --git a/Source/SourceKittenFramework/String+SourceKitten.swift b/Source/SourceKittenFramework/String+SourceKitten.swift index 1a102f4f3..b98fb57b6 100644 --- a/Source/SourceKittenFramework/String+SourceKitten.swift +++ b/Source/SourceKittenFramework/String+SourceKitten.swift @@ -83,12 +83,13 @@ extension NSString { let startUTF8Index = string.utf8.startIndex.advancedBy(start) let endUTF8Index = startUTF8Index.advancedBy(length) - guard let startUTF16Index = startUTF8Index.samePositionIn(string.utf16), - let endUTF16Index = endUTF8Index.samePositionIn(string.utf16) else { + let utf16View = string.utf16 + guard let startUTF16Index = startUTF8Index.samePositionIn(utf16View), + let endUTF16Index = endUTF8Index.samePositionIn(utf16View) else { return nil } - let location = string.utf16.startIndex.distanceTo(startUTF16Index) + let location = utf16View.startIndex.distanceTo(startUTF16Index) let length = startUTF16Index.distanceTo(endUTF16Index) return NSRange(location: location, length: length) } @@ -107,12 +108,13 @@ extension NSString { let startUTF16Index = string.utf16.startIndex.advancedBy(start) let endUTF16Index = startUTF16Index.advancedBy(length) - guard let startUTF8Index = startUTF16Index.samePositionIn(string.utf8), - let endUTF8Index = endUTF16Index.samePositionIn(string.utf8) else { + let utf8View = string.utf8 + guard let startUTF8Index = startUTF16Index.samePositionIn(utf8View), + let endUTF8Index = endUTF16Index.samePositionIn(utf8View) else { return nil } - let location = string.utf8.startIndex.distanceTo(startUTF8Index) + let location = utf8View.startIndex.distanceTo(startUTF8Index) let length = startUTF8Index.distanceTo(endUTF8Index) return NSRange(location: location, length: length) }