module ByteString.StrictBuilder
(
Builder,
builderBytes,
builderChunksBuilder,
builderLength,
builderPtrFiller,
bytes,
lazyBytes,
asciiIntegral,
asciiChar,
utf8Char,
storable,
word8,
word16BE,
word32BE,
word64BE,
int8,
int16BE,
int32BE,
int64BE,
)
where
import ByteString.StrictBuilder.Prelude
import qualified ByteString.StrictBuilder.Population as A
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as C
import qualified Data.ByteString.Lazy as F
import qualified Data.ByteString.Builder.Internal as G
import qualified ByteString.StrictBuilder.UTF8 as E
data Builder =
Builder !Int !A.Population
instance Monoid Builder where
{-# INLINE mempty #-}
mempty =
Builder 0 mempty
{-# INLINE mappend #-}
mappend (Builder leftSize leftPopulation) (Builder rightSize rightPopulation) =
Builder (leftSize + rightSize) (leftPopulation <> rightPopulation)
{-# INLINE mconcat #-}
mconcat builders =
Builder size population
where
size =
foldl' (\acc (Builder x _) -> acc + x) 0 builders
population =
foldMap (\(Builder _ x) -> x) builders
instance Semigroup Builder where
(<>) = mappend
instance IsString Builder where
fromString =
bytes . fromString
instance Show Builder where
show =
show . builderBytes
{-# INLINE builderBytes #-}
builderBytes :: Builder -> ByteString
builderBytes (Builder size population) =
C.unsafeCreate size $ \ptr -> A.populationPtrUpdate population ptr $> ()
{-# INLINE builderChunksBuilder #-}
builderChunksBuilder :: Builder -> G.Builder
builderChunksBuilder (Builder size population) =
G.ensureFree size <> A.populationChunksBuilder population
{-# INLINE builderLength #-}
builderLength :: Builder -> Int
builderLength (Builder size population) =
size
{-# INLINE builderPtrFiller #-}
builderPtrFiller ::
Builder ->
(Int -> (Ptr Word8 -> IO ()) -> result) -> result
builderPtrFiller (Builder size (A.Population ptrUpdate)) cont =
cont size (void . ptrUpdate)
{-# INLINE bytes #-}
bytes :: ByteString -> Builder
bytes bytes =
Builder (B.length bytes) (A.bytes bytes)
{-# INLINE lazyBytes #-}
lazyBytes :: F.ByteString -> Builder
lazyBytes =
F.foldlChunks (\builder -> mappend builder . bytes) mempty
{-# INLINE byte #-}
byte :: Word8 -> Builder
byte =
word8
{-# INLINABLE asciiIntegral #-}
asciiIntegral :: Integral a => a -> Builder
asciiIntegral =
\case
0 ->
byte 48
x ->
bool ((<>) (byte 45)) id (x >= 0) $
loop mempty $
abs x
where
loop builder remainder =
case remainder of
0 ->
builder
_ ->
case quotRem remainder 10 of
(quot, rem) ->
loop (byte (48 + fromIntegral rem) <> builder) quot
{-# INLINE asciiChar #-}
asciiChar :: Char -> Builder
asciiChar =
byte . fromIntegral . ord
{-# INLINE CONLIKE storable #-}
storable :: Storable a => a -> Builder
storable value =
Builder size (A.storable size value)
where
size =
sizeOf value
{-# INLINE word8 #-}
word8 :: Word8 -> Builder
word8 =
Builder 1 . A.word8
{-# INLINE word16BE #-}
word16BE :: Word16 -> Builder
word16BE =
Builder 2 . A.word16BE
{-# INLINE word32BE #-}
word32BE :: Word32 -> Builder
word32BE =
Builder 4 . A.word32BE
{-# INLINE word64BE #-}
word64BE :: Word64 -> Builder
word64BE =
Builder 8 . A.word64BE
{-# INLINE int8 #-}
int8 :: Int8 -> Builder
int8 =
Builder 1 . A.int8
{-# INLINE int16BE #-}
int16BE :: Int16 -> Builder
int16BE =
Builder 2 . A.int16BE
{-# INLINE int32BE #-}
int32BE :: Int32 -> Builder
int32BE =
Builder 4 . A.int32BE
{-# INLINE int64BE #-}
int64BE :: Int64 -> Builder
int64BE =
Builder 8 . A.int64BE
{-# INLINE utf8Char #-}
utf8Char :: Char -> Builder
utf8Char x =
E.char x bytes_1 bytes_2 bytes_3 bytes_4
{-# INLINE bytes_1 #-}
bytes_1 :: Word8 -> Builder
bytes_1 b1 =
Builder 1 (A.bytes_1 b1)
{-# INLINE bytes_2 #-}
bytes_2 :: Word8 -> Word8 -> Builder
bytes_2 b1 b2 =
Builder 2 (A.bytes_2 b1 b2)
{-# INLINE bytes_3 #-}
bytes_3 :: Word8 -> Word8 -> Word8 -> Builder
bytes_3 b1 b2 b3 =
Builder 3 (A.bytes_3 b1 b2 b3)
{-# INLINE bytes_4 #-}
bytes_4 :: Word8 -> Word8 -> Word8 -> Word8 -> Builder
bytes_4 b1 b2 b3 b4 =
Builder 4 (A.bytes_4 b1 b2 b3 b4)