(ns cljam.io.cram.codecs.rans4x8 (:require [cljam.io.util.byte-buffer :as bb] [cljam.io.cram.itf8 :as itf8]) (:import [java.util Arrays])) | |
(def ^:private byte-array-type (type (byte-array 0))) (def ^:private int-array-type (type (int-array 0))) | |
(defmacro ^:private read-frequencies* [bb init-expr read-expr] `(let [ret# ~init-expr] (loop [sym# (long (bb/read-ubyte ~bb)) rle# 0] (aset ret# sym# ~read-expr) (if (pos? rle#) (recur (inc sym#) (dec rle#)) (let [sym'# (long (bb/read-ubyte ~bb)) rle'# (if (= sym'# (inc sym#)) (long (bb/read-ubyte ~bb)) rle#)] (if (zero? sym'#) ret# (recur sym'# rle'#))))))) | |
(defn- read-frequencies0 ^ints [bb] (read-frequencies* bb (int-array 256) (int (itf8/decode-itf8 bb)))) | |
(defn- read-frequencies1 ^"[[I" [bb] (read-frequencies* bb ^"[[I" (make-array int-array-type 256) (read-frequencies0 bb))) | |
(def ^:private zero-int-array (int-array 256)) | |
(defn- cumulative-frequencies ^ints [^ints freqs] (if (nil? freqs) zero-int-array (let [cum-freqs (int-array 256)] (loop [i 0 sum 0] (when (< i 256) (let [f (aget freqs i)] (aset cum-freqs i sum) (recur (inc i) (+ sum (long f)))))) cum-freqs))) | |
(defn- reverse-lookup-table ^bytes [^ints cum-freqs] (let [arr (byte-array 4096) n (alength cum-freqs)] (loop [i 1, start 0] (if (< i n) (let [curr (aget cum-freqs i)] (if (= start curr) (recur (inc i) start) (do (Arrays/fill arr start curr (byte (dec i))) (recur (inc i) curr)))) (Arrays/fill arr start 4096 (byte 255)))) arr)) | |
(defn- advance-step ^long [^long c ^long f ^long state] (-> (* f (bit-shift-right state 12)) (+ (bit-and state 0xfff)) (- c))) | |
(defn- renormalize-state ^long [bb ^long state] (loop [state state] (if (< state 0x800000) (recur (bit-or (bit-shift-left state 8) (long (bb/read-ubyte bb)))) state))) | |
(defn- decode0 [bb ^long n-out] (let [freqs (read-frequencies0 bb) cum-freqs (cumulative-frequencies freqs) table (reverse-lookup-table cum-freqs) states (bb/read-ints bb 4) out (byte-array n-out)] (dotimes [i n-out] (let [j (rem i 4) state (aget states j) f (bit-and state 0xfff) sym (bit-and (aget table f) 0xff) state' (->> state (advance-step (aget cum-freqs sym) (aget freqs sym)) (renormalize-state bb))] (aset out i (byte sym)) (aset states j state'))) out)) | |
(defn- decode1 [bb ^long n-out] (let [freqs (read-frequencies1 bb) ^"[[I" cum-freqs (make-array int-array-type 256) _ (dotimes [i 256] (aset cum-freqs i (cumulative-frequencies (aget freqs i)))) ^"[[B" tables (make-array byte-array-type 256) _ (dotimes [i 256] (aset tables i (reverse-lookup-table (aget cum-freqs i)))) quarter (quot n-out 4) truncated (* 4 quarter) states (bb/read-ints bb 4) last-syms (int-array 4) out (byte-array n-out)] (dotimes [i quarter] (dotimes [j 4] (let [state (aget states j) f (bit-and state 0xfff) last-sym (aget last-syms j) ^ints cfreqs (aget cum-freqs last-sym) sym (bit-and (aget ^bytes (aget tables last-sym) f) 0xff) state' (->> state (advance-step (aget cfreqs sym) (aget ^ints (aget freqs last-sym) sym)) (renormalize-state bb))] (aset out (+ i (* j quarter)) (byte sym)) (aset states j state') (aset last-syms j sym)))) (dotimes [i (- n-out truncated)] (let [state (aget states 3) f (bit-and state 0xfff) last-sym (aget last-syms 3) ^ints cfreq (aget cum-freqs last-sym) sym (bit-and (aget ^bytes (aget tables last-sym) f) 0xff) state' (->> state (advance-step (aget cfreq sym) (aget ^ints (aget freqs last-sym) sym)) (renormalize-state bb))] (aset out (+ i truncated) (byte sym)) (aset states 3 state') (aset last-syms 3 sym))) out)) | |
Reads a byte sequence from the given ByteBuffer and decodes it by the rANS4x8 codec. Returns the decoded result as a byte array. | (defn decode ^bytes [bb] (let [order (long (bb/read-ubyte bb)) _n-in (bb/read-uint bb) n-out (bb/read-uint bb)] (if (zero? order) (decode0 bb n-out) (decode1 bb n-out)))) |