Clojureでバイト配列を整数に変換する方法のメモ。
以下のコードでバイト配列を符号あり/なしのlong値に変換できます。
※ビッグエンディアンでの変換
sample.clj
(def << bit-shift-left)
(def >> bit-shift-right)
(defn unsigned [^bytes bytea]
{:pre [(<= 1 (alength bytea) 7)]}
(areduce bytea i ret 0
(bit-or (<< ret 8) (bit-and 0xff (aget bytea i)))))
(defn signed [^bytes bytea]
{:pre [(<= 1 (alength bytea) 8)]}
(areduce bytea i ret (if (neg? (aget bytea 0)) -1 0)
(bit-or (<< ret 8) (bit-and 0xff (aget bytea i)))))
areduce
を使うと、配列に対してJavaのforループと似たような処理ができます。
areduce
の引数のi
とret
はインデックスと戻り値の名前で、名前は自由に決められます。
リトルエンディアンのバイト配列の場合、配列に対するreverse
を先にしておきます。
sample2.clj
(defn areverse-byte [^bytes bytea]
(let [len (alength bytea)]
(areduce bytea i ret (byte-array len)
(do (aset-byte ret (- len i 1) (aget bytea i)) ret))))
整数からバイト配列への変換は以下のコードでできます。
sample3.clj
(defn ^bytes ->bytes [^long len ^long value]
{:pre [(<= 1 len 8)]}
(byte-array
(reduce (fn [a i] (conj a (>> value (* (- len i 1) 8)))) [] (range len))))
なお、バイト数が8固定で符号ありlongへの変換のみなら
(.. (java.nio.ByteBuffer/wrap bytea) asLongBuffer get)
の方が4倍くらい性能はいいです。