Word256 lacunae for big-endian and little-endian output

Implement BE and LE builders for 256-bit words and arrays of 256-bit words.
Test new functions in the test suite.
This commit is contained in:
Zankoku Okuno 2020-02-07 09:39:59 -05:00 committed by GitHub
parent 6657cc0383
commit f8a32ebb1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 5 deletions

View file

@ -3,6 +3,7 @@
## 0.3.3.0 -- 2020-??-?? ## 0.3.3.0 -- 2020-??-??
* Add `word64PaddedLowerHex` and `word32PaddedLowerHex` * Add `word64PaddedLowerHex` and `word32PaddedLowerHex`
* Add `word256Array{LE,BE}` and `word256{LE,BE}`
* Add `word{128,256}Padded{Lower,Upper}Hex` * Add `word{128,256}Padded{Lower,Upper}Hex`
## 0.3.2.0 -- 2020-01-20 ## 0.3.2.0 -- 2020-01-20

View file

@ -1,6 +1,6 @@
cabal-version: 2.2 cabal-version: 2.2
name: small-bytearray-builder name: small-bytearray-builder
version: 0.3.2.0 version: 0.3.3.0
synopsis: Serialize to a small byte arrays synopsis: Serialize to a small byte arrays
description: description:
This is similar to the builder facilities provided by This is similar to the builder facilities provided by

View file

@ -57,6 +57,7 @@ module Data.ByteArray.Builder
-- *** One -- *** One
, word8 , word8
-- **** Big Endian -- **** Big Endian
, word256BE
, word128BE , word128BE
, word64BE , word64BE
, word32BE , word32BE
@ -65,6 +66,7 @@ module Data.ByteArray.Builder
, int32BE , int32BE
, int16BE , int16BE
-- **** Little Endian -- **** Little Endian
, word256LE
, word128LE , word128LE
, word64LE , word64LE
, word32LE , word32LE
@ -79,6 +81,7 @@ module Data.ByteArray.Builder
, word32ArrayBE , word32ArrayBE
, word64ArrayBE , word64ArrayBE
, word128ArrayBE , word128ArrayBE
, word256ArrayBE
, int64ArrayBE , int64ArrayBE
, int32ArrayBE , int32ArrayBE
, int16ArrayBE , int16ArrayBE
@ -87,6 +90,7 @@ module Data.ByteArray.Builder
, word32ArrayLE , word32ArrayLE
, word64ArrayLE , word64ArrayLE
, word128ArrayLE , word128ArrayLE
, word256ArrayLE
, int64ArrayLE , int64ArrayLE
, int32ArrayLE , int32ArrayLE
, int16ArrayLE , int16ArrayLE
@ -119,7 +123,7 @@ import Data.Foldable (foldlM)
import Data.Int (Int64,Int32,Int16,Int8) import Data.Int (Int64,Int32,Int16,Int8)
import Data.Primitive (ByteArray(..),MutableByteArray(..),PrimArray(..)) import Data.Primitive (ByteArray(..),MutableByteArray(..),PrimArray(..))
import Data.Text.Short (ShortText) import Data.Text.Short (ShortText)
import Data.WideWord (Word128) import Data.WideWord (Word128,Word256)
import Data.Word (Word64,Word32,Word16,Word8) import Data.Word (Word64,Word32,Word16,Word8)
import GHC.ByteOrder (ByteOrder(BigEndian,LittleEndian),targetByteOrder) import GHC.ByteOrder (ByteOrder(BigEndian,LittleEndian),targetByteOrder)
import GHC.Exts (Int(I#),Char(C#),Int#,State#,ByteArray#,(>=#)) import GHC.Exts (Int(I#),Char(C#),Int#,State#,ByteArray#,(>=#))
@ -390,6 +394,16 @@ word128ArrayBE src@(PrimArray arr) soff0 slen0 = case targetByteOrder of
BigEndian -> bytes (Bytes (ByteArray arr) (soff0 * 16) (slen0 * 16)) BigEndian -> bytes (Bytes (ByteArray arr) (soff0 * 16) (slen0 * 16))
LittleEndian -> word128ArraySwap src soff0 slen0 LittleEndian -> word128ArraySwap src soff0 slen0
word256ArrayLE :: PrimArray Word256 -> Int -> Int -> Builder
word256ArrayLE src@(PrimArray arr) soff0 slen0 = case targetByteOrder of
LittleEndian -> bytes (Bytes (ByteArray arr) (soff0 * 32) (slen0 * 32))
BigEndian -> word256ArraySwap src soff0 slen0
word256ArrayBE :: PrimArray Word256 -> Int -> Int -> Builder
word256ArrayBE src@(PrimArray arr) soff0 slen0 = case targetByteOrder of
BigEndian -> bytes (Bytes (ByteArray arr) (soff0 * 32) (slen0 * 32))
LittleEndian -> word256ArraySwap src soff0 slen0
word64ArrayLE :: PrimArray Word64 -> Int -> Int -> Builder word64ArrayLE :: PrimArray Word64 -> Int -> Int -> Builder
word64ArrayLE src@(PrimArray arr) soff0 slen0 = case targetByteOrder of word64ArrayLE src@(PrimArray arr) soff0 slen0 = case targetByteOrder of
LittleEndian -> bytes (Bytes (ByteArray arr) (soff0 * 8) (slen0 * 8)) LittleEndian -> bytes (Bytes (ByteArray arr) (soff0 * 8) (slen0 * 8))
@ -525,6 +539,28 @@ word128ArraySwap src soff0 slen0 =
go (soff + 16) send dst (doff + 16) go (soff + 16) send dst (doff + 16)
else pure doff else pure doff
word256ArraySwap :: PrimArray Word256 -> Int -> Int -> Builder
word256ArraySwap src soff0 slen0 =
fromFunction (slen0 * 32) (go (soff0 * 32) ((soff0 + slen0) * 32))
where
-- TODO: Perhaps we could put byteswapping functions to use
-- rather than indexing tons of Word8s. This could be done
-- both here and in the other swap functions. There are a
-- decent number of tests for these array-swapping functions,
-- which makes changing this less scary.
go :: Int -> Int -> MutableByteArray s -> Int -> ST s Int
go !soff !send !dst !doff = if soff < send
then do
let loop !i
| i < 32 = do
let v = PM.indexPrimArray (asWord8s src) (soff + i)
PM.writeByteArray dst (doff + (31 - i)) v
loop (i + 1)
| otherwise = pure ()
loop 0
go (soff + 32) send dst (doff + 32)
else pure doff
asWord8s :: PrimArray a -> PrimArray Word8 asWord8s :: PrimArray a -> PrimArray Word8
asWord8s (PrimArray x) = PrimArray x asWord8s (PrimArray x) = PrimArray x
@ -766,6 +802,11 @@ int32BE w = fromBounded Nat.constant (Bounded.int32BE w)
int16BE :: Int16 -> Builder int16BE :: Int16 -> Builder
int16BE w = fromBounded Nat.constant (Bounded.int16BE w) int16BE w = fromBounded Nat.constant (Bounded.int16BE w)
-- | Requires exactly 32 bytes. Dump the octets of a 256-bit
-- word in a little-endian fashion.
word256LE :: Word256 -> Builder
word256LE w = fromBounded Nat.constant (Bounded.word256LE w)
-- | Requires exactly 16 bytes. Dump the octets of a 128-bit -- | Requires exactly 16 bytes. Dump the octets of a 128-bit
-- word in a little-endian fashion. -- word in a little-endian fashion.
word128LE :: Word128 -> Builder word128LE :: Word128 -> Builder
@ -786,16 +827,22 @@ word32LE w = fromBounded Nat.constant (Bounded.word32LE w)
word16LE :: Word16 -> Builder word16LE :: Word16 -> Builder
word16LE w = fromBounded Nat.constant (Bounded.word16LE w) word16LE w = fromBounded Nat.constant (Bounded.word16LE w)
-- | Requires exactly 8 bytes. Dump the octets of a 64-bit
-- | Requires exactly 32 bytes. Dump the octets of a 256-bit
-- word in a big-endian fashion. -- word in a big-endian fashion.
word64BE :: Word64 -> Builder word256BE :: Word256 -> Builder
word64BE w = fromBounded Nat.constant (Bounded.word64BE w) word256BE w = fromBounded Nat.constant (Bounded.word256BE w)
-- | Requires exactly 16 bytes. Dump the octets of a 128-bit -- | Requires exactly 16 bytes. Dump the octets of a 128-bit
-- word in a big-endian fashion. -- word in a big-endian fashion.
word128BE :: Word128 -> Builder word128BE :: Word128 -> Builder
word128BE w = fromBounded Nat.constant (Bounded.word128BE w) word128BE w = fromBounded Nat.constant (Bounded.word128BE w)
-- | Requires exactly 8 bytes. Dump the octets of a 64-bit
-- word in a big-endian fashion.
word64BE :: Word64 -> Builder
word64BE w = fromBounded Nat.constant (Bounded.word64BE w)
-- | Requires exactly 4 bytes. Dump the octets of a 32-bit -- | Requires exactly 4 bytes. Dump the octets of a 32-bit
-- word in a big-endian fashion. -- word in a big-endian fashion.
word32BE :: Word32 -> Builder word32BE :: Word32 -> Builder

View file

@ -66,6 +66,7 @@ module Data.ByteArray.Builder.Bounded
-- *** One -- *** One
, word8 , word8
-- **** Big Endian -- **** Big Endian
, word256BE
, word128BE , word128BE
, word64BE , word64BE
, word32BE , word32BE
@ -74,6 +75,7 @@ module Data.ByteArray.Builder.Bounded
, int32BE , int32BE
, int16BE , int16BE
-- **** Little Endian -- **** Little Endian
, word256LE
, word128LE , word128LE
, word64LE , word64LE
, word32LE , word32LE
@ -764,6 +766,12 @@ word128LE (Word128 hi lo) = append (word64LE lo) (word64LE hi)
word128BE :: Word128 -> Builder 16 word128BE :: Word128 -> Builder 16
word128BE (Word128 hi lo) = append (word64BE hi) (word64BE lo) word128BE (Word128 hi lo) = append (word64BE hi) (word64BE lo)
word256LE :: Word256 -> Builder 32
word256LE (Word256 hi mhi mlo lo) = word64LE lo `append` word64LE mlo `append` word64LE mhi `append` word64LE hi
word256BE :: Word256 -> Builder 32
word256BE (Word256 hi mhi mlo lo) = word64BE hi `append` word64BE mhi `append` word64BE mlo `append` word64BE lo
-- | Requires exactly 8 bytes. Dump the octets of a 64-bit -- | Requires exactly 8 bytes. Dump the octets of a 64-bit
-- word in a little-endian fashion. -- word in a little-endian fashion.
word64LE :: Word64 -> Builder 8 word64LE :: Word64 -> Builder 8

View file

@ -201,6 +201,16 @@ tests = testGroup "Tests"
in runConcat 1 (foldMap word128BE xs) in runConcat 1 (foldMap word128BE xs)
=== ===
runConcat 1 (word128ArrayBE ys 0 (Prelude.length xs)) runConcat 1 (word128ArrayBE ys 0 (Prelude.length xs))
, TQC.testProperty "word256ArrayLE" $ \(xs :: [Word256]) ->
let ys = Exts.fromList xs :: PrimArray Word256
in runConcat 1 (foldMap word256LE xs)
===
runConcat 1 (word256ArrayLE ys 0 (Prelude.length xs))
, TQC.testProperty "word256ArrayBE" $ \(xs :: [Word256]) ->
let ys = Exts.fromList xs :: PrimArray Word256
in runConcat 1 (foldMap word256BE xs)
===
runConcat 1 (word256ArrayBE ys 0 (Prelude.length xs))
] ]
, testGroup "alternate" , testGroup "alternate"
[ TQC.testProperty "HexWord64" $ \x y -> [ TQC.testProperty "HexWord64" $ \x y ->