{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE Rank2Types #-}
module Data.Streaming.ByteString.Builder.Buffer
(
Buffer (..)
, freeSize
, sliceSize
, bufferSize
, allocBuffer
, reuseBuffer
, nextSlice
, updateEndOfSlice
, unsafeFreezeBuffer
, unsafeFreezeNonEmptyBuffer
, BufferAllocStrategy
, allNewBuffersStrategy
, reuseBufferStrategy
, defaultStrategy
) where
import Data.ByteString.Lazy.Internal (defaultChunkSize)
import qualified Data.ByteString as S
import qualified Data.ByteString.Internal as S
import Foreign (Word8, ForeignPtr, Ptr, plusPtr, minusPtr)
import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
data Buffer = Buffer {-# UNPACK #-} !(ForeignPtr Word8)
{-# UNPACK #-} !(Ptr Word8)
{-# UNPACK #-} !(Ptr Word8)
{-# UNPACK #-} !(Ptr Word8)
freeSize :: Buffer -> Int
freeSize :: Buffer -> Int
freeSize (Buffer ForeignPtr Word8
_ Ptr Word8
_ Ptr Word8
op Ptr Word8
ope) = Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr Word8
op
sliceSize :: Buffer -> Int
sliceSize :: Buffer -> Int
sliceSize (Buffer ForeignPtr Word8
_ Ptr Word8
p0 Ptr Word8
op Ptr Word8
_) = Ptr Word8
op Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr Word8
p0
bufferSize :: Buffer -> Int
bufferSize :: Buffer -> Int
bufferSize (Buffer ForeignPtr Word8
fpbuf Ptr Word8
_ Ptr Word8
_ Ptr Word8
ope) =
Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr Word8
fpbuf
{-# INLINE allocBuffer #-}
allocBuffer :: Int -> IO Buffer
allocBuffer :: Int -> IO Buffer
allocBuffer Int
size = do
ForeignPtr Word8
fpbuf <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
S.mallocByteString Int
size
let !pbuf :: Ptr Word8
pbuf = ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr Word8
fpbuf
Buffer -> IO Buffer
forall (m :: * -> *) a. Monad m => a -> m a
return (Buffer -> IO Buffer) -> Buffer -> IO Buffer
forall a b. (a -> b) -> a -> b
$! ForeignPtr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Buffer
Buffer ForeignPtr Word8
fpbuf Ptr Word8
pbuf Ptr Word8
pbuf (Ptr Word8
pbuf Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
size)
{-# INLINE reuseBuffer #-}
reuseBuffer :: Buffer -> Buffer
reuseBuffer :: Buffer -> Buffer
reuseBuffer (Buffer ForeignPtr Word8
fpbuf Ptr Word8
_ Ptr Word8
_ Ptr Word8
ope) = ForeignPtr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Buffer
Buffer ForeignPtr Word8
fpbuf Ptr Word8
p0 Ptr Word8
p0 Ptr Word8
ope
where
p0 :: Ptr Word8
p0 = ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr Word8
fpbuf
{-# INLINE unsafeFreezeBuffer #-}
unsafeFreezeBuffer :: Buffer -> S.ByteString
unsafeFreezeBuffer :: Buffer -> ByteString
unsafeFreezeBuffer (Buffer ForeignPtr Word8
fpbuf Ptr Word8
p0 Ptr Word8
op Ptr Word8
_) =
ForeignPtr Word8 -> Int -> Int -> ByteString
S.PS ForeignPtr Word8
fpbuf (Ptr Word8
p0 Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr Word8
fpbuf) (Ptr Word8
op Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr Word8
p0)
{-# INLINE unsafeFreezeNonEmptyBuffer #-}
unsafeFreezeNonEmptyBuffer :: Buffer -> Maybe S.ByteString
unsafeFreezeNonEmptyBuffer :: Buffer -> Maybe ByteString
unsafeFreezeNonEmptyBuffer Buffer
buf
| Buffer -> Int
sliceSize Buffer
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = Maybe ByteString
forall a. Maybe a
Nothing
| Bool
otherwise = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Buffer -> ByteString
unsafeFreezeBuffer Buffer
buf
{-# INLINE updateEndOfSlice #-}
updateEndOfSlice :: Buffer
-> Ptr Word8
-> Buffer
updateEndOfSlice :: Buffer -> Ptr Word8 -> Buffer
updateEndOfSlice (Buffer ForeignPtr Word8
fpbuf Ptr Word8
p0 Ptr Word8
_ Ptr Word8
ope) Ptr Word8
op' = ForeignPtr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Buffer
Buffer ForeignPtr Word8
fpbuf Ptr Word8
p0 Ptr Word8
op' Ptr Word8
ope
{-# INLINE nextSlice #-}
nextSlice :: Int -> Buffer -> Maybe Buffer
nextSlice :: Int -> Buffer -> Maybe Buffer
nextSlice Int
minSize (Buffer ForeignPtr Word8
fpbuf Ptr Word8
_ Ptr Word8
op Ptr Word8
ope)
| Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr Word8
op Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
minSize = Maybe Buffer
forall a. Maybe a
Nothing
| Bool
otherwise = Buffer -> Maybe Buffer
forall a. a -> Maybe a
Just (ForeignPtr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Buffer
Buffer ForeignPtr Word8
fpbuf Ptr Word8
op Ptr Word8
op Ptr Word8
ope)
type BufferAllocStrategy = (IO Buffer, Int -> Buffer -> IO (IO Buffer))
allNewBuffersStrategy :: Int
-> BufferAllocStrategy
Int
bufSize =
( Int -> IO Buffer
allocBuffer Int
bufSize
, \Int
reqSize Buffer
_ -> IO Buffer -> IO (IO Buffer)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> IO Buffer
allocBuffer (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
reqSize Int
bufSize)) )
reuseBufferStrategy :: IO Buffer
-> BufferAllocStrategy
reuseBufferStrategy :: IO Buffer -> BufferAllocStrategy
reuseBufferStrategy IO Buffer
buf0 =
(IO Buffer
buf0, Int -> Buffer -> IO (IO Buffer)
forall (m :: * -> *). Monad m => Int -> Buffer -> m (IO Buffer)
tryReuseBuffer)
where
tryReuseBuffer :: Int -> Buffer -> m (IO Buffer)
tryReuseBuffer Int
reqSize Buffer
buf
| Buffer -> Int
bufferSize Buffer
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
reqSize = IO Buffer -> m (IO Buffer)
forall (m :: * -> *) a. Monad m => a -> m a
return (IO Buffer -> m (IO Buffer)) -> IO Buffer -> m (IO Buffer)
forall a b. (a -> b) -> a -> b
$ Buffer -> IO Buffer
forall (m :: * -> *) a. Monad m => a -> m a
return (Buffer -> Buffer
reuseBuffer Buffer
buf)
| Bool
otherwise = IO Buffer -> m (IO Buffer)
forall (m :: * -> *) a. Monad m => a -> m a
return (IO Buffer -> m (IO Buffer)) -> IO Buffer -> m (IO Buffer)
forall a b. (a -> b) -> a -> b
$ Int -> IO Buffer
allocBuffer Int
reqSize
defaultStrategy :: BufferAllocStrategy
defaultStrategy :: BufferAllocStrategy
defaultStrategy = Int -> BufferAllocStrategy
allNewBuffersStrategy Int
defaultChunkSize