@@ -53,24 +53,22 @@ import Control.Monad.ST.Unsafe (unsafeIOToST, unsafeSTToIO)
5353#else
5454import Control.Monad.ST (unsafeIOToST, unsafeSTToIO)
5555#endif
56−import Data.Bits ((.&.))
5756import Data.ByteString as B
5857import Data.ByteString.Internal as B
5958import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)
6059import Data.Text.Internal (Text(..), textP)
61−import Data.Text.UnsafeChar (ord, unsafeWrite)
62−import Data.Text.UnsafeShift (shiftL, shiftR)
60+import Data.Text.UnsafeChar (unsafeWrite)
6361import Data.Word (Word8)
6462import Foreign.C.Types (CSize)
65−import Foreign.ForeignPtr (withForeignPtr)
63+import Foreign.ForeignPtr (newForeignPtr, withForeignPtr)
6664import Foreign.Marshal.Utils (with)
6765import Foreign.Ptr (Ptr, plusPtr)
6866import Foreign.Storable (peek, poke)
69−import GHC.Base (MutableByteArray#)
67+import GHC.Base (ByteArray#, MutableByteArray#)
7068import System.IO.Unsafe (unsafePerformIO)
7169import qualified Data.Text.Array as A
7270import qualified Data.Text.Encoding.Fusion as E
73−import qualified Data.Text.Encoding.Utf16 as U16
71+
7472import qualified Data.Text.Fusion as F
7573
7674-- $strict
@@ -145,45 +143,14 @@ decodeUtf8' = unsafePerformIO . try . evaluate . decodeUtf8With strictDecode
145143
146144-- | Encode text using UTF-8 encoding.
147145encodeUtf8 :: Text -> ByteString
148−encodeUtf8 (Text arr off len) = unsafePerformIO $ do
149− let size0 = max len 4
150− mallocByteString size0 >>= start size0 off 0
151− where
152− start size n0 m0 fp = withForeignPtr fp $ loop n0 m0
153− where
154− loop n1 m1 ptr = go n1 m1
155− where
156− go !n !m
157− | n == off+len = return (PS fp 0 m)
158− | otherwise = do
159− let poke8 k v = poke (ptr `plusPtr` k) (fromIntegral v :: Word8)
160− ensure k act
161− | size-m >= k = act
162− | otherwise = {-# SCC "resizeUtf8/ensure" #-} do
163− let newSize = size `shiftL` 1
164− fp' <- mallocByteString newSize
165− withForeignPtr fp' $ \ptr' ->
166− memcpy ptr' ptr (fromIntegral m)
167− start newSize n m fp'
168− {-# INLINE ensure #-}
169− case A.unsafeIndex arr n of
170− w| w <= 0x7F -> poke8 m w >> go (n+1) (m+1)
171− | w <= 0x7FF -> ensure 2 $ do
172− poke8 m $ (w `shiftR` 6) + 0xC0
173− poke8 (m+1) $ (w .&. 0x3f) + 0x80
174− go (n+1) (m+2)
175− | 0xD800 <= w && w <= 0xDBFF -> ensure 4 $ do
176− let c = ord $ U16.chr2 w (A.unsafeIndex arr (n+1))
177− poke8 m $ (c `shiftR` 18) + 0xF0
178− poke8 (m+1) $ ((c `shiftR` 12) .&. 0x3F) + 0x80
179− poke8 (m+2) $ ((c `shiftR` 6) .&. 0x3F) + 0x80
180− poke8 (m+3) $ (c .&. 0x3F) + 0x80
181− go (n+2) (m+4)
182− | otherwise -> ensure 3 $ do
183− poke8 m $ (w `shiftR` 12) + 0xE0
184− poke8 (m+1) $ ((w `shiftR` 6) .&. 0x3F) + 0x80
185− poke8 (m+2) $ (w .&. 0x3F) + 0x80
186− go (n+1) (m+3)
146+encodeUtf8 (Text arr off len)
147+ | len == 0 = empty
148+ | otherwise = unsafePerformIO $ do
149+ with (fromIntegral len ::CSize) $ \lenPtr -> do
150+ dptr <- c_encode_utf8 lenPtr (A.aBA arr) (fromIntegral off)
151+ fp <- newForeignPtr c_free_finalizer dptr
152+ dlen <- peek lenPtr
153+ return (PS fp 0 (fromIntegral dlen))
187154
188155-- | Decode text from little endian UTF-16 encoding.
189156decodeUtf16LEWith :: OnDecodeError -> ByteString -> Text
@@ -264,3 +231,6 @@ encodeUtf32BE txt = E.unstream (E.restreamUtf32BE (F.stream txt))
264231foreign import ccall unsafe "_hs_text_decode_utf8" c_decode_utf8
265232 :: MutableByteArray# s -> Ptr CSize
266233 -> Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8)
234+
235+foreign import ccall unsafe "_hs_text_encode_utf8" c_encode_utf8
236+ :: Ptr CSize -> ByteArray# -> CSize -> IO (Ptr Word8)