Skip to content

Commit 140c6ad

Browse files
Watson1978claude
andcommitted
IO::Buffer: 領域操作の 6 メソッドを追加
slice / copy / clear / resize / transfer / free を追加した。 いずれも IO::Buffer が導入された 3.1 から存在する。 記述にあたって実機で確認したところ、2 つの版差があった。 slice の引数は 3.1 では 2 つとも必須で、3.2 から省略できるようになっている。 3.1 で slice() や slice(2) を呼ぶと「wrong number of arguments (given 0, expected 2)」になる。シグネチャを #@SInCE 3.2 で分岐した。 free の後の挙動は 3.3 で変わっている。3.2 以前は読み書きしようとすると IO::Buffer::AllocationError が発生するが、3.3 以降は例外にならず 大きさ 0 のバッファとして扱われる (get_string は "" を返す)。 rdoc には「no further operations can't be performed on it」とあるが、 3.3 以降の実機はそうなっていないため、実機に合わせて #@SInCE 3.3 で分岐した。 例に使ったコードは 3.1 / 3.2 / 3.3 / 4.0 で実行し、すべて同じ出力になることを 確認している。slice の例は 3.1 でも動くよう引数を 2 つとも指定した。 bitclust のデータベース生成を 3.1 / 3.2 / 3.3 / 4.0 で実行してエラーが出ないこと、 6 メソッドすべてが登録されること、および slice のシグネチャと free の説明が 版ごとに切り替わることを確認済み。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c85e036 commit 140c6ad

1 file changed

Lines changed: 164 additions & 0 deletions

File tree

manual/api/_builtin/IO__Buffer.md

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,167 @@ IO::Buffer.new(2).set_string("TOOLONG") # ~> ArgumentError
205205
```
206206

207207
- **SEE** [m:IO::Buffer#get_string]
208+
209+
#@since 3.2
210+
### def slice(offset = 0, length = nil) -> IO::Buffer
211+
#@else
212+
### def slice(offset, length) -> IO::Buffer
213+
#@end
214+
215+
バッファの一部を指す新しい [c:IO::Buffer] を返します。
216+
217+
メモリのコピーは行わず、返されるバッファは元のバッファと同じメモリ領域を参照します。
218+
そのため、一方への書き込みはもう一方からも見えます。
219+
元のバッファが文字列やファイルに由来する場合、その関連も引き継がれます。
220+
221+
- **param** `offset` -- 参照を開始する位置をバッファの先頭からのバイト数で指定します。
222+
#@since 3.2
223+
省略した場合は 0 になります。
224+
#@end
225+
- **param** `length` -- 参照するバイト数を指定します。
226+
#@since 3.2
227+
省略した場合はバッファの末尾までになります。
228+
#@end
229+
- **raise** `ArgumentError` -- offset や length が負の場合、
230+
または offset と length の合計がバッファのバイト数を超える場合に発生します。
231+
232+
```ruby
233+
buf = IO::Buffer.new(8)
234+
buf.set_string("Ruby")
235+
236+
part = buf.slice(0, 4)
237+
p part.get_string # => "Ruby"
238+
239+
# 同じメモリ領域を参照しているので、変更は元のバッファにも反映される
240+
part.set_string("Xy")
241+
p buf.get_string # => "Xyby\x00\x00\x00\x00"
242+
```
243+
244+
- **SEE** [m:IO::Buffer#copy]
245+
246+
### def copy(source, offset = 0, length = nil, source_offset = 0) -> Integer
247+
248+
別の [c:IO::Buffer] の内容を自身へコピーします。コピーしたバイト数を返します。
249+
250+
[c:String] の内容を書き込む場合は [m:IO::Buffer#set_string] を使用してください。
251+
252+
- **param** `source` -- コピー元を [c:IO::Buffer] で指定します。
253+
- **param** `offset` -- 書き込みを開始する位置をバッファの先頭からのバイト数で指定します。
254+
- **param** `length` -- コピーするバイト数を指定します。省略した場合は source 全体をコピーします。
255+
- **param** `source_offset` -- source のどの位置から読み出すかをバイト数で指定します。
256+
- **raise** `ArgumentError` -- offset と length の合計がバッファのバイト数を超える場合に発生します。
257+
- **raise** `IO::Buffer::AccessError` -- 書き込みできないバッファに対して呼び出した場合に発生します。
258+
259+
```ruby
260+
buf = IO::Buffer.new(8)
261+
262+
p buf.copy(IO::Buffer.for("test"), 2) # => 4
263+
p buf.get_string # => "\x00\x00test\x00\x00"
264+
265+
# 長さを指定して先頭 3 バイトだけコピーする
266+
other = IO::Buffer.new(8)
267+
p other.copy(IO::Buffer.for("abcdef"), 0, 3) # => 3
268+
p other.get_string(0, 3) # => "abc"
269+
```
270+
271+
- **SEE** [m:IO::Buffer#set_string], [m:IO::Buffer#slice]
272+
273+
### def clear(value = 0, offset = 0, length = nil) -> self
274+
275+
バッファを value で埋めます。
276+
277+
- **param** `value` -- 埋める値を 0 から 255 の [c:Integer] で指定します。
278+
- **param** `offset` -- 埋め始める位置をバッファの先頭からのバイト数で指定します。
279+
- **param** `length` -- 埋めるバイト数を指定します。省略した場合はバッファの末尾までを埋めます。
280+
- **raise** `IO::Buffer::AccessError` -- 書き込みできないバッファに対して呼び出した場合に発生します。
281+
282+
```ruby
283+
buf = IO::Buffer.new(4)
284+
buf.set_string("test")
285+
286+
buf.clear
287+
p buf.get_string # => "\x00\x00\x00\x00"
288+
289+
# 位置と長さを指定して "A" (0x41) で埋める
290+
buf.clear(0x41, 1, 2)
291+
p buf.get_string # => "\x00AA\x00"
292+
```
293+
294+
### def resize(size) -> self
295+
296+
バッファの大きさを size バイトに変更します。
297+
298+
変更前の内容は保持されます。
299+
変更後の大きさによっては、メモリ領域が別の場所に確保しなおされ、
300+
内容がそこへコピーされます。
301+
302+
[m:IO::Buffer.for] で作った外部バッファや、ロックされたバッファは大きさを変更できません。
303+
304+
- **param** `size` -- 変更後の大きさをバイト数で指定します。
305+
- **raise** `IO::Buffer::AccessError` -- 大きさを変更できないバッファに対して呼び出した場合に発生します。
306+
307+
```ruby
308+
buf = IO::Buffer.new(4)
309+
buf.set_string("test")
310+
311+
buf.resize(8)
312+
p buf.size # => 8
313+
p buf.get_string(0, 4) # => "test"
314+
315+
IO::Buffer.for("abc").resize(8) # ~> IO::Buffer::AccessError
316+
```
317+
318+
### def transfer -> IO::Buffer
319+
320+
メモリ領域の所有権を新しい [c:IO::Buffer] へ移し、その新しいバッファを返します。
321+
322+
所有権を手放した自身は、どのメモリ領域も指さない状態になります。
323+
この状態は [m:IO::Buffer#null?] で調べられます。
324+
325+
```ruby
326+
buf = IO::Buffer.new(4)
327+
buf.set_string("Ruby")
328+
329+
other = buf.transfer
330+
p other.get_string # => "Ruby"
331+
332+
p buf.null? # => true
333+
p buf.size # => 0
334+
```
335+
336+
- **SEE** [m:IO::Buffer#free], [m:IO::Buffer#null?]
337+
338+
### def free -> self
339+
340+
バッファが確保しているメモリ領域を解放します。
341+
342+
解放の内容はバッファの種類によって異なります。
343+
344+
- 内部(internal) -- 確保したメモリを解放します。
345+
- 外部(external) -- 元のオブジェクトとの関連を解消します。
346+
- マップ(mapped) -- マッピングを解除します。
347+
348+
解放後は、どのメモリ領域も指さない状態になります。
349+
#@since 3.3
350+
この状態のバッファは大きさ 0 のバッファとして扱われます。
351+
#@else
352+
この状態のバッファを読み書きしようとすると
353+
[c:IO::Buffer::AllocationError] が発生します。
354+
#@end
355+
356+
解放したバッファでも [m:IO::Buffer#resize] を呼べば、あらためてメモリ領域を確保できます。
357+
358+
```ruby
359+
buf = IO::Buffer.new(4)
360+
buf.set_string("Ruby")
361+
362+
buf.free
363+
p buf.null? # => true
364+
p buf.size # => 0
365+
366+
# resize すれば再び使える
367+
buf.resize(4)
368+
p buf.size # => 4
369+
```
370+
371+
- **SEE** [m:IO::Buffer#transfer], [m:IO::Buffer#null?]

0 commit comments

Comments
 (0)