Buf — 이진 데이터를 위한 변경 가능한 버퍼
Buf — 이진 데이터를 위한 변경 가능한 버퍼
원시 바이트를 담는 버퍼를 만들고, 그 값을 바꿔가며 다루고 싶을 때가 있어요. Buf는 그런 "변경 가능한(mutable) 정수 시퀀스" 역할을 하는 타입입니다.
출처: Raku 공식 문서 — Buf
본문
role Buf[::T = uint8] does Blob[T] is repr('VMArray') is array_type(T){ ... }
Buf는 (보통 부호 없는) 정수의 변경 가능한 시퀀스 역할을 담당해요.
my $bú = Buf.new(1, 2, 3);
$bú[1] = 42;
say $bú.raku; # OUTPUT: «Buf.new(1,42,3)»
그런데 이건 매개변수화된 타입이라서, 여러 정수 타입으로 인스턴스를 만들 수 있어요.
my $bú = Buf[int32].new(3, -3, 0xff32, -44);
say $bú; # OUTPUT: «Buf[int32]:0x<03 -3 FF32 -2C>»
기본적으로 Buf는 8비트 부호 없는 정수를 쓰는데, 즉 Buf[uint8]과 동등해요. 자주 쓰이는 몇 가지 Buf 타입은 따로 클래스 이름이 정해져 있습니다.
| buf8 | Buf[uint8] |
|---|---|
| buf16 | Buf[uint16] |
| buf32 | Buf[uint32] |
| buf64 | Buf[uint64] |
Buf를 쓰는 것처럼 똑같이 사용할 수 있어요.
my $bú = buf8.new(3, 6, 254);
say $bú; # OUTPUT: «Buf[uint8]:0x<03 06 fe>»
다른 객체에 있는 일부 메서드, 예를 들어 encode는 특정 인코딩에 가장 적합한 표현이 buf8일 때 buf8을 반환할 수 있어요.
메서드
method subbuf-rw
method subbuf-rw($from = 0, $elems = self.elems - $from) is rw
버퍼의 일부분을 가리키는 쓰기 가능한 참조 역할을 하는 Proxy를 반환하는 subbuf의 변경 가능한 버전이에요. 첫 번째 인자 $from은 치환이 일어나야 할 버퍼 내 인덱스를, 마지막 인자 $elems는 교체할 요소 개수를 지정해요. 예를 들어 인덱스 3의 요소 하나를 100, 101 두 요소로 바꾸려면:
my Buf $bú .= new(0..5);
$bú.subbuf-rw(3,1) = Buf.new(100, 101);
say $bú.raku; # OUTPUT: «Buf.new(0,1,2,100,101,4,5)»
$elems 인자를 지정하지 않으면 지정한 인덱스 $from에서 뒤쪽 요소를 모두 제거하며 치환이 일어나요.
my Buf $bú .= new(0..5);
$bú.subbuf-rw(3) = Buf.new(200);
say $bú.raku; # OUTPUT: «Buf.new(0,1,2,200)»
$from 인자를 지정하지 않으면 버퍼의 맨 처음부터 치환이 일어나요.
my Buf $bú .= new(0..5);
$bú.subbuf-rw = Buf.new(123, 123);
say $bú.raku; # OUTPUT: «Buf.new(123, 123)»
routine subbuf-rw
multi subbuf-rw(Buf:D \b) is rw
multi subbuf-rw(Buf:D \b, Int() $from) is rw
multi subbuf-rw(Buf:D \b, $from, $elems) is rw
버퍼의 일부분에 대한 쓰기 가능한 참조를 반환해요. 지정된 Buf에서 subbuf-rw 메서드를 호출합니다.
my Buf $bú .= new(1,2,3);
subbuf-rw($bú,2,1) = Buf.new(42);
say $bú.raku; # OUTPUT: «Buf.new(1,2,42)»
method reallocate
method reallocate(Buf:D: Int:D $elems)
Buf의 요소 개수를 바꾸고, 바뀐 Buf를 반환해요. $elems 수에 맞춰 크기가 조정되는데, 실제 크기보다 작으면 줄어들고 크면 맞춰 늘어납니다. Buf가 커지는 경우 새로 생긴 항목에는 가상 머신 특유의 null 값이 할당되므로, 값에 의존하면 안 돼요. 가상 머신마다 값이 달라질 수 있기 때문입니다.
my Buf $bú .= new(^10);
$bú.reallocate(5);
say $bú.raku; # OUTPUT: «Buf.new(0,1,2,3,4)»
$bú = Buf.new( 1..3 );
$bú.reallocate( 10 );
say $bú.raku; # OUTPUT: «Buf.new(1,2,3,0,0,0,0,0,0,0)»
method list
multi method list(Buf:D:)
정수의 List를 반환해요.
say Buf.new(122,105,112,205).list; # OUTPUT: «(122 105 112 205)»
method push
method push( $elems )
버퍼 끝에 요소를 추가해요.
my $bú = Buf.new( 1, 1, 2, 3, 5 );
$bú.push( 8 );
say $bú.raku; # OUTPUT: «Buf.new(1,1,2,3,5,8)»
method pop
method pop()
버퍼의 마지막 요소를 반환하고 제거해요.
my $bú = Buf.new( 1, 1, 2, 3, 5 );
say $bú.pop(); # OUTPUT: «5»
say $bú.raku; # OUTPUT: «Buf.new(1,1,2,3)»
method append
method append( $elems )
버퍼 끝에 이어 붙여요.
my $bú = Buf.new( 1, 1, 2, 3, 5 );
$bú.append(9, 8, 7, 6);
say $bú.raku; # OUTPUT: «Buf.new(1,1,2,3,5,9,8,7,6)»
method prepend
method prepend( $elems )
버퍼 맨 앞에 요소를 삽입해요.
my $bú = Buf.new( 1, 1, 2, 3, 5 );
$bú.prepend( 0 );
say $bú.raku; # OUTPUT: «Buf.new(0,1,1,2,3,5)»
unshift 메서드와의 차이는, 배열이나 리스트 인자를 하나만 prepend 하면 prepend는 그 배열/리스트를 펼치지만 unshift는 리스트/배열을 하나의 요소로 그대로 앞에 붙인다는 점이에요.
method shift
method shift()
버퍼의 첫 번째 요소를 제거하고 반환해요.
my $bú = Buf.new( 1, 1, 2, 3, 5 );
say $bú.shift(); # OUTPUT: «1»
say $bú.raku; # OUTPUT: «Buf.new(1,2,3,5)»
method unshift
method unshift()
버퍼 맨 앞에 요소를 삽입해요.
my $bú = Buf.new( 1, 1, 2, 3, 5 );
$bú.unshift( 0 );
say $bú.raku; # OUTPUT: «Buf.new(0,1,1,2,3,5)»
method splice
method splice( Buf:D: $start = 0, $elems?, *@replacement --> Buf)
버퍼의 요소들을 다른 요소들로 치환하고, 제거된 요소들을 담은 버퍼를 반환해요.
my $bú = Buf.new( 1, 1, 2, 3, 5 );
say $bú.splice: 0, 3, <3 2 1>; # OUTPUT: «Buf:0x<01 01 02>»
say $bú.raku; # OUTPUT: «Buf.new(3,2,1,3,5)»
buf8에만 있는 메서드 (6.d, 2018.12 이후)
이 메서드들은 buf8 타입에서만 사용할 수 있어요. 바탕 데이터에 바이트를 쓰는 저수준 접근을 제공하는데, 타입(정수 또는 부동소수점(num)), 크기(8·16·32·64·128비트), 부호 여부(정수 값의 경우), 엔디언(네이티브·리틀·빅) 면에서 다양한 방식으로 쓸 수 있어요. 이 메서드들은 항상 Nil을 반환합니다.
엔디언은 이 메서드들의 세 번째 매개변수로 Endian 열거형 값을 사용해 지정해야 해요. 엔디언을 지정하지 않으면 NativeEndian이 가정됩니다. 그 밖의 값은 LittleEndian과 BigEndian이에요.
버퍼가 쓰는 바이트를 담기에 충분히 크지 않으면 자동으로 크기가 조정됩니다.
method write-uint8
method write-uint8(buf8:D: uint $pos, uint8 $value, $endian = NativeEndian --> Nil)
주어진 위치에 부호 없는 8비트 정수 값을 써요. $endian 매개변수는 의미가 없지만 일관성을 위해 제공됩니다.
method write-int8
method write-int8(buf8:D: uint $pos, int8 $value, $endian = NativeEndian --> Nil)
주어진 위치에 부호 있는 8비트 정수 값을 써요. $endian 매개변수는 의미가 없지만 일관성을 위해 제공됩니다.
method write-uint16
method write-uint16(buf8:D: uint $pos, uint16 $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 없는 16비트 정수 값을 써요.
method write-int16
method write-int16(buf8:D: uint $pos, int16 $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 있는 16비트 정수 값을 써요.
method write-uint32
method write-uint32(buf8:D: uint $pos, uint32 $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 없는 32비트 정수 값을 써요.
method write-int32
method write-int32(buf8:D: uint $pos, int32 $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 있는 32비트 정수 값을 써요.
method write-uint64
method write-uint64(buf8:D: uint $pos, uint64 $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 없는 64비트 정수 값을 써요.
method write-int64
method write-int64(buf8:D: uint $pos, Int:D $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 있는 64비트 정수 값을 써요.
method write-uint128
method write-uint128(buf8:D: uint $pos, UInt:D $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 없는 128비트 정수 값을 써요.
method write-int128
method write-int128(buf8:D: uint $pos, Int:D $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 부호 있는 128비트 정수 값을 써요.
method write-num32
method write-num32(buf8:D: uint $pos, num32 $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 네이티브 num32 IEEE 부동소수점 값을 써요.
method write-num64
method write-num64(buf8:D: uint $pos, num64 $value, $endian = NativeEndian --> Nil)
주어진 위치에 주어진 엔디언으로 네이티브 num64 IEEE 부동소수점 값을 써요.
buf8에만 있는 메서드 (6.d, 2019.03 이후)
method write-ubits
method write-ubits(buf8:D: uint $pos, uint $bits, UInt:D $value --> Nil)
주어진 비트 오프셋과 비트 수로, 부호 없는 정수 값을 비트들에 써요. 비트의 엔디언은 BigEndian이라고 가정해요. 항상 Nil을 반환합니다.
method write-bits
method write-bits(buf8:D: uint $pos, uint $bits, Int:D $value --> Nil)
주어진 비트 오프셋과 비트 수로, 부호 있는 정수 값을 비트들에 써요. 비트의 엔디언은 BigEndian이라고 가정해요. 항상 Nil을 반환합니다.
buf8에만 있는 메서드 (6.d, 2019.10 이후)
이 메서드들은 buf8 타입에서만 사용할 수 있어요. 바탕 데이터에 바이트를 쓰는 저수준 접근을 제공하는데, 타입(정수 또는 부동소수점(num)), 크기(8·16·32·64·128비트), 부호 여부(정수 값의 경우), 엔디언(네이티브·리틀·빅) 면에서 다양한 방식으로 쓸 수 있어요.
이 메서드들은 buf8 타입 객체에서도 호출할 수 있는데, 그 경우 새 buf8 객체가 반환됩니다. 그 외에는 buf8 객체에서 연산을 쉽게 체이닝할 수 있도록 invocant를 반환해요. 버퍼가 쓰는 바이트를 담기에 충분히 크지 않으면 자동으로 크기가 조정됩니다.
엔디언은 이 메서드들의 세 번째 매개변수로 Endian 열거형 값을 사용해 지정해야 해요. 엔디언을 지정하지 않으면 NativeEndian이 가정됩니다. 그 밖의 값은 LittleEndian과 BigEndian이에요.
method write-uint8
method write-uint8(buf8: uint $pos, uint8 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 부호 없는 8비트 정수 값을 써요. $endian 매개변수는 의미가 없지만 일관성을 위해 제공됩니다.
method write-int8
method write-int8(buf8: uint $pos, int8 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 부호 있는 8비트 정수 값을 써요. $endian 매개변수는 의미가 없지만 일관성을 위해 제공됩니다.
method write-uint16
method write-uint16(buf8: uint $pos, uint16 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 없는 16비트 정수 값을 써요.
method write-int16
method write-int16(buf8: uint $pos, int16 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 있는 16비트 정수 값을 써요.
method write-uint32
method write-uint32(buf8: uint $pos, uint32 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 없는 32비트 정수 값을 써요.
method write-int32
method write-int32(buf8: uint $pos, int32 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 있는 32비트 정수 값을 써요.
method write-uint64
method write-uint64(buf8: uint $pos, uint64 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 없는 64비트 정수 값을 써요.
method write-int64
method write-int64(buf8: uint $pos, Int:D $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 있는 64비트 정수 값을 써요.
method write-uint128
method write-uint128(buf8: uint $pos, UInt:D $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 없는 128비트 정수 값을 써요.
method write-int128
method write-int128(buf8: uint $pos, Int:D $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 부호 있는 128비트 정수 값을 써요.
method write-num32
method write-num32(buf8: uint $pos, num32 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 네이티브 num32 IEEE 부동소수점 값을 써요.
method write-num64
method write-num64(buf8: uint $pos, num64 $value, $endian = NativeEndian --> buf8:D)
주어진 위치에 주어진 엔디언으로 네이티브 num64 IEEE 부동소수점 값을 써요.
method write-ubits
method write-ubits(buf8: uint $pos, uint $bits, UInt:D $value --> buf8:D)
주어진 비트 오프셋과 비트 수로, 부호 없는 정수 값을 비트들에 써요. 비트의 엔디언은 BigEndian이라고 가정해요.
method write-bits
method write-bits(buf8: uint $pos, uint $bits, Int:D $value --> buf8:D)
주어진 비트 오프셋과 비트 수로, 부호 있는 정수 값을 비트들에 써요. 비트의 엔디언은 BigEndian이라고 가정해요.
method Blob
method Buf(Buf:D: --> Blob:D)
2021.06 Rakudo 컴파일러 릴리즈부터 사용할 수 있어요. invocant를 변경 불가능한 Blob 객체로 강제 변환해요.