apple / swift-algorithms

Commonly used sequence and collection algorithms for Swift
Apache License 2.0
5.92k stars 440 forks source link

[Rotate] Non-mutating variants for rotating APIs #175

Closed LucianoPAlmeida closed 1 year ago

LucianoPAlmeida commented 2 years ago

This is an implementation of non-mutating variant for rotate(toStartAt:) and rotate(subrange:toStartAt:) that are rotated(toStartAt:) and rotated(subrange:toStartAt:) respectively that results in a RotatedCollection view. The useful aspects of such API is that when preserving the original collection, the mutating version requires a copy. Also, when base conforms to RandomAccessCollection calling rotated is O(1) time and elements at each position are also computed in constant time.

Couple of other points to note:

Let me know what you think @natecook1000 @timvermeulen @lorentey

Checklist

LucianoPAlmeida commented 2 years ago

A quick bench about difference in perf for a single all elements iteration just out of curiosity

var benchmark = Benchmark(title: "Rotated Algorithm")
let inputGenerator: (Int) -> [Int] = { size in
  return (0..<size).map { $0 }
}
benchmark.registerInputGenerator(inputGenerator)

benchmark.add(
  title: "In place rotation 25%",
  input: [Int].self
) { input in
  var mInput = input
  let count = mInput.count / 4 // 25% rotation
  return { timer in
    mInput.rotate(toStartAt: count)
    for value in mInput {
      blackHole(value)
    }
  }
}

benchmark.add(
  title: "Rotated View 25%",
  input: [Int].self
) { input in
  let count = input.count / 4 // 25% rotation
  return { timer in
    for value in input.rotated(toStartAt: count) {
      blackHole(value)
    }
  }
}

benchmark.main()
chart