Add overrides taking an UnsafePointer source to non-destructive copying methods on UnsafeMutablePointer
01 何が問題だったのか
UnsafeMutablePointer には、別のポインタが指すメモリから要素を非破壊的にコピーするためのメソッドがいくつかありました。具体的には次の3つで、いずれも source として UnsafeMutablePointer<Pointee> を受け取る形になっていました。
func assignFrom(source: UnsafeMutablePointer<Pointee>, count: Int)
func assignBackwardFrom(source: UnsafeMutablePointer<Pointee>, count: Int)
func initializeFrom(source: UnsafeMutablePointer<Pointee>, count: Int)
assignFrom と assignBackwardFrom は初期化済みメモリへの代入、initializeFrom は未初期化メモリへの初期化を行うもので、コピー元のメモリを変更しない(非破壊的)点が共通しています。
問題は、コピー元が UnsafePointer である場合に、これらのメソッドを素直に呼び出せないことでした。source の型が UnsafeMutablePointer に固定されているため、呼び出し側で UnsafeMutablePointer へのキャストを挟む必要がありました。
let source: UnsafePointer<Int> = ...
let destination: UnsafeMutablePointer<Int> = ...
// 提案前は明示的なキャストが必要
destination.assignFrom(UnsafeMutablePointer(source), count: count)
非破壊的なコピーではコピー元のメモリは読み取られるだけなので、UnsafePointer(読み取り専用)を渡しても本来は安全です。それにもかかわらず、型だけを合わせるために UnsafeMutablePointer への明示的なキャストを書かされるのは、視覚的なノイズが増えるだけでなく、コードを読む側に「ここで可変性を付け足している」という警戒感を与える原因にもなっていました。
02 どのように解決されるのか
UnsafeMutablePointer に、source として UnsafePointer<Pointee> を受け取るオーバーロードを追加します。既存の UnsafeMutablePointer を受け取るメソッドはそのまま残るため、呼び出し側はコピー元の型に応じて自然にどちらかが選ばれます。
追加されるのは次の3メソッドです。
/// 初期化済みメモリに、source から count 個の値を先頭から順に代入する。
public func assignFrom(source: UnsafePointer<Pointee>, count: Int)
/// 初期化済みメモリに、source から count 個の値を末尾から順に代入する。
/// 代入先のメモリが source の範囲と重なり、かつ代入先の方が後方にある場合に使う。
/// 要件: source が self より前にあるか、source が self + count より後ろにあること。
public func assignBackwardFrom(source: UnsafePointer<Pointee>, count: Int)
/// 未初期化メモリに、source から count 個の値をコピーして初期化する。
/// 前提: self が指すメモリは未初期化であること。
/// 要件: self と source のメモリ範囲は重なっていないこと。
public func initializeFrom(source: UnsafePointer<Pointee>, count: Int)
これにより、UnsafePointer をコピー元として渡す際にキャストが不要になります。
let source: UnsafePointer<Int> = ...
let destination: UnsafeMutablePointer<Int> = ...
// 提案後はそのまま渡せる
destination.assignFrom(source, count: count)
なぜ単に既存メソッドを UnsafePointer 版に置き換えないのか
UnsafeMutablePointer から UnsafePointer への暗黙変換を利用すれば、既存メソッドを削除して UnsafePointer 版のみを残すことでも同じ呼び出しは書けます。しかし、明示的なオーバーロードを両方用意する方がドキュメントやコード補完の観点で意図が明確になるため、オーバーロードを追加する形が採用されています。
なお本提案は純粋に追加的な変更で、既存のコードに影響はありません。