Skip to content

Instantly share code, notes, and snippets.

@mathewsanders
Created January 3, 2017 15:41
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 mathewsanders/c4c43915c5e1c13e8fe3b912bf4c27d1 to your computer and use it in GitHub Desktop.
Save mathewsanders/c4c43915c5e1c13e8fe3b912bf4c27d1 to your computer and use it in GitHub Desktop.
Benchmark substring speed
//
// SubstringTests.swift
// SubstringTests
//
// Created by Mat on 1/3/17.
// Copyright © 2017 Mat. All rights reserved.
//
import XCTest
class SubstringTests: XCTestCase {
let tests = "Hello, tests"
let empty = ""
let start = 1
let end = 10
let itrations = 1000000
// benchmark substring
func testPerformanceBaseline() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.tests.substringBaseline(start: self.start, end: self.end)
}
}
}
func testPerformanceAlternative() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.tests.substringAlternative(start: self.start, end: self.end)
}
}
}
func testPerformanceUTF16() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.tests.substringUTF16(start: self.start, end: self.end)
}
}
}
func testPerformanceUTF16Nil() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.tests.substringUTF16Nil(start: self.start, end: self.end)
}
}
}
// benchmark early exit
func testPerformanceBaselineEmptyString() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.empty.substringBaseline(start: self.start, end: self.end)
}
}
}
func testPerformanceAlternativeEmptyString() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.empty.substringAlternative(start: self.start, end: self.end)
}
}
}
func testPerformanceUTF16EmptyString() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.empty.substringUTF16(start: self.start, end: self.end)
}
}
}
func testPerformanceUTF16NilEmptyString() {
self.measure {
for _ in 0..<self.itrations {
let _ = self.empty.substringUTF16Nil(start: self.start, end: self.end)
}
}
}
}
// "hello tests".substring(1,10)
// baseline -> 1.151s (2% STDEV)
// alternative -> 0.633s (1% STDEV)
// UTF16 -> 0.408s (2% STDEV)
// UTF16 nil -> 0.404s (1% STDEV)
// "".substring(1,10)
// baseline -> 0.074s (4% STDEV)
// alternative -> 0.024s (12% STDEV)
// UTF16 -> 0.024s (11% STDEV)
// UTF16 nil -> 0.019s (12% STDEV)
// baseline approach
extension String {
func substringBaseline(start: Int, end: Int) -> String {
if (start == end || self.strlen() == 0) {
return ""
}
let startIndex = self.index(self.startIndex, offsetBy: start)
let endIndex = self.index(self.startIndex, offsetBy: end)
return self[startIndex..<endIndex]
}
func strlen() -> Int {
return self.characters.count
}
}
// reusing startIndex
extension String {
func substringAlternative(start: Int, end: Int) -> String {
guard !(start == end || isEmpty) else { return "" }
let startIndex = index(self.startIndex, offsetBy: start)
let endIndex = index(startIndex, offsetBy: end - start)
return self[startIndex..<endIndex]
}
}
// using UTF16
extension String {
func substringUTF16(start: Int, end: Int) -> String {
guard !(start == end || isEmpty) else { return "" }
let start16 = String.UTF16Index(start)
let end16 = String.UTF16Index(end)
return String(utf16[start16..<end16])!
}
}
// using UTF16 with optional return
extension String {
func substringUTF16Nil(start: Int, end: Int) -> String? {
guard !(start == end || isEmpty) else { return nil }
let start16 = String.UTF16Index(start)
let end16 = String.UTF16Index(end)
return String(utf16[start16..<end16])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment