on master help sign in
Use streaming UTF-8 decode to implement lazy decode
commit77825a2f250f7494a369f43db4ef2f60e023e678 authorBryan O'Sullivan <bos@serpentine.com> dateMon 23 Sep 2013, 12:29 (13 years ago) parent2097f2a
1 file changed+14−36
Data/Text/Lazy/Encoding.hs+14−36
Data/Text/Lazy/Encoding.hs+14−36
@@ -49,15 +49,14 @@ module Data.Text.Lazy.Encoding
4949 ) where
5050
5151import Control.Exception (evaluate, try)
52−import Data.Bits ((.&.))
5352import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)
5453import Data.Text.Lazy.Internal (Text(..), chunk, empty, foldrChunks)
5554import qualified Data.ByteString as S
5655import qualified Data.ByteString.Lazy as B
5756import qualified Data.ByteString.Lazy.Internal as B
58−import qualified Data.ByteString.Unsafe as S
59−import qualified Data.Text as T
57+import qualified Data.ByteString.Unsafe as B
6058import qualified Data.Text.Encoding as TE
59+import qualified Data.Text.Lazy as L
6160import qualified Data.Text.Lazy.Encoding.Fusion as E
6261import qualified Data.Text.Lazy.Fusion as F
6362import Data.Text.Unsafe (unsafeDupablePerformIO)
@@ -89,41 +88,20 @@ decodeLatin1 = foldr (chunk . TE.decodeLatin1) empty . B.toChunks
8988
9089-- | Decode a 'ByteString' containing UTF-8 encoded text.
9190decodeUtf8With :: OnDecodeError -> B.ByteString -> Text
92−decodeUtf8With onErr bs0 = fast bs0
91+decodeUtf8With onErr (B.Chunk b0 bs0) =
92+ case TE.streamDecodeUtf8With onErr b0 of
93+ TE.Some t l f -> chunk t (go f l bs0)
9394 where
94− decode = TE.decodeUtf8With onErr
95− fast (B.Chunk p ps) | isComplete p = chunk (decode p) (fast ps)
96− | otherwise = chunk (decode h) (slow t ps)
97− where (h,t) = S.splitAt pivot p
98− pivot | at 1 = len-1
99− | at 2 = len-2
100− | otherwise = len-3
101− len = S.length p
102− at n = len >= n && S.unsafeIndex p (len-n) .&. 0xc0 == 0xc0
103− fast B.Empty = empty
104− slow i bs = {-# SCC "decodeUtf8With'/slow" #-}
105− case B.uncons bs of
106− Just (w,bs') | isComplete i' -> chunk (decode i') (fast bs')
107− | otherwise -> slow i' bs'
108− where i' = S.snoc i w
109− Nothing -> case S.uncons i of
110− Just (j,i') ->
111− case onErr desc (Just j) of
112− Nothing -> slow i' bs
113− Just c -> Chunk (T.singleton c) (slow i' bs)
114− Nothing ->
115− case onErr desc Nothing of
116− Nothing -> empty
117− Just c -> Chunk (T.singleton c) empty
118− isComplete bs = {-# SCC "decodeUtf8With'/isComplete" #-}
119− ix 1 .&. 0x80 == 0 ||
120− (len >= 2 && ix 2 .&. 0xe0 == 0xc0) ||
121− (len >= 3 && ix 3 .&. 0xf0 == 0xe0) ||
122− (len >= 4 && ix 4 .&. 0xf8 == 0xf0)
123− where len = S.length bs
124− ix n = S.unsafeIndex bs (len-n)
95+ go f0 _ (B.Chunk b bs) =
96+ case f0 b of
97+ TE.Some t l f -> chunk t (go f l bs)
98+ go _ l _
99+ | S.null l = empty
100+ | otherwise = case onErr desc (Just (B.unsafeHead l)) of
101+ Nothing -> empty
102+ Just c -> L.singleton c
125103 desc = "Data.Text.Lazy.Encoding.decodeUtf8With: Invalid UTF-8 stream"
126−{-# INLINE[0] decodeUtf8With #-}
104+decodeUtf8With _ _ = empty
127105
128106-- | Decode a 'ByteString' containing UTF-8 encoded text that is known
129107-- to be valid.