on master help sign in
An experimental attempt to speed up lazy decoding

--HG-- extra : convert_revision : df6512bf477405dbace4228b6d680bf5bd091d5e

commitc8ddf0f86de6f6c69a82b8d776948d3504cfaa7c authorBryan O'Sullivan <bos@serpentine.com> dateFri 20 Aug 2010, 06:28 (16 years ago) parentaea07e7
2 files changed+64−5
Data/Text/Encoding/Fusion/Common.hs+49−4 Data/Text/Lazy/Encoding/Fusion.hs+15−1
Data/Text/Encoding/Fusion/Common.hs+49−4
@@ -25,16 +25,46 @@ module Data.Text.Encoding.Fusion.Common
2525 , restreamUtf16BE
2626 , restreamUtf32LE
2727 , restreamUtf32BE
28+ , istreamUtf8
2829 ) where
2930
30−import Data.Bits ((.&.))
31+import Control.Monad.ST
32+import Data.Bits ((.&.), (.|.))
33+import Data.Text.Array
3134import Data.Text.Fusion (Step(..), Stream(..))
3235import Data.Text.Fusion.Internal (M(..), S(..))
33−import Data.Text.UnsafeChar (ord)
34−import Data.Text.UnsafeShift (shiftR)
35−import Data.Word (Word8)
36+import Data.Text.UnsafeChar (ord, unsafeChr32)
37+import Data.Text.UnsafeShift (shiftL, shiftR)
38+import Data.Word (Word8, Word32)
3639import qualified Data.Text.Encoding.Utf8 as U8
3740
41+accept, reject :: Word32
42+accept = 0
43+reject = 12
44+
45+data S8 s = S8 !s {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32
46+
47+istreamUtf8 :: Stream Word8 -> Stream Char
48+istreamUtf8 (Stream next0 s0 len) =
49+ Stream next (S8 s0 accept 0) len
50+ where
51+ next (S8 s state code) =
52+ case next0 s of
53+ Done -> Done
54+ Skip s' -> Skip (S8 s' state code)
55+ Yield w s'
56+ | state' == accept -> Yield (unsafeChr32 code') (S8 s' accept code')
57+ | state' /= reject -> Skip (S8 s' state' code')
58+ where
59+ word = fromIntegral w
60+ peeku :: Int -> Word32
61+ peeku n = fromIntegral (unsafeIndexWord8 utf8d n)
62+ !kind = peeku (fromIntegral word)
63+ !code' | state /= accept = (word .&. 0x3f) .|. (code `shiftL` 6)
64+ | otherwise = (0xff `shiftR` fromIntegral kind) .&. word
65+ !state' = peeku (256 + fromIntegral (state + kind))
66+
67+
3868-- | /O(n)/ Convert a Stream Char into a UTF-8 encoded Stream Word8.
3969restreamUtf8 :: Stream Char -> Stream Word8
4070restreamUtf8 (Stream next0 s0 len) =
@@ -160,3 +190,18 @@ restreamUtf32LE (Stream next0 s0 len) =
160190internalError :: String -> a
161191internalError func =
162192 error $ "Data.Text.Encoding.Fusion.Common." ++ func ++ ": internal error"
193+
194+utf8d :: Array
195+{-# NOINLINE utf8d #-}
196+utf8d = runST fill where
197+ fill = do
198+ ary <- unsafeNew . (`div` 2) . sum . map fst $ xs
199+ mapM_ (uncurry (unsafeWriteWord8 ary))
200+ (zip [0..] (concatMap (uncurry replicate) xs))
201+ unsafeFreeze ary
202+ xs = [(128,0),(16,1),(16,9),(32,7),(2,8),(30,2),(1,10),(12,3),(1,4),(2,3),
203+ (1,11),(3,6),(1,5),(11,8),(1,0),(1,12),(1,24),(1,36),(1,60),(1,96),
204+ (1,84),(3,12),(1,48),(1,72),(13,12),(1,0),(5,12),(1,0),(1,12),(1,0),
205+ (3,12),(1,24),(5,12),(1,24),(1,12),(1,24),(9,12),(1,24),(5,12),(1,24),
206+ (7,12),(1,24),(9,12),(1,36),(1,12),(1,36),(3,12),(1,36),(5,12),(1,36),
207+ (1,12),(1,36),(3,12),(1,36),(10,12)]
Data/Text/Lazy/Encoding/Fusion.hs+15−1
@@ -57,12 +57,26 @@ data S = S0
5757 | S3 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8
5858 | S4 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8
5959
60+data SS = SS ByteString {-# UNPACK #-} !Int
61+
62+streamBytes :: ByteString -> Stream Word8
63+streamBytes bs0 = Stream next (SS bs0 0) unknownSize
64+ where
65+ next (SS bs@(Chunk s ss) i)
66+ | i < len = Yield (B.unsafeIndex s i) (SS bs (i+1))
67+ | otherwise = next (SS ss 0)
68+ where len = B.length s
69+ next _ = Done
70+
6071data T = T {-# UNPACK #-} !ByteString {-# UNPACK #-} !S {-# UNPACK #-} !Int
6172
6273-- | /O(n)/ Convert a lazy 'ByteString' into a 'Stream Char', using
6374-- UTF-8 encoding.
6475streamUtf8 :: OnDecodeError -> ByteString -> Stream Char
65−streamUtf8 onErr bs0 = Stream next (T bs0 S0 0) unknownSize
76+streamUtf8 onErr = istreamUtf8 . streamBytes
77+
78+streamUtf8' :: OnDecodeError -> ByteString -> Stream Char
79+streamUtf8' onErr bs0 = Stream next (T bs0 S0 0) unknownSize
6680 where
6781 next (T bs@(Chunk ps _) S0 i)
6882 | i < len && U8.validate1 a =