on master help sign in
Speed up UTF-8 decoding by a little over 2x

The previous code was more concise, but alas GHC boxed each Word8 it read from the ByteString, which resulted in poor performance. This mankier code adds (seemingly required) strictness annotations, along with a little bit of manual CSE. Timing of the DecodeUtf8/Strict benchmark went from 41.8ms to 19.6ms, a pleasing improvement.

commit0c1bc821ab496bc1810c4ac4a3df77025ae159c3 authorBryan O'Sullivan <bos@serpentine.com> dateThu 7 Jul 2011, 23:47 (15 years ago) parent9dec3d6
1 file changed+34−26
Data/Text/Encoding.hs+34−26
Data/Text/Encoding.hs+34−26
@@ -90,34 +90,42 @@ decodeUtf8With onErr bs = textP (fst a) 0 (snd a)
9090 where
9191 a = A.run2 (A.new len >>= outer 0 0)
9292 len = B.length bs
93+ idx = B.unsafeIndex bs
94+ desc = "Data.Text.Encoding.decodeUtf8: Invalid UTF-8 stream"
9395 outer n0 m0 arr = go n0 m0
9496 where
95− go !n !m = do
96− let x1 = idx m
97− x2 = idx (m + 1)
98− x3 = idx (m + 2)
99− x4 = idx (m + 3)
100− idx = B.unsafeIndex bs
101− case undefined of
102− _| m >= len -> return (arr,n)
103− | U8.validate1 x1 -> do
104− A.unsafeWrite arr n (fromIntegral x1)
105− go (n+1) (m+1)
106− | m+1 < len && U8.validate2 x1 x2 -> do
107− w <- unsafeWrite arr n (U8.chr2 x1 x2)
108− go (n+w) (m+2)
109− | m+2 < len && U8.validate3 x1 x2 x3 -> do
110− w <- unsafeWrite arr n (U8.chr3 x1 x2 x3)
111− go (n+w) (m+3)
112− | m+3 < len && U8.validate4 x1 x2 x3 x4 -> do
113− w <- unsafeWrite arr n (U8.chr4 x1 x2 x3 x4)
114− go (n+w) (m+4)
115− | otherwise -> case onErr desc (Just x1) of
116− Nothing -> go n (m+1)
117− Just c -> do
118− w <- unsafeWrite arr n c
119− go (n+w) (m+1)
120− desc = "Data.Text.Encoding.decodeUtf8: Invalid UTF-8 stream"
97+ go !n !m =
98+ if m < len
99+ then let !x1 = idx m
100+ !m1 = m + 1
101+ barf = case onErr desc (Just x1) of
102+ Nothing -> go n m1
103+ Just c -> do
104+ w <- unsafeWrite arr n c
105+ go (n+w) m1
106+ in if U8.validate1 x1 then do
107+ A.unsafeWrite arr n (fromIntegral x1)
108+ go (n+1) m1
109+ else if m1 < len then
110+ let !x2 = idx m1; !m2 = m + 2 in
111+ if U8.validate2 x1 x2 then do
112+ w <- unsafeWrite arr n (U8.chr2 x1 x2)
113+ go (n+w) m2
114+ else if m2 < len then
115+ let !x3 = idx m2; !m3 = m + 3 in
116+ if U8.validate3 x1 x2 x3 then do
117+ w <- unsafeWrite arr n (U8.chr3 x1 x2 x3)
118+ go (n+w) m3
119+ else if m3 < len then
120+ let !x4 = idx m3 in
121+ if U8.validate4 x1 x2 x3 x4 then do
122+ w <- unsafeWrite arr n (U8.chr4 x1 x2 x3 x4)
123+ go (n+w) (m+4)
124+ else barf
125+ else barf
126+ else barf
127+ else barf
128+ else return (arr,n)
121129{-# INLINE[0] decodeUtf8With #-}
122130
123131-- | Decode a 'ByteString' containing UTF-8 encoded text that is known