on master help sign in
Add decodeLatin and faster decodeUtf8
commitced5579e278bfaeaf7fd6a5470767fdf9c4dbd4e authorLuigy Leon <luigy@outlook.com> dateTue 4 Oct 2016, 18:10 (10 years ago) parent4e9f934
3 files changed+58−52
Data/Text/Encoding.hs+49−48 Data/Text/Internal.hs+8−3 text.cabal+1−1
Data/Text/Encoding.hs+49−48
@@ -74,7 +74,7 @@ import Data.ByteString as B
7474import Data.ByteString.Internal as B hiding (c2w)
7575import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)
7676import Data.Text.Internal (Text(..), safe, text)
77−-- import Data.Text.Internal.Private (runText)
77+import Data.Text.Internal.Private (runText)
7878import Data.Text.Internal.Unsafe.Char (ord, unsafeWrite)
7979import Data.Text.Internal.Unsafe.Shift (shiftR)
8080-- import Data.Text.Show ()
@@ -95,7 +95,7 @@ import qualified Data.Text.Internal.Encoding.Fusion as E
9595import qualified Data.Text.Internal.Encoding.Utf16 as U16
9696import qualified Data.Text.Internal.Fusion as F
9797
98−import GHC.Exts (ByteArray#, Int(..), Int#, Any)
98+import GHC.Exts (ByteArray#, Int(..), Int#, Any, Addr#, Ptr(..))
9999{-
100100#include "text_cbits.h"
101101-}
@@ -105,6 +105,7 @@ import Data.ByteString (ByteString)
105105import Data.Text.Internal (Text)
106106
107107-------------------------------------
108+import GHC.ForeignPtr
108109import GHCJS.Types
109110import GHCJS.Buffer
110111import Data.JSString (JSString)
@@ -137,55 +138,55 @@ decodeASCII = decodeUtf8
137138-- 'decodeLatin1' is semantically equivalent to
138139-- @Data.Text.pack . Data.ByteString.Char8.unpack@
139140decodeLatin1 :: ByteString -> Text
140−decodeLatin1 = error "decodeLatin1"
141−-- decodeLatin1 (PS fp off len) = text a 0 len
142−-- where
143−-- a = A.run (A.new len >>= unsafeIOToST . go)
144−-- go dest = withForeignPtr fp $ \ptr -> do
145−-- c_decode_latin1 (A.maBA dest) (ptr `plusPtr` off) (ptr `plusPtr` (off+len))
146−-- return dest
141+decodeLatin1 (PS fp off len) = text a 0 len
142+ where
143+ a = A.run (A.new len >>= unsafeIOToST . go)
144+ go dest = withForeignPtr fp $ \ptr -> do
145+ c_decode_latin1 (A.maBA dest) (ptr `plusPtr` off) (ptr `plusPtr` (off+len))
146+ return dest
147147
148148-- foreign import javascript unsafe "h$textToString" js_toString :: JSVal -> Text
149149
150150foreign import javascript unsafe "h$textFromString" js_fromString :: JSString -> (# ByteArray#, Int# #)
151151foreign import javascript unsafe "String['fromCharCode']['apply'](null, $1['u8'])" js_decodeBytes :: JSVal -> JSString
152152foreign import javascript unsafe "h$decodeUtf8z($1, $2)" js_fromByteStringBuffer :: Buffer -> Int -> JSString
153+foreign import javascript unsafe "h$decodeUtf8z($1, $2)" js_fromByteStringBufferz :: Addr# -> Int -> JSString
153154foreign import javascript unsafe "h$encodeUtf8($1)" js_encodeUtf8 :: JSString -> Buffer
155+
156+foreign import javascript unsafe "String['fromCharCode']['apply'](null, $1['u8'])" js_decodeUtf8Hack :: Addr# -> JSString
157+
154158foreign import javascript unsafe "h$encodeUtf8($1)" js_encodeUtf8Mut :: JSString -> MutableBuffer
155159foreign import javascript unsafe "h$encodeUtf16($1)" js_encodeUtf16 :: JSString -> Buffer
156160foreign import javascript unsafe "$1['length']" js_length :: JSString -> Int
157161foreign import javascript unsafe "h$jsstringTake" js_take :: Int -> JSString -> JSString
162+foreign import javascript unsafe "$3.substring($1,$2)" js_substring :: Int# -> Int# -> JSString -> JSString
158163
159164-- | Decode a 'ByteString' containing UTF-8 encoded text.
160165decodeUtf8With :: OnDecodeError -> ByteString -> Text
161−-- decodeUtf8With _ bs@(PS fp off len) = Text $ js_decodeBytes $ unsafeCoerce bs
162− -- decodeUtf8With _ bs = Text $ js_fromByteStringBuffer buf off
163−decodeUtf8With _ bs = Text $ js_take (len) $ js_fromByteStringBuffer buf off
164− where (buf, off, len) = fromByteString bs
165−-- decodeUtf8With onErr (PS fp off len) = runText $ \done -> do
166− -- let go dest = withForeignPtr fp $ \ptr ->
167− -- with (0::CSize) $ \destOffPtr -> do
168− -- let end = ptr `plusPtr` (off + len)
169− -- loop curPtr = do
170− -- curPtr' <- c_decode_utf8 (A.maBA dest) destOffPtr curPtr end
171− -- if curPtr' == end
172− -- then do
173− -- n <- peek destOffPtr
174− -- unsafeSTToIO (done dest (fromIntegral n))
175− -- else do
176− -- x <- peek curPtr'
177− -- case onErr desc (Just x) of
178− -- Nothing -> loop $ curPtr' `plusPtr` 1
179− -- Just c -> do
180− -- destOff <- peek destOffPtr
181− -- w <- unsafeSTToIO $
182− -- unsafeWrite dest (fromIntegral destOff) (safe c)
183− -- poke destOffPtr (destOff + fromIntegral w)
184− -- loop $ curPtr' `plusPtr` 1
185− -- loop (ptr `plusPtr` off)
186− -- (unsafeIOToST . go) =<< A.new len
187− -- where
188− -- desc = "Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream"
166+decodeUtf8With onErr (PS fp off len) = runText $ \done -> do
167+ let go dest = withForeignPtr fp $ \ptr ->
168+ with (0::CSize) $ \destOffPtr -> do
169+ let end = ptr `plusPtr` (off + len)
170+ loop curPtr = do
171+ curPtr' <- c_decode_utf8 (A.maBA dest) destOffPtr curPtr end
172+ if curPtr' == end
173+ then do
174+ n <- peek destOffPtr
175+ unsafeSTToIO (done dest (fromIntegral n))
176+ else do
177+ x <- peek curPtr'
178+ case onErr desc (Just x) of
179+ Nothing -> loop $ curPtr' `plusPtr` 1
180+ Just c -> do
181+ destOff <- peek destOffPtr
182+ w <- unsafeSTToIO $
183+ unsafeWrite dest (fromIntegral destOff) (safe c)
184+ poke destOffPtr (destOff + fromIntegral w)
185+ loop $ curPtr' `plusPtr` 1
186+ loop (ptr `plusPtr` off)
187+ (unsafeIOToST . go) =<< A.new len
188+ where
189+ desc = "Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream"
189190{- INLINE[0] decodeUtf8With #-}
190191
191192-- $stream
@@ -504,17 +505,17 @@ encodeUtf32BE :: Text -> ByteString
504505encodeUtf32BE txt = E.unstream (E.restreamUtf32BE (F.stream txt))
505506{-# INLINE encodeUtf32BE #-}
506507
507−-- foreign import ccall unsafe "_hs_text_decode_utf8" c_decode_utf8
508−-- :: MutableByteArray# s -> Ptr CSize
509−-- -> Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8)
508+foreign import ccall unsafe "_hs_text_decode_utf8" c_decode_utf8
509+ :: MutableByteArray# s -> Ptr CSize
510+ -> Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8)
510511
511−-- foreign import ccall unsafe "_hs_text_decode_utf8_state" c_decode_utf8_with_state
512−-- :: MutableByteArray# s -> Ptr CSize
513−-- -> Ptr (Ptr Word8) -> Ptr Word8
514−-- -> Ptr CodePoint -> Ptr DecoderState -> IO (Ptr Word8)
512+foreign import ccall unsafe "_hs_text_decode_utf8_state" c_decode_utf8_with_state
513+ :: MutableByteArray# s -> Ptr CSize
514+ -> Ptr (Ptr Word8) -> Ptr Word8
515+ -> Ptr CodePoint -> Ptr DecoderState -> IO (Ptr Word8)
515516
516−-- foreign import ccall unsafe "_hs_text_decode_latin1" c_decode_latin1
517−-- :: MutableByteArray# s -> Ptr Word8 -> Ptr Word8 -> IO ()
517+foreign import ccall unsafe "_hs_text_decode_latin1" c_decode_latin1
518+ :: MutableByteArray# s -> Ptr Word8 -> Ptr Word8 -> IO ()
518519
519−-- foreign import ccall unsafe "_hs_text_encode_utf8" c_encode_utf8
520−-- :: Ptr (Ptr Word8) -> ByteArray# -> CSize -> CSize -> IO ()
520+foreign import ccall unsafe "_hs_text_encode_utf8" c_encode_utf8
521+ :: Ptr (Ptr Word8) -> ByteArray# -> CSize -> CSize -> IO ()
Data/Text/Internal.hs+8−3
@@ -26,10 +26,11 @@ import Data.Bits
2626import Data.Int (Int32, Int64)
2727-- import Data.Text.Internal.Unsafe.Char (ord)
2828import Data.Typeable (Typeable)
29−import GHC.Exts (ByteArray#, Char(..), ord#, andI#, (/=#), isTrue#)
29+import GHC.Exts (ByteArray#, Char(..), ord#, andI#, (/=#), isTrue#, (==#), Int(..), Int#, isTrue#)
3030-- import qualified Data.Text.Array as A
3131import GHCJS.Marshal.Pure
3232import GHCJS.Marshal
33+import qualified GHC.CString as GHC
3334
3435
3536newtype Text = Text JSString
@@ -49,13 +50,17 @@ foreign import javascript unsafe
4950 "String.fromCharCode.apply(null, $1['u8'])"
5051 js_decodeBytes :: ByteArray# -> JSString
5152
53+foreign import javascript unsafe
54+ "h$textToString"
55+ js_textToString :: ByteArray# -> Int# -> Int# -> JSString
56+
5257-- | Construct a 'Text' without invisibly pinning its byte array in
5358-- memory if its length has dwindled to zero.
5459text :: A.Array -> Int -> Int -> Text
5560-- text arr off len | len == 0 = empty
5661-- | otherwise = text_ arr off len
57−text (A.Array ba) off len | len == 0 = empty
58− | otherwise = Text (js_decodeBytes ba)
62+text (A.Array ba) (I# off#) (I# len#) | isTrue# (len# ==# 0#) = empty
63+ | otherwise = Text $ js_textToString ba off# len#
5964
6065-- | Checked multiplication. Calls 'error' if the result would
6166-- overflow.
text.cabal+1−1
@@ -111,7 +111,7 @@ library
111111 -- Data.Text.Internal.Lazy.Encoding.Fusion
112112 Data.Text.Internal.Lazy.Fusion
113113 Data.Text.Internal.Lazy.Search
114− -- Data.Text.Internal.Private
114+ Data.Text.Internal.Private
115115 Data.Text.Internal.Read
116116 -- Data.Text.Internal.Search
117117 Data.Text.Internal.Unsafe