packages feed

mason 0.2.2 → 0.2.3

raw patch · 5 files changed

+118/−20 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Mason.Builder.Internal: StreamingEnv :: !ByteString -> IO () -> !IORef (ForeignPtr Word8) -> StreamingEnv
- Mason.Builder.Internal: data StreamingEnv
- Mason.Builder.Internal: instance Mason.Builder.Internal.Buildable Mason.Builder.Internal.StreamingEnv
+ Mason.Builder: data StreamingBackend
+ Mason.Builder: intDecPadded :: Int -> Int -> Builder
+ Mason.Builder: type BufferedIOBackend = PutEnv
+ Mason.Builder: type LazyByteStringBackend = Channel
+ Mason.Builder: type StrictByteStringBackend = GrowingBuffer
+ Mason.Builder.Internal: StreamingBackend :: !ByteString -> IO () -> !IORef (ForeignPtr Word8) -> StreamingBackend
+ Mason.Builder.Internal: data StreamingBackend
+ Mason.Builder.Internal: instance Mason.Builder.Internal.Buildable Mason.Builder.Internal.StreamingBackend
+ Mason.Builder.Internal: type BufferedIOBackend = PutEnv
+ Mason.Builder.Internal: type LazyByteStringBackend = Channel
+ Mason.Builder.Internal: type StrictByteStringBackend = GrowingBuffer
- Mason.Builder: hPutBuilderLen :: Handle -> BuilderFor PutEnv -> IO Int
+ Mason.Builder: hPutBuilderLen :: Handle -> BuilderFor BufferedIOBackend -> IO Int
- Mason.Builder: sendBuilder :: Socket -> BuilderFor PutEnv -> IO Int
+ Mason.Builder: sendBuilder :: Socket -> BuilderFor BufferedIOBackend -> IO Int
- Mason.Builder: toLazyByteString :: BuilderFor Channel -> ByteString
+ Mason.Builder: toLazyByteString :: BuilderFor LazyByteStringBackend -> ByteString
- Mason.Builder: toStreamingBody :: BuilderFor StreamingEnv -> (Builder -> IO ()) -> IO () -> IO ()
+ Mason.Builder: toStreamingBody :: BuilderFor StreamingBackend -> (Builder -> IO ()) -> IO () -> IO ()
- Mason.Builder: toStrictByteString :: BuilderFor GrowingBuffer -> ByteString
+ Mason.Builder: toStrictByteString :: BuilderFor StrictByteStringBackend -> ByteString
- Mason.Builder: withPopper :: BuilderFor Channel -> (IO ByteString -> IO a) -> IO a
+ Mason.Builder: withPopper :: BuilderFor LazyByteStringBackend -> (IO ByteString -> IO a) -> IO a
- Mason.Builder.Internal: [seBuffer] :: StreamingEnv -> !IORef (ForeignPtr Word8)
+ Mason.Builder.Internal: [seBuffer] :: StreamingBackend -> !IORef (ForeignPtr Word8)
- Mason.Builder.Internal: [sePush] :: StreamingEnv -> !ByteString -> IO ()
+ Mason.Builder.Internal: [sePush] :: StreamingBackend -> !ByteString -> IO ()
- Mason.Builder.Internal: hPutBuilderLen :: Handle -> BuilderFor PutEnv -> IO Int
+ Mason.Builder.Internal: hPutBuilderLen :: Handle -> BuilderFor BufferedIOBackend -> IO Int
- Mason.Builder.Internal: sendBuilder :: Socket -> BuilderFor PutEnv -> IO Int
+ Mason.Builder.Internal: sendBuilder :: Socket -> BuilderFor BufferedIOBackend -> IO Int
- Mason.Builder.Internal: toLazyByteString :: BuilderFor Channel -> ByteString
+ Mason.Builder.Internal: toLazyByteString :: BuilderFor LazyByteStringBackend -> ByteString
- Mason.Builder.Internal: toStreamingBody :: BuilderFor StreamingEnv -> (Builder -> IO ()) -> IO () -> IO ()
+ Mason.Builder.Internal: toStreamingBody :: BuilderFor StreamingBackend -> (Builder -> IO ()) -> IO () -> IO ()
- Mason.Builder.Internal: toStrictByteString :: BuilderFor GrowingBuffer -> ByteString
+ Mason.Builder.Internal: toStrictByteString :: BuilderFor StrictByteStringBackend -> ByteString
- Mason.Builder.Internal: withPopper :: BuilderFor Channel -> (IO ByteString -> IO a) -> IO a
+ Mason.Builder.Internal: withPopper :: BuilderFor LazyByteStringBackend -> (IO ByteString -> IO a) -> IO a

Files

CHANGELOG.md view
@@ -1,4 +1,7 @@-# Revision history for mason+## 0.2.3++* Added `intDecPadded`+* Exported backend types: `StrictByteStringBackend`, `LazyByteStringBackend` and `BufferedIOBackend`  ## 0.2.2 
README.md view
@@ -15,11 +15,13 @@ * `toStrictByteString` produces a strict `ByteString` directly. * `hPutBuilderLen` writes a builder to a handle and returns the number of bytes. * `sendBuilder` sends the content of `Builder` over a socket.+* `withPopper` turns a builder into http-client's[GivesPopper](http://hackage.haskell.org/package/http-client-0.7.2.1/docs/Network-HTTP-Client.html#t:GivesPopper)+* `toStreamingBody` creates wai's [StreamingBody](http://hackage.haskell.org/package/wai-3.2.2.1/docs/Network-Wai.html#t:StreamingBody)  Usage ---- -Replace `Data.ByteString.Builder` with `Mason.Builder`. Note that if you have `Builder` in the type signature, you'll need `RankNTypes` extensions because of the design explained below.+Replace `Data.ByteString.Builder` with `Mason.Builder`. Note that if you have `Builder` in the type signature, you'll need `RankNTypes` extensions because of the design explained below. Alternatively, you can also import `Mason.Builder.Compat` which has an API almost compatible with `Data.ByteString.Builder`.  Performance ----@@ -63,7 +65,83 @@ bytestring/double                        mean 2.312 μs  ( +- 118.8 ns  ) ``` -TBD: more benchmarks+You can find more benchmarks below:++* [bytes-builder-shootout](https://github.com/andrewthad/bytes-builder-shootout)++<details>+<summary>Click to expand</summary>+<pre>+treeToHex-2000/small-bytearray-builder   mean 44.01 μs  ( +- 1.620 μs  )+treeToHex-2000/fast-builder              mean 34.40 μs  ( +- 390.1 ns  )+treeToHex-2000/bytestring                mean 58.76 μs  ( +- 3.843 μs  )+treeToHex-2000/mason                     mean 41.08 μs  ( +- 180.8 ns  )+treeToHex-9000/small-bytearray-builder   mean 191.8 μs  ( +- 1.835 μs  )+treeToHex-9000/bytestring                mean 284.8 μs  ( +- 1.156 μs  )+treeToHex-9000/mason                     mean 181.2 μs  ( +- 386.3 ns  )+short-text-tree-1000/small-bytearray-builder mean 26.54 μs  ( +- 34.08 ns  )+short-text-tree-1000/fast-builder        mean 37.51 μs  ( +- 99.85 ns  )+short-text-tree-1000/bytestring          mean 37.95 μs  ( +- 167.5 ns  )+short-text-tree-1000/mason               mean 26.87 μs  ( +- 312.4 ns  )+byte-tree-2000/small-bytearray-builder   mean 30.53 μs  ( +- 51.53 ns  )+byte-tree-2000/fast-builder              mean 26.91 μs  ( +- 592.2 ns  )+byte-tree-2000/bytestring                mean 54.40 μs  ( +- 1.743 μs  )+byte-tree-2000/mason                     mean 34.34 μs  ( +- 193.5 ns  )+</pre>+</details>++* [haskell-perf/strict-bytestring-builder](https://github.com/haskell-perf/strict-bytestring-builders)++<details>+<summary>Click to expand</summary>+<pre>+averagedAppends-1/byteStringStrictBuilder mean 116.3 ns  ( +- 6.479 ns  )+averagedAppends-1/byteStringTreeBuilder  mean 181.7 ns  ( +- 20.88 ns  )+averagedAppends-1/fastBuilder            mean 181.5 ns  ( +- 7.219 ns  )+averagedAppends-1/bufferBuilder          mean 728.5 ns  ( +- 9.114 ns  )+averagedAppends-1/byteString             mean 358.7 ns  ( +- 4.663 ns  )+averagedAppends-1/blazeBuilder           mean 356.0 ns  ( +- 7.604 ns  )+averagedAppends-1/binary                 mean 635.0 ns  ( +- 7.936 ns  )+averagedAppends-1/cereal                 mean 638.6 ns  ( +- 12.40 ns  )+averagedAppends-1/mason                  mean 155.2 ns  ( +- 2.000 ns  )+averagedAppends-100/byteStringStrictBuilder mean 7.290 μs  ( +- 99.74 ns  )+averagedAppends-100/byteStringTreeBuilder mean 13.40 μs  ( +- 283.4 ns  )+averagedAppends-100/fastBuilder          mean 13.07 μs  ( +- 418.2 ns  )+averagedAppends-100/bufferBuilder        mean 19.57 μs  ( +- 5.644 μs  )+averagedAppends-100/byteString           mean 17.31 μs  ( +- 1.609 μs  )+averagedAppends-100/blazeBuilder         mean 19.15 μs  ( +- 6.533 μs  )+averagedAppends-100/binary               mean 48.26 μs  ( +- 727.1 ns  )+averagedAppends-100/cereal               mean 51.57 μs  ( +- 21.81 μs  )+averagedAppends-100/mason                mean 12.07 μs  ( +- 233.8 ns  )+averagedAppends-10000/byteStringStrictBuilder mean 1.038 ms  ( +- 18.63 μs  )+averagedAppends-10000/byteStringTreeBuilder mean 1.989 ms  ( +- 70.63 μs  )+averagedAppends-10000/fastBuilder        mean 1.611 ms  ( +- 42.24 μs  )+averagedAppends-10000/bufferBuilder      mean 1.895 ms  ( +- 25.09 μs  )+averagedAppends-10000/byteString         mean 2.248 ms  ( +- 40.99 μs  )+averagedAppends-10000/blazeBuilder       mean 2.394 ms  ( +- 1.016 ms  )+averagedAppends-10000/binary             mean 6.503 ms  ( +- 157.6 μs  )+averagedAppends-10000/cereal             mean 6.458 ms  ( +- 221.6 μs  )+averagedAppends-10000/mason              mean 1.738 ms  ( +- 25.89 μs  )+regularConcat-100/byteStringStrictBuilder mean 1.606 μs  ( +- 32.93 ns  )+regularConcat-100/byteStringTreeBuilder  mean 2.000 μs  ( +- 43.73 ns  )+regularConcat-100/fastBuilder            mean 1.364 μs  ( +- 37.95 ns  )+regularConcat-100/bufferBuilder          mean 2.204 μs  ( +- 48.40 ns  )+regularConcat-100/byteString             mean 1.253 μs  ( +- 25.68 ns  )+regularConcat-100/blazeBuilder           mean 1.317 μs  ( +- 24.05 ns  )+regularConcat-100/binary                 mean 2.845 μs  ( +- 62.24 ns  )+regularConcat-100/cereal                 mean 3.021 μs  ( +- 48.53 ns  )+regularConcat-100/mason                  mean 1.405 μs  ( +- 35.11 ns  )+regularConcat-10000/byteStringStrictBuilder mean 321.3 μs  ( +- 11.13 μs  )+regularConcat-10000/byteStringTreeBuilder mean 349.1 μs  ( +- 4.359 μs  )+regularConcat-10000/fastBuilder          mean 121.0 μs  ( +- 1.755 μs  )+regularConcat-10000/bufferBuilder        mean 156.1 μs  ( +- 2.050 μs  )+regularConcat-10000/byteString           mean 106.6 μs  ( +- 1.355 μs  )+regularConcat-10000/blazeBuilder         mean 110.8 μs  ( +- 1.397 μs  )+regularConcat-10000/binary               mean 308.1 μs  ( +- 5.346 μs  )+regularConcat-10000/cereal               mean 352.0 μs  ( +- 6.142 μs  )+regularConcat-10000/mason                mean 130.2 μs  ( +- 10.39 μs  )+</pre>+</details>  Architecture ----
mason.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.4  name:                mason-version:             0.2.2+version:             0.2.3 synopsis:            Fast and extensible bytestring builder description:   This package provides efficient implementation of bytestring builders.
src/Mason/Builder.hs view
@@ -16,12 +16,16 @@   , BuilderFor   , Buildable   -- * Runners+  , StrictByteStringBackend   , toStrictByteString+  , LazyByteStringBackend   , toLazyByteString+  , BufferedIOBackend   , hPutBuilderLen   , hPutBuilder   , sendBuilder   , withPopper+  , StreamingBackend   , toStreamingBody   -- * Primitives   , flush@@ -75,6 +79,7 @@   , int32Dec   , int64Dec   , intDec+  , intDecPadded   , integerDec   , word8Hex   , word16Hex@@ -481,7 +486,10 @@ intDec :: Int -> Builder intDec = B.primBounded P.intDec -+-- | 'intDec' with 0 padding+intDecPadded :: Int -> Int -> Builder+intDecPadded n = zeroPaddedBoundedPrim n P.intDec+{-# INLINE intDecPadded #-}  ------------------------------------------------------------------------------ -- Hexadecimal Encoding@@ -615,7 +623,7 @@     go n | n < maxPow10 = intDec (fromInteger n)          | otherwise    =              case putH (splitf (maxPow10 * maxPow10) n) of-               (x:xs) -> intDec x `mappend` B.primMapListBounded intDecPadded xs+               (x:xs) -> intDec x `mappend` B.primMapListBounded intDecPadded18 xs                []     -> errImpossible "integerDec: go"      splitf :: Integer -> Integer -> [Integer]@@ -653,9 +661,9 @@ foreign import ccall unsafe "static _hs_bytestring_long_long_int_dec_padded18"     c_long_long_int_dec_padded18 :: CLLong -> Ptr Word8 -> IO () -{-# INLINE intDecPadded #-}-intDecPadded :: P.BoundedPrim Int-intDecPadded = P.liftFixedToBounded $ caseWordSize_32_64+{-# INLINE intDecPadded18 #-}+intDecPadded18 :: P.BoundedPrim Int+intDecPadded18 = P.liftFixedToBounded $ caseWordSize_32_64     (P.fixedPrim  9 $ c_int_dec_padded9            . fromIntegral)     (P.fixedPrim 18 $ c_long_long_int_dec_padded18 . fromIntegral) 
src/Mason/Builder/Internal.hs view
@@ -16,11 +16,13 @@   , unBuilder   , byteStringCopy   , shortByteString+  , StrictByteStringBackend   , toStrictByteString   , Channel(..)+  , LazyByteStringBackend   , toLazyByteString   , withPopper-  , StreamingEnv(..)+  , StreamingBackend(..)   , toStreamingBody   , stringUtf8   , lengthPrefixedWithin@@ -31,6 +33,7 @@   , primMapByteStringFixed   , primMapLazyByteStringFixed   , PutEnv(..)+  , BufferedIOBackend   , hPutBuilderLen   , encodeUtf8BuilderEscaped   , sendBuilder@@ -305,8 +308,10 @@     return $ Buffer (dst' `plusPtr` size') (dst' `plusPtr` pos)   {-# INLINE allocate #-} +type StrictByteStringBackend = GrowingBuffer+ -- | Create a strict 'B.ByteString'-toStrictByteString :: BuilderFor GrowingBuffer -> B.ByteString+toStrictByteString :: BuilderFor StrictByteStringBackend -> B.ByteString toStrictByteString b = unsafePerformIO $ do   fptr0 <- mallocForeignPtrBytes initialSize   bufferRef <- newIORef fptr0@@ -341,8 +346,10 @@   allocate = allocateConstant chBuffer   {-# INLINE allocate #-} +type LazyByteStringBackend = Channel+ -- | Create a lazy 'BL.ByteString'. Threaded runtime is required.-toLazyByteString :: BuilderFor Channel -> BL.ByteString+toLazyByteString :: BuilderFor LazyByteStringBackend -> BL.ByteString toLazyByteString body = unsafePerformIO $ withPopper body $ \pop -> do   let go _ = unsafePerformIO $ do         bs <- pop@@ -353,7 +360,7 @@ {-# INLINE toLazyByteString #-}  -- | Use 'Builder' as a <http://hackage.haskell.org/package/http-client-0.7.1/docs/Network-HTTP-Client.html#t:GivesPopper GivesPopper'-withPopper :: BuilderFor Channel -> (IO B.ByteString -> IO a) -> IO a+withPopper :: BuilderFor LazyByteStringBackend -> (IO B.ByteString -> IO a) -> IO a withPopper body cont = do   resp <- newEmptyMVar @@ -410,10 +417,12 @@   allocate = allocateConstant peBuffer   {-# INLINE allocate #-} +type BufferedIOBackend = PutEnv+ -- | Write a 'Builder' into a handle and obtain the number of bytes written. -- 'flush' does not imply actual disk operations. Set 'NoBuffering' if you want -- it to write the content immediately.-hPutBuilderLen :: Handle -> BuilderFor PutEnv -> IO Int+hPutBuilderLen :: Handle -> BuilderFor BufferedIOBackend -> IO Int hPutBuilderLen h b = do   let initialSize = 4096   fptr <- mallocForeignPtrBytes initialSize@@ -436,7 +445,7 @@       when (sent > 0) $ go $ p `plusPtr` sent  -- | Write a 'Builder' into a handle and obtain the number of bytes written.-sendBuilder :: S.Socket -> BuilderFor PutEnv -> IO Int+sendBuilder :: S.Socket -> BuilderFor BufferedIOBackend -> IO Int sendBuilder sock b = do   let initialSize = 4096   fptr <- mallocForeignPtrBytes initialSize@@ -542,17 +551,17 @@ foreign import ccall unsafe "static grisu3"   c_grisu3 :: CDouble -> Ptr Word8 -> Ptr CInt -> Ptr CInt -> IO CInt -data StreamingEnv = StreamingEnv+data StreamingBackend = StreamingBackend   { sePush :: !(B.ByteString -> IO ())   , seBuffer :: !(IORef (ForeignPtr Word8))   } -instance Buildable StreamingEnv where+instance Buildable StreamingBackend where   byteString bs     | B.length bs < 4096 = byteStringCopy bs     | otherwise = flush <> Builder (\env b -> b <$ sePush env bs)   {-# INLINE byteString #-}-  flush = Builder $ \(StreamingEnv push ref) (Buffer end ptr) -> do+  flush = Builder $ \(StreamingBackend push ref) (Buffer end ptr) -> do     ptr0 <- unsafeForeignPtrToPtr <$> readIORef ref     let len = minusPtr ptr ptr0     when (len > 0) $ push $! B.unsafeCreate len $ \dst -> B.memcpy dst ptr0 len@@ -562,14 +571,14 @@   {-# INLINE allocate #-}  -- | Convert a 'Builder' into a <http://hackage.haskell.org/package/wai-3.2.2.1/docs/Network-Wai.html#t:StreamingBody StreamingBody>.-toStreamingBody :: BuilderFor StreamingEnv -> (BB.Builder -> IO ()) -> IO () -> IO ()+toStreamingBody :: BuilderFor StreamingBackend -> (BB.Builder -> IO ()) -> IO () -> IO () toStreamingBody body = \write _ -> do   let initialSize = 4080   fptr <- mallocForeignPtrBytes initialSize   ref <- newIORef fptr   let ptr = unsafeForeignPtrToPtr fptr   Buffer _ ptr2 <- unBuilder body-    (StreamingEnv (write . BB.byteString) ref)+    (StreamingBackend (write . BB.byteString) ref)     (Buffer (ptr `plusPtr` initialSize) ptr)   fptr' <- readIORef ref   let ptr1 = unsafeForeignPtrToPtr fptr'