fast-builder 0.1.0.2 → 0.1.1.0
raw patch · 4 files changed
+48/−12 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Data.ByteString.FastBuilder: hPutBuilderLen :: Handle -> Builder -> IO Int
+ Data.ByteString.FastBuilder.Internal: [queueBuffer] :: Queue -> !ForeignPtr Word8
+ Data.ByteString.FastBuilder.Internal: [queueStart] :: Queue -> !Int
+ Data.ByteString.FastBuilder.Internal: [queueTotal] :: Queue -> !Int
+ Data.ByteString.FastBuilder.Internal: hPutBuilderLen :: Handle -> Builder -> IO Int
- Data.ByteString.FastBuilder: hPutBuilderWith :: Handle -> Int -> Int -> Builder -> IO ()
+ Data.ByteString.FastBuilder: hPutBuilderWith :: Handle -> Int -> Int -> Builder -> IO Int
- Data.ByteString.FastBuilder.Internal: Queue :: !ForeignPtr Word8 -> !Int -> Queue
+ Data.ByteString.FastBuilder.Internal: Queue :: !ForeignPtr Word8 -> !Int -> !Int -> Queue
- Data.ByteString.FastBuilder.Internal: hPutBuilderWith :: Handle -> Int -> Int -> Builder -> IO ()
+ Data.ByteString.FastBuilder.Internal: hPutBuilderWith :: Handle -> Int -> Int -> Builder -> IO Int
Files
- Data/ByteString/FastBuilder.hs +1/−0
- Data/ByteString/FastBuilder/Internal.hs +38/−11
- fast-builder.cabal +1/−1
- tests/prop.hs +8/−0
Data/ByteString/FastBuilder.hs view
@@ -74,6 +74,7 @@ , toLazyByteStringWith , toStrictByteString , hPutBuilder+ , hPutBuilderLen , hPutBuilderWith -- * Performance tuning
Data/ByteString/FastBuilder/Internal.hs view
@@ -36,6 +36,7 @@ , toLazyByteStringWith , toStrictByteString , hPutBuilder+ , hPutBuilderLen , hPutBuilderWith -- * Basic builders@@ -152,8 +153,14 @@ -- size limit is reached. After that, the destination switches -- to a 'ThreadedSink'. --- | A mutable buffer. The 'Int' specifies where the data start.-data Queue = Queue !(ForeignPtr Word8) !Int{-start-}+-- | A mutable buffer.+data Queue = Queue+ { queueBuffer :: !(ForeignPtr Word8)+ , queueStart :: !Int+ -- ^ Starting position.+ , queueTotal :: !Int+ -- ^ Bytes written to the handle so far.+ } -- TODO: this is not really needed -- | A request from the driver thread to the builder thread.@@ -462,19 +469,30 @@ -- | Output a 'Builder' to a 'IO.Handle'. hPutBuilder :: IO.Handle -> Builder -> IO ()-hPutBuilder !h builder = hPutBuilderWith h 100 4096 builder+hPutBuilder !h builder = void $ hPutBuilderLen h builder+{-# INLINE hPutBuilder #-} +-- | Output a 'Builder' to a 'IO.Handle'. Returns the number of bytes written.+hPutBuilderLen :: IO.Handle -> Builder -> IO Int+hPutBuilderLen !h builder = hPutBuilderWith h 100 4096 builder+ -- | Like 'hPutBuffer', but allows the user to specify the initial -- and the subsequent desired buffer sizes. This function may be useful for -- setting large buffer when high throughput I/O is needed.-hPutBuilderWith :: IO.Handle -> Int -> Int -> Builder -> IO ()+hPutBuilderWith :: IO.Handle -> Int -> Int -> Builder -> IO Int hPutBuilderWith !h !initialCap !nextCap builder = do fptr <- mallocForeignPtrBytes initialCap- qRef <- newIORef $ Queue fptr 0+ qRef <- newIORef $ Queue+ { queueBuffer = fptr+ , queueStart = 0+ , queueTotal = 0+ } let !base = unsafeForeignPtrToPtr fptr cur <- runBuilder builder (HandleSink h nextCap qRef) base (base `plusPtr` initialCap) flushQueue h qRef cur+ Queue{ queueTotal = len } <- readIORef qRef+ return len ---------------------------------------------------------------- -- builders@@ -647,7 +665,7 @@ HandleSink h nextCap queueRef -> do cur <- getCur io $ flushQueue h queueRef cur- switchQueue queueRef $ max nextCap (I# n)+ switchQueue queueRef (max nextCap (I# n)) {-# NOINLINE getBytes_ #-} -- | Return the remaining size of the current buffer, in bytes.@@ -715,26 +733,35 @@ -- the 'Queue'. flushQueue :: IO.Handle -> IORef Queue -> Ptr Word8 -> IO () flushQueue !h !qRef !cur = do- Queue fptr start <- readIORef qRef+ Queue{ queueBuffer = fptr, queueStart = start, queueTotal = total }+ <- readIORef qRef let !end = cur `minusPtr` unsafeForeignPtrToPtr fptr when (end > start) $ do S.hPut h $ S.fromForeignPtr fptr start (end - start)- writeIORef qRef $ Queue fptr end+ writeIORef qRef Queue+ { queueBuffer = fptr+ , queueStart = end+ , queueTotal = total + end - start+ } --- | @switchQueue qRef minSize@ discards the old 'Queue' and sets up+-- | @switchQueue qRef minSize adv@ discards the old 'Queue' and sets up -- a new empty 'Queue' of at least @minSize@ large. If the old 'Queue' -- is large enough, it is re-used. switchQueue :: IORef Queue -> Int -> BuildM () switchQueue !qRef !minSize = do end <- getCur- Queue fptr _ <- io $ readIORef qRef+ Queue{ queueBuffer = fptr, queueTotal = total } <- io $ readIORef qRef let !base = unsafeForeignPtrToPtr fptr let !cap = end `minusPtr` base newFptr <- if minSize <= cap then return fptr else io $ mallocForeignPtrBytes minSize let !newBase = unsafeForeignPtrToPtr newFptr- io $ writeIORef qRef $ Queue newFptr 0+ io $ writeIORef qRef Queue+ { queueBuffer = newFptr+ , queueStart = 0+ , queueTotal = total+ } setCur newBase setEnd $ newBase `plusPtr` max minSize cap
fast-builder.cabal view
@@ -1,5 +1,5 @@ name: fast-builder-version: 0.1.0.2+version: 0.1.1.0 synopsis: Fast ByteString Builder description: An efficient implementation of ByteString builder. It should be faster than the standard implementation in most cases.
tests/prop.hs view
@@ -196,6 +196,14 @@ prop_writeWrite w0 w1 = toStrictByteString (word8 w0 <> word8 w1) == BS.pack [w0, w1] +-- | hPutBuilderLen returns the correct number of bytes.+prop_length :: BuilderTree -> QC.Property+prop_length tree = QC.ioProperty $ IO.withFile "/dev/null" IO.WriteMode $ \h -> do+ let b = mkBuilder tree+ let len = BS.length $ toStrictByteString b+ len' <- hPutBuilderLen h b+ return $ len QC.=== len'+ return [] main :: IO ()