bytebuild 0.3.10.0 → 0.3.11.0
raw patch · 8 files changed
+132/−29 lines, 8 filesdep ~basedep ~tastyPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, tasty
API changes (from Hackage documentation)
Files
- CHANGELOG.md +6/−0
- bytebuild.cabal +11/−4
- src-9.0/Compat.hs +53/−0
- src-9.2/Compat.hs +15/−0
- src/Data/Bytes/Builder.hs +6/−1
- src/Data/Bytes/Builder/Bounded.hs +26/−21
- src/Data/Bytes/Builder/Unsafe.hs +5/−3
- test/Main.hs +10/−0
CHANGELOG.md view
@@ -5,6 +5,12 @@ `small-bytearray-builder` is now just a compatibility shim to ease the migration process. +## 0.3.11.0 -- 2022-04-12++* Support GHC 9.2+* Inline pragmas for better LEB encoding perf+* Bump upper bound on tasty in test suite+ ## 0.3.10.0 -- 2022-03-01 * Add upper bound on base since this does not build with GHC 9.2.
bytebuild.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: bytebuild-version: 0.3.10.0-synopsis: Serialize to a small byte arrays+version: 0.3.11.0+synopsis: Build byte arrays description: This is similar to the builder facilities provided by `Data.ByteString.Builder`. It is intended to be used in@@ -43,10 +43,12 @@ Data.Bytes.Builder.Bounded Data.Bytes.Builder.Bounded.Class Data.Bytes.Builder.Bounded.Unsafe+ other-modules:+ Compat reexported-modules: Data.Bytes.Chunks build-depends:- , base >=4.12.0.0 && <4.16+ , base >=4.12.0.0 && <4.17 , byteslice >=0.2.6 && <0.3 , bytestring >=0.10.8.2 && <0.12 , haskell-src-meta >=0.8@@ -59,6 +61,11 @@ , text-short >=0.1.3 && <0.2 , wide-word >=0.1.0.9 && <0.2 , zigzag+ if impl(ghc >= 9.2)+ hs-source-dirs: src-9.2+ else+ if impl(ghc >= 8.10)+ hs-source-dirs: src-9.0 if flag(checked) build-depends: primitive-checked >= 0.7 && <0.8 else@@ -89,7 +96,7 @@ , quickcheck-classes >=0.6.4 , quickcheck-instances >=0.3.22 , text-short- , tasty >=1.2.3 && <1.3+ , tasty >=1.2.3 && <1.5 , tasty-hunit >=0.10.0.2 && <0.11 , tasty-quickcheck >=0.10.1 && <0.11 , text >=1.2 && <1.3
+ src-9.0/Compat.hs view
@@ -0,0 +1,53 @@+{-# language MagicHash #-}++-- This is actually used with both GHC 8.10 and with GHC 9.0.+-- The name of the directory is a little misleading.+module Compat+ ( int8ToInt#+ , int16ToInt#+ , int32ToInt#+ , wordToWord8#+ , wordToWord16#+ , wordToWord32#+ , word8ToWord#+ , word16ToWord#+ , word32ToWord#+ ) where++import GHC.Exts (Int#,Word#)++int8ToInt# :: Int# -> Int#+{-# inline int8ToInt# #-}+int8ToInt# x = x++int16ToInt# :: Int# -> Int#+{-# inline int16ToInt# #-}+int16ToInt# x = x++int32ToInt# :: Int# -> Int#+{-# inline int32ToInt# #-}+int32ToInt# x = x++wordToWord8# :: Word# -> Word#+{-# inline wordToWord8# #-}+wordToWord8# x = x++wordToWord16# :: Word# -> Word#+{-# inline wordToWord16# #-}+wordToWord16# x = x++wordToWord32# :: Word# -> Word#+{-# inline wordToWord32# #-}+wordToWord32# x = x++word8ToWord# :: Word# -> Word#+{-# inline word8ToWord# #-}+word8ToWord# x = x++word16ToWord# :: Word# -> Word#+{-# inline word16ToWord# #-}+word16ToWord# x = x++word32ToWord# :: Word# -> Word#+{-# inline word32ToWord# #-}+word32ToWord# x = x
+ src-9.2/Compat.hs view
@@ -0,0 +1,15 @@+{-# language MagicHash #-}++module Compat + ( int8ToInt#+ , int16ToInt#+ , int32ToInt#+ , wordToWord8# + , wordToWord16#+ , wordToWord32#+ , word8ToWord#+ , word16ToWord#+ , word32ToWord#+ ) where++import GHC.Exts
src/Data/Bytes/Builder.hs view
@@ -172,6 +172,8 @@ import GHC.Word (Word(W#),Word8(W8#)) import Numeric.Natural (Natural) +import qualified Compat as C+ import qualified Arithmetic.Nat as Nat import qualified Arithmetic.Types as Arithmetic import qualified Data.Bytes as Bytes@@ -1160,14 +1162,17 @@ -- | Encode a machine-sized word with LEB-128. wordLEB128 :: Word -> Builder+{-# inline wordLEB128 #-} wordLEB128 w = fromBounded Nat.constant (Bounded.wordLEB128 w) -- | Encode a 32-bit word with LEB-128. word32LEB128 :: Word32 -> Builder+{-# inline word32LEB128 #-} word32LEB128 w = fromBounded Nat.constant (Bounded.word32LEB128 w) -- | Encode a 64-bit word with LEB-128. word64LEB128 :: Word64 -> Builder+{-# inline word64LEB128 #-} word64LEB128 w = fromBounded Nat.constant (Bounded.word64LEB128 w) -- | Encode a signed arbitrary-precision integer as decimal.@@ -1277,7 +1282,7 @@ -- (# sX, bufX, 0#, lenX, Mutable buf0 off0 cs0 #) unsafeWordToWord8 :: Word -> Word8-unsafeWordToWord8 (W# w) = W8# w+unsafeWordToWord8 (W# w) = W8# (C.wordToWord8# w) -- | This function and the documentation for it are copied from -- Takano Akio's fast-builder library.
src/Data/Bytes/Builder/Bounded.hs view
@@ -123,6 +123,8 @@ import GHC.Word (Word8(W8#),Word16(W16#),Word32(W32#),Word64(W64#)) import Data.Bytes.Types (Bytes(Bytes)) +import qualified Compat as C+ import qualified Arithmetic.Lte as Lte import qualified Arithmetic.Nat as Nat import qualified Arithmetic.Types as Arithmetic@@ -230,12 +232,12 @@ -- | Requires up to 10 bytes. Encodes an unsigned 32-bit integer as decimal. -- This encoding never starts with a zero unless the argument was zero. word32Dec :: Word32 -> Builder 10-word32Dec (W32# w) = wordCommonDec# w+word32Dec (W32# w) = wordCommonDec# (C.word32ToWord# w) -- | Requires up to 5 bytes. Encodes an unsigned 16-bit integer as decimal. -- This encoding never starts with a zero unless the argument was zero. word16Dec :: Word16 -> Builder 5-word16Dec (W16# w) = wordCommonDec# w+word16Dec (W16# w) = wordCommonDec# (C.word16ToWord# w) -- | Requires up to 3 bytes. Encodes an unsigned 8-bit integer as decimal. -- This encoding never starts with a zero unless the argument was zero.@@ -247,7 +249,7 @@ -- However, I (Andrew Martin) am concerned that although lookup -- table perform very well in microbenchmarks, they can thrash -- L1 cache in real applications.- word8Dec# w+ word8Dec# (C.word8ToWord# w) -- | Requires up to 19 bytes. Encodes an unsigned machine-sized integer -- as decimal. This encoding never starts with a zero unless the argument@@ -267,21 +269,21 @@ -- Negative numbers are preceded by a minus sign. Positive numbers -- are not preceded by anything. int32Dec :: Int32 -> Builder 11-int32Dec (I32# w) = intCommonDec# w+int32Dec (I32# w) = intCommonDec# (C.int32ToInt# w) -- | Requires up to 6 bytes. Encodes a signed 16-bit integer as decimal. -- This encoding never starts with a zero unless the argument was zero. -- Negative numbers are preceded by a minus sign. Positive numbers -- are not preceded by anything. int16Dec :: Int16 -> Builder 6-int16Dec (I16# w) = intCommonDec# w+int16Dec (I16# w) = intCommonDec# (C.int16ToInt# w) -- | Requires up to 4 bytes. Encodes a signed 8-bit integer as decimal. -- This encoding never starts with a zero unless the argument was zero. -- Negative numbers are preceded by a minus sign. Positive numbers -- are not preceded by anything. int8Dec :: Int8 -> Builder 4-int8Dec (I8# w) = intCommonDec# w+int8Dec (I8# w) = intCommonDec# (C.int8ToInt# w) -- | Requires up to 20 bytes. Encodes a signed machine-sized integer -- as decimal. This encoding never starts with a zero unless the@@ -441,13 +443,13 @@ -- hexadecimal, zero-padding the encoding to 8 digits. This uses -- uppercase for the alphabetical digits. word32PaddedUpperHex :: Word32 -> Builder 8-word32PaddedUpperHex (W32# w) = word32PaddedUpperHex# w+word32PaddedUpperHex (W32# w) = word32PaddedUpperHex# (C.word32ToWord# w) -- | Requires exactly 8 bytes. Encodes a 32-bit unsigned integer as -- hexadecimal, zero-padding the encoding to 8 digits. This uses -- lowercase for the alphabetical digits. word32PaddedLowerHex :: Word32 -> Builder 8-word32PaddedLowerHex (W32# w) = word32PaddedLowerHex# w+word32PaddedLowerHex (W32# w) = word32PaddedLowerHex# (C.word32ToWord# w) -- | Requires exactly 4 bytes. Encodes a 16-bit unsigned integer as -- hexadecimal, zero-padding the encoding to 4 digits. This uses@@ -456,7 +458,7 @@ -- >>> word16PaddedUpperHex 0xab0 -- 0AB0 word16PaddedUpperHex :: Word16 -> Builder 4-word16PaddedUpperHex (W16# w) = word16PaddedUpperHex# w+word16PaddedUpperHex (W16# w) = word16PaddedUpperHex# (C.word16ToWord# w) -- | Requires exactly 4 bytes. Encodes a 16-bit unsigned integer as -- hexadecimal, zero-padding the encoding to 4 digits. This uses@@ -465,7 +467,7 @@ -- >>> word16PaddedLowerHex 0xab0 -- 0ab0 word16PaddedLowerHex :: Word16 -> Builder 4-word16PaddedLowerHex (W16# w) = word16PaddedLowerHex# w+word16PaddedLowerHex (W16# w) = word16PaddedLowerHex# (C.word16ToWord# w) -- | Requires at most 4 bytes. Encodes a 16-bit unsigned integer as -- hexadecimal. No leading zeroes are displayed. Letters are presented@@ -474,7 +476,7 @@ -- >>> word16LowerHex 0xab0 -- ab0 word16LowerHex :: Word16 -> Builder 4-word16LowerHex (W16# w) = word16LowerHex# w+word16LowerHex (W16# w) = word16LowerHex# (C.word16ToWord# w) -- | Requires at most 4 bytes. Encodes a 16-bit unsigned integer as -- hexadecimal. No leading zeroes are displayed. Letters are presented@@ -483,25 +485,25 @@ -- >>> word16UpperHex 0xab0 -- AB0 word16UpperHex :: Word16 -> Builder 4-word16UpperHex (W16# w) = word16UpperHex# w+word16UpperHex (W16# w) = word16UpperHex# (C.word16ToWord# w) -- | Requires at most 2 bytes. Encodes a 8-bit unsigned integer as -- hexadecimal. No leading zeroes are displayed. If the number is zero, -- a single zero digit is used. word8LowerHex :: Word8 -> Builder 2-word8LowerHex (W8# w) = word8LowerHex# w+word8LowerHex (W8# w) = word8LowerHex# (C.word8ToWord# w) -- | Requires exactly 2 bytes. Encodes a 8-bit unsigned integer as -- hexadecimal, zero-padding the encoding to 2 digits. This uses -- uppercase for the alphabetical digits. word8PaddedUpperHex :: Word8 -> Builder 2-word8PaddedUpperHex (W8# w) = word8PaddedUpperHex# w+word8PaddedUpperHex (W8# w) = word8PaddedUpperHex# (C.word8ToWord# w) -- | Requires exactly 2 bytes. Encodes a 8-bit unsigned integer as -- hexadecimal, zero-padding the encoding to 2 digits. This uses -- lowercase for the alphabetical digits. word8PaddedLowerHex :: Word8 -> Builder 2-word8PaddedLowerHex (W8# w) = word8PaddedLowerHex# w+word8PaddedLowerHex (W8# w) = word8PaddedLowerHex# (C.word8ToWord# w) -- TODO: Is it actually worth unrolling this loop. I suspect that it -- might not be. Benchmark this.@@ -849,14 +851,17 @@ -- | Encode a machine-sized word with LEB-128. wordLEB128 :: Word -> Builder 10+{-# inline wordLEB128 #-} wordLEB128 (W# w) = lebCommon (W# w) -- | Encode a 32-bit word with LEB-128. word32LEB128 :: Word32 -> Builder 5-word32LEB128 (W32# w) = lebCommon (W# w)+{-# inline word32LEB128 #-}+word32LEB128 (W32# w) = lebCommon (W# (C.word32ToWord# w)) -- | Encode a 64-bit word with LEB-128. word64LEB128 :: Word64 -> Builder 10+{-# inline word64LEB128 #-} word64LEB128 (W64# w) = lebCommon (W# w) lebCommon :: Word -> Builder n@@ -933,19 +938,19 @@ int64BE (I64# i) = word64BE (W64# (int2Word# i)) int32BE :: Int32 -> Builder 4-int32BE (I32# i) = word32BE (W32# (int2Word# i))+int32BE (I32# i) = word32BE (W32# (C.wordToWord32# (int2Word# (C.int32ToInt# i)))) int16BE :: Int16 -> Builder 2-int16BE (I16# i) = word16BE (W16# (int2Word# i))+int16BE (I16# i) = word16BE (W16# (C.wordToWord16# (int2Word# (C.int16ToInt# i)))) int64LE :: Int64 -> Builder 8 int64LE (I64# i) = word64LE (W64# (int2Word# i)) int32LE :: Int32 -> Builder 4-int32LE (I32# i) = word32LE (W32# (int2Word# i))+int32LE (I32# i) = word32LE (W32# (C.wordToWord32# (int2Word# (C.int32ToInt# i)))) int16LE :: Int16 -> Builder 2-int16LE (I16# i) = word16LE (W16# (int2Word# i))+int16LE (I16# i) = word16LE (W16# (C.wordToWord16# (int2Word# (C.int16ToInt# i)))) word128LE :: Word128 -> Builder 16 word128LE (Word128 hi lo) = append (word64LE lo) (word64LE hi)@@ -1072,7 +1077,7 @@ approxDiv10 !n = unsafeShiftR (0x1999999A * n) 32 unsafeWordToWord8 :: Word -> Word8-unsafeWordToWord8 (W# w) = W8# w+unsafeWordToWord8 (W# w) = W8# (C.wordToWord8# w) foreign import ccall unsafe "bytebuild_paste_double" c_paste_double :: MutableByteArray# s -> Int# -> Double# -> IO Int
src/Data/Bytes/Builder/Unsafe.hs view
@@ -47,6 +47,8 @@ import GHC.ST (ST(ST)) import GHC.IO (stToIO) +import qualified Compat as C+ import qualified Data.Bytes.Builder.Bounded as Bounded import qualified Data.Bytes.Builder.Bounded.Unsafe as UnsafeBounded import qualified Data.Primitive as PM@@ -246,16 +248,16 @@ goCString :: Addr# -> MutableByteArray# s -> Int# -> Int# -> Commits s -> State# s -> (# State# s, MutableByteArray# s, Int#, Int#, Commits s #)-goCString addr buf0 off0 len0 cs0 s0 = case Exts.indexWord8OffAddr# addr 0# of+goCString addr buf0 off0 len0 cs0 s0 = case C.word8ToWord# (Exts.indexWord8OffAddr# addr 0#) of 0## -> (# s0, buf0, off0, len0, cs0 #) w -> case len0 of 0# -> case Exts.newByteArray# 4080# s0 of- (# s1, buf1 #) -> case Exts.writeWord8Array# buf1 0# w s1 of+ (# s1, buf1 #) -> case Exts.writeWord8Array# buf1 0# (C.wordToWord8# w) s1 of s2 -> goCString (Exts.plusAddr# addr 1# ) buf1 1# (4080# -# 1# ) (Mutable buf0 off0 cs0) s2- _ -> case Exts.writeWord8Array# buf0 off0 w s0 of+ _ -> case Exts.writeWord8Array# buf0 off0 (C.wordToWord8# w) s0 of s1 -> goCString (Exts.plusAddr# addr 1# ) buf0 (off0 +# 1# ) (len0 -# 1# ) cs0 s1 fromEffect ::
test/Main.hs view
@@ -255,6 +255,16 @@ runConcat 1 (naturalDec y) === pack (show y)+ , testGroup "leb128-encoding"+ [ THU.testCase "16" $+ Chunks.concat (run 16 (word64LEB128 16))+ @=?+ Latin1.fromString "\x10"+ , THU.testCase "deadbeef-smile" $ do+ let inp = Latin1.fromString "\xDE\xAD\xBE\xEF"+ (Chunks.concat . run 16) (sevenEightSmile inp)+ @=?Latin1.fromString "\x6F\x2B\x37\x6E\x0F"+ ] , testGroup "seven/eight encoding" [ THU.testCase "deadbeef" $ do let inp = Latin1.fromString "\xDE\xAD\xBE\xEF"