packages feed

ip-1.7.8: src/Data/Text/Builder/Common/Internal.hs

module Data.Text.Builder.Common.Internal where

import Control.Monad.ST
import Data.Char (ord)
import Data.Foldable (fold)
import Data.Monoid
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Array as A
import qualified Data.Text.Internal.Unsafe.Char as TC
import Text.Printf

{- | This is slower that just pattern matching on the Text data constructor.
  However, it will work with GHCJS. This should only be used in places
  where we know that it will only be evaluated once.
-}
portableTextArray :: Text -> A.Array
portableTextArray = fst . portableUntext
{-# INLINE portableTextArray #-}

{- | This length is not the character length. It is the length of Word16s
  required by a UTF16 representation.
-}
portableTextLength :: Text -> Int
portableTextLength = snd . portableUntext
{-# INLINE portableTextLength #-}

portableUntext :: Text -> (A.Array, Int)
portableUntext t =
  let str = Text.unpack t
      Sum len = foldMap (Sum . charUtf16Size) str
      arr = A.run $ do
        marr <- A.new len
        writeString marr str
        return marr
   in (arr, len)
{-# NOINLINE portableUntext #-}

writeString :: A.MArray s -> String -> ST s ()
writeString marr = go 0
 where
  go i s = case s of
    c : cs -> do
      n <- TC.unsafeWrite marr i c
      go (i + n) cs
    [] -> return ()

charUtf16Size :: Char -> Int
charUtf16Size c = if ord c < 0x10000 then 1 else 2

hexValuesWord12Upper :: A.Array
hexValuesWord12Upper =
  portableTextArray $
    fold $
      map (Text.pack . printf "%03X") [0 :: Int .. 4096]
{-# NOINLINE hexValuesWord12Upper #-}

hexValuesWord12Lower :: A.Array
hexValuesWord12Lower =
  portableTextArray $
    fold $
      map (Text.pack . printf "%03x") [0 :: Int .. 4096]
{-# NOINLINE hexValuesWord12Lower #-}

hexValuesWord8Upper :: A.Array
hexValuesWord8Upper =
  portableTextArray $
    fold $
      map (Text.pack . printf "%02X") [0 :: Int .. 255]
{-# NOINLINE hexValuesWord8Upper #-}

hexValuesWord8Lower :: A.Array
hexValuesWord8Lower =
  portableTextArray $
    fold $
      map (Text.pack . printf "%02x") [0 :: Int .. 255]
{-# NOINLINE hexValuesWord8Lower #-}

twoDecimalDigits :: A.Array
twoDecimalDigits =
  portableTextArray $
    foldMap (Text.pack . printf "%02d") [0 :: Int .. 99]
{-# NOINLINE twoDecimalDigits #-}

threeDecimalDigits :: A.Array
threeDecimalDigits =
  portableTextArray $
    foldMap (Text.pack . printf "%03d") [0 :: Int .. 255]
{-# NOINLINE threeDecimalDigits #-}