Kinx ライブラリ - Binary

# Binary

## はじめに

**「見た目は JavaScript、頭脳(中身)は Ruby、（安定感は AC/DC）」** でお届けしているスクリプト言語 [Kinx](https://github.com/Kray-G/kinx)。言語はライブラリが命。ということでライブラリの使い方編。 

今回は Binary です。

* 参考
    * 最初の動機 ... [スクリプト言語 KINX（ご紹介）](https://qiita.com/Kray-G/items/ca08b6fb40d15dd0ec76)
        * 個別記事へのリンクは全てここに集約してあります。
    * リポジトリ ... [https://github.com/Kray-G/kinx](https://github.com/Kray-G/kinx)
        * Pull Request 等お待ちしております。 

バイナリ（Binary）は配列（Array）に似ているが、保持できる値が 0x00 ～ 0xFF までのバイト列である点が異なる。内部実装的にも単純にバイトの Vector として実装されており、バイナリデータを格納するのに適している。

## Binary 特殊オブジェクト

Binary にも特殊オブジェクト `Binary` があり、`Binary` オブジェクトに対して関数定義することができる。尚、後述するがバイナリデータはスプレッド演算子を使って配列と相互変換できる。以下の例はバイナリを配列に変換して配列に対して `map` している例となる。

```javascript
Binary.toStringArray = function(bin) {
    return [...bin].map(&(e) => *e);
};
System.println([...<97, 98, 99>]);            // => [97, 98, 99]
System.println(<97, 98, 99>.toStringArray()); // => ["a", "b", "c"]
```

## Binary

### ファイル・ロード

バイナリデータは以下のように `File.BINARY` を指定することでファイルから読み込むこともできる。指定しなかった場合は `File.TEXT` と同様、文字列としてファイルを読み込む。

```javascript
var file = File.load("filename", File.BINARY);
```

### 組み込み特殊メソッド

Binary には Array と同じようなメソッドが登録されている。が、基本的にバイナリ列に適用することになるため、あまり複雑なことはできない。`push`、`pop`、`unshift`、`shift` は破壊的な操作を行う。

|              メソッド               |                                                                   意味                                                                    |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Binary.length(bin)                  | バイナリ bin の要素数を返す。                                                                                                             |
| Binary.push(bin, e)                 | バイナリ bin の最後の要素として e を追加する。                                                                                            |
| Binary.pop(bin)                     | バイナリ bin の最後の要素を返し、要素から削除する。                                                                                       |
| Binary.unshift(bin, e)              | バイナリ bin の最初の要素として e を追加する。                                                                                            |
| Binary.shift(bin)                   | バイナリ bin の最初の要素を返し、要素から削除する。後ろの要素は順次先頭方向に移動する。                                                   |
| Binary.join(bin, sep, fmt)          | バイナリ bin の要素を全てつなげた文字列として返す。要素と要素の間は sep でつなぐ。`fmt` が省略された場合 "0x02x" でフォーマットされる。   |
| Binary.reverse(bin)                 | バイナリ bin の要素を逆順にした新たなバイナリを返す。                                                                                     |
| Binary.toString(bin, sep, fmt)      | バイナリ bin を文字列化して返す。デフォルトのセパレータは `", "`。`fmt` が省略された場合 "0x02x" でフォーマットされる。                   |
| Binary.apply(bin, func)             | func(bin) を実行する。                                                                                                                    |
| Binary.each(bin, callback)          | bin の各要素 e に対して callback(e, index) を実行する。                                                                                   |
| Binary.map(bin, callback)           | bin の各要素 e に対して callback(e, index) の結果の集合となる新たなバイナリを返す。                                                       |
| Binary.filter(bin, callback)        | bin の各要素 e に対して callback(e, index) の結果が真となるもののみの集合として新たなバイナリを返す。                                     |
| Binary.reject(bin, callback)        | bin の各要素 e に対して callback(e, index) の結果が偽となるもののみの集合として新たなバイナリを返す。                                     |
| Binary.reduce(bin, callback, initr) | 前の要素までの結果を r （初期値は initr、指定されていなければ null）として、ary の各要素 e に対し callback(r, e) を行った最終結果を返す。 |
| Binary.sort(bin, comp)              | 任意の bin の要素 e1, e2 に対する comp(e1, e2) の結果を利用して bin 全体をソートした新たなバイナリを返す。                                |
| Binary.clone(bin)                   | bin のコピーを作成する。                                                                                                                  |
| Binary.println(bin)                 | bin の各要素 e に対して System.println(e) を適用する。                                                                                    |

### 特殊オペレーター

#### 後置 `[]` オペレーター

バイナリの要素にアクセスする。

```javascript
var e = ary[5];  // index は 0 はじまりなので 6 番目の要素
```

左辺値にもなり、バイト列を直接書き換えることができる。

```javascript
var bin = <1,2,3,4,5>;
bin[2] = 255;
System.println(bin);  // => <0x01, 0x02, 0xff, 0x04, 0x05>
```

#### 二項 `+` オペレーター

バイナリ同士をつなげる。右辺値がバイナリではない場合、`SystemException("Unsupported Operator")` 例外が発生する。

```javascript
var bin = <1, 2, 3>;
var r = bin + <2, 4>;  // => <0x01, 0x02, 0x03, 0x02, 0x04>
```

#### 単項 `*` オペレーター

単項 `*` オペレーターをバイナリに適用した場合、バイナリを文字列に変換する。

```javascript
var a = *<97, 98, 99>;  // => "abc"
```

尚、文字列に単項 `*` オペレーターを適用すると配列になるため、バイナリには戻らない。代わりに、バイナリは下記のスプレッド演算子で配列と相互変換ができる。

#### スプレッド演算子

配列とバイナリで相互変換可能。配列からバイナリに変換する際は、数値であれば 0x00～0xFF の値に丸められる。文字の場合は先頭の文字のみ使われる。

```javascript
var a = <97, 98, 99>; // == <0x61, 0x62, 0x63>
var b = [...a];       // => [97, 98, 99]
var c = <...b>;       // => <0x61, 0x62, 0x63>
var d = <...[1024,1025,1026,"abc"]>;  // => <0x00, 0x01, 0x02, 0x61>
                                      //    0x61 == 97 == 'a'
```

## おわりに

バイナリデータも割と扱いたくなるので、一通り機能を揃えてみました。バイト単位でゴニョゴニョできると良いことあるかもしれない。なんとなく例えば x64 向け JIT ライブラリとか作れそうですね。

では、また次回。