Make use of assert conditional
authorBryan O'Sullivan <bos@serpentine.com>
Sun, 15 Aug 2010 01:47:15 +0000 (01:47 +0000)
committerBryan O'Sullivan <bos@serpentine.com>
Sun, 15 Aug 2010 01:47:15 +0000 (01:47 +0000)
This turns out to make about a 10% difference to performance, even
though the GHC docs claim it shouldn't :-(

--HG--
extra : convert_revision : 446f05ea889a715272cd709cbd2d3b11260df7ba

14 files changed:
Data/Text.hs
Data/Text/Array.hs
Data/Text/Encoding/Fusion.hs
Data/Text/Encoding/Fusion/Common.hs
Data/Text/Encoding/Utf8.hs
Data/Text/Foreign.hs
Data/Text/Fusion.hs
Data/Text/Fusion/Size.hs
Data/Text/Internal.hs
Data/Text/Lazy/Builder.hs
Data/Text/Lazy/Encoding/Fusion.hs
Data/Text/Unsafe.hs
Data/Text/UnsafeChar.hs
text.cabal

index 5f0b5b7..79b1340 100644 (file)
@@ -174,7 +174,9 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
 #if defined(HAVE_DEEPSEQ)
 import Control.DeepSeq (NFData)
 #endif
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import Data.Char (isSpace)
 import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf))
 #if __GLASGOW_HASKELL__ >= 612
@@ -395,7 +397,11 @@ init (Text arr off len) | len <= 0                   = emptyError "init"
 -- | /O(1)/ Tests whether a 'Text' is empty or not.  Subject to
 -- fusion.
 null :: Text -> Bool
-null (Text _arr _off len) = assert (len >= 0) $ len <= 0
+null (Text _arr _off len) =
+#if defined(ASSERTS)
+    assert (len >= 0) $
+#endif
+    len <= 0
 {-# INLINE [1] null #-}
 
 {-# RULES
index 2633b23..cd72845 100644 (file)
@@ -42,19 +42,20 @@ module Data.Text.Array
     , unsafeWrite
     ) where
 
-#if 0
-#define BOUNDS_CHECKING
+#if defined(ASSERTS)
 -- This fugly hack is brought by GHC's apparent reluctance to deal
 -- with MagicHash and UnboxedTuples when inferring types. Eek!
-#define CHECK_BOUNDS(_func_,_len_,_k_) \
+# define CHECK_BOUNDS(_func_,_len_,_k_) \
 if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else
 #else
-#define CHECK_BOUNDS(_func_,_len_,_k_)
+# define CHECK_BOUNDS(_func_,_len_,_k_)
 #endif
 
 #include "MachDeps.h"
 
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import Data.Text.UnsafeShift (shiftL)
 import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
                  indexWord16Array#, newByteArray#,
@@ -92,10 +93,14 @@ unsafeFreeze :: MArray s -> ST s (Array)
 
 -- | Create an uninitialized mutable array.
 unsafeNew :: forall s. Int -> ST s (MArray s)
-unsafeNew n = assert (n >= 0) . ST $ \s1# ->
-   case bytesInArray n of
-     len@(I# len#) ->
-#if defined(BOUNDS_CHECKING)
+unsafeNew n =
+#if defined(ASSERTS)
+    assert (n >= 0) .
+#endif
+    ST $ \s1# ->
+    case bytesInArray n of
+      len@(I# len#) ->
+#if defined(ASSERTS)
          if len < 0 then error (show ("unsafeNew",len)) else
 #endif
          case newByteArray# len# s1# of
@@ -181,8 +186,10 @@ copy src dest
 -- | Unsafely copy the elements of an array.
 unsafeCopy :: MArray s -> Int -> MArray s -> Int -> Int -> ST s ()
 unsafeCopy src sidx dest didx count =
+#if defined(ASSERTS)
     assert (sidx + count <= length src) .
     assert (didx + count <= length dest) $
+#endif
     copy_loop sidx didx 0
     where
       copy_loop !i !j !c
index 62aacca..70ab8d9 100644 (file)
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns, Rank2Types #-}
+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
 
 -- |
 -- Module      : Data.Text.Encoding.Fusion
@@ -31,7 +31,9 @@ module Data.Text.Encoding.Fusion
     , module Data.Text.Encoding.Fusion.Common
     ) where
 
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)
 import Data.Text.Fusion (Step(..), Stream(..))
 import Data.Text.Fusion.Size
@@ -182,7 +184,11 @@ unstream (Stream next s0 len) = unsafePerformIO $ do
       {-# NOINLINE trimUp #-}
       trimUp fp _ off = return $! PS fp 0 off
       copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
-      copy0 !src !srcLen !destLen = assert (srcLen <= destLen) $ do
+      copy0 !src !srcLen !destLen =
+#if defined(ASSERTS)
+        assert (srcLen <= destLen) $
+#endif
+        do
           dest <- mallocByteString destLen
           withForeignPtr src  $ \src'  ->
               withForeignPtr dest $ \dest' ->
index 5b0fcd4..eedb59d 100644 (file)
@@ -28,9 +28,9 @@ module Data.Text.Encoding.Fusion.Common
     ) where
 
 import Data.Bits ((.&.))
-import Data.Char (ord)
 import Data.Text.Fusion (Step(..), Stream(..))
 import Data.Text.Fusion.Internal (M(..), S(..))
+import Data.Text.UnsafeChar (ord)
 import Data.Text.UnsafeShift (shiftR)
 import Data.Word (Word8)
 import qualified Data.Text.Encoding.Utf8 as U8
index 4c66d07..a828091 100644 (file)
@@ -1,4 +1,4 @@
-{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE CPP, MagicHash #-}
 
 -- |
 -- Module      : Data.Text.Encoding.Utf16
@@ -30,9 +30,11 @@ module Data.Text.Encoding.Utf8
     , validate4
     ) where
 
+#if defined(ASSERTS)
 import Control.Exception (assert)
-import Data.Char (ord)
+#endif
 import Data.Bits ((.&.))
+import Data.Text.UnsafeChar (ord)
 import Data.Text.UnsafeShift (shiftR)
 import GHC.Exts
 import GHC.Word (Word8(..))
@@ -47,14 +49,22 @@ between x y z = x >= y && x <= z
 {-# INLINE between #-}
 
 ord2   :: Char -> (Word8,Word8)
-ord2 c = assert (n >= 0x80 && n <= 0x07ff) (x1,x2)
+ord2 c =
+#if defined(ASSERTS)
+    assert (n >= 0x80 && n <= 0x07ff)
+#endif
+    (x1,x2)
     where
       n  = ord c
       x1 = fromIntegral $ (n `shiftR` 6) + 0xC0
       x2 = fromIntegral $ (n .&. 0x3F)   + 0x80
 
 ord3   :: Char -> (Word8,Word8,Word8)
-ord3 c = assert (n >= 0x0800 && n <= 0xffff) (x1,x2,x3)
+ord3 c =
+#if defined(ASSERTS)
+    assert (n >= 0x0800 && n <= 0xffff)
+#endif
+    (x1,x2,x3)
     where
       n  = ord c
       x1 = fromIntegral $ (n `shiftR` 12) + 0xE0
@@ -62,7 +72,11 @@ ord3 c = assert (n >= 0x0800 && n <= 0xffff) (x1,x2,x3)
       x3 = fromIntegral $ (n .&. 0x3F) + 0x80
 
 ord4   :: Char -> (Word8,Word8,Word8,Word8)
-ord4 c = assert (n >= 0x10000) (x1,x2,x3,x4)
+ord4 c =
+#if defined(ASSERTS)
+    assert (n >= 0x10000)
+#endif
+    (x1,x2,x3,x4)
     where
       n  = ord c
       x1 = fromIntegral $ (n `shiftR` 18) + 0xF0
index c70a3e2..ebfae08 100644 (file)
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BangPatterns, CPP #-}
 -- |
 -- Module      : Data.Text.Foreign
 -- Copyright   : (c) Bryan O'Sullivan 2009
@@ -25,7 +25,9 @@ module Data.Text.Foreign
     , unsafeCopyToPtr
     ) where
 
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import Control.Monad.ST (unsafeIOToST)
 import Data.Text.Internal (Text(..), empty)
 import qualified Data.Text.Array as A
@@ -53,7 +55,11 @@ fromPtr :: Ptr Word16           -- ^ source array
         -> Int                  -- ^ length of source array (in 'Word16' units)
         -> IO Text
 fromPtr _   0   = return empty
-fromPtr ptr len = assert (len > 0) $ return (Text arr 0 len)
+fromPtr ptr len =
+#if defined(ASSERTS)
+    assert (len > 0) $
+#endif
+    return $! Text arr 0 len
   where
     arr = A.run (A.unsafeNew len >>= copy)
     copy marr = loop ptr 0
@@ -68,6 +74,7 @@ fromPtr ptr len = assert (len > 0) $ return (Text arr 0 len)
 -- 'unsafeCopyToPtr'.
 lengthWord16 :: Text -> Int
 lengthWord16 (Text _arr _off len) = len
+{-# INLINE lengthWord16 #-}
 
 -- | /O(n)/ Copy a 'Text' to an array.  The array is assumed to be big
 -- enough to hold the contents of the entire 'Text'.
index 98dca48..0328711 100644 (file)
@@ -47,9 +47,8 @@ import Prelude (Bool(..), Char, Maybe(..), Monad(..), Int,
                 Num(..), Ord(..), ($), (&&),
                 fromIntegral, otherwise)
 import Data.Bits ((.&.))
-import Data.Char (ord)
 import Data.Text.Internal (Text(..))
-import Data.Text.UnsafeChar (unsafeChr, unsafeWrite)
+import Data.Text.UnsafeChar (ord, unsafeChr, unsafeWrite)
 import Data.Text.UnsafeShift (shiftL, shiftR)
 import qualified Data.Text.Array as A
 import qualified Data.Text.Fusion.Common as S
index 3366b50..d63886e 100644 (file)
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-missing-methods #-}
 -- |
 -- Module      : Data.Text.Fusion.Internal
@@ -26,7 +27,9 @@ module Data.Text.Fusion.Size
     , isEmpty
     ) where
 
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 
 data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
           | Max   {-# UNPACK #-} !Int -- ^ Upper bound on size.
@@ -34,11 +37,19 @@ data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
             deriving (Eq, Show)
 
 exactSize :: Int -> Size
-exactSize n = assert (n >= 0) Exact n
+exactSize n =
+#if defined(ASSERTS)
+    assert (n >= 0)
+#endif
+    Exact n
 {-# INLINE exactSize #-}
 
 maxSize :: Int -> Size
-maxSize n = assert (n >= 0) Max n
+maxSize n =
+#if defined(ASSERTS)
+    assert (n >= 0)
+#endif
+    Max n
 {-# INLINE maxSize #-}
 
 unknownSize :: Size
index 847973e..89793b9 100644 (file)
@@ -1,4 +1,4 @@
-{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE CPP, DeriveDataTypeable #-}
 
 -- |
 -- Module      : Data.Text.Internal
@@ -28,7 +28,9 @@ module Data.Text.Internal
     , showText
     ) where
 
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import qualified Data.Text.Array as A
 import Data.Typeable (Typeable)
 
@@ -42,13 +44,15 @@ data Text = Text
 -- | Smart constructor.
 text :: A.Array -> Int -> Int -> Text
 text arr off len =
-    assert (len >= 0) .
-    assert (off >= 0) .
-    assert (alen == 0 || len == 0 || off < alen) .
-    assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $
-    Text arr off len
-  where c    = A.unsafeIndex arr off
-        alen = A.length arr
+#if defined(ASSERTS)
+  let c    = A.unsafeIndex arr off
+      alen = A.length arr
+  in assert (len >= 0) .
+     assert (off >= 0) .
+     assert (alen == 0 || len == 0 || off < alen) .
+     assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $
+#endif
+     Text arr off len
 {-# INLINE text #-}
 
 -- | /O(1)/ The empty 'Text'.
index 52f312b..4476fa4 100644 (file)
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns, Rank2Types #-}
+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -29,7 +29,9 @@ module Data.Text.Lazy.Builder
    , flush
    ) where
 
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import Control.Monad.ST (ST, runST)
 import Data.Bits ((.&.))
 import Data.Char (ord)
@@ -259,8 +261,10 @@ newBuffer size = do
 -- | Unsafely copy the elements of an array.
 unsafeCopy :: A.Array -> Int -> A.MArray s -> Int -> Int -> ST s ()
 unsafeCopy src sidx dest didx count =
+#if defined(ASSERTS)
     assert (sidx + count <= A.length src) .
     assert (didx + count <= A.length dest) $
+#endif
     copy_loop sidx didx 0
   where
     copy_loop !i !j !c
@@ -274,12 +278,16 @@ unsafeCopy src sidx dest didx count =
 unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
 unsafeWrite marr i c
     | n < 0x10000 = do
-        assert (i >= 0) . assert (i < A.length marr) $
-          A.unsafeWrite marr i (fromIntegral n)
+#if defined(ASSERTS)
+        assert (i >= 0) . assert (i < A.length marr) $ return ()
+#endif
+        A.unsafeWrite marr i (fromIntegral n)
         return 1
     | otherwise = do
-        assert (i >= 0) . assert (i < A.length marr - 1) $
-          A.unsafeWrite marr i lo
+#if defined(ASSERTS)
+        assert (i >= 0) . assert (i < A.length marr - 1) $ return ()
+#endif
+        A.unsafeWrite marr i lo
         A.unsafeWrite marr (i+1) hi
         return 2
     where n = ord c
index 94c358f..8327b94 100644 (file)
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns, Rank2Types #-}
+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
 
 -- |
 -- Module      : Data.Text.Lazy.Encoding.Fusion
@@ -43,7 +43,9 @@ import System.IO.Unsafe (unsafePerformIO)
 import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
 import Foreign.Storable (pokeByteOff)
 import Data.ByteString.Internal (mallocByteString, memcpy)
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import qualified Data.ByteString.Internal as B
 
 data S = S0
@@ -123,7 +125,11 @@ unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 (upperBound 4 len0)
               loop n' (off+1) s fp'
             trimUp fp off = B.PS fp 0 off
             copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
-            copy0 !src !srcLen !destLen = assert (srcLen <= destLen) $ do
+            copy0 !src !srcLen !destLen =
+#if defined(ASSERTS)
+              assert (srcLen <= destLen) $
+#endif
+              do
                 dest <- mallocByteString destLen
                 withForeignPtr src  $ \src'  ->
                     withForeignPtr dest $ \dest' ->
index 9566507..c8f5fd0 100644 (file)
@@ -21,7 +21,9 @@ module Data.Text.Unsafe
     , unsafeTail
     ) where
      
+#if defined(ASSERTS)
 import Control.Exception (assert)
+#endif
 import Data.Text.Encoding.Utf16 (chr2)
 import Data.Text.Internal (Text(..))
 import Data.Text.UnsafeChar (unsafeChr)
@@ -40,11 +42,11 @@ import GHC.Base (realWorld#)
 -- omits the check for the empty case, so there is an obligation on
 -- the programmer to provide a proof that the 'Text' is non-empty.
 unsafeHead :: Text -> Char
-unsafeHead (Text arr off len)
+unsafeHead (Text arr off _len)
     | m < 0xD800 || m > 0xDBFF = unsafeChr m
     | otherwise                = chr2 m n
-    where m = assert (len > 0) $ A.unsafeIndex arr off
-          n = assert (len > 1) $ A.unsafeIndex arr (off+1)
+    where m = A.unsafeIndex arr off
+          n = A.unsafeIndex arr (off+1)
 {-# INLINE unsafeHead #-}
 
 -- | /O(1)/ A variant of 'tail' for non-empty 'Text'. 'unsafeHead'
@@ -52,42 +54,45 @@ unsafeHead (Text arr off len)
 -- the programmer to provide a proof that the 'Text' is non-empty.
 unsafeTail :: Text -> Text
 unsafeTail t@(Text arr off len) =
-    assert (d <= len) $ Text arr (off+d) (len-d)
+#if defined(ASSERTS)
+    assert (d <= len) $
+#endif
+    Text arr (off+d) (len-d)
   where d = iter_ t 0
 {-# INLINE unsafeTail #-}
 
--- | /O(1)/ Iterate one step forwards through a UTF-16 array,
--- returning the current character and the delta to add to give the
--- next offset to iterate at.
+-- | /O(1)/ Iterate (unsafely) one step forwards through a UTF-16
+-- array, returning the current character and the delta to add to give
+-- the next offset to iterate at.
 iter :: Text -> Int -> (Char,Int)
-iter (Text arr off len) i
+iter (Text arr off _len) i
     | m < 0xD800 || m > 0xDBFF = (unsafeChr m, 1)
     | otherwise                = (chr2 m n,    2)
-  where m = assert (i < len)     $ A.unsafeIndex arr j
-        n = assert (i + 1 < len) $ A.unsafeIndex arr k
-        j = assert (i >= 0)      $ off + i
-        k =                        j + 1
+  where m = A.unsafeIndex arr j
+        n = A.unsafeIndex arr k
+        j = off + i
+        k = j + 1
 {-# INLINE iter #-}
 
 -- | /O(1)/ Iterate one step through a UTF-16 array, returning the
 -- delta to add to give the next offset to iterate at.
 iter_ :: Text -> Int -> Int
-iter_ (Text arr off len) i | m < 0xD800 || m > 0xDBFF = 1
-                           | otherwise                = 2
-  where m = assert (i >= 0 && i < len) $ A.unsafeIndex arr (off+i)
+iter_ (Text arr off _len) i | m < 0xD800 || m > 0xDBFF = 1
+                            | otherwise                = 2
+  where m = A.unsafeIndex arr (off+i)
 {-# INLINE iter_ #-}
 
 -- | /O(1)/ Iterate one step backwards through a UTF-16 array,
 -- returning the current character and the delta to add (i.e. a
 -- negative number) to give the next offset to iterate at.
 reverseIter :: Text -> Int -> (Char,Int)
-reverseIter (Text arr off len) i
+reverseIter (Text arr off _len) i
     | m < 0xDC00 || m > 0xDFFF = (unsafeChr m, -1)
     | otherwise                = (chr2 n m,    -2)
-  where m = assert (i < len)    $ A.unsafeIndex arr j
-        n = assert (i - 1 >= 0) $ A.unsafeIndex arr k
-        j = assert (i >= 0)     $ off + i
-        k =                       j - 1
+  where m = A.unsafeIndex arr j
+        n = A.unsafeIndex arr k
+        j = off + i
+        k = j - 1
 {-# INLINE reverseIter #-}
 
 -- | Just like unsafePerformIO, but we inline it. Big performance gains as
index 01d29da..6c203f7 100644 (file)
@@ -1,4 +1,4 @@
-{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE CPP, MagicHash #-}
 
 -- |
 -- Module      : Data.Text.UnsafeChar
 -- Fast character manipulation functions.
 module Data.Text.UnsafeChar
     (
-      unsafeChr
+      ord
+    , unsafeChr
     , unsafeChr8
     , unsafeChr32
     , unsafeWrite
     -- , unsafeWriteRev
     ) where
 
+#ifdef ASSERTS
 import Control.Exception (assert)
+#endif
 import Control.Monad.ST (ST)
 import Data.Bits ((.&.))
-import Data.Char (ord)
 import Data.Text.UnsafeShift (shiftR)
-import GHC.Exts (Char(..), chr#, word2Int#)
+import GHC.Exts (Char(..), Int(..), chr#, ord#, word2Int#)
 import GHC.Word (Word8(..), Word16(..), Word32(..))
 import qualified Data.Text.Array as A
 
+ord :: Char -> Int
+ord (C# c#) = I# (ord# c#)
+{-# INLINE ord #-}
+
 unsafeChr :: Word16 -> Char
 unsafeChr (W16# w#) = C# (chr# (word2Int# w#))
 {-# INLINE unsafeChr #-}
@@ -46,12 +52,16 @@ unsafeChr32 (W32# w#) = C# (chr# (word2Int# w#))
 unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
 unsafeWrite marr i c
     | n < 0x10000 = do
-        assert (i >= 0) . assert (i < A.length marr) $
-          A.unsafeWrite marr i (fromIntegral n)
+#if defined(ASSERTS)
+        assert (i >= 0) . assert (i < A.length marr) $ return ()
+#endif
+        A.unsafeWrite marr i (fromIntegral n)
         return $! i+1
     | otherwise = do
-        assert (i >= 0) . assert (i < A.length marr - 1) $
-          A.unsafeWrite marr i lo
+#if defined(ASSERTS)
+        assert (i >= 0) . assert (i < A.length marr - 1) $ return ()
+#endif
+        A.unsafeWrite marr i lo
         A.unsafeWrite marr (i+1) hi
         return $! i+2
     where n = ord c
index 4c5f927..47b6812 100644 (file)
@@ -85,3 +85,4 @@ library
     ghc-options: -fwarn-tabs
   if flag(developer)
     ghc-options: -Werror
+    cpp-options: -DASSERTS