on master help sign in
Add a Binary instance for strict Text

Step one towards a fix for gh-115.

commitd70ce2713b997a84b56017009d5a2f5b919c6e4c authorBryan O'Sullivan <bos@serpentine.com> dateFri 22 May 2015, 13:03 (11 years ago) parentdc49f02
5 files changed+103−61
Data/Text.hs+10−60 Data/Text/Encoding.hs+1−1 Data/Text/Show.hs+85 tests/text-tests.cabal+2 text.cabal+5
Data/Text.hs+10−60
@@ -195,7 +195,7 @@ module Data.Text
195195
196196import Prelude (Char, Bool(..), Int, Maybe(..), String,
197197 Eq(..), Ord(..), Ordering(..), (++),
198− Read(..), Show(..),
198+ Read(..),
199199 (&&), (||), (+), (-), (.), ($), ($!), (>>),
200200 not, return, otherwise, quot)
201201#if defined(HAVE_DEEPSEQ)
@@ -211,17 +211,20 @@ import Control.Monad (foldM)
211211import Control.Monad.ST (ST)
212212import qualified Data.Text.Array as A
213213import qualified Data.List as L
214+import Data.Binary (Binary(get, put))
214215import Data.Monoid (Monoid(..))
215216import Data.String (IsString(..))
216217import qualified Data.Text.Internal.Fusion as S
217218import qualified Data.Text.Internal.Fusion.Common as S
219+import Data.Text.Encoding (decodeUtf8, encodeUtf8)
218220import Data.Text.Internal.Fusion (stream, reverseStream, unstream)
219221import Data.Text.Internal.Private (span_)
220−import Data.Text.Internal (Text(..), empty, empty_, firstf, mul, safe, text)
222+import Data.Text.Internal (Text(..), empty, firstf, mul, safe, text)
223+import Data.Text.Show (singleton, unpack)
221224import qualified Prelude as P
222225import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,
223226 reverseIter_, unsafeHead, unsafeTail)
224−import Data.Text.Internal.Unsafe.Char (unsafeChr, unsafeWrite)
227+import Data.Text.Internal.Unsafe.Char (unsafeChr)
225228import qualified Data.Text.Internal.Functions as F
226229import qualified Data.Text.Internal.Encoding.Utf16 as U16
227230import Data.Text.Internal.Search (indices)
@@ -230,15 +233,9 @@ import Data.ByteString (ByteString)
230233import qualified Data.Text.Lazy as L
231234import Data.Int (Int64)
232235#endif
233−#if __GLASGOW_HASKELL__ >= 702
234−import qualified GHC.CString as GHC
235−#else
236−import qualified GHC.Base as GHC
237−#endif
238236#if __GLASGOW_HASKELL__ >= 708
239237import qualified GHC.Exts as Exts
240238#endif
241−import GHC.Prim (Addr#)
242239
243240-- $strict
244241--
@@ -324,9 +321,6 @@ instance Eq Text where
324321instance Ord Text where
325322 compare = compareText
326323
327−instance Show Text where
328− showsPrec p ps r = showsPrec p (unpack ps) r
329−
330324instance Read Text where
331325 readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]
332326
@@ -349,6 +343,10 @@ instance Exts.IsList Text where
349343instance NFData Text where rnf !_ = ()
350344#endif
351345
346+instance Binary Text where
347+ put t = put (encodeUtf8 t)
348+ get = P.fmap decodeUtf8 get
349+
352350-- | This instance preserves data abstraction at the cost of inefficiency.
353351-- We omit reflection services for the sake of data abstraction.
354352--
@@ -401,54 +399,6 @@ pack :: String -> Text
401399pack = unstream . S.map safe . S.streamList
402400{-# INLINE [1] pack #-}
403401
404−-- | /O(n)/ Convert a 'Text' into a 'String'. Subject to fusion.
405−unpack :: Text -> String
406−unpack = S.unstreamList . stream
407−{-# INLINE [1] unpack #-}
408−
409−-- | /O(n)/ Convert a literal string into a Text. Subject to fusion.
410−unpackCString# :: Addr# -> Text
411−unpackCString# addr# = unstream (S.streamCString# addr#)
412−{-# NOINLINE unpackCString# #-}
413−
414−{-# RULES "TEXT literal" forall a.
415− unstream (S.map safe (S.streamList (GHC.unpackCString# a)))
416− = unpackCString# a #-}
417−
418−{-# RULES "TEXT literal UTF8" forall a.
419− unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))
420− = unpackCString# a #-}
421−
422−{-# RULES "TEXT empty literal"
423− unstream (S.map safe (S.streamList []))
424− = empty_ #-}
425−
426−{-# RULES "TEXT singleton literal" forall a.
427− unstream (S.map safe (S.streamList [a]))
428− = singleton_ a #-}
429−
430−-- | /O(1)/ Convert a character into a Text. Subject to fusion.
431−-- Performs replacement on invalid scalar values.
432−singleton :: Char -> Text
433−singleton = unstream . S.singleton . safe
434−{-# INLINE [1] singleton #-}
435−
436−{-# RULES "TEXT singleton" forall a.
437− unstream (S.singleton (safe a))
438− = singleton_ a #-}
439−
440−-- This is intended to reduce inlining bloat.
441−singleton_ :: Char -> Text
442−singleton_ c = Text (A.run x) 0 len
443− where x :: ST s (A.MArray s)
444− x = do arr <- A.new len
445− _ <- unsafeWrite arr 0 d
446− return arr
447− len | d < '\x10000' = 1
448− | otherwise = 2
449− d = safe c
450−{-# NOINLINE singleton_ #-}
451−
452402-- -----------------------------------------------------------------------------
453403-- * Basic functions
454404
Data/Text/Encoding.hs+1−1
@@ -84,12 +84,12 @@ import Control.Exception (evaluate, try)
8484import Control.Monad.ST (runST)
8585import Data.ByteString as B
8686import Data.ByteString.Internal as B hiding (c2w)
87−import Data.Text ()
8887import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)
8988import Data.Text.Internal (Text(..), safe, text)
9089import Data.Text.Internal.Private (runText)
9190import Data.Text.Internal.Unsafe.Char (unsafeWrite)
9291import Data.Text.Internal.Unsafe.Shift (shiftR)
92+import Data.Text.Show ()
9393import Data.Text.Unsafe (unsafeDupablePerformIO)
9494import Data.Word (Word8, Word32)
9595import Foreign.C.Types (CSize(..))
Data/Text/Show.hsnew file+85
@@ -0,0 +1,85 @@
1+{-# LANGUAGE CPP, MagicHash #-}
2+{-# OPTIONS_GHC -fno-warn-orphans #-}
3+#if __GLASGOW_HASKELL__ >= 702
4+{-# LANGUAGE Trustworthy #-}
5+#endif
6+
7+-- |
8+-- Module : Data.Text.Show
9+-- Copyright : (c) 2009-2015 Bryan O'Sullivan
10+--
11+-- License : BSD-style
12+-- Maintainer : bos@serpentine.com
13+-- Stability : experimental
14+-- Portability : GHC
15+
16+module Data.Text.Show
17+ (
18+ singleton
19+ , unpack
20+ ) where
21+
22+import Control.Monad.ST (ST)
23+import Data.Text.Internal (Text(..), empty_, safe)
24+import Data.Text.Internal.Fusion (stream, unstream)
25+import Data.Text.Internal.Unsafe.Char (unsafeWrite)
26+import GHC.Prim (Addr#)
27+import qualified Data.Text.Array as A
28+import qualified Data.Text.Internal.Fusion.Common as S
29+
30+#if __GLASGOW_HASKELL__ >= 702
31+import qualified GHC.CString as GHC
32+#else
33+import qualified GHC.Base as GHC
34+#endif
35+
36+instance Show Text where
37+ showsPrec p ps r = showsPrec p (unpack ps) r
38+
39+-- | /O(n)/ Convert a 'Text' into a 'String'. Subject to fusion.
40+unpack :: Text -> String
41+unpack = S.unstreamList . stream
42+{-# INLINE [1] unpack #-}
43+
44+-- | /O(n)/ Convert a literal string into a Text. Subject to fusion.
45+unpackCString# :: Addr# -> Text
46+unpackCString# addr# = unstream (S.streamCString# addr#)
47+{-# NOINLINE unpackCString# #-}
48+
49+{-# RULES "TEXT literal" forall a.
50+ unstream (S.map safe (S.streamList (GHC.unpackCString# a)))
51+ = unpackCString# a #-}
52+
53+{-# RULES "TEXT literal UTF8" forall a.
54+ unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))
55+ = unpackCString# a #-}
56+
57+{-# RULES "TEXT empty literal"
58+ unstream (S.map safe (S.streamList []))
59+ = empty_ #-}
60+
61+{-# RULES "TEXT singleton literal" forall a.
62+ unstream (S.map safe (S.streamList [a]))
63+ = singleton_ a #-}
64+
65+-- | /O(1)/ Convert a character into a Text. Subject to fusion.
66+-- Performs replacement on invalid scalar values.
67+singleton :: Char -> Text
68+singleton = unstream . S.singleton . safe
69+{-# INLINE [1] singleton #-}
70+
71+{-# RULES "TEXT singleton" forall a.
72+ unstream (S.singleton (safe a))
73+ = singleton_ a #-}
74+
75+-- This is intended to reduce inlining bloat.
76+singleton_ :: Char -> Text
77+singleton_ c = Text (A.run x) 0 len
78+ where x :: ST s (A.MArray s)
79+ x = do arr <- A.new len
80+ _ <- unsafeWrite arr 0 d
81+ return arr
82+ len | d < '\x10000' = 1
83+ | otherwise = 2
84+ d = safe c
85+{-# NOINLINE singleton_ #-}
tests/text-tests.cabal+2
@@ -114,6 +114,7 @@ library
114114 Data.Text.Internal.Lazy.Search
115115 Data.Text.Internal.Private
116116 Data.Text.Read
117+ Data.Text.Show
117118 Data.Text.Internal.Read
118119 Data.Text.Internal.Search
119120 Data.Text.Unsafe
@@ -135,6 +136,7 @@ library
135136 build-depends:
136137 array,
137138 base == 4.*,
139+ binary,
138140 bytestring,
139141 deepseq,
140142 ghc-prim,
text.cabal+5
@@ -121,9 +121,13 @@ library
121121 Data.Text.Read
122122 Data.Text.Unsafe
123123
124+ other-modules:
125+ Data.Text.Show
126+
124127 build-depends:
125128 array >= 0.3,
126129 base >= 4.2 && < 5,
130+ binary,
127131 deepseq >= 1.1.0.0,
128132 ghc-prim >= 0.2
129133
@@ -164,6 +168,7 @@ test-suite tests
164168 QuickCheck >= 2.7,
165169 array,
166170 base,
171+ binary,
167172 bytestring,
168173 deepseq,
169174 directory,