Carp/core/Binary.carp
Scott Olsen d3f99487db Move partition function into the Array module
Since the function is generic over arrays, it makes more sense to house
it here.

I've also fixed an issue with its definition whereby we produced extra
empty arrays when n was greater than the original array length. We now
return an array of a length that matches precisely the number of
partitions with values we're able to create.
2020-02-16 15:57:38 -05:00

102 lines
4.3 KiB
Plaintext

(system-include "carp_binary.h")
(defmodule Binary
(doc Order
"The type of byte orders.
LittleEndian designates the little endian ordering, and indicates the least
significant byte appears first in a given byte sequence.
BigEndian designates the big endian ordering, and indicates the most
significant byte occurs first in a given byte sequence.")
(deftype Order LittleEndian BigEndian)
(register to-int16 (λ [Byte Byte] Int))
(register to-int32 (λ [Byte Byte Byte Byte] Int))
(register to-int64 (λ [Byte Byte Byte Byte Byte Byte Byte Byte] Int))
(doc bytes->int16-unsafe
"Interprets the first two bytes in a byte sequence as an int16 value.
**This operation is unsafe.**")
(sig bytes->int16-unsafe (Fn [Order (Ref (Array Byte) a)] Int))
(defn bytes->int16-unsafe [order bs]
(match order
(Order.LittleEndian)
(to-int16 @(Array.unsafe-nth bs 0) @(Array.unsafe-nth bs 1))
(Order.BigEndian)
(to-int16 @(Array.unsafe-nth bs 1) @(Array.unsafe-nth bs 0))))
(doc bytes->int32-unsafe
"Interprets the first four bytes in a byte sequence as an int32 value.
**This operation is unsafe.**")
(sig bytes->int32-unsafe (Fn [Order (Ref (Array Byte))] Int))
(defn bytes->int32-unsafe [order bs]
(match order
(Order.LittleEndian)
(to-int32 @(Array.unsafe-nth bs 0) @(Array.unsafe-nth bs 1)
@(Array.unsafe-nth bs 2) @(Array.unsafe-nth bs 3))
(Order.BigEndian)
(to-int32 @(Array.unsafe-nth bs 3) @(Array.unsafe-nth bs 2)
@(Array.unsafe-nth bs 1) @(Array.unsafe-nth bs 0))))
(doc bytes->int64-unsafe
"Interprets the first eight bytes in a byte sequence as an int64 value.
**This operation is unsafe.**")
(sig bytes->int64-unsafe (Fn [Order (Ref (Array Byte) a)] Int))
(defn bytes->int64-unsafe [order bs]
(match order
(Order.LittleEndian)
(to-int64 @(Array.unsafe-nth bs 0) @(Array.unsafe-nth bs 1)
@(Array.unsafe-nth bs 2) @(Array.unsafe-nth bs 3)
@(Array.unsafe-nth bs 4) @(Array.unsafe-nth bs 5)
@(Array.unsafe-nth bs 6) @(Array.unsafe-nth bs 7))
(Order.BigEndian)
(to-int64 @(Array.unsafe-nth bs 7) @(Array.unsafe-nth bs 6)
@(Array.unsafe-nth bs 5) @(Array.unsafe-nth bs 4)
@(Array.unsafe-nth bs 3) @(Array.unsafe-nth bs 2)
@(Array.unsafe-nth bs 1) @(Array.unsafe-nth bs 0))))
(doc byte-seq->int8-seq-unsafe
"Interprets a sequence of bytes as a sequence of int8 values.
**This operation is unsafe.**")
(sig byte-seq->int8-seq (Fn [(Ref (Array Byte) a)] (Array Int)))
(defn byte-seq->int8-seq [bs]
(let [f (fn [b] (Byte.to-int @b))]
(Array.copy-map &f bs)))
(doc byte-seq->int16-seq-unsafe
"Interprets a sequence of bytes as a sequence of int16 values.
**This operation is unsafe.**")
(sig byte-seq->int16-seq (Fn [Order (Ref (Array Byte) a)] (Array Int)))
(defn byte-seq->int16-seq [order bs]
;; This is way less efficient than it could be.
;; Instead of allocating about 4 extra arrays, we can express this
;; as a fold.
(let [enum (Array.enumerated bs)]
(let [evens (Array.copy-filter &(fn [p] (Int.even? @(Pair.a p))) &enum)
odds (Array.copy-filter &(fn [p] (Int.odd? @(Pair.a p))) &enum)
intf (fn [r1 r2] (to-int16 @(Pair.b r1) @(Pair.b r2)))]
(match order
(Order.LittleEndian) (Array.zip &intf &evens &odds)
(Order.BigEndian) (Array.zip &intf &odds &evens)))))
(doc byte-seq->int32-seq-unsafe
"Interprets a sequence of bytes as a sequence of int32 values.
**This operation is unsafe.**")
(sig byte-seq->int32-seq (Fn [Order (Ref (Array Byte) a)] (Array Int)))
(defn byte-seq->int32-seq [order bs]
(let [partitions (Array.partition bs 4)
f (fn [b] (bytes->int32-unsafe order b))]
(Array.copy-map &f &partitions)))
(doc byte-seq->int64-seq-unsafe
"Interprets a sequence of bytes as a sequence of int32 values.
**This operation is unsafe.**")
(sig byte-seq->int64-seq (Fn [Order (Ref (Array Byte) a)] (Array Int)))
(defn byte-seq->int64-seq [order bs]
(let [partitions (Array.partition bs 8)
f (fn [b] (bytes->int64-unsafe order b))]
(Array.copy-map &f &partitions)))
)