on master help sign in
Use unsafeDupablePerformIO where possible

unsafeDupablePerformIO is much faster than unsafePerformIO and can be used safely as long as the underlying operation is pure and we're fine risking duplicating it in a multi-core scenario. unsafeDupablePerformIO helps performance a lot on short string where the overhead of unsafePerformIO dominates. Closes #41.

commit779189de142f1a95dc60533422c60cb665badd82 authorJohan Tibell <johan.tibell@gmail.com> dateSun 24 Feb 2013, 17:58 (14 years ago) parent7fd8f18
5 files changed+15−9
Data/Text/Encoding.hs+3−3 Data/Text/Encoding/Fusion.hs+2−2 Data/Text/Lazy/Encoding.hs+2−2 Data/Text/Lazy/Encoding/Fusion.hs+2−2 Data/Text/Unsafe.hs+6
Data/Text/Encoding.hs+3−3
@@ -72,11 +72,11 @@ import Foreign.Marshal.Utils (with)
7272import Foreign.Ptr (Ptr, minusPtr, plusPtr)
7373import Foreign.Storable (peek, poke)
7474import GHC.Base (MutableByteArray#)
75−import System.IO.Unsafe (unsafePerformIO)
7675import qualified Data.Text.Array as A
7776import qualified Data.Text.Encoding.Fusion as E
7877import qualified Data.Text.Encoding.Utf16 as U16
7978import qualified Data.Text.Fusion as F
79+import Data.Text.Unsafe (unsafeDupablePerformIO)
8080
8181-- $strict
8282--
@@ -157,12 +157,12 @@ decodeUtf8 = decodeUtf8With strictDecode
157157-- If the input contains any invalid UTF-8 data, the relevant
158158-- exception will be returned, otherwise the decoded text.
159159decodeUtf8' :: ByteString -> Either UnicodeException Text
160−decodeUtf8' = unsafePerformIO . try . evaluate . decodeUtf8With strictDecode
160+decodeUtf8' = unsafeDupablePerformIO . try . evaluate . decodeUtf8With strictDecode
161161{-# INLINE decodeUtf8' #-}
162162
163163-- | Encode text using UTF-8 encoding.
164164encodeUtf8 :: Text -> ByteString
165−encodeUtf8 (Text arr off len) = unsafePerformIO $ do
165+encodeUtf8 (Text arr off len) = unsafeDupablePerformIO $ do
166166 let size0 = max len 4
167167 mallocByteString size0 >>= start size0 off 0
168168 where
Data/Text/Encoding/Fusion.hs+2−2
@@ -44,12 +44,12 @@ import Data.Text.UnsafeShift (shiftL, shiftR)
4444import Data.Word (Word8, Word16, Word32)
4545import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
4646import Foreign.Storable (pokeByteOff)
47−import System.IO.Unsafe (unsafePerformIO)
4847import qualified Data.ByteString as B
4948import qualified Data.ByteString.Unsafe as B
5049import qualified Data.Text.Encoding.Utf8 as U8
5150import qualified Data.Text.Encoding.Utf16 as U16
5251import qualified Data.Text.Encoding.Utf32 as U32
52+import Data.Text.Unsafe (unsafeDupablePerformIO)
5353
5454streamASCII :: ByteString -> Stream Char
5555streamASCII bs = Stream next 0 (maxSize l)
@@ -163,7 +163,7 @@ streamUtf32LE onErr bs = Stream next 0 (maxSize (l `shiftR` 2))
163163
164164-- | /O(n)/ Convert a 'Stream' 'Word8' to a 'ByteString'.
165165unstream :: Stream Word8 -> ByteString
166−unstream (Stream next s0 len) = unsafePerformIO $ do
166+unstream (Stream next s0 len) = unsafeDupablePerformIO $ do
167167 let mlen = upperBound 4 len
168168 mallocByteString mlen >>= loop mlen 0 s0
169169 where
Data/Text/Lazy/Encoding.hs+2−2
@@ -52,7 +52,6 @@ import Control.Exception (evaluate, try)
5252import Data.Bits ((.&.))
5353import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)
5454import Data.Text.Lazy.Internal (Text(..), chunk, empty, foldrChunks)
55−import System.IO.Unsafe (unsafePerformIO)
5655import qualified Data.ByteString as S
5756import qualified Data.ByteString.Lazy as B
5857import qualified Data.ByteString.Lazy.Internal as B
@@ -61,6 +60,7 @@ import qualified Data.Text as T
6160import qualified Data.Text.Encoding as TE
6261import qualified Data.Text.Lazy.Encoding.Fusion as E
6362import qualified Data.Text.Lazy.Fusion as F
63+import Data.Text.Unsafe (unsafeDupablePerformIO)
6464
6565-- $strict
6666--
@@ -149,7 +149,7 @@ decodeUtf8 = decodeUtf8With strictDecode
149149-- input before it can return a result. If you need lazy (streaming)
150150-- decoding, use 'decodeUtf8With' in lenient mode.
151151decodeUtf8' :: B.ByteString -> Either UnicodeException Text
152−decodeUtf8' bs = unsafePerformIO $ do
152+decodeUtf8' bs = unsafeDupablePerformIO $ do
153153 let t = decodeUtf8 bs
154154 try (evaluate (rnf t `seq` t))
155155 where
Data/Text/Lazy/Encoding/Fusion.hs+2−2
@@ -42,7 +42,7 @@ import Data.Word (Word8, Word16, Word32)
4242import qualified Data.Text.Encoding.Utf8 as U8
4343import qualified Data.Text.Encoding.Utf16 as U16
4444import qualified Data.Text.Encoding.Utf32 as U32
45−import System.IO.Unsafe (unsafePerformIO)
45+import Data.Text.Unsafe (unsafeDupablePerformIO)
4646import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
4747import Foreign.Storable (pokeByteOff)
4848import Data.ByteString.Internal (mallocByteString, memcpy)
@@ -272,7 +272,7 @@ streamUtf32LE onErr bs0 = Stream next (T bs0 S0 0) unknownSize
272272-- | /O(n)/ Convert a 'Stream' 'Word8' to a lazy 'ByteString'.
273273unstreamChunks :: Int -> Stream Word8 -> ByteString
274274unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 (upperBound 4 len0)
275− where chunk s1 len1 = unsafePerformIO $ do
275+ where chunk s1 len1 = unsafeDupablePerformIO $ do
276276 let len = max 4 (min len1 chunkSize)
277277 mallocByteString len >>= loop len 0 s1
278278 where
Data/Text/Unsafe.hs+6
@@ -14,6 +14,7 @@ module Data.Text.Unsafe
1414 (
1515 inlineInterleaveST
1616 , inlinePerformIO
17+ , unsafeDupablePerformIO
1718 , Iter(..)
1819 , iter
1920 , iter_
@@ -33,6 +34,11 @@ import Data.Text.Internal (Text(..))
3334import Data.Text.Unsafe.Base (inlineInterleaveST, inlinePerformIO)
3435import Data.Text.UnsafeChar (unsafeChr)
3536import qualified Data.Text.Array as A
37+#if __GLASGOW_HASKELL__ >= 611
38+import GHC.IO (unsafeDupablePerformIO)
39+#else
40+import GHC.IOBase (unsafeDupablePerformIO)
41+#endif
3642
3743-- | /O(1)/ A variant of 'head' for non-empty 'Text'. 'unsafeHead'
3844-- omits the check for the empty case, so there is an obligation on