module Data.Text.Builder.Variable
( Builder
, run
, contramap
, charBmp
, staticCharBmp
, word8
) where
import Data.Word
import Data.Text (Text)
import Control.Monad.ST
import Data.Char (ord)
import Data.Vector (Vector)
import Data.Maybe (fromMaybe)
import qualified Data.Vector as Vector
import qualified Data.Text.Array as A
import qualified Data.Text.Builder.Common.Internal as I
import qualified Data.Text.Internal as TI
data Builder a
= Builder
!Int
!(forall s. Int -> A.MArray s -> a -> ST s Int)
instance Monoid (Builder a) where
mempty = Builder 0 (\i _ _ -> return i)
mappend (Builder len1 f) (Builder len2 g) =
Builder (len1 + len2) $ \ix1 marr a -> do
ix2 <- f ix1 marr a
g ix2 marr a
run :: Builder a -> a -> Text
run (Builder maxLen f) = \a ->
let (outArr,len) = A.run2 $ do
marr <- A.new maxLen
finalIx <- f 0 marr a
return (marr,finalIx)
in TI.text outArr 0 len
contramap :: (b -> a) -> Builder a -> Builder b
contramap f (Builder len g) = Builder len $ \i marr b ->
g i marr (f b)
charBmp :: Builder Char
charBmp = Builder 1 $ \i marr c -> do
A.unsafeWrite marr i (fromIntegral (ord c))
return (i + 1)
staticCharBmp :: Char -> Builder a
staticCharBmp c = Builder 1 $ \i marr _ -> do
A.unsafeWrite marr i (fromIntegral (ord c))
return (i + 1)
word8 :: Builder Word8
word8 = Builder 3 $ \pos marr w -> if
| w < 10 -> do
A.unsafeWrite marr pos (i2w w)
return (pos + 1)
| w < 100 -> do
let wInt = fromIntegral w
ix = wInt + wInt
A.unsafeWrite marr pos (A.unsafeIndex I.twoDecimalDigits ix)
A.unsafeWrite marr (pos + 1) (A.unsafeIndex I.twoDecimalDigits (ix + 1))
return (pos + 2)
| otherwise -> do
let wInt = fromIntegral w
ix = wInt + wInt + wInt
A.unsafeWrite marr pos (A.unsafeIndex I.threeDecimalDigits ix)
A.unsafeWrite marr (pos + 1) (A.unsafeIndex I.threeDecimalDigits (ix + 1))
A.unsafeWrite marr (pos + 2) (A.unsafeIndex I.threeDecimalDigits (ix + 2))
return (pos + 3)
_vector ::
Text
-> Vector Text
-> Builder Int
_vector tDef v =
let xs = Vector.map I.portableUntext v
xDef = I.portableUntext tDef
in Builder
(Vector.maximum $ Vector.map I.portableTextLength $ Vector.cons tDef v)
$ \_ marr i -> do
let (arr,len) = fromMaybe xDef (xs Vector.!? i)
finalIx = i + len
A.copyI marr i arr 0 finalIx
return finalIx
i2w :: Integral a => a -> Word16
i2w v = asciiZero + fromIntegral v
asciiZero :: Word16
asciiZero = 48