I’m doing a basic planarize operation ([[a1, b1, c1], [a2, b2, c2], [a3, b3, c3]]
→ [a1, a2, a3, b1, b2, b3, c1, c2, c3]
) and am running into an 80% slowdown when using a function expression as opposed to a looped-based one.
import func Glibc.clock
struct S:RandomAccessCollection
{
let a:Int,
b:Int,
c:Int,
d:Int
var startIndex:Int
{
return 0
}
var endIndex:Int
{
return 4
}
subscript(index:Int) -> Int
{
switch index
{
case 0:
return self.a
case 1:
return self.b
case 2:
return self.c
case 3:
return self.d
default:
fatalError("(_RGBAColor) index \(index) out of range")
}
}
}
let structured:[S] = (0 ..< 1 << 16).map
{
_ in
.init( a: Int.random(in: .min ... .max),
b: Int.random(in: .min ... .max),
c: Int.random(in: .min ... .max),
d: Int.random(in: .min ... .max))
}
func planarFunctional(_ structured:[S]) -> [Int]
{
return (0 ..< 4).map
{
(ci:Int) in
structured.map{ $0[ci] }
}.flatMap{ $0 }
}
func planarLoop(_ structured:[S]) -> [Int]
{
var planar:[Int] = []
planar.reserveCapacity(structured.count << 2)
for ci:Int in 0 ..< 4
{
for element:S in structured
{
planar.append(element[ci])
}
}
return planar
}
func planarHybrid(_ structured:[S]) -> [Int]
{
var planar:[Int] = []
planar.reserveCapacity(structured.count << 2)
for ci:Int in 0 ..< 4
{
planar.append(contentsOf: structured.map{ $0[ci] })
}
return planar
}
let t1:Int = clock()
let planar1:[Int] = planarLoop(structured)
print(clock() - t1)
print(planar1.last as Any)
let t2:Int = clock()
let planar2:[Int] = planarFunctional(structured)
print(clock() - t2)
print(planar2.last as Any)
let t3:Int = clock()
let planar3:[Int] = planarHybrid(structured)
print(clock() - t3)
print(planar3.last as Any)
$ swiftc -O planar.swift
$ ./planar
1539 // loop
Optional(5101610777180498905)
2698 // functional (map + flatmap)
Optional(5101610777180498905)
1713 // hybrid (loop + flatmap)
Optional(5101610777180498905)
Last time, it was a missing RandomAccessCollection
conformance that was slowing down the flatmap. But all the involved types here are RandomAccessCollections
, including the 0 ..< 4
range. What is going on?