Created
June 13, 2018 04:56
-
-
Save tayloraswift/54accbf3265cb10cfb52b668173906f1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protocol Convolvable | |
{ | |
static | |
func convolve(_ a:Self, _ b:Self) -> Self | |
static | |
func generate() -> Self | |
} | |
extension Int:Convolvable | |
{ | |
static | |
func convolve(_ a:Int, _ b:Int) -> Int | |
{ | |
return a &+ b | |
} | |
static | |
func generate() -> Int | |
{ | |
return random(in: 0 ..< max) | |
} | |
} | |
struct TestElement:Convolvable | |
{ | |
let a:Int, | |
b:Int, | |
c:Float, | |
d:Float, | |
e:UnsafeMutablePointer<Double>, | |
f:Bool, | |
g:Bool | |
static | |
func convolve(_ a:TestElement, _ b:TestElement) -> TestElement | |
{ | |
return TestElement(a: a.a &+ b.a, b: a.b &+ b.b, c: a.d * b.c, d: a.c * b.d, | |
e: a.e + b.a, f: a.f != b.f, g: a.f && b.f) | |
} | |
static | |
func generate() -> TestElement | |
{ | |
return TestElement(a: Int.random(in: 0 ..< .max), b: Int.random(in: 0 ..< .max), | |
c: Float.random(in: 0 ..< 1), | |
d: Float.random(in: 0 ..< 1), | |
e: UnsafeMutablePointer<Double>(bitPattern: Int.random(in: 1 ..< .max))!, | |
f: Bool.random(), | |
g: Bool.random()) | |
} | |
} | |
struct Array4<Element>:RandomAccessCollection, MutableCollection | |
{ | |
var storage:(Element, Element, Element, Element), | |
_count:UInt8 | |
static | |
var capacity:Int | |
{ | |
return 4 | |
} | |
var count:Int | |
{ | |
return Int(self._count) | |
} | |
internal var startIndex:Int | |
{ | |
return 0 | |
} | |
internal var endIndex:Int | |
{ | |
return self.count | |
} | |
@inline(__always) | |
func index(after i:Int) -> Int | |
{ | |
return i + 1 | |
} | |
@inline(__always) | |
func index(before i:Int) -> Int | |
{ | |
return i - 1 | |
} | |
subscript(i:Int) -> Element | |
{ | |
get | |
{ | |
guard 0 ..< self.count ~= i | |
else | |
{ | |
fatalError("index out of range") | |
} | |
var copy:(Element, Element, Element, Element) = self.storage | |
return withUnsafeBytes(of: ©) | |
{ | |
(pointer:UnsafeRawBufferPointer) -> Element in | |
return pointer.load(fromByteOffset: MemoryLayout<Element>.stride * i, | |
as: Element.self) | |
} | |
} | |
set(v) | |
{ | |
guard 0 ..< self.count ~= i | |
else | |
{ | |
fatalError("index out of range") | |
} | |
self.withUnsafeMutableBufferPointer | |
{ | |
(buffer:UnsafeMutableBufferPointer<Element>) in | |
buffer[i] = v | |
} | |
} | |
} | |
mutating | |
func withUnsafeMutableBufferPointer<Result>( | |
_ body: (UnsafeMutableBufferPointer<Element>) throws -> Result) rethrows | |
-> Result | |
{ | |
let count = self.count // for exclusive access | |
return try withUnsafeMutableBytes(of: &self.storage) | |
{ | |
(pointer:UnsafeMutableRawBufferPointer) -> Result in | |
let buffer:UnsafeMutableBufferPointer<Element> = | |
.init(start: pointer.baseAddress._unsafelyUnwrappedUnchecked | |
.assumingMemoryBound(to: Element.self), | |
count: count) | |
return try body(buffer) | |
} | |
} | |
mutating | |
func withUnsafeBufferPointer<Result>( | |
_ body: (UnsafeBufferPointer<Element>) throws -> Result) rethrows | |
-> Result | |
{ | |
let count = self.count // for exclusive access | |
return try withUnsafeBytes(of: &self.storage) | |
{ | |
(pointer:UnsafeRawBufferPointer) -> Result in | |
let buffer:UnsafeBufferPointer<Element> = | |
.init(start: pointer.baseAddress._unsafelyUnwrappedUnchecked | |
.assumingMemoryBound(to: Element.self), | |
count: count) | |
return try body(buffer) | |
} | |
} | |
} | |
struct SwitchArray4<Element>:RandomAccessCollection, MutableCollection | |
{ | |
var storage:(Element, Element, Element, Element), | |
_count:UInt8 | |
static | |
var capacity:Int | |
{ | |
return 4 | |
} | |
var count:Int | |
{ | |
return Int(self._count) | |
} | |
internal var startIndex:Int | |
{ | |
return 0 | |
} | |
internal var endIndex:Int | |
{ | |
return self.count | |
} | |
@inline(__always) | |
func index(after i:Int) -> Int | |
{ | |
return i + 1 | |
} | |
@inline(__always) | |
func index(before i:Int) -> Int | |
{ | |
return i - 1 | |
} | |
subscript(i:Int) -> Element | |
{ | |
get | |
{ | |
switch i | |
{ | |
case 0: | |
return self.storage.0 | |
case 1: | |
return self.storage.1 | |
case 2: | |
return self.storage.2 | |
case 3: | |
return self.storage.3 | |
default: | |
fatalError("index out of range") | |
} | |
} | |
set(v) | |
{ | |
switch i | |
{ | |
case 0: | |
self.storage.0 = v | |
case 1: | |
self.storage.1 = v | |
case 2: | |
self.storage.2 = v | |
case 3: | |
self.storage.3 = v | |
default: | |
fatalError("index out of range") | |
} | |
} | |
} | |
} | |
import func Glibc.clock | |
func benchmark<C>(_ arrays:[C]) where C:RandomAccessCollection, C:MutableCollection, | |
C.Element:Convolvable, C.Index == Int | |
{ | |
let start:Int = clock() | |
let combination:C.Element = arrays.reduce(arrays[0][0]) | |
{ | |
(residue:C.Element, array:C) -> C.Element in | |
return (0 ..< 4).map({ _ in Int.random(in: 0 ..< 4) }).reduce(residue) | |
{ | |
(residue:C.Element, next:Int) -> C.Element in | |
C.Element.convolve(residue, array[next]) | |
} | |
} | |
let runtime:Int = clock() - start | |
print(runtime, combination) | |
} | |
func generateSamples<Element>(_ count:Int) -> ([Array4<Element>], [SwitchArray4<Element>], [[Element]]) | |
where Element:Convolvable | |
{ | |
// make a bunch of fixed arrays | |
let a1:[Array4<Element>] = (0 ..< count).map | |
{ | |
_ in | |
return Array4(storage: | |
(Element.generate(), Element.generate(), Element.generate(), Element.generate()), | |
_count: 4) | |
} | |
let a2:[SwitchArray4<Element>] = (0 ..< count).map | |
{ | |
_ in | |
return SwitchArray4(storage: | |
(Element.generate(), Element.generate(), Element.generate(), Element.generate()), | |
_count: 4) | |
} | |
// normal arrays | |
let a3:[[Element]] = (0 ..< count).map | |
{ | |
_ in | |
return [Element.generate(), Element.generate(), Element.generate(), Element.generate()] | |
} | |
return (a1, a2, a3) | |
} | |
let (a1, a2, a3):([Array4<Int>], [SwitchArray4<Int>], [[Int]]) = | |
generateSamples(100000) | |
benchmark(a1) | |
benchmark(a2) | |
benchmark(a3) | |
let (b1, b2, b3):([Array4<TestElement>], [SwitchArray4<TestElement>], [[TestElement]]) = | |
generateSamples(100000) | |
benchmark(b1) | |
benchmark(b2) | |
benchmark(b3) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment