on master help sign in
Eliminate unnecessary resizes from encodeUtf8.

We had been performing a resize any time that (a) we had data to write and (b) we got to within 4 bytes of filling the target bytestring. This was safe, but suboptimal, as it meant that in the common case of encoding ASCII text, we would *always* perform a resize. Now, we check the exact number of bytes we need to fit, and resize only if they won't fit. This eliminates resizes for ASCII data, and makes them a little less likely for other data.

commit4050227910a7435f2cb110c206c2bcef41912c3c authorBryan O'Sullivan <bos@serpentine.com> dateMon 27 Jun 2011, 17:42 (15 years ago) parenta871416
1 file changed+15−13
Data/Text/Encoding.hs+15−13
Data/Text/Encoding.hs+15−13
@@ -152,36 +152,38 @@ encodeUtf8 (Text arr off len) = unsafePerformIO $ do
152152 loop n1 m1 ptr = go n1 m1
153153 where
154154 go !n !m
155− | n-off == len = return $! PS fp 0 m
156− | size-m < 4 = {-# SCC "encodeUtf8/resize" #-} do
157− let newSize = size `shiftL` 1
158− fp' <- mallocByteString newSize
159− withForeignPtr fp' $ \ptr' -> memcpy ptr' ptr (fromIntegral m)
160− start newSize n m fp'
155+ | n-off == len = return (PS fp 0 m)
161156 | otherwise = do
162157 let poke8 k v = poke (ptr `plusPtr` k) (fromIntegral v :: Word8)
163− w = A.unsafeIndex arr n
164− case undefined of
165− _| w <= 0x7F -> do
158+ ensure k act
159+ | size-m >= k = act
160+ | otherwise = {-# SCC "resizeUtf8/ensure" #-} do
161+ let newSize = size `shiftL` 1
162+ fp' <- mallocByteString newSize
163+ withForeignPtr fp' $ \ptr' ->
164+ memcpy ptr' ptr (fromIntegral m)
165+ start newSize n m fp'
166+ {-# INLINE ensure #-}
167+ case A.unsafeIndex arr n of
168+ w| w <= 0x7F -> ensure 1 $ do
166169 poke8 m w
167170 go (n+1) (m+1)
168− | w <= 0x7FF -> do
171+ | w <= 0x7FF -> ensure 2 $ do
169172 poke8 m $ (w `shiftR` 6) + 0xC0
170173 poke8 (m+1) $ (w .&. 0x3f) + 0x80
171174 go (n+1) (m+2)
172− | 0xD800 <= w && w <= 0xDBFF -> do
175+ | 0xD800 <= w && w <= 0xDBFF -> ensure 4 $ do
173176 let c = ord $ U16.chr2 w (A.unsafeIndex arr (n+1))
174177 poke8 m $ (c `shiftR` 18) + 0xF0
175178 poke8 (m+1) $ ((c `shiftR` 12) .&. 0x3F) + 0x80
176179 poke8 (m+2) $ ((c `shiftR` 6) .&. 0x3F) + 0x80
177180 poke8 (m+3) $ (c .&. 0x3F) + 0x80
178181 go (n+2) (m+4)
179− | otherwise -> do
182+ | otherwise -> ensure 3 $ do
180183 poke8 m $ (w `shiftR` 12) + 0xE0
181184 poke8 (m+1) $ ((w `shiftR` 6) .&. 0x3F) + 0x80
182185 poke8 (m+2) $ (w .&. 0x3F) + 0x80
183186 go (n+1) (m+3)
184−{- INLINE encodeUtf8 #-}
185187
186188-- | Decode text from little endian UTF-16 encoding.
187189decodeUtf16LEWith :: OnDecodeError -> ByteString -> Text