module Data.Text.Builder.Variable
( Builder
, run
, contramap
, charBmp
, staticCharBmp
, word8
) where
import Data.Monoid
import Data.Word
import Data.Text (Text)
import Text.Printf (printf)
import Control.Monad.ST
import Data.Char (ord)
import Data.Vector (Vector)
import Data.Function (on)
import Data.Maybe (fromMaybe)
import qualified Data.Vector as Vector
import qualified Data.Text as Text
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)
$ \pos 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