Swift Digest
SE-0551 | Swift Evolution↗

単一の値に対する Span

Span over a single value

Proposal
SE-0551↗
Authors
Guillaume Lessard
Review Manager
Doug Gregor
Status
Accepted

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら↗。

01 何が問題だったのか

Span や MutableSpan を受け取るAPIに、単一の値を渡したくなる場面がときどきあります。たとえばパケットのヘッダ1つ分のバイト列をチェックサム計算に渡したり、1つの変数へパーサに直接書き込ませたりするケースです。

現状でも、CollectionOfOne の span / mutableSpan プロパティを使えば、単一の値を Span パラメータに渡せます。しかし、この方法には次の制約があります。

  • CollectionOfOne はいったん値をコピーして保持するため、本来 Span には不要なコピーが発生します。
  • コピーを前提とするため、non-copyable な型の値には使えません。
  • アクセスできるのは CollectionOfOne 自身のストレージに限られ、既存の変数(別のバインディング)のストレージをその場で参照することはできません。

また、単一の値のメモリを直接扱う手段としては withUnsafePointer(to:) / withUnsafeMutablePointer(to:) / withUnsafeBytes(of:) / withUnsafeMutableBytes(of:) がありますが、これらは名前のとおり unsafe なポインタを経由するAPIです。安全に単一の値のスパンを得る手段が求められていました。

02 どのように解決されるのか

Span / MutableSpan / RawSpan / MutableRawSpan に、単一の値をその場で借用(borrow)または変更するための、要素数 1 のスパンを作るイニシャライザを追加します。値をコピーせずにそのまま参照するため、non-copyable な値でも利用できます。

要素としてのスパン

Span と MutableSpan には、単一の値を要素 1 つとして持つスパンを作る ofOne: ラベル付きイニシャライザが追加されます。

let header = PacketHeader(...)
let c = checksum(Span(ofOne: header).bytes) // header をその場で borrow する

var timestamp = UInt64.zero
var span = MutableSpan(ofOne: &timestamp)
parser.read(into: span.mutableBytes)        // timestamp に書き込む

Span(ofOne:) は値を借用し、MutableSpan(ofOne:) は inout で受け取った値への変更を表します。要素型は ~Copyable でもかまいません。

バイト列としてのスパン

RawSpan と MutableRawSpan には、単一の値のバイト列を表すスパンを作る bytesOf: ラベル付きイニシャライザが追加されます。作られるスパンの byteCount は MemoryLayout<Element>.size になります。

let header = PacketHeader(...)
let c = checksum(RawSpan(bytesOf: header))

var timestamp = UInt64.zero
var bytes = MutableRawSpan(bytesOf: &timestamp)
parser.read(into: bytes)

要素としてのスパンには ofOne:、バイト列としてのスパンには bytesOf: と、ラベルを使い分けています。ofOne は「1 要素」を、bytesOf は「複数バイト」を連想させるためです。RawSpan / MutableRawSpan 版は、バイト列として安全に扱える型(ConvertibleToBytes など)に制約されます。

unsafe なAPIの安全な代替

これらのイニシャライザは、withUnsafePointer(to:) / withUnsafeMutablePointer(to:) / withUnsafeBytes(of:) / withUnsafeMutableBytes(of:) の安全な代替としても使えます。ポインタを直接扱うことなく、単一の値に対する安全なスパンを得られます。