[benchmarks] Add some more benchmarks by our very own airspeedswift.

With his permission of course.
This commit is contained in:
Michael Gottesman
2018-01-05 17:14:50 -08:00
committed by Michael Gottesman
parent fc64e34c8e
commit 24027067b9
11 changed files with 1081 additions and 3 deletions

View File

@@ -42,6 +42,7 @@ set(SWIFT_BENCH_MODULES
single-source/ArraySubscript
single-source/BitCount
single-source/ByteSwap
single-source/COWTree
single-source/CString
single-source/CSVParsing
single-source/Calculator
@@ -51,7 +52,9 @@ set(SWIFT_BENCH_MODULES
single-source/CharacterProperties
single-source/Chars
single-source/ClassArrayGetter
single-source/Combos
single-source/DeadArray
single-source/DictOfArraysToArrayOfDicts
single-source/DictTest
single-source/DictTest2
single-source/DictTest3
@@ -77,6 +80,8 @@ set(SWIFT_BENCH_MODULES
single-source/Join
single-source/LazyFilter
single-source/LinkedList
single-source/LuhnAlgoEager
single-source/LuhnAlgoLazy
single-source/MapReduce
single-source/Memset
single-source/MonteCarloE
@@ -84,6 +89,7 @@ set(SWIFT_BENCH_MODULES
single-source/NSDictionaryCastToSwift
single-source/NSError
single-source/NSStringConversion
single-source/NibbleSort
single-source/NopDeinit
single-source/ObjectAllocation
single-source/ObjectiveCBridging
@@ -94,6 +100,7 @@ set(SWIFT_BENCH_MODULES
single-source/ObserverPartiallyAppliedMethod
single-source/ObserverUnappliedMethod
single-source/OpenClose
single-source/PartialApplyDynamicType
single-source/Phonebook
single-source/PolymorphicCalls
single-source/PopFront
@@ -107,6 +114,7 @@ set(SWIFT_BENCH_MODULES
single-source/RGBHistogram
single-source/RangeAssignment
single-source/RangeIteration
single-source/RangeReplaceableCollectionPlusDefault
single-source/RecursiveOwnedParameter
single-source/ReduceInto
single-source/ReversedCollections
@@ -126,6 +134,7 @@ set(SWIFT_BENCH_MODULES
single-source/StringEnum
single-source/StringInterpolation
single-source/StringMatch
single-source/StringRemoveDupes
single-source/StringTests
single-source/StringWalk
single-source/Substring

View File

@@ -0,0 +1,146 @@
// COWTree benchmark
//
// Description: Copy-On-Write behaviour for a struct
// Source: https://gist.github.com/airspeedswift/71f15d1eb866be9e5ac7
import TestsUtils
public var COWTree = BenchmarkInfo(
name: "COWTree",
runFunction: run_COWTree,
tags: [.validation, .abstraction, .String]
)
@inline(never)
public func run_COWTree(_ N: Int) {
var tree1 = Tree<String>()
var tree2 = Tree<String>()
var tree3 = Tree<String>()
for _ in 1...1000*N {
tree1 = Tree<String>()
tree1.insert("Emily")
tree2 = tree1
tree1.insert("Gordon")
tree3 = tree2
tree3.insert("Spencer")
if !checkRef(tree1, tree2, tree3) {
break
}
}
CheckResults(checkRef(tree1, tree2, tree3))
}
@inline(never)
func checkRef(_ t1: Tree<String>, _ t2: Tree<String>,
_ t3: Tree<String>) -> Bool {
if !(t1.contains("Emily") && t1.contains("Gordon") &&
!t1.contains("Spencer")) {
return false
}
if !(t2.contains("Emily") && !t2.contains("Gordon") &&
!t2.contains("Spencer")) {
return false
}
if !(t3.contains("Emily") && !t3.contains("Gordon") &&
t3.contains("Spencer")) {
return false
}
return true
}
// ideally we would define this inside the tree struct
private class _Node<T: Comparable> {
var _value: T
var _left: _Node<T>? = nil
var _right: _Node<T>? = nil
init(value: T) { _value = value }
}
public struct Tree<T: Comparable> {
// this makes things a bit more pleasant later
fileprivate typealias Node = _Node<T>
fileprivate var _root: Node? = nil
public init() { }
// constructor from a sequence
public init<S: Sequence>(_ seq: S) where S.Iterator.Element == T {
var g = seq.makeIterator()
while let x = g.next() {
self.insert(x)
}
}
private mutating func ensureUnique() {
if !isKnownUniquelyReferenced(&_root) {
// inefficiently...
self = Tree<T>(self)
}
}
public mutating func insert(_ value: T) {
ensureUnique()
_root = insert(_root, value)
}
private mutating func insert(_ node: Node?, _ value: T) -> Node? {
switch node {
case .none:
return Node(value: value)
case let .some(node) where value < node._value:
node._left = insert(node._left, value)
return node
case let .some(node):
node._right = insert(node._right, value)
return node
}
}
public func contains(_ value: T) -> Bool {
return contains(_root, value)
}
private func contains(_ node: Node?, _ value: T) -> Bool {
switch node {
case .none:
return false
case let .some(node) where node._value == value:
return true
case let .some(node):
return contains(value < node._value ? node._left : node._right,
value)
}
}
}
extension Tree: Sequence {
public typealias Iterator = AnyIterator<T>
public func makeIterator() -> Iterator {
var stack: [Node] = []
var current: Node? = _root
return AnyIterator {
// stack-based technique for inorder traversal
// without recursion
while true {
if let node = current {
stack.append(node)
current = node._left
}
else if !stack.isEmpty {
let pop = stack.removeLast()
current = pop._right
return pop._value
}
else {
return nil
}
}
}
}
}

View File

@@ -0,0 +1,84 @@
// Combos benchmark
//
// Description: Generates every combination of every element in two sequences
// Source: https://gist.github.com/airspeedswift/34251f2ddb1b038c5d88
import TestsUtils
public var Combos = BenchmarkInfo(
name: "Combos",
runFunction: run_Combos,
tags: [.validation, .abstraction]
)
@inline(never)
public func run_Combos(_ N: Int) {
let firstRef = [Character("A"), Character("0")]
let lastRef = [Character("J"), Character("9")]
var combos = [[Character]]()
for _ in 1...10*N {
combos = combinations("ABCDEFGHIJ".characters, "0123456789".characters).map {
return [$0] + [$1]
}
if combos.first! != firstRef || combos.last! != lastRef {
break
}
}
CheckResults(combos.first! == firstRef && combos.last! == lastRef)
}
func combinations
<First: Sequence, Second: Collection>
(_ first: First, _ second: Second)
-> AnyIterator<(First.Iterator.Element, Second.Iterator.Element)> {
var first_gen = first.makeIterator()
var second_gen = second.makeIterator()
var current_first = first_gen.next()
return AnyIterator {
// check if there's more of first to consume
if let this_first = current_first {
// if so, is there more of this go-around
// of second to consume?
if let this_second = second_gen.next() {
return (this_first, this_second)
}
// if second used up, reset it
else {
// go back to the beginning of second
second_gen = second.makeIterator()
// and take the first element of it
let next_second = second_gen.next()
// was there a first element?
if let this_second = next_second {
// move on to the next element of first
current_first = first_gen.next()
// is there such an element?
if let this_first = current_first {
return (this_first, this_second)
}
// if not, we've reached the end of
// the first sequence
else {
// so we've finished
return nil
}
}
// if not, second is empty
else {
// so we need to guard against
// infinite looping in that case
return nil
}
}
}
// if not, we've reached the end of
// the first sequence
else {
// so we've finished
return nil
}
}
}

View File

@@ -0,0 +1,141 @@
// DictOfArraysToArrayOfDicts benchmark
//
// Description: Convert a dictionary of [key: [values]] to an array of
// dictionaries [[key: value]] using zipWith.
// Source: https://gist.github.com/airspeedswift/3675952127ee775551b0
import TestsUtils
public var DictOfArraysToArrayOfDicts = BenchmarkInfo(
name: "DictOfArraysToArrayOfDicts",
runFunction: run_DictOfArraysToArrayOfDicts,
tags: [.algorithm, .Dictionary]
)
@inline(never)
public func run_DictOfArraysToArrayOfDicts(_ N: Int) {
let returnedFromServer = [
"title": ["abc", "def", "ghi"],
"time": ["1234", "5678", "0123"],
"content": ["qwerty", "asdfg", "zxcvb"],
]
var pairs: [[(String, String)]] = []
var inverted: [[(String, String)]] = []
var arrayOfDicts: [[String: String]] = [[:]]
for _ in 1...100*N {
pairs = returnedFromServer.map {
(key, value) in value.map { (key, $0) }
}
inverted = zipWith(pairs[0], pairs[1], pairs[2]) {
[$0] + [$1] + [$2]
}
arrayOfDicts = inverted
.map { $0.map { (key: $0.0, value: $0.1) } }
.map { Dictionary($0) }
if !(arrayOfDicts.count == 3) {
break
}
}
CheckResults(arrayOfDicts.count == 3)
}
// Given [
// "title" : ["abc", "def"],
// "time" : ["1234", "5678", "0123"],
// "content":["qwerty", "asdfg", "zxcvb"]
// ]
//
// how do you get to this:
//
// [
// ["title" : "abc",
// "time" : "1234",
// "content": "qwerty"],
// ["title" : "def",
// "time" : "5678",
// "content": "asdfg"],
// ["title" : "ghi",
// "time" : "0123",
// "content": "zxcvb"]]
public func zip3 <A: Sequence,
B: Sequence,
C: Sequence> (_ a: A, _ b: B, _ c: C)
-> ZipSequence3<A, B, C> {
return ZipSequence3(a, b, c)
}
// Sequence of tuples created from values from three other sequences
public struct ZipSequence3<A: Sequence,
B: Sequence,
C: Sequence>: Sequence {
public typealias Iterator = ZipGenerator3
<A.Iterator, B.Iterator, C.Iterator>
public typealias SubSequence = AnySequence<Iterator.Element>
private var a: A
private var b: B
private var c: C
public init (_ a: A, _ b: B, _ c: C) {
self.a = a
self.b = b
self.c = c
}
public func makeIterator() -> Iterator {
return ZipGenerator3(a.makeIterator(), b.makeIterator(), c.makeIterator())
}
}
// Iterator that creates tuples of values from three other generators
public struct ZipGenerator3<A: IteratorProtocol,
B: IteratorProtocol,
C: IteratorProtocol>: IteratorProtocol {
private var a: A
private var b: B
private var c: C
public init(_ a: A, _ b: B, _ c: C) {
self.a = a
self.b = b
self.c = c
}
mutating public func next() -> (A.Element, B.Element, C.Element)? {
switch (a.next(), b.next(), c.next()) {
case let (.some(aValue), .some(bValue), .some(cValue)):
return (aValue, bValue, cValue)
default:
return nil
}
}
}
func zipWith
<S1: Sequence, S2: Sequence, S3: Sequence, T>
(_ s1: S1, _ s2: S2, _ s3: S3, _ combine: (S1.Iterator.Element,
S2.Iterator.Element,
S3.Iterator.Element) -> T) -> [T] {
return zip3(s1,s2,s3).map(combine)
}
extension Dictionary {
// Construct from an arbitrary sequence with elements of the tupe
// `(Key,Value)`
init<S: Sequence> (_ seq: S) where S.Iterator.Element == Element {
self.init()
self.merge(seq)
}
// Merge a sequence of `(Key,Value)` tuples into the dictionary
mutating func merge<S: Sequence> (_ seq: S) where S.Iterator.Element == Element {
var gen = seq.makeIterator()
while let (k, v) = gen.next() {
self[k] = v
}
}
}

View File

@@ -0,0 +1,232 @@
// LuhnAlgoEager benchmark
//
// Description: Performs a Luhn checksum eagerly
// Source: https://gist.github.com/airspeedswift/e584239d7658b317f59a
import TestsUtils
public var LuhnAlgoEager = BenchmarkInfo(
name: "LuhnAlgoEager",
runFunction: run_LuhnAlgoEager,
tags: [.algorithm]
)
@inline(never)
public func run_LuhnAlgoEager(_ N: Int) {
let resultRef = true
var result = false
for _ in 1...100*N {
result = eagerchecksum(ccnum)
if result != resultRef {
break
}
}
CheckResults(result == resultRef)
}
// Another version of the Luhn algorithm, similar to the one found here:
// https://gist.github.com/airspeedswift/b349c256e90da746b852
//
// This time, trying to keep two versions, one eager one lazy,
// as similar as possible. Only adding "lazy" to the start of
// the expression to switch between the two.
//
// Much of the same code as the previous version at the top,
// Skip down to line 110 for the different par
// mapSome is my Swift version of Haskell's mapMaybe, which
// is a map that takes a transform function that returns an
// optional, and returns a collection of only those values
// that weren't nil
// first we need a lazy view that holds the original
// sequence and the transform function
struct MapSomeSequenceView<Base: Sequence, T> {
fileprivate let _base: Base
fileprivate let _transform: (Base.Iterator.Element) -> T?
}
// extend it to implement Sequence
extension MapSomeSequenceView: Sequence {
typealias Iterator = AnyIterator<T>
func makeIterator() -> Iterator {
var g = _base.makeIterator()
// AnyIterator is a helper that takes a
// closure and calls it to generate each
// element
return AnyIterator {
while let element = g.next() {
if let some = self._transform(element) {
return some
}
}
return nil
}
}
}
// now extend a lazy collection to return that view
// from a call to mapSome. In pracice, when doing this,
// you should do it for all the lazy wrappers
// (i.e. random-access, forward and sequence)
extension LazyCollectionProtocol {
// I might be missing a trick with this super-ugly return type, is there a
// better way?
func mapSome<U>(
_ transform: @escaping (Elements.Iterator.Element) -> U?
) -> LazySequence<MapSomeSequenceView<Elements, U>> {
return MapSomeSequenceView(_base: elements, _transform: transform).lazy
}
}
// curried function - call with 1 argument to get a function
// that tells you if i is a multiple of a given number
// e.g.
// let isEven = isMultipleOf(2)
// isEven(4) // true
func isMultipleOf<T: FixedWidthInteger>(_ of: T)->(T)->Bool {
return { $0 % of == 0 }
}
// extend LazySequence to map only every nth element, with all
// other elements untransformed.
extension LazySequenceProtocol {
func mapEveryN(
_ n: Int,
_ transform: @escaping (Iterator.Element) -> Iterator.Element
) -> LazyMapSequence<EnumeratedSequence<Self>, Iterator.Element> {
let isNth = isMultipleOf(n)
func transform2(
_ pair: EnumeratedSequence<Self>.Iterator.Element
) -> Iterator.Element {
return isNth(pair.0 + 1) ? transform(pair.1) : pair.1
}
return self.enumerated().lazy.map(transform2)
}
}
infix operator |> : PipeRightPrecedence
precedencegroup PipeRightPrecedence {
associativity: left
}
func |><T,U>(t: T, f: (T)->U) -> U {
return f(t)
}
infix operator : DotPrecedence
precedencegroup DotPrecedence {
associativity: left
}
func <T, U, V> (g: @escaping (U) -> V, f: @escaping (T) -> U) -> (T) -> V {
return { x in g(f(x)) }
}
// function to free a method from the shackles
// of it's owner
func freeMemberFunc<T,U>(_ f: @escaping (T)->()->U)->(T)->U {
return { (t: T)->U in f(t)() }
}
extension String {
func toInt() -> Int? { return Int(self) }
}
// stringToInt can now be pipelined or composed
let stringToInt = freeMemberFunc(String.toInt)
// if only Character also had a toInt method
let charToString = { (c: Character) -> String in String(c) }
let charToInt = stringToInt charToString
func sum<S: Sequence>(_ nums: S)->S.Iterator.Element where S.Iterator.Element: FixedWidthInteger {
return nums.reduce(0) { $0.0 + $0.1 }
}
func reverse<C: LazyCollectionProtocol>(
_ source: C
) -> LazyCollection<ReversedCollection<C.Elements>> {
return source.elements.reversed().lazy
}
func map<S: LazySequenceProtocol, U>(
_ source: S, _ transform: @escaping (S.Elements.Iterator.Element)->U
) -> LazyMapSequence<S.Elements,U> {
return source.map(transform)
}
func mapSome<C: LazyCollectionProtocol, U>(
_ source: C,
_ transform: @escaping (C.Elements.Iterator.Element)->U?
) -> LazySequence<MapSomeSequenceView<C.Elements, U>> {
return source.mapSome(transform)
}
func mapEveryN<S: LazySequenceProtocol>(
_ source: S, _ n: Int,
_ transform: @escaping (S.Iterator.Element)->S.Iterator.Element
) -> LazyMapSequence<EnumeratedSequence<S>, S.Iterator.Element> {
return source.mapEveryN(n, transform)
}
// Non-lazy version of mapSome:
func mapSome<S: Sequence, C: RangeReplaceableCollection>(
_ source: S,
_ transform: @escaping (S.Iterator.Element)->C.Iterator.Element?
) -> C {
var result = C()
for x in source {
if let y = transform(x) {
result.append(y)
}
}
return result
}
// Specialized default version of mapSome that returns an array, to avoid
// forcing the user having to specify:
func mapSome<S: Sequence,U>(
_ source: S,
_ transform: @escaping (S.Iterator.Element
)->U?)->[U] {
// just calls the more generalized version
return mapSome(source, transform)
}
// Non-lazy version of mapEveryN:
func mapEveryN<S: Sequence>(
_ source: S, _ n: Int,
_ transform: @escaping (S.Iterator.Element) -> S.Iterator.Element
) -> [S.Iterator.Element] {
let isNth = isMultipleOf(n)
return source.enumerated().map {
(pair: (index: Int, elem: S.Iterator.Element)) in
isNth(pair.index+1)
? transform(pair.elem)
: pair.elem
}
}
let double = { $0*2 }
let combineDoubleDigits = {
(10...18).contains($0) ? $0-9 : $0
}
// removing lazy at start of pipeline
// switches to array-based version
let eagerchecksum = { (ccnum: String) -> Bool in
ccnum.characters//.lazy
|> { $0.reversed().lazy }
|> { mapSome($0, charToInt) }
|> { mapEveryN($0, 2, double) }
|> { map($0, combineDoubleDigits) }
|> sum
|> isMultipleOf(10)
}
let ccnum = "4012 8888 8888 1881"

View File

@@ -0,0 +1,231 @@
// LuhnAlgoLazy benchmark
//
// Description: Performs a Luhn checksum lazily
// Source: https://gist.github.com/airspeedswift/e584239d7658b317f59a
import TestsUtils
public var LuhnAlgoLazy = BenchmarkInfo(
name: "LuhnAlgoLazy",
runFunction: run_LuhnAlgoLazy,
tags: [.algorithm]
)
@inline(never)
public func run_LuhnAlgoLazy(_ N: Int) {
let resultRef = true
var result = false
for _ in 1...100*N {
result = lazychecksum(ccnum)
if result != resultRef {
break
}
}
CheckResults(result == resultRef)
}
// Another version of the Luhn algorithm, similar to the one found here:
// https://gist.github.com/airspeedswift/b349c256e90da746b852
//
// This time, trying to keep two versions, one eager one lazy,
// as similar as possible. Only adding "lazy" to the start of
// the expression to switch between the two.
//
// Much of the same code as the previous version at the top,
// Skip down to line 110 for the different par
// mapSome is my Swift version of Haskell's mapMaybe, which
// is a map that takes a transform function that returns an
// optional, and returns a collection of only those values
// that weren't nil
// first we need a lazy view that holds the original
// sequence and the transform function
struct MapSomeSequenceView<Base: Sequence, T> {
fileprivate let _base: Base
fileprivate let _transform: (Base.Iterator.Element) -> T?
}
// extend it to implement Sequence
extension MapSomeSequenceView: Sequence {
typealias Iterator = AnyIterator<T>
func makeIterator() -> Iterator {
var g = _base.makeIterator()
// AnyIterator is a helper that takes a
// closure and calls it to generate each
// element
return AnyIterator {
while let element = g.next() {
if let some = self._transform(element) {
return some
}
}
return nil
}
}
}
// now extend a lazy collection to return that view
// from a call to mapSome. In pracice, when doing this,
// you should do it for all the lazy wrappers
// (i.e. random-access, forward and sequence)
extension LazyCollectionProtocol {
// I might be missing a trick with this super-ugly return type, is there a
// better way?
func mapSome<U>(
_ transform: @escaping (Elements.Iterator.Element) -> U?
) -> LazySequence<MapSomeSequenceView<Elements, U>> {
return MapSomeSequenceView(_base: elements, _transform: transform).lazy
}
}
// curried function - call with 1 argument to get a function
// that tells you if i is a multiple of a given number
// e.g.
// let isEven = isMultipleOf(2)
// isEven(4) // true
func isMultipleOf<T: FixedWidthInteger>(_ of: T)->(T)->Bool {
return { $0 % of == 0 }
}
// extend LazySequence to map only every nth element, with all
// other elements untransformed.
extension LazySequenceProtocol {
func mapEveryN(
_ n: Int,
_ transform: @escaping (Iterator.Element) -> Iterator.Element
) -> LazyMapSequence<EnumeratedSequence<Self>, Iterator.Element> {
let isNth = isMultipleOf(n)
func transform2(
_ pair: EnumeratedSequence<Self>.Iterator.Element
) -> Iterator.Element {
return isNth(pair.0 + 1) ? transform(pair.1) : pair.1
}
return self.enumerated().lazy.map(transform2)
}
}
infix operator |> : PipeRightPrecedence
precedencegroup PipeRightPrecedence {
associativity: left
}
func |><T,U>(t: T, f: (T)->U) -> U {
return f(t)
}
infix operator : DotPrecedence
precedencegroup DotPrecedence {
associativity: left
}
func <T, U, V> (g: @escaping (U) -> V, f: @escaping (T) -> U) -> (T) -> V {
return { x in g(f(x)) }
}
// function to free a method from the shackles
// of it's owner
func freeMemberFunc<T,U>(_ f: @escaping (T)->()->U)->(T)->U {
return { (t: T)->U in f(t)() }
}
extension String {
func toInt() -> Int? { return Int(self) }
}
// stringToInt can now be pipelined or composed
let stringToInt = freeMemberFunc(String.toInt)
// if only Character also had a toInt method
let charToString = { (c: Character) -> String in String(c) }
let charToInt = stringToInt charToString
func sum<S: Sequence>(_ nums: S)->S.Iterator.Element where S.Iterator.Element: FixedWidthInteger {
return nums.reduce(0) { $0.0 + $0.1 }
}
func reverse<C: LazyCollectionProtocol>(
_ source: C
) -> LazyCollection<ReversedCollection<C.Elements>> {
return source.elements.reversed().lazy
}
func map<S: LazySequenceProtocol, U>(
_ source: S, _ transform: @escaping (S.Elements.Iterator.Element)->U
) -> LazyMapSequence<S.Elements,U> {
return source.map(transform)
}
func mapSome<C: LazyCollectionProtocol, U>(
_ source: C,
_ transform: @escaping (C.Elements.Iterator.Element)->U?
) -> LazySequence<MapSomeSequenceView<C.Elements, U>> {
return source.mapSome(transform)
}
func mapEveryN<S: LazySequenceProtocol>(
_ source: S, _ n: Int,
_ transform: @escaping (S.Iterator.Element)->S.Iterator.Element
) -> LazyMapSequence<EnumeratedSequence<S>, S.Iterator.Element> {
return source.mapEveryN(n, transform)
}
// Non-lazy version of mapSome:
func mapSome<S: Sequence, C: RangeReplaceableCollection>(
_ source: S,
_ transform: @escaping (S.Iterator.Element)->C.Iterator.Element?
) -> C {
var result = C()
for x in source {
if let y = transform(x) {
result.append(y)
}
}
return result
}
// Specialized default version of mapSome that returns an array, to avoid
// forcing the user having to specify:
func mapSome<S: Sequence,U>(
_ source: S,
_ transform: @escaping (S.Iterator.Element
)->U?)->[U] {
// just calls the more generalized version
return mapSome(source, transform)
}
// Non-lazy version of mapEveryN:
func mapEveryN<S: Sequence>(
_ source: S, _ n: Int,
_ transform: @escaping (S.Iterator.Element) -> S.Iterator.Element
) -> [S.Iterator.Element] {
let isNth = isMultipleOf(n)
return source.enumerated().map {
(pair: (index: Int, elem: S.Iterator.Element)) in
isNth(pair.index+1)
? transform(pair.elem)
: pair.elem
}
}
let double = { $0*2 }
let combineDoubleDigits = {
(10...18).contains($0) ? $0-9 : $0
}
// first, the lazy version of checksum calcuation
let lazychecksum = { (ccnum: String) -> Bool in
ccnum.characters.lazy
|> reverse
|> { mapSome($0, charToInt) }
|> { mapEveryN($0, 2, double) }
|> { map($0, combineDoubleDigits) }
|> sum
|> isMultipleOf(10)
}
let ccnum = "4012 8888 8888 1881"

View File

@@ -0,0 +1,64 @@
// NibbleSort benchmark
//
// Source: https://gist.github.com/airspeedswift/f4daff4ea5c6de9e1fdf
import TestsUtils
public var NibbleSort = BenchmarkInfo(
name: "NibbleSort",
runFunction: run_NibbleSort,
tags: [.validation]
)
@inline(never)
public func run_NibbleSort(_ N: Int) {
let vRef: UInt64 = 0xfeedbba000000000
let v: UInt64 = 0xbadbeef
var c = NibbleCollection(v)
for _ in 1...10000*N {
c.val = v
c.sort()
if c.val != vRef {
break
}
}
CheckResults(c.val == vRef)
}
struct NibbleCollection: RandomAccessCollection, MutableCollection {
typealias Indices = CountableRange<UInt64>
var val: UInt64
init(_ val: UInt64) { self.val = val }
typealias Index = UInt64
let startIndex: UInt64 = 0
let endIndex: UInt64 = 16
subscript(bounds: Range<Index>)
-> MutableRandomAccessSlice<NibbleCollection> {
get {
fatalError("Should not be called. Added here to please the type checker")
}
set {
fatalError("Should not be called. Added here to please the type checker")
}
}
subscript(idx: UInt64) -> UInt64 {
get {
return (val >> (idx*4)) & 0xf
}
set(n) {
let mask = (0xf as UInt64) << (idx * 4)
val &= ~mask
val |= n << (idx * 4)
}
}
typealias Iterator = IndexingIterator<NibbleCollection>
func makeIterator() -> Iterator { return Iterator(_elements: self) }
}

View File

@@ -0,0 +1,42 @@
// PartialApplyDynamicType benchmark
//
// Description: Create and call a generic partially applied dynamic type method.
// Source: https://gist.github.com/airspeedswift/f14f13960270004fbe64
import TestsUtils
public var PartialApplyDynamicType = BenchmarkInfo(
name: "PartialApplyDynamicType",
runFunction: run_PartialApplyDynamicType,
tags: [.validation, .abstraction]
)
@inline(never)
public func run_PartialApplyDynamicType(_ N: Int) {
let expectedResult = 2
var result = 0
for _ in 1...100000*N {
result = g(c)(c)(1)
if result != expectedResult {
break
}
}
CheckResults(result == expectedResult)
}
let c = C()
protocol P {
func f(_ i: Int) -> Int
}
func g<T: P>(_ t: T) -> ((T) -> (Int) -> Int) {
let f = { type(of: t).f($0) }
return f
}
class C: P {
func f(_ i: Int) -> Int {
return i + 1
}
}

View File

@@ -0,0 +1,60 @@
// RangeReplaceablePlusDefault benchmark
//
// Source: https://gist.github.com/airspeedswift/392599e7eeeb74b481a7
import TestsUtils
public var RangeReplaceableCollectionPlusDefault = BenchmarkInfo(
name: "RangeReplaceableCollectionPlusDefault",
runFunction: run_RangeReplaceableCollectionPlusDefault,
tags: [.validation]
)
@inline(never)
public func run_RangeReplaceableCollectionPlusDefault(_ N: Int) {
let stringsRef = [1, 2, 3]
let strings = ["1", "2", "3"]
let toInt = { (s: String) -> Int? in Int(s) }
var a = [Int]()
var b = [Int]()
for _ in 1...1000*N {
let a2: Array = mapSome(strings, toInt)
let b2 = mapSome(strings, toInt)
a = a2
b = b2
if !compareRef(a, b, stringsRef) {
break
}
}
CheckResults(compareRef(a, b, stringsRef))
}
func compareRef(_ a: [Int], _ b: [Int], _ ref: [Int]) -> Bool {
return ref == a && ref == b
}
// This algorithm returns a generic placeholder
// that can be any kind of range-replaceable collection:
func mapSome
<S: Sequence, C: RangeReplaceableCollection>
(_ source: S, _ transform: (S.Iterator.Element)->C.Iterator.Element?) -> C {
var result = C()
for x in source {
if let y = transform(x) {
result.append(y)
}
}
return result
}
// If you write a second version that returns an array,
// you can call the more general version for implementation:
func mapSome<S: Sequence,U>(_ source: S, _ transform: (S.Iterator.Element)->U?)->[U] {
// just calls the more generalized version
// (works because here, the return type
// is now of a specific type, an Array)
return mapSome(source, transform)
}

View File

@@ -0,0 +1,51 @@
// StringRemoveDupes benchmark
//
// Source: https://gist.github.com/airspeedswift/83eee31e1d9e52fd5570
import TestsUtils
public var StringRemoveDupes = BenchmarkInfo(
name: "StringRemoveDupes",
runFunction: run_StringRemoveDupes,
tags: [.validation, .String]
)
@inline(never)
public func run_StringRemoveDupes(_ N: Int) {
let textLengthRef = 25
let text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
"Morbi nisi metus, accumsan eu sagittis et, condimentum ut " +
"arcu. Morbi aliquet porta velit, accumsan aliquam ante " +
"facilisis non. Maecenas lobortis erat vel elit fringilla " +
"blandit. Praesent euismod mauris sodales velit facilisis " +
"blandit. Morbi leo neque, finibus ut mi in, auctor sagittis."
var s = ""
for _ in 1...10*N {
s = text.removeDuplicates()
if s.characters.count != textLengthRef {
break
}
}
CheckResults(s.characters.count == textLengthRef)
}
// removes all but first occurrence from a sequence, returning an array.
// requires elements to be hashable, not just equatable, but the alternative
// of using contains is very inefficient
// alternatively, could require comparable, sort, and remove adjacent dupes
func uniq<S: Sequence,
E: Hashable>(_ seq: S) -> [E] where E == S.Iterator.Element {
var seen: [S.Iterator.Element:Int] = [:]
return seq.filter { seen.updateValue(1, forKey: $0) == nil }
}
// removeDuplicates returns a version of the String with
// all duplicates removed
extension String {
func removeDuplicates() -> String {
return String(uniq(self.characters))
}
}

View File

@@ -29,16 +29,19 @@ import ArraySetElement
import ArraySubscript
import BitCount
import ByteSwap
import COWTree
import CString
import CSVParsing
import Calculator
import CaptureProp
import CharacterProperties
import CharacterLiteralsLarge
import CharacterLiteralsSmall
import CharacterProperties
import Chars
import ClassArrayGetter
import Combos
import DeadArray
import DictOfArraysToArrayOfDicts
import DictTest
import DictTest2
import DictTest3
@@ -64,10 +67,13 @@ import IterateData
import Join
import LazyFilter
import LinkedList
import LuhnAlgoEager
import LuhnAlgoLazy
import MapReduce
import Memset
import MonteCarloE
import MonteCarloPi
import NibbleSort
import NSDictionaryCastToSwift
import NSError
import NSStringConversion
@@ -81,6 +87,7 @@ import ObserverForwarderStruct
import ObserverPartiallyAppliedMethod
import ObserverUnappliedMethod
import OpenClose
import PartialApplyDynamicType
import Phonebook
import PolymorphicCalls
import PopFront
@@ -95,6 +102,7 @@ import RC4
import RGBHistogram
import RangeAssignment
import RangeIteration
import RangeReplaceableCollectionPlusDefault
import RecursiveOwnedParameter
import ReduceInto
import ReversedCollections
@@ -114,6 +122,7 @@ import StringEdits
import StringEnum
import StringInterpolation
import StringMatch
import StringRemoveDupes
import StringTests
import StringWalk
import Substring
@@ -152,17 +161,20 @@ registerBenchmark(ArraySetElement)
registerBenchmark(ArraySubscript)
registerBenchmark(BitCount)
registerBenchmark(ByteSwap)
registerBenchmark(COWTree)
registerBenchmark(CString)
registerBenchmark(CSVParsing)
registerBenchmark(Calculator)
registerBenchmark(CaptureProp)
registerBenchmark(CharacterPropertiesFetch)
registerBenchmark(CharacterPropertiesStashed)
registerBenchmark(CharacterLiteralsLarge)
registerBenchmark(CharacterLiteralsSmall)
registerBenchmark(CharacterPropertiesFetch)
registerBenchmark(CharacterPropertiesStashed)
registerBenchmark(Chars)
registerBenchmark(Combos)
registerBenchmark(ClassArrayGetter)
registerBenchmark(DeadArray)
registerBenchmark(DictOfArraysToArrayOfDicts)
registerBenchmark(Dictionary)
registerBenchmark(Dictionary2)
registerBenchmark(Dictionary3)
@@ -188,6 +200,8 @@ registerBenchmark(IterateData)
registerBenchmark(Join)
registerBenchmark(LazyFilter)
registerBenchmark(LinkedList)
registerBenchmark(LuhnAlgoEager)
registerBenchmark(LuhnAlgoLazy)
registerBenchmark(MapReduce)
registerBenchmark(Memset)
registerBenchmark(MonteCarloE)
@@ -195,6 +209,7 @@ registerBenchmark(MonteCarloPi)
registerBenchmark(NSDictionaryCastToSwift)
registerBenchmark(NSErrorTest)
registerBenchmark(NSStringConversion)
registerBenchmark(NibbleSort)
registerBenchmark(NopDeinit)
registerBenchmark(ObjectAllocation)
registerBenchmark(ObjectiveCBridging)
@@ -205,6 +220,7 @@ registerBenchmark(ObserverForwarderStruct)
registerBenchmark(ObserverPartiallyAppliedMethod)
registerBenchmark(ObserverUnappliedMethod)
registerBenchmark(OpenClose)
registerBenchmark(PartialApplyDynamicType)
registerBenchmark(Phonebook)
registerBenchmark(PolymorphicCalls)
registerBenchmark(PopFront)
@@ -219,6 +235,7 @@ registerBenchmark(RC4Test)
registerBenchmark(RGBHistogram)
registerBenchmark(RangeAssignment)
registerBenchmark(RangeIteration)
registerBenchmark(RangeReplaceableCollectionPlusDefault)
registerBenchmark(RecursiveOwnedParameter)
registerBenchmark(ReduceInto)
registerBenchmark(ReversedCollections)
@@ -238,6 +255,7 @@ registerBenchmark(StringEdits)
registerBenchmark(StringEnum)
registerBenchmark(StringInterpolation)
registerBenchmark(StringMatch)
registerBenchmark(StringRemoveDupes)
registerBenchmark(StringTests)
registerBenchmark(StringWalk)
registerBenchmark(SubstringTest)