on master help sign in
Get rendering of numbers working in all cases
0d6703cBryan O'Sullivan
Data/Text/Lazy/Builder/Int.hs+46−16
@@ -1,6 +1,6 @@
1{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
1{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
2
2
3−-- Module: Data.Text.Lazy.Builder.Int
3+-- Module: Data.Text.Lazy.Builder.Intxo
4-- Copyright: (c) 2011 MailRank, Inc.
4-- Copyright: (c) 2011 MailRank, Inc.
5-- License: BSD3
5-- License: BSD3
6-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
6-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
@@ -19,6 +19,7 @@ import Data.Int (Int8, Int16, Int32, Int64)
19import Data.Monoid (mempty)
19import Data.Monoid (mempty)
20import Data.Text.Lazy.Builder.Functions ((<>), i2d)
20import Data.Text.Lazy.Builder.Functions ((<>), i2d)
21import Data.Text.Lazy.Builder
21import Data.Text.Lazy.Builder
22+import Data.Text.Lazy (pack)
22import Data.Word (Word, Word8, Word16, Word32, Word64)
23import Data.Word (Word, Word8, Word16, Word32, Word64)
23import GHC.Base (quotInt, remInt)
24import GHC.Base (quotInt, remInt)
24import GHC.Num (quotRemInteger)
25import GHC.Num (quotRemInteger)
@@ -43,23 +44,51 @@ import GHC.Integer
43#endif
44#endif
44
45
45decimal :: Integral a => a -> Builder
46decimal :: Integral a => a -> Builder
46−{-# SPECIALIZE decimal :: Int -> Builder #-}
47{-# SPECIALIZE decimal :: Int8 -> Builder #-}
47{-# SPECIALIZE decimal :: Int8 -> Builder #-}
48−{-# SPECIALIZE decimal :: Int16 -> Builder #-}
48+{-# RULES "decimal/Int" decimal = boundedDecimal :: Int -> Builder #-}
49+{-# RULES "decimal/Int16" decimal = boundedDecimal :: Int16 -> Builder #-}
49−{-# SPECIALIZE decimal :: Int32 -> Builder #-}
50+{-# RULES "decimal/Int32" decimal = boundedDecimal :: Int32 -> Builder #-}
50−{-# SPECIALIZE decimal :: Int64 -> Builder #-}
51+{-# RULES "decimal/Int64" decimal = boundedDecimal :: Int64 -> Builder #-}
51−{-# SPECIALIZE decimal :: Word -> Builder #-}
52+{-# RULES "decimal/Word" decimal = positive :: Word -> Builder #-}
52−{-# SPECIALIZE decimal :: Word8 -> Builder #-}
53+{-# RULES "decimal/Word8" decimal = positive :: Word8 -> Builder #-}
53−{-# SPECIALIZE decimal :: Word16 -> Builder #-}
54+{-# RULES "decimal/Word16" decimal = positive :: Word16 -> Builder #-}
54−{-# SPECIALIZE decimal :: Word32 -> Builder #-}
55+{-# RULES "decimal/Word32" decimal = positive :: Word32 -> Builder #-}
55−{-# SPECIALIZE decimal :: Word64 -> Builder #-}
56+{-# RULES "decimal/Word64" decimal = positive :: Word64 -> Builder #-}
56{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}
57{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}
57decimal i
58decimal i
59+ | i < 0 = singleton '-' <>
60+ if i <= -128
61+ then positive (-(i `quot` 10)) <> digit (-(i `rem` 10))
62+ else positive (-i)
63+ | otherwise = positive i
64+
65+boundedDecimal :: (Integral a, Bounded a) => a -> Builder
66+{-# SPECIALIZE boundedDecimal :: Int -> Builder #-}
67+{-# SPECIALIZE boundedDecimal :: Int8 -> Builder #-}
68+{-# SPECIALIZE boundedDecimal :: Int16 -> Builder #-}
69+{-# SPECIALIZE boundedDecimal :: Int32 -> Builder #-}
70+{-# SPECIALIZE boundedDecimal :: Int64 -> Builder #-}
71+boundedDecimal i
58− | i < 0 = singleton '-' <> go (-i)
72+ | i < 0 = singleton '-' <>
73+ if i == minBound
74+ then positive (-(i `quot` 10)) <> digit (-(i `rem` 10))
75+ else positive (-i)
59− | otherwise = go i
76+ | otherwise = positive i
60− where
77+
78+positive :: (Integral a) => a -> Builder
79+{-# SPECIALIZE positive :: Int -> Builder #-}
80+{-# SPECIALIZE positive :: Int8 -> Builder #-}
81+{-# SPECIALIZE positive :: Int16 -> Builder #-}
82+{-# SPECIALIZE positive :: Int32 -> Builder #-}
83+{-# SPECIALIZE positive :: Int64 -> Builder #-}
84+{-# SPECIALIZE positive :: Word -> Builder #-}
85+{-# SPECIALIZE positive :: Word8 -> Builder #-}
86+{-# SPECIALIZE positive :: Word16 -> Builder #-}
87+{-# SPECIALIZE positive :: Word32 -> Builder #-}
88+{-# SPECIALIZE positive :: Word64 -> Builder #-}
89+positive = go
61− go n | n < 10 = digit n
90+ where go n | n < 10 = digit n
62− | otherwise = go (n `quot` 10) <> digit (n `rem` 10)
91+ | otherwise = go (n `quot` 10) <> digit (n `rem` 10)
63
92
64hexadecimal :: Integral a => a -> Builder
93hexadecimal :: Integral a => a -> Builder
65{-# SPECIALIZE hexadecimal :: Int -> Builder #-}
94{-# SPECIALIZE hexadecimal :: Int -> Builder #-}
@@ -74,11 +103,12 @@ hexadecimal :: Integral a => a -> Builder
74{-# SPECIALIZE hexadecimal :: Word64 -> Builder #-}
103{-# SPECIALIZE hexadecimal :: Word64 -> Builder #-}
75{-# RULES "hexadecimal/Integer" hexadecimal = integer 16 :: Integer -> Builder #-}
104{-# RULES "hexadecimal/Integer" hexadecimal = integer 16 :: Integer -> Builder #-}
76hexadecimal i
105hexadecimal i
77− | i < 0 = singleton '-' <> go (-i)
106+ | i < 0 = error msg
78 | otherwise = go i
107 | otherwise = go i
79 where
108 where
80 go n | n < 16 = hexDigit n
109 go n | n < 16 = hexDigit n
81 | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)
110 | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)
111+ msg = "Data.Text.Lazy.Builder.Int.hexadecimal: applied to negative number"
82
112
83digit :: Integral a => a -> Builder
113digit :: Integral a => a -> Builder
84digit n = singleton $! i2d (fromIntegral n)
114digit n = singleton $! i2d (fromIntegral n)