Skip to content

Commit c237075

Browse files
Watson1978claude
andcommitted
IO::Buffer: 生成の 3 メソッド (for / map / string) を追加
IO::Buffer.for / IO::Buffer.map / IO::Buffer.string を追加した。 IO::Buffer.string は 3.3 で追加されたため #@SInCE 3.3 で分岐する。 実機で確認した挙動: - for はブロックを渡さない場合、内容を複製した凍結済みの文字列を元にするため、 あとから元の文字列を変更してもバッファは変わらない。 - for にブロックを渡した場合は元の文字列自身を参照し、ブロックの実行中は 元の文字列を変更できない (RuntimeError)。 - map は既定で書き込み可能かつ共有のマップになるため、読み込み専用で開いた ファイルをそのまま渡すと Errno::EACCES になる。 - offset はシステム依存で、多くの環境ではページサイズの倍数である必要がある。 あわせて以下を修正した。 - #3305 で平文にしていた IO::Buffer.for / IO::Buffer.map への参照をリンクに戻した。 - PAGE_SIZE 定数の説明が「size がこの値より大きい場合」のままだった。 #3305 で IO::Buffer.new 側は「以上」に直したが、定数側が残っていた。 - get_string の例の期待値 #<Encoding:BINARY (ASCII-8BIT)> は 3.4 以降の表示で、 3.1〜3.3 では #<Encoding:ASCII-8BIT> になる。.encoding.name に変えて 全版で一致するようにした。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 84c6e2b commit c237075

1 file changed

Lines changed: 119 additions & 13 deletions

File tree

manual/api/_builtin/IO__Buffer.md

Lines changed: 119 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ p buf.get_string(0, 4) # => "Ruby"
4848

4949
OS のページサイズをバイト数で表した値です。
5050

51-
[m:IO::Buffer.new] は、size がこの値より大きい場合に仮想メモリ機構を用いて
51+
[m:IO::Buffer.new] は、size がこの値以上の場合に仮想メモリ機構を用いて
5252
バッファを確保します。
5353

5454
値は環境依存です。
@@ -115,6 +115,90 @@ p IO::Buffer::HOST_ENDIAN == IO::Buffer::LITTLE_ENDIAN # => true
115115

116116
## Class Methods
117117

118+
### def for(string) -> IO::Buffer
119+
### def for(string) {|buffer| ... } -> object
120+
121+
文字列 string のメモリ領域を参照する、コピーを伴わないバッファを作成します。
122+
123+
ブロックを渡さない場合は、string の内容を複製した凍結済みの文字列を
124+
バッファの元として使い、読み取り専用のバッファを返します。
125+
元の文字列とは切り離されるため、あとから元の文字列を変更してもバッファの
126+
内容は変わりません。
127+
128+
ブロックを渡した場合は、string 自身のメモリ領域を参照するバッファを
129+
ブロックに渡し、ブロックの評価結果を返します。バッファへの書き込みは
130+
string に反映されます。ブロックの実行中、string は変更できません。
131+
string が freeze されている場合は読み取り専用のバッファになります。
132+
133+
- **param** `string` -- バッファの元にする [c:String] を指定します。
134+
135+
```ruby title="例: ブロックを渡さない場合"
136+
buffer = IO::Buffer.for("test")
137+
p buffer.get_string # => "test"
138+
p buffer.external? # => true
139+
p buffer.readonly? # => true
140+
141+
# 元の文字列を変更してもバッファには影響しない
142+
str = +"test"
143+
buffer = IO::Buffer.for(str)
144+
str << "XY"
145+
p str # => "testXY"
146+
p buffer.get_string # => "test"
147+
```
148+
149+
```ruby title="例: ブロックを渡した場合"
150+
str = +"test"
151+
IO::Buffer.for(str) do |buffer|
152+
p buffer.readonly? # => false
153+
buffer.set_string("Ruby")
154+
end
155+
p str # => "Ruby"
156+
```
157+
158+
- **SEE** [m:IO::Buffer.new], [m:IO::Buffer.map]
159+
160+
### def map(file, size = nil, offset = 0, flags = 0) -> IO::Buffer
161+
162+
ファイルをメモリにマップしたバッファを作成して返します。
163+
164+
既定では書き込み可能かつ共有(shared)のマップになるため、file は書き込み
165+
可能な状態で開いておく必要があります。読み込み専用で開いたファイルを
166+
マップするには、flags に [m:IO::Buffer::READONLY] を指定します。
167+
[m:IO::Buffer::PRIVATE] を指定するとコピーオンライトのマップになり、
168+
バッファへの変更はファイルにも他のプロセスにも反映されません。
169+
170+
- **param** `file` -- マップする [c:File] を指定します。
171+
172+
- **param** `size` -- マップするバイト数を指定します。省略するとファイル全体を
173+
マップします。0 を指定した場合と空のファイルを指定した場合は
174+
エラーになります。
175+
176+
- **param** `offset` -- マップを開始する位置をファイルの先頭からのバイト数で
177+
指定します。指定できる値はシステム依存で、多くの環境では
178+
ページサイズの倍数である必要があります。
179+
180+
- **param** `flags` -- [m:IO::Buffer::READONLY][m:IO::Buffer::PRIVATE]
181+
指定します。
182+
183+
```ruby title="例: 読み込み専用でマップする"
184+
File.write("test.txt", "hello world")
185+
186+
buffer = IO::Buffer.map(File.open("test.txt"), nil, 0, IO::Buffer::READONLY)
187+
p buffer.get_string # => "hello world"
188+
p buffer.mapped? # => true
189+
p buffer.readonly? # => true
190+
```
191+
192+
```ruby title="例: 書き込み可能なマップ"
193+
File.write("test.txt", "hello world")
194+
195+
buffer = IO::Buffer.map(File.open("test.txt", "r+"))
196+
buffer.set_string("HELLO")
197+
p File.read("test.txt") # => "HELLO world"
198+
```
199+
200+
- **SEE** [m:IO::Buffer.new], [m:IO::Buffer.for]
201+
118202
### def new(size = IO::Buffer::DEFAULT_SIZE, flags = 0) -> IO::Buffer
119203

120204
size バイトの、0 で埋められた新しいバッファを作成して返します。
@@ -137,6 +221,32 @@ p buf.internal? # => true
137221
p buf.get_string # => "\x00\x00\x00\x00"
138222
```
139223

224+
- **SEE** [m:IO::Buffer.for], [m:IO::Buffer.map]
225+
226+
#@since 3.3
227+
### def string(length) {|buffer| ... } -> String
228+
229+
length バイトの文字列を新しく作り、それを元にしたコピーを伴わないバッファを
230+
ブロックに渡します。ブロックの実行後、その文字列を返します。
231+
232+
ブロックの中でバッファに書き込んだ内容が、そのまま返される文字列の内容に
233+
なります。返される文字列のエンコーディングは [m:Encoding::BINARY] です。
234+
235+
- **param** `length` -- 作成する文字列のバイト数を整数で指定します。
236+
237+
- **raise** `LocalJumpError` -- ブロックを渡さなかった場合に発生します。
238+
239+
```ruby
240+
str = IO::Buffer.string(4) do |buffer|
241+
buffer.set_string("Ruby")
242+
end
243+
p str # => "Ruby"
244+
p str.encoding.name # => "ASCII-8BIT"
245+
```
246+
247+
- **SEE** [m:IO::Buffer.for]
248+
#@end
249+
140250
## Instance Methods
141251

142252
### def size -> Integer
@@ -169,8 +279,8 @@ p buf.get_string # => "Ruby\x00\x00\x00\x00"
169279
p buf.get_string(0, 4) # => "Ruby"
170280
p buf.get_string(1, 3) # => "uby"
171281

172-
p buf.get_string(0, 4).encoding # => #<Encoding:BINARY (ASCII-8BIT)>
173-
p buf.get_string(0, 4, Encoding::UTF_8).encoding # => #<Encoding:UTF-8>
282+
p buf.get_string(0, 4).encoding.name # => "ASCII-8BIT"
283+
p buf.get_string(0, 4, Encoding::UTF_8).encoding.name # => "UTF-8"
174284

175285
buf.get_string(0, 99) # ~> ArgumentError
176286
```
@@ -301,8 +411,7 @@ p buf.get_string # => "\x00AA\x00"
301411
変更後の大きさによっては、メモリ領域が別の場所に確保しなおされ、
302412
内容がそこへコピーされます。
303413

304-
#@# for を収録したらリンクに戻す
305-
`IO::Buffer.for` で作った外部バッファや、ロックされたバッファは大きさを変更できません。
414+
[m:IO::Buffer.for] で作った外部バッファや、ロックされたバッファは大きさを変更できません。
306415

307416
- **param** `size` -- 変更後の大きさをバイト数で指定します。
308417
- **raise** `IO::Buffer::AccessError` -- 大きさを変更できないバッファに対して呼び出した場合に発生します。
@@ -377,9 +486,8 @@ p buf.size # => 4
377486

378487
バッファの大きさが 0 の場合に true を返します。
379488

380-
#@# for を収録したらリンクに戻す
381489
大きさ 0 のバッファは、[m:IO::Buffer.new] に 0 を渡すか、
382-
空文字列から `IO::Buffer.for` で作った場合などにできます。
490+
空文字列から [m:IO::Buffer.for] で作った場合などにできます。
383491

384492
```ruby
385493
p IO::Buffer.new(0).empty? # => true
@@ -430,8 +538,7 @@ p IO::Buffer.new(4).internal? # => true
430538
バッファが外部(external)バッファである場合に true を返します。
431539

432540
外部バッファは、バッファ自身が確保・マップしたのではないメモリ領域を参照します。
433-
#@# for を収録したらリンクに戻す
434-
`IO::Buffer.for` で作ったバッファは、文字列のメモリを外部参照します。
541+
[m:IO::Buffer.for] で作ったバッファは、文字列のメモリを外部参照します。
435542
外部バッファは大きさを変更できません。
436543

437544
```ruby
@@ -445,11 +552,11 @@ p IO::Buffer.new(4).external? # => false
445552

446553
バッファが読み取り専用の場合に true を返します。
447554

448-
#@# set_value / for を収録したらリンクに戻す
555+
#@# set_value を収録したらリンクに戻す
449556
読み取り専用のバッファは、`IO::Buffer#set_value`[m:IO::Buffer#set_string]
450557
[m:IO::Buffer#copy] などで変更できません。
451558

452-
`IO::Buffer.for` にブロックを渡さずに作ったバッファは、元の文字列が freeze
559+
[m:IO::Buffer.for] にブロックを渡さずに作ったバッファは、元の文字列が freeze
453560
されているかどうかによらず、常に読み取り専用になります。内部で作った文字列の
454561
複製をバッファの元として使うためです。
455562
ブロックを渡した場合は元の文字列のメモリを直接参照するため、
@@ -474,8 +581,7 @@ p IO::Buffer.new(4).readonly? # => false
474581
マップバッファは、仮想メモリ機構でマップされたメモリ領域を参照します。
475582
[m:IO::Buffer.new][m:IO::Buffer::MAPPED] を指定した場合や、
476583
大きさが [m:IO::Buffer::PAGE_SIZE] 以上の場合は匿名のマップになります。
477-
#@# map を収録したらリンクに戻す
478-
`IO::Buffer.map` で作った場合はファイルに紐づいたマップになります。
584+
[m:IO::Buffer.map] で作った場合はファイルに紐づいたマップになります。
479585

480586
### def locked? -> bool
481587

0 commit comments

Comments
 (0)