@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
1+{-# LANGUAGE BangPatterns, CPP, MagicHash, RankNTypes, UnboxedTuples #-}
22
33-- Module: Data.Text.Lazy.Builder.Int
44-- Copyright: (c) 2011 MailRank, Inc.
@@ -19,10 +19,12 @@ import Data.Int (Int8, Int16, Int32, Int64)
1919import Data.Monoid (mempty)
2020import Data.Text.Lazy.Builder.Functions ((<>), i2d)
2121import Data.Text.Lazy.Builder.Internal
22+import Data.Text.Array
2223import Data.Word (Word, Word8, Word16, Word32, Word64)
2324import GHC.Base (quotInt, remInt)
2425import GHC.Num (quotRemInteger)
2526import GHC.Types (Int(..))
27+import Control.Monad.ST
2628
2729#ifdef __GLASGOW_HASKELL__
2830# if __GLASGOW_HASKELL__ < 611
@@ -69,14 +71,16 @@ decimal' :: (Integral a) => (a -> Bool) -> a -> Builder
6971decimal' p i
7072 | i < 0 = if p i
7173 then let j = -(i `quot` 10)
72− n = countDigits j + 2
73− in go n $ singleton '-' <>
74− positive j <> digit (-(i `rem` 10))
74+ !n = countDigits j
75+ in writeN (n + 2) $ \marr off -> do
76+ unsafeWrite marr off minus
77+ posDecimal marr (off+1) n j
78+ unsafeWrite marr (off+n+1) (i2w (-(i `rem` 10)))
7579 else let j = -i
76− n = countDigits j + 1
77− in go n $ singleton '-' <> positive j
78− | otherwise = go (countDigits i) $ positive i
79− where go k b = ensureFree k `append'` b
80+ !n = countDigits j
81+ in writeN (n + 1) $ \marr off ->
82+ unsafeWrite marr off minus >> posDecimal marr (off+1) n j
83+ | otherwise = positive i
8084
8185positive :: (Integral a) => a -> Builder
8286{-# SPECIALIZE positive :: Int -> Builder #-}
@@ -89,9 +93,29 @@ positive :: (Integral a) => a -> Builder
8993{-# SPECIALIZE positive :: Word16 -> Builder #-}
9094{-# SPECIALIZE positive :: Word32 -> Builder #-}
9195{-# SPECIALIZE positive :: Word64 -> Builder #-}
92−positive = go
93− where go n | n < 10 = digit n
94− | otherwise = go (n `quot` 10) <> digit (n `rem` 10)
96+positive i
97+ | i < 10 = writeN 1 $ \marr off -> unsafeWrite marr off (i2w i)
98+ | otherwise = let !n = countDigits i
99+ in writeN n $ \marr off -> posDecimal marr off n i
100+
101+posDecimal :: Integral a => forall s. MArray s -> Int -> Int -> a -> ST s ()
102+{-# INLINE posDecimal #-}
103+posDecimal marr off0 ds v0 = go (off0 + ds - 1) v0
104+ where go off v
105+ | v < 10 = unsafeWrite marr off (i2w v)
106+ | otherwise = do
107+ unsafeWrite marr off (i2w (v `rem` 10))
108+ go (off-1) (v `div` 10)
109+
110+minus, zero :: Word16
111+{-# INLINE minus #-}
112+{-# INLINE zero #-}
113+minus = 45
114+zero = 48
115+
116+i2w :: (Integral a) => a -> Word16
117+{-# INLINE i2w #-}
118+i2w v = zero + fromIntegral v
95119
96120countDigits :: (Integral a) => a -> Int
97121{-# INLINE countDigits #-}