mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[benchmarks] Add some more benchmarks by our very own airspeedswift.
With his permission of course.
This commit is contained in:
committed by
Michael Gottesman
parent
fc64e34c8e
commit
24027067b9
@@ -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
|
||||
|
||||
146
benchmark/single-source/COWTree.swift
Normal file
146
benchmark/single-source/COWTree.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
benchmark/single-source/Combos.swift
Normal file
84
benchmark/single-source/Combos.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
141
benchmark/single-source/DictOfArraysToArrayOfDicts.swift
Normal file
141
benchmark/single-source/DictOfArraysToArrayOfDicts.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
232
benchmark/single-source/LuhnAlgoEager.swift
Normal file
232
benchmark/single-source/LuhnAlgoEager.swift
Normal 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"
|
||||
231
benchmark/single-source/LuhnAlgoLazy.swift
Normal file
231
benchmark/single-source/LuhnAlgoLazy.swift
Normal 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"
|
||||
64
benchmark/single-source/NibbleSort.swift
Normal file
64
benchmark/single-source/NibbleSort.swift
Normal 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) }
|
||||
}
|
||||
42
benchmark/single-source/PartialApplyDynamicType.swift
Normal file
42
benchmark/single-source/PartialApplyDynamicType.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
51
benchmark/single-source/StringRemoveDupes.swift
Normal file
51
benchmark/single-source/StringRemoveDupes.swift
Normal 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))
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user