For Development HEAD DRAFTSearch (procedure/syntax/module):

9.38 gauche.uvector - ユニフォームベクタライブラリ

Module: gauche.uvector

ユニフォームベクタを扱う手続きを提供します (ユニフォームベクタ参照)。 このモジュールは、R7RSユニフォームベクタライブラリ (scheme.vector.@)とSRFI-4のスーパーセットです。

@の部分は実際には要素の型を示す次タグのいずれかです: u8, s8, u16, s16, u32, s32, u64, s64, f16, f32, f64, c32, c64, c128

Gaucheで拡張されている機能は次のとおりです:

ベクタの型が許す範囲外の値を格納しようとした場合、通常はエラーとなります。 いくつかの手続きは省略可能な引数clampによって、 そのような場合に別のふるまいを指定することができます。 clampには以下のいずれかの値を与えることが出来ます。

#f

デフォルト (エラーを通知)

high

高い方の値をクランプ、すなわち、格納しようとする値が許される値の最大値より大きかった 場合は、可能な最大値を代わりに格納します。

low

低い方の値をクランプ、すなわち、格納しようとする値が許される値の最小値より大きかった 場合は、可能な最小値を代わりに格納します。

both

高いほうと低いほうの両方の値をクランプします。

(list->u8vector '(-1))         ⇒ error
(list->u8vector '(-1) 'low)    ⇒ #u8(0)
(list->u8vector '(-1) 'high)   ⇒ error
(list->u8vector '(3000) 'high) ⇒ #u8(255)
(list->u8vector '(-100 20 300) 'both) ⇒ #u8(0 20 255)

以下の記述では、@s8, u8, s16, u16, s32, u32, s64, u64, f16, f32, f64, c32, c64, c128 のいずれにも置き換えて読むことができるものとします。

註: R7RS-largeでは、それぞれの型に対して個別のライブラリがあり、 例えばu8ベクタが使いたければ (use scheme.vector.u8) (Gauche式) あるいは (import (scheme vector u8)) (R7RS式) のようにする必要があります。

一方、gauche.uvector使った場合は全ての手続きがインポートされます。


9.38.1 ユニフォームベクタの基本操作

次の手続きは組み込みです。ユニフォームベクタ参照:

make-@vector
uvector?          @vector?
uvector-ref       @vector-ref
uvector-set!      @vector-set!
uvector-length
Function: @? obj

[R7RS vector.@] {gauche.uvector} 引数が@ベクタの要素に収まるなら#tを、そうでなければ#fを返します。

Function: @vector-empty? obj

[R7RS vector.@] {gauche.uvector} 引数は@vectorでなければなりません。 それが空なら#tを、そうでなければ#fを返します。

Function: @vector x …

[R7RS vector.@] {gauche.uvector} 数値x … を要素に持つ@vectorを作成して返します。 正確な整数のベクタに対しては、数値は正確な整数でなければならず、 また有効な範囲内の値でなければなりません。

(s8vector 1 2 3) ⇒ #s8(1 2 3)
Function: make-uvector class len :optional fill

{gauche.uvector} これはGaucheの拡張です。各ユニフォームベクタの型に対応する関数を呼ぶかわりに、 欲しいユニフォームベクタのクラスを渡してベクタを作ることができます。

型ごとのコンストラクタ (make-s8vector等)はコアのライブラリで提供 されています (ユニフォームベクタ参照)。

(make-uvector <u8vector> 3)    ⇒ #u8(0 0 0)
(make-uvector <s8vector> 5 -1) ⇒ #s8(-1 -1 -1 -1 -1)
Function: @vector-unfold f len seed
Function: @vector-unfold-right f len seed

[R7RS vector.@] {gauche.uvector} 長さlenの@vectorを作り、 (f seed)(f (f seed))(f (f (f seed)))、… の結果を順に要素とします。 @vector-unfoldは左から右に、 @vector-unfold-rightは右から左に埋めてゆきます。

(u8vector-unfold (cut + 2 <>) 5 0)
 ⇒ #u8(2 4 6 8 10)
(u8vector-unfold-right (pa$ + 2) 5 0)
 ⇒ #u8(10 8 6 4 2)
Function: @vector-unfold! f vec start end seed
Function: @vector-unfold-right! f vec start end seed

[R7RS vector.@] {gauche.uvector} @vectorであるvecの、start要素目(含む)からend要素目(含まない) までを、fの呼び出し結果で埋めてゆきます。fは整数のインデックスと 現在のシード値を引数にして呼ばれます。

@vector-unfold!では、fはまずstartseedを引数にして 呼ばれます。fstartに埋めるべき値と次のシード値の2値を返さねばなりません。 次にfstart+1と戻されたシード値を引数に呼ばれ…と、 それがend-start回繰り返されます。

@vector-unfold-right!も同様に動作しますが、右から左、 つまりend-1から始めてstartに向けて値が埋めてゆかれます。

start >= end であった場合、fは呼ばれることなく、 vecは変更されません。もしインデックスがvecの範囲の外に出た場合は エラーが投げられます。

戻り値は未規定です。

Function: @vector-length vec

[R7RS vector.@] {gauche.uvector} @vector vecの長さを返します。

モジュールgauche.collectionをインポートしていれば、 vecの長さを知るのに、総称関数size-ofを使うこともできます (gauche.collection - コレクションフレームワーク参照)。

(s16vector-length '#s16(111 222 333)) ⇒ 3

(use gauche.collection)
(size-of '#s16(111 222 333)) ⇒ 3
Function: uvector-size uvector :optional start end

{gauche.uvector} この手続きは全てのユニフォームベクタに適用することができます。 uvectorのバイナリデータとしてのサイズをオクテット数で返します。

startおよび/またはendが与えられた場合は、 これらのインデックスの間のデータについてのみサイズが計算されます。 endには、ベクタ終端を示すために-1を与えることもできます。 返される値は (write-uvector uvector port start end) によって 出力されるオクテット数と一致します。

(要素数を返すuvector-lengthと混同しないようにしてください。)

(uvector-size '#u8(1 2 3))        ⇒ 3
(uvector-size '#u64(1 2 3))       ⇒ 24

(uvector-size '#u32(0 1 2 3) 2)   ⇒ 8
(uvector-size '#u32(0 1 2 3) 0 1) ⇒ 4
Function: uvector-class-element-size class

{gauche.uvector} 与えられたクラスのユニフォームベクタの1要素が占める大きさをバイト数で返します。 classがユニフォームベクタのクラスでない場合はエラーが投げられます。

(uvector-class-element-size <u8vector>)  ⇒ 1
(uvector-class-element-size <s64vector>) ⇒ 8
Function: @vector-swap! vec i j

[R7RS vector.@] {gauche.uvector} ユニフォームベクタveci番目とj番目の要素を入れ替えます。 戻り値は規定されていません。

Function: @vector-fill! vec fill :optional start end

{gauche.uvector} vecのすべて要素にfillをセットします。 startendで要素の範囲を指定することも出来ます。 戻り値は規定されていません。

Function: @vector= vec1

[R7RS vector.@] {gauche.uvector} 全ての引数は@vectorでなければなりません。 引数が全て同じ長さで、対応する要素が同じ価(=の意味で)なら#tを、 そうでなければ#fを返します。

Gaucheでは、uvectorはequal?で比較することができます。

Function: @vector=? vec1 vec2

[SRFI-66]{gauche.uvector} 註: これはSRFI-66との互換性のためだけに提供されています。 @vector= を使ってください。

引数はどちらも@vectorでなければなりません。 両引数が等価なら#tが、そうでなければ#fが返されます。

Function: @vector-compare vec1 vec2

[SRFI-66]{gauche.uvector} 引数はどちらも@vectorでなければなりません。 vec1vec2よりも小さければ-1が、 両者が等しければ0が、 vec1vec2よりも大きければ1が返されます。

短い方のベクタが常に小さいと評価されます。長さが等しい場合は要素を左から順に比較します。

Gaucheでは、uvectorはcompareで比較することができます。 これらの手続きが提供されるのは、SRFI-66がu8vector-compareを定義しているためです。 引数が特定の型のベクタであることを明示したい場合に使っても良いでしょう。

Function: @vector-copy vec :optional start end

[R7RS vector.@] {gauche.uvector} ベクタvecの新たなコピーを返します。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。

(u8vector-copy '#u8(1 2 3 4))     ⇒ #u8(1 2 3 4)
(u8vector-copy '#u8(1 2 3 4) 2)   ⇒ #u8(3 4)
(u8vector-copy '#u8(1 2 3 4) 1 3) ⇒ #u8(2 3)
Function: uvector-copy vec :optional start end

{gauche.uvector} これは@vector-copyの汎用バージョンです。 どんな型のuvectorでもvecに渡すことができ、そのコピー (もしくは、start/endによっては一部のコピー)が返されます。

Function: @vector-reverse-copy vec :optional start end

[R7RS vector.@] {gauche.uvector} vecの要素を逆順にしたコピーを作って返します。 省略可能なstartendはコピー範囲を限定します。

(u8vector-reverse-copy '#u8(1 2 3 4 5))
  ⇒ #u8(5 4 3 2 1)

(u8vector-reverse-copy '#u8(1 2 3 4 5) 1 4)
  ⇒ #u8(4 3 2)
Function: @vector-copy! target tstart source :optional sstart send

[R7RS vector.@] {gauche.uvector} target および source はともに @vector でなければ なりません。さらに、target は変更可能でなければなりません。 この手続きは、sourceの要素を、インデックスsstartから(これを含み) send までを、target へインデックス tstartからコピーします。 sstartおよびsendは省略可能で、その場合には、それぞれ、 0 および sourceの長さが仮定されます。

(let ((target (u8vector 0 1 2 3 4 5 6)))
  (u8vector-copy! target 2 '#u8(10 11 12 13 14) 1 4)
  target)
 ⇒ #u8(0 1 11 12 13 6)

もし、コピー元のベクタの sstartsend の間にある要素の 数がコピー先のベクタのtstart以降の部分よりも大きければ、超過分の ベクタはだまって捨てられます。

targetsourceに同一のベクタを渡しても構いません。 コピー先とコピー元の領域が重なっていても、コピーは常に正しく行われます。

注意事項: この手続きは以前はユニフォームベクタ target および source のみを引数としてとり、source の内容を target へ コピーするためだけに使われました。両方のベクタは同じ型で、同じ長さでなけ ればなりませんでした。この API はSRFI-160にあわせて現在の形式に改訂されています。 旧来のインタフェースも後方互換性のためにサポートされて いますが、これは廃止予定で、将来のリリースではサポートされなくなります。

また、SRFI-66もu8vector-copy!を提供していますが、 引数の順序が異なります(srfi.66 - オクテットベクタ参照)。

Function: @vector-reverse! vec :optional start end

[R7RS vector.@] {gauche.uvector}

Function: @vector-reverse-copy! target tstart source :optional start end

[R7RS vector.@] {gauche.uvector}

Function: @vector-multi-copy! target tstart tstride source :optional sstart ssize sstride count

{gauche.uvector} この手続きは、コピー元ベクタsourceの異なる部分を コピー先ベクタtargetの異なる部分へと一度にコピーするのに使えます。

ssizeが省略されるか0の場合、この手続きは次の動作をします。

;; For each i from 0 to count:
(u8vector-copy! target (+ tstart (* i tstride))
                source sstart)

つまり、sourceベクタの内容 (sstartが指定されてればそこから、 指定が無ければ最初から)をtargetベクタに、tstrideづつインデックスを 進めながらコピーします。コピー先のインデックスがtargetベクタの範囲を 越えるか、countが指定されていればその回数分だけコピーが済むかすれば 手続きは終了します。次の例を見てください。

(define t (make-u8vector 10 0))
(u8vector-multi-copy! t 0 4 '#u8(1 2 3))

t ⇒ #u8(1 2 3 0 1 2 3 0 1 2)

ssizeに正の整数が与えられた場合は、コピー元ベクタもssizeごとに 分割されます。

;; For each i from 0 to count:
(u8vector-copy! target (+ tstart (* i tstride))
                source (+ sstart (* i sstride))
                       (+ sstart (* i sstride) ssize))

つまり、コピー元インデックスをsstrideづつ、コピー先を dstrideづつ増やしながら、コピー元からそれぞれssize分のデータが切り出されて targetにコピーされます。この場合、sstrideは省略されると ssizeと同じになります。

(define t (make-u8vector 12 0))
(u8vector-multi-copy! t 0 4 '#u8(1 2 3 4 5 6 7 8 9) 0 3)

t ⇒ #u8(1 2 3 0 4 5 6 0 7 8 9 0)

操作はcount個のデータ片がコピーされるか、コピー元あるいはコピー先の インデックスがそれぞれのベクタの終端に達したら終わります。

ヒント: コピー元のベクタの中程だけ (最後までではなく) をコピーしたい場合は、 sstrideに0を与えればできます。

(define t (make-u8vector 12 0))
(u8vector-multi-copy! t 0 4 '#u8(1 2 3 4 5 6 7 8 9) 2 4 0)

t ⇒ #u8(3 4 5 6 3 4 5 6 3 4 5 6)

コレクションやシーケンスフレームワークを使うと、さらに様々な操作を 行うことができます。

(use gauche.collection)
(use gauche.sequence)

(fold + 0 '#s32(1 2 3 4)) ⇒ 10

(map-to <f32vector> * '#f32(3.2 1.1 4.3) '#f32(-4.3 2.2 9.4))
  ⇒ #f32(-13.760001 2.420000 40.420002)

(subseq #u32(1 4 3 4 5) 2 4) ⇒ #u32(3 4)
Function: uvector-copy! target tstart source :optional sstart send

{gauche.uvector} これは@vector-copy!の汎用バージョンです。 コピー元sourceとコピー先targetはユニフォームベクタであれば どの型でも許され、また両者の型が異なっていても構いません。 ビット表現がそのままコピーされます。従って異なる型のユニフォームベクタ間で コピーした場合は、結果は数値の内部表現に依存します。 そのような用法は、バイナリデータを扱う時には便利でしょう。

tstarttargetの型によって解釈され、 sstartsendsourceの型によって解釈されます。

(rlet1 v (make-u8vector 6 0)
  (uvector-copy! v 1 '#u32(0 #x01020304 0) 1 2))
 ⇒ #u8(0 1 2 3 4 0) or #u8(0 4 3 2 1 0)
Function: @vector-append vec …

[R7RS vector.@] {gauche.uvector} 引数はすべて@vectorでなければなりません。 引数ベクタの内容を全てつなぎ合わせた新たなベクタを返します。 (引数が一つだけの場合も、新たにアロケートされたベクタが返されます。)

(u8vector-append '#u8(1 2 3) '#u8(4 5) '#u8() '#u8(6 7 8))
  ⇒ #u8(1 2 3 4 5 6 7 8)
Function: @vector-concatenate vecs

[R7RS vector.@] {gauche.uvector} @vectorのリストvecsにあるベクタを全て連結した新たな @vectorを返します。

(u8vector-concatenate '(#u8(1 2 3) #u8(4 5 6)))
  ⇒ #u8(1 2 3 4 5 6)
Function: @vector-append-subvectors :optional vec start end …

[R7RS vector.@] {gauche.uvector} 各vecstartendで指定される範囲のサブベクタを 連結した新たな@vectorを返します。

(u8vector-append-subvectors '#u8(1 2 3 4) 1 3 '#u8(5 6 7 8) 0 2)
  ⇒ #u8(2 3 5 6)
Function: @vector-take vec n
Function: @vector-take-right vec n
Function: @vector-drop vec n
Function: @vector-drop-right vec n

[R7RS vector.@] {gauche.uvector} それぞれ、最初のn要素、最後のn要素、最初のn要素を取り残り、 および最後のn要素を取り除いた残り、を要素とするuvectorを作って返します。

nは非負の正確な整数で、vecの長さを越えてはいけません。

(u8vector-take '#u8(0 1 2 3 4 5) 4) ⇒ #u8(0 1 2 3)
(u8vector-drop '#u8(0 1 2 3 4 5) 4) ⇒ #u8(4 5)

(u8vector-take-right '#u8(0 1 2 3 4 5) 4) ⇒ #u8(2 3 4 5)
(u8vector-drop-right '#u8(0 1 2 3 4 5) 4) ⇒ #u8(0 1)

なお、uvector-aliasを使うと、元のuvectorと記憶領域を共有する 部分的なuvectorを得ることができます。コピーのオーバヘッドを避けることができます。

Function: @vector-segment vec n

[R7RS vector.@] {gauche.uvector} vecを長さnの新たなuvectorに分割し、そのリストを返します。 vecの長さがnの倍数でなければ、最後のuvectorはnより短くなります。

nは正の正確な整数でなければなりません。

(u8vector-segment '#u8(0 1 2 3 4 5 6 7) 3)
 ⇒ (#u8(0 1 2) #u8(3 4 5) #u8(6 7))
Function: @vector-fold kons knil vec vec2 …
Function: @vector-fold-right kons knil vec vec2 …

[R7RS vector.@] {gauche.uvector}

Function: @vector-unfold! f vec start end seed
Function: @vector-unfold-right! f vec start end seed

[R7RS vector.@] {gauche.uvector}

Function: @vector-map f vec vec2 …
Function: @vector-map! f vec vec2 …
Function: @vector-for-each f vec vec2 …

[R7RS vector.@] {gauche.uvector}

Function: @vector-count pred vec vec2 …

[R7RS vector.@] {gauche.uvector}

Function: @vector-cumulate f knil vec

[R7RS vector.@] {gauche.uvector}

Function: @vector-take-while pred vec
Function: @vector-take-while-right pred vec
Function: @vector-drop-while pred vec
Function: @vector-drop-while-right pred vec

[R7RS vector.@] {gauche.uvector}

Function: @vector-index pred vec vec2 …
Function: @vector-index-right pred vec vec2 …

[R7RS vector.@] {gauche.uvector}

Function: @vector-skip pred vec vec2 …
Function: @vector-skip-right pred vec vec2 …

[R7RS vector.@] {gauche.uvector}

Function: @vector-any pred vec vec2 …
Function: @vector-every pred vec vec2 …

[R7RS vector.@] {gauche.uvector}

Function: @vector-partition pred vec

[R7RS vector.@] {gauche.uvector}

Function: @vector-filter pred vec
Function: @vector-remove pred vec

[R7RS vector.@] {gauche.uvector}

Function: make-@vector-generator vec

[R7RS vector.@] {gauche.uvector}

Variable: @vector-comparator

[R7RS vector.@] {gauche.uvector} ふたつの@vectorを比較したり、@vectorのハッシュを取ったりできる 比較器に束縛された変数です。比較器の詳細については 基本的な比較器を参照してください。 これらの比較器は順序手続きとハッシュ関数を両方とも実装しています。

Function: uvector-binary-search uvector key :optional start end skip rounding

{gauche.uvector} uvectorは値が昇順に格納されたユニフォームベクタでなければなりません。 この手続きは二分探索を使って、keyと一致する要素を探し、そのインデックスを返します。 一致する要素が無ければ#fが返されます。

(uvector-binary-search '#u8(0 5 19 32 58 96) 32)
  ⇒ 3

(uvector-binary-search '#u8(0 5 19 32 58 96) 33)
  ⇒ #f

省略可能引数startenduvector中の探すべき部分を制限します。 startが開始インデックス(その要素も含む)、endが終了インデックス (その要素自体は含まない)です。 #fを渡すとデフォルト値(startは0、endはベクタの長さ)と みなされます。返ってくるインデックスはベクタ全体から見たインデックスになりますが、 start-end間以外のuvectorの要素はソートされている必要はありません。

(uvector-binary-search '#u8(99 99 19 32 58 99) 32 2 5)
  ⇒ 3

(uvector-binary-search '#u8(99 99 19 32 58 99) 99 2 5)
  ⇒ #f

省略可能なskip引数は、非負の正確な整数か#fでなければなりません。 skipが正の整数の場合、uvector中の各キーに続くskip個の要素を 飛ばして探索します。例えばskipが2でuvector#u8(3 100 101 5 102 103 13 104 105)であれば、 3513だけが探索の対象となります。 この機能を使うと、キーに結びつけられた値(ペイロード)をuvector中に直接 格納したまま探索を行うことができます。skipが正の整数の場合、 uvectorの探索が行われる部分の大きさはskip+1の整数倍でなければなりません。

(uvector-binary-search '#u8(3 100 101 5 102 103 13 104 105) 13 #f #f 2)
  ⇒ 6

(uvector-binary-search '#u8(3 100 101 5 102 103 13 104) 13 #f #f 2)
  ⇒ ; Error: uvector size (8) isn’t multiple of record size (3)

最後に、rounding引数は一致する要素が見つからなかった場合の振る舞いを 調整します。値は以下のいずれかでなければなりません。

#f

これがデフォルトです。keyと等しい要素だけを探し、 見つからなければ#fを返します。

a symbol floor

keyと等しい要素がみつからなかった場合、keyを越えない、もっとも近い 要素のインデックスを返します。keyがどの要素よりも小さい場合は#fが 返されます。

a symbol ceiling

keyと等しい要素がみつからなかった場合、keyを下回らない、もっとも近い 要素のインデックスを返します。keyがどの要素よりも大きい場合は#fが 返されます。

(uvector-binary-search '#u32(1 10 100 1000 10000) 3757)
  ⇒ #f

(uvector-binary-search '#u32(1 10 100 1000 10000) 3757 #f #f #f 'floor)
  ⇒ 3

(uvector-binary-search '#u32(1 10 100 1000 10000) 3757 #f #f #f 'ceiling)
  ⇒ 4

註: SRFI-133のvector-binary-searchはこの手続きと良く似ています (scheme.vector - R7RSベクタ参照)。ただし、 そちらは一般のScheme値を相手にするために、比較手続きも取ります。 またskiprounding引数の機能はサポートされません。


9.38.2 ユニフォームベクタの変換

Function: @vector->list vec :optional start end

[R7RS vector.@] {gauche.uvector} @vector vecをリストに変換します。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

(u32vector->list '#u32(9 2 5)) ⇒ (9 2 5)

(use gauche.collection)
(coerce-to <list> '#u32(9 2 5)) ⇒ (9 2 5)
Function: uvector->list uvec :optional start end

{gauche.uvector} これは@vector->listの汎用バージョンで、 ユニフォームベクタなら何であれuvecに取ることができます。 省略可能引数の意味は@vector->listと同じです。

Function: @vector->vector vec :optional start end

[R7RS vector.@] {gauche.uvector} @vector vecをベクタに変換します。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

(f32vector->vector '#f32(9.3 2.2 5.5))   ⇒ #(9.3 2.2 5.5)
(f32vector->vector '#f32(9.3 2.2 5.5) 2) ⇒ #(5.5)

(use gauche.collection)
(coerce-to <vector> '#f32(9.3 2.2 5.5)) ⇒ #(9.3 2.2 5.5)
Function: uvector->vector uvec :optional start end

{gauche.uvector} これは@vector->vectorの汎用バージョンで、 ユニフォームベクタなら何であれuvecに取ることができます。 省略可能引数の意味は@vector->vectorと同じです。

Function: list->@vector list :optional clamp

[R7RS vector.@] {gauche.uvector} リストlistを@vectorに変換します。 省略可能な引数clampが、リスト内の要素が正しい範囲外の数であった場合の 動作を指定します。 (clamp引数はGauche独自拡張です。)

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

(list->s64vector '(9 2 5)) ⇒ #s64(9 2 5)

(use gauche.collection)
(coerce-to <s64vector> '(9 2 5)) ⇒ #s64(9 2 5)
Function: reverse-list->@vector list :optional clamp

[R7RS vector.@] {gauche.uvector} listの要素を逆順に持つ新たな@vectorを作って返します。 省略可能な引数clampが、リスト内の要素が正しい範囲外の数であった場合の 動作を指定します。 (clamp引数はGauche独自拡張です。)

Function: vector->@vector vec :optional start end clamp

[R7RS vector.@] {gauche.uvector} ベクタvecを@vectorに変換します。 省略可能な引数startendが与えられた場合、 それらは取り出される要素の範囲を制限します。 省略可能な引数clampが、ベクタ内の要素が正しい範囲外の数であった場合の 動作を指定します。 (clamp引数はGauche独自拡張です。)

モジュールgauche.collectionをインポートしていれば、 総称関数coerce-toを使うこともできます。

(vector->f64vector '#(3.1 5.4 3.2)) ⇒ #f64(3.1 5.4 3.2)

(use gauche.collection)
(coerce-to <f64vector> '#(3.1 5.4 3.2)) ⇒ #f64(3.1 5.4 3.2)
Function: uvector-alias uvector-class vec :optional start end

{gauche.uvector} この手続きは、クラスがuvector-classであり、 ユニフォームベクタvecのメモリ領域を共有するような 新しいユニフォームベクタを作成して返します。 省略可能な引数startendが与えられた場合は vecの内容のうちそれらのインデックスで指定される範囲のみが使われます。 メモリ領域が共有されているので、vecに加える変更は 新しいベクタから見えますし、その逆も可能です。

クラスuvector-classはユニフォームベクタのクラスでなければなりませんが、 vecのクラスと一致している必要はありません。 そのような場合は、新しいベクタはvecと同じメモリ領域の値を 異なる値と解釈するかもしれません。 例えば、次のコードはGaucheが走っているマシンが リトルエンディアンであるかビッグエンディアンであるかを判定します。

(let ((u8v (uvector-alias <u8vector> #u32(1))))
  (if (zero? (u8vector-ref u8v 0))
      'big-endian
      'little-endian))

uvector-classがs8vectorかu8vector以外の場合、 新しいベクタが指す領域は、そのベクタの要素のアラインメントの要請に したがっていなければなりません。 ユニフォームベクタの開始点は常に全てのユニフォームベクタのアラインメント要請を 満たします。したがって、例えばu8vectorからu32vectorを作成する場合、 startおよびendは4の倍数でなければなりません (あるいは、start/endが省略された場合、vecの長さが 4の倍数でなければなりません)。 与えられたパラメータでアラインメントの要請が満たせない場合はエラーが通知されます。


9.38.3 ユニフォームベクタの数値演算

ここに上げる手続きはGaucheの拡張で、 ユニフォームベクタ全体に渡る演算を、要素ごとに計算するよりも速く行います。

ほとんどの手続きには関数型バージョン(名前に!の無いもの)と 線形更新バージョン(名前に!のついたもの)の二つが用意されています。

関数型バージョンは、呼び出し元が引数と戻り値を変更不可なオブジェクトとして 扱うことを期待します。後からそれらを変更することは予想外の結果を引き起こすかも しれません(特に、関数型バージョンでは引数に渡されたオブジェクトをそのまま 返したり、既に計算済みの値を返したりする可能性もあるので、 特に記述されてなければ、戻り値が常に新たにアロケートされたものであると考えてはいけません。)

線形更新バージョンは、結果を作るために特定の引数のメモリを再利用する可能性が あります。Gaucheではアロケーションを最小化するようにできるだけメモリの再利用をしますが、 引数がその場で変更されていることをあてにしてはいけません。必ず戻り値を利用するように してください。 変更され得る引数については、呼び出し後にそれがどういう状態になっているかは定義されません。

Function: @vector-add vec val :optional clamp
Function: @vector-add! vec val :optional clamp
Function: @vector-sub vec val :optional clamp
Function: @vector-sub! vec val :optional clamp
Function: @vector-mul vec val :optional clamp
Function: @vector-mul! vec val :optional clamp

{gauche.uvector} 要素毎の計算手続きです。vecは@vectorでなければなりません。 また、valvecと同じ長さの@vectorかベクタかリスト、 あるいは数値(整数ベクタに対しては正確な整数、実数ベクタに対しては実数) でなければなりません。

valが@vectorの場合、 vecと対応する要素毎に加算、減算、乗算が行われ、 結果が@vectorとして返されます。 線形更新バージョン(名前に‘!’がついているもの)では、vecが 結果を格納するために再利用され、またそれが返されます。 演算の結果が@vectorの要素の値域外になった場合の動作は 省略可能な引数clampによって指定されます。 (f32vectorとf64vectorでは、値域外になった要素にはinfinityが格納され、 clampの値は無視されます)。

valが数値である場合、vecの各要素とその数値の間で演算が行われます。

(s8vector-add '#s8(1 2 3 4) '#s8(5 6 7 8)) ⇒ #s8(6 8 10 12)
(u8vector-sub '#u8(1 2 3 4) '#u8(2 2 2 2)) ⇒ error
(u8vector-sub '#u8(1 2 3 4) '#u8(2 2 2 2) 'both) ⇒ #u8(0 0 1 2)

(f32vector-mul '#f32(3.0 2.0 1.0) 1.5) ⇒ #f32(4.5 3.0 1.5)
Function: @vector-div vec val
Function: @vector-div! vec val

{gauche.uvector} 要素毎の除算です。これらはf32vectorとf64vectorのみに対して定義されます。 valvecと同じ大きさの@vectorかベクタかリスト、 あるいは実数でなければなりません。

(f32vector-div '#f32(1.0 2.0 3.0) 2.0) ⇒ #f32(0.5 1.0 1.5)
Function: @vector-and vec val
Function: @vector-and! vec val
Function: @vector-ior vec val
Function: @vector-ior! vec val
Function: @vector-xor vec val
Function: @vector-xor! vec val

{gauche.uvector} 要素毎の論理(ビット)演算です。 これらの手続きは整数ベクタに対してのみ定義されています。 valvecと同じ大きさの@vectorかベクタかリスト、 あるいは正確な整数でなければなりません。vecの各要素と、対応するvalの要素 (valが非スカラー値の場合)もしくはval自身 (valが整数の場合)とのビット毎のand, inclusive orまたはexclusive or が計算され、結果が@vectorで返されます。 線形更新バージョン(名前に‘!’がついているもの)では、vecが 結果を格納するために再利用され、またそれが返されます。

Function: @vector-dot vec0 vec1

{gauche.uvector} ふたつの@vectorの内積を計算します。 vec0vec1の長さは等しくなければなりません。

Function: @vector-range-check vec min max

{gauche.uvector} vecは@vectorでなければなりません。 minmaxはそれぞれ、vecと同じ長さの@vector、 ベクタ、リストのいずれかか、実数もしくは#fでなければなりません。

vecの各要素に対して、この手続きはそれが対応するminvalmaxval の間にあるかどうかを検査します。minvalmaxvalも範囲に含みます。 ここで、minvalmaxvalは、min/maxが非スカラー値 であればvecの要素に対応するそれぞれの要素、 min/maxが数値であればその数値そのものです。 min#fの場合、最小値はマイナス無限大と考えられます。 max#fの場合、最大値はプラス無限大と考えられます。

vecの全ての要素が範囲内であった場合は#fが返されます。 そうでなければ、範囲を外れた要素のうちもっとも左のもののvec内での インデックスが返されます。

(u8vector-range-check '#u8(3 1 0 2) 0 3)  ⇒ #f
(u8vector-range-check '#u8(3 1 0 2) 1 3)  ⇒ 2

(u8vector-range-check '#u8(4 32 64 98) 0 '#u8(10 40 70 90))
  ⇒ 3

;; Range check in a program
(cond
 ((u8vector-range-check u8v 1 31)
  => (lambda (i)
      (errorf "~sth vector element is out of range: ~s"
              i (u8vector-ref u8v i))))
 (else (do-something u8v)))
Function: @vector-clamp vec min max
Function: @vector-clamp! vec min max

{gauche.uvector} vecは@vectorでなければなりません。 minmaxはそれぞれ、vecと同じ長さの@vector、 ベクタ、リストのいずれかか、実数もしくは#fでなければなりません。

@vector-range-checkと同じように、この手続きはvecの各要素が minおよびmaxで指定される最小値と最大値の間にあるかどうかを 検査します。要素が最小値より小さかった場合はそれが最小値に置き換えられます。 要素が最大値より大きかった場合はそれが最大値に置き換えられます。

@vector-clampはvecのコピーを作ってそれに対して クランプ操作を行います。@vector-clamp!はvecを直接 変更します。どちらもクランプ操作が行われた後の@vectorを返します。

(s8vector-clamp '#s8(8 14 -3 -22 0) -10 10) ⇒ #s8(8 10 -3 -10 0)

9.38.4 ユニフォームベクタのブロック入出力

ユニフォームベクタは、メモリの固まりを抽象化しているものと考えることも できます。それなら、それをバイナリI/Oに使えないでしょうか。もちろんできます。

Function: read-uvector class size :optional iport endian

{gauche.uvector} クラスclassのユニフォームベクタの要素をsize個、iportから 読み込み、それを新たに作ったユニフォームベクタとして返します。 iportが省略された場合は、現在の入力ポートが使われます。

例えば次のようにして、入力をオクテットストリームとして読み込めます:

(with-input-from-string "abcde"
  (^[] (read-uvector <u8vector> 5)))
 ⇒ #u8(97 98 99 100 101)

入力ポートが既にEOFに達していた場合はEOFオブジェクトが返されます。 size要素を読む前に入力がEOFに達した場合、返されるuvectorの長さは sizeより短いものとなります。

iportがバッファードポートであり、そのバッファリングモードが ‘modest’ か ‘none’ であった場合、read-uvectoriportが EOFに達していなくても、size要素を読む前に戻ることがあります (バッファリングモードについてはファイルポートを参照して下さい)。 パイプやネットワークに接続されたポートはデフォルトでそのように振舞います。

データはバイトストリームとして読まれるので、 s8vectorとu8vector以外のユニフォームベクタを与えた場合は 結果がエンディアンに影響を受けることに注意して下さい。 省略可能引数endianによって、入力データのエンディアンを指定 することができます。省略した場合はパラメータdefault-endianの 値が使われます。エンディアンの扱いについてより詳しくはエンディアンネスを参照して ください。

入力データの大きさが不明で、EOFまで全てを読み込みたい場合は、下の port->uvectorを使ってください。

Function: read-bytevector size :optional iport

[R7RS base] {gauche.uvector} (read-uvector <u8vector> size iport)と等価です。 R7RS baseにある手続きです。

Function: read-uvector! vec :optional iport start end endian

{gauche.uvector} 与えられた入力ポートiportからデータの固まりを読みだし、それを ユニフォームベクタvecに格納します。 どんな種類のユニフォームベクタでも与えることができます。 省略可能な引数startendが与えられた場合は、 それらがvec中でデータが格納されるべき領域のインデックスの範囲を 示します。endについては-1でvecの最後を示すこともできます。 その範囲外のvecの値は変更されません。 startendが与えられなかった場合はvec全体が使われます。 iportが省略された場合はカレント入力ポートが使われます。

要求された領域を埋め終る前に入力がEOFに達した場合は、ベクタの残りの部分は 変更されません。

read-uvector!が呼ばれた時既にiportがEOFに達していた場合は EOFが、そうでなければ読まれた要素の数 (バイト数ではありません) が返されます。

iportがバッファードポートであり、そのバッファリングモードが ‘modest’ か ‘none’ であった場合、read-uvector!iportが EOFに達していなくても、vecを埋める前に戻ることがあります (バッファリングモードについてはファイルポートを参照して下さい)。 パイプやネットワークに接続されたポートはデフォルトでそのように振舞います。 もし、十分なデータが到着することがわかっており、vecを確実に埋めたい場合は ポートのバッファリングモードを‘full’に変更して下さい。

データはバイトストリームとして読まれるので、 s8vectorとu8vector以外のユニフォームベクタを与えた場合は 結果がエンディアンに影響を受けることに注意して下さい。 省略可能引数endianによって、入力データのエンディアンを指定 することができます。省略した場合はパラメータdefault-endianの 値が使われます。エンディアンの扱いについてより詳しくはエンディアンネスを参照して ください。

Function: read-block! vec :optional iport start end endian

{gauche.uvector} Deprecated. read-uvector!の古い名前です。互換性のためサポートされていますが、 新しいコードではread-uvector!を使ってください。

Function: port->uvector iport :optional class

{gauche.uvector} 入力ポートiportからEOFまでデータを読み込み、classクラスの ユニフォームベクタに格納して返します。classが省略された場合は <u8vector>が使われます。

要素が1オクテット以上のユニフォームベクタのクラスを指定した場合、 各要素はプラットフォームのネイティブバイトオーダーで埋められます。

この手続きは組み込みのport->string等と対応しています (入力ユーティリティ手続き参照)。

Function: read-bytevector! bv :optional iport start end

[R7RS base] {gauche.uvector.} read-uvector!と似ていますが、bvはu8vectorでなければなりません。 これはR7RS baseにある手続きです。

Function: write-uvector vec :optional oport start end endian

{gauche.uvector} ユニフォームベクタvecの内容を「そのまま」oportに書き出します。 oportが省略された場合はカレント出力ポートが使われます。 省略可能な引数startendが与えられた場合は、 それらのインデックスの範囲が示すvecの内容のみが出力されます。 endに-1を渡してvecの最後を示すこともできます。 この手続きの返す値は未定義です。

s8vectoru8vector以外のユニフォームベクタを与えた場合、 read-uvectorと同じようにエンディアンの影響を受けることに注意して 下さい。省略可能引数endianによって出力のエンディアンを 指定できます。省略した場合はパラメータdefault-endianの値が 使われます (エンディアンネス参照)。

Function: write-@vector vec :optional port

[R7RS vector.@] {gauche.uvector}

Function: write-bytevector bv :optional oport start end

[R7RS base] {gauche.uvector} write-uvectorと似ていますが、bvはu8vectorでなければなりません。 R7RS baseの手続きです。

Function: write-block vec :optional oport start end endian

{gauche.uvector} Deprecated. write-uvectorの古い名前です。互換性のためサポートされていますが、 新しいコードではwrite-uvectorを使ってください。


9.38.5 バイトベクタ互換性

R7RS-smallはコア(scheme.base)にバイトベクタを含んでいます。 Gaucheでは、バイトベクタはu8vectorと同じです。

R7RSのバイトベクタの基本的な手続きはこのモジュールで提供されます。 ただし、文字列とバイトベクタの変換手続きは gauche.unicode(Unicode transfer encodings参照)および srfi.181(符号変換ポート参照)にあります。

Function: bytevector byte …

{gauche.uvector} [R7RS base] u8vectorの別名です。byte …を要素とするバイトベクタ(u8vector)を 新たに作って返します。

Function: bytevector? obj

{gauche.uvector} [R7RS base] u8vector?の別名です。objがバイトベクタ(u8vector)なら #tを、そうでなければ#fを返します。

Function: make-bytevector len :optional byte

{gauche.uvector} [R7RS base][R7RS bytevector] 長さlenの新たなバイトベクタ(u8vector)を作って返します。 byteが与えられていれば、全ての要素をそれで初期化します。

R7RS baseではbyteの範囲を0から255(両端含む)としていますが、 R7RS bytevectorではそれを-128から255(両端含む)に拡張しています。 負の場合は256を法としてラップアラウンドします。この手続きは拡張範囲をサポートします。

Function: bytevector-length bv

{gauche.uvector} [R7RS base] u8vector-lengthの別名です。バイトベクタ(u8vector) bvの長さを返します。

Function: bytevector-u8-ref bv k
Function: bytevector-u8-set! bv k byte

{gauche.uvector} [R7RS base] u8vector-refu8vector-set!の別名です。 バイトベクタ(u8vector) bvk番目の要素を返す/セットします。

kが領域外ならエラーが投げられます。

bytevector-u8-set!の戻り値は規定されていません。

Gaucheの拡張として、(setter bytevector-u8-ref)bytevector-u8-set!になっています。

Function: bytevector-s8-ref bv k
Function: bytevector-s8-set! bv k signed-byte

{gauche.uvector} [R7RS bytevector] オクテットを-128から127までの符号つきバイトと扱うことを除き、 それぞれbytevector-u8-refおよびbytevector-u8-set!と同じです。

Gaucheの拡張として、(setter bytevector-s8-ref)bytevector-s8-set!になっています。

Function: bytevector-copy bv :optional start end

{gauche.uvector} [R7RS base] u8vector-copyの別名です。 バイトベクタ(u8vector) bv の新たなコピーを作って返します。 インデックスstartendでコピーする範囲を限定することができます (startは含まれ、endは含まれない)。

Function: bytevector-copy! target tstart source :optional sstart send

{gauche.uvector} [R7RS base] u8vector-copy!の別名です。 targetsourceはバイトベクタ(u8vector)で、targetは 変更可能でなければなりません。sourceの内容 (startendで 範囲を限定することもできます) をtargettstart以降へとコピーします。

Function: bytevector-copy!-r6 src sstart target tstart len

{gauche.uvector} これはR6RSのbytevector-copy!との互換ルーチンです (なので-r6サフィックスがついています)。 R6RSバイトベクタライブラリがR7RS-largeにもscheme.bytevectorとして 採り入れられたので、R6RSバージョンのbytevector-copy!もR7RSに入ってきました。 (なのでR7RSには二つの異なるbytevector-copy!があります。 ひとつはscheme.baseに、もうひとつはscheme.bytevectorに。)

残念なことに、R6RSはしばしば伝統を破って新しいAPIを発明することがあり、 この手続きもそのひとつで、他の*-copy!系の手続きと引数が異なります。 この手続きでは、バイトベクタsrcsstartからlenの長さのデータを targettstartからの領域にコピーします。

Function: bytevector-append bv …

{gauche.uvector} [R7RS base] u8vector-appendの別名です。 全ての引数はバイトベクタ(u8vector)でなければなりません。 引数の全ての要素をつなげた新たなバイトベクタを作って返します。

Function: bytevector=? bv1 bv2

{gauche.uvector} [R7RS bytevector] u8vector=?の別名です。全ての引数はバイトベクタ(u8vector)でなければなりません。 引数の大きさと内容が一致している時に限り#tを返します。

Function: bytevector->u8-list bv
Function: u8-list->bytevector list

[R7RS bytevector] それぞれ、u8vectorをバイトのリストへ変換、およびその逆を行う手続きです。 省略可能なstart/end引数を取らないことを除き、 u8vector->listおよぎlist->u8vectorと同じです。



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT