on master help sign in
Make use of assert conditional
a99b318Bryan O'Sullivan
Data/Text.hs+7−1
@@ -174,7 +174,9 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
174#if defined(HAVE_DEEPSEQ)
174#if defined(HAVE_DEEPSEQ)
175import Control.DeepSeq (NFData)
175import Control.DeepSeq (NFData)
176#endif
176#endif
177+#if defined(ASSERTS)
177import Control.Exception (assert)
178import Control.Exception (assert)
179+#endif
178import Data.Char (isSpace)
180import Data.Char (isSpace)
179import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf))
181import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf))
180#if __GLASGOW_HASKELL__ >= 612
182#if __GLASGOW_HASKELL__ >= 612
@@ -395,7 +397,11 @@ init (Text arr off len) | len <= 0 = emptyError "init"
395-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
397-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
396-- fusion.
398-- fusion.
397null :: Text -> Bool
399null :: Text -> Bool
398−null (Text _arr _off len) = assert (len >= 0) $ len <= 0
400+null (Text _arr _off len) =
401+#if defined(ASSERTS)
402+ assert (len >= 0) $
403+#endif
404+ len <= 0
399{-# INLINE [1] null #-}
405{-# INLINE [1] null #-}
400
406
401{-# RULES
407{-# RULES
Data/Text/Array.hs+15−8
@@ -42,19 +42,20 @@ module Data.Text.Array
42 , unsafeWrite
42 , unsafeWrite
43 ) where
43 ) where
44
44
45−#if 0
45+#if defined(ASSERTS)
46−#define BOUNDS_CHECKING
47-- This fugly hack is brought by GHC's apparent reluctance to deal
46-- This fugly hack is brought by GHC's apparent reluctance to deal
48-- with MagicHash and UnboxedTuples when inferring types. Eek!
47-- with MagicHash and UnboxedTuples when inferring types. Eek!
49−#define CHECK_BOUNDS(_func_,_len_,_k_) \
48+# define CHECK_BOUNDS(_func_,_len_,_k_) \
50if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else
49if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else
51#else
50#else
52−#define CHECK_BOUNDS(_func_,_len_,_k_)
51+# define CHECK_BOUNDS(_func_,_len_,_k_)
53#endif
52#endif
54
53
55#include "MachDeps.h"
54#include "MachDeps.h"
56
55
56+#if defined(ASSERTS)
57import Control.Exception (assert)
57import Control.Exception (assert)
58+#endif
58import Data.Text.UnsafeShift (shiftL)
59import Data.Text.UnsafeShift (shiftL)
59import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
60import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
60 indexWord16Array#, newByteArray#,
61 indexWord16Array#, newByteArray#,
@@ -92,10 +93,14 @@ unsafeFreeze :: MArray s -> ST s (Array)
92
93
93-- | Create an uninitialized mutable array.
94-- | Create an uninitialized mutable array.
94unsafeNew :: forall s. Int -> ST s (MArray s)
95unsafeNew :: forall s. Int -> ST s (MArray s)
95−unsafeNew n = assert (n >= 0) . ST $ \s1# ->
96+unsafeNew n =
97+#if defined(ASSERTS)
98+ assert (n >= 0) .
99+#endif
100+ ST $ \s1# ->
96− case bytesInArray n of
101+ case bytesInArray n of
97− len@(I# len#) ->
102+ len@(I# len#) ->
98−#if defined(BOUNDS_CHECKING)
103+#if defined(ASSERTS)
99 if len < 0 then error (show ("unsafeNew",len)) else
104 if len < 0 then error (show ("unsafeNew",len)) else
100#endif
105#endif
101 case newByteArray# len# s1# of
106 case newByteArray# len# s1# of
@@ -181,8 +186,10 @@ copy src dest
181-- | Unsafely copy the elements of an array.
186-- | Unsafely copy the elements of an array.
182unsafeCopy :: MArray s -> Int -> MArray s -> Int -> Int -> ST s ()
187unsafeCopy :: MArray s -> Int -> MArray s -> Int -> Int -> ST s ()
183unsafeCopy src sidx dest didx count =
188unsafeCopy src sidx dest didx count =
189+#if defined(ASSERTS)
184 assert (sidx + count <= length src) .
190 assert (sidx + count <= length src) .
185 assert (didx + count <= length dest) $
191 assert (didx + count <= length dest) $
192+#endif
186 copy_loop sidx didx 0
193 copy_loop sidx didx 0
187 where
194 where
188 copy_loop !i !j !c
195 copy_loop !i !j !c
Data/Text/Encoding/Fusion.hs+8−2
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, Rank2Types #-}
1+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
2
2
3-- |
3-- |
4-- Module : Data.Text.Encoding.Fusion
4-- Module : Data.Text.Encoding.Fusion
@@ -31,7 +31,9 @@ module Data.Text.Encoding.Fusion
31 , module Data.Text.Encoding.Fusion.Common
31 , module Data.Text.Encoding.Fusion.Common
32 ) where
32 ) where
33
33
34+#if defined(ASSERTS)
34import Control.Exception (assert)
35import Control.Exception (assert)
36+#endif
35import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)
37import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)
36import Data.Text.Fusion (Step(..), Stream(..))
38import Data.Text.Fusion (Step(..), Stream(..))
37import Data.Text.Fusion.Size
39import Data.Text.Fusion.Size
@@ -182,7 +184,11 @@ unstream (Stream next s0 len) = unsafePerformIO $ do
182 {-# NOINLINE trimUp #-}
184 {-# NOINLINE trimUp #-}
183 trimUp fp _ off = return $! PS fp 0 off
185 trimUp fp _ off = return $! PS fp 0 off
184 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
186 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
185− copy0 !src !srcLen !destLen = assert (srcLen <= destLen) $ do
187+ copy0 !src !srcLen !destLen =
188+#if defined(ASSERTS)
189+ assert (srcLen <= destLen) $
190+#endif
191+ do
186 dest <- mallocByteString destLen
192 dest <- mallocByteString destLen
187 withForeignPtr src $ \src' ->
193 withForeignPtr src $ \src' ->
188 withForeignPtr dest $ \dest' ->
194 withForeignPtr dest $ \dest' ->
Data/Text/Encoding/Fusion/Common.hs+1−1
@@ -28,9 +28,9 @@ module Data.Text.Encoding.Fusion.Common
28 ) where
28 ) where
29
29
30import Data.Bits ((.&.))
30import Data.Bits ((.&.))
31−import Data.Char (ord)
32import Data.Text.Fusion (Step(..), Stream(..))
31import Data.Text.Fusion (Step(..), Stream(..))
33import Data.Text.Fusion.Internal (M(..), S(..))
32import Data.Text.Fusion.Internal (M(..), S(..))
33+import Data.Text.UnsafeChar (ord)
34import Data.Text.UnsafeShift (shiftR)
34import Data.Text.UnsafeShift (shiftR)
35import Data.Word (Word8)
35import Data.Word (Word8)
36import qualified Data.Text.Encoding.Utf8 as U8
36import qualified Data.Text.Encoding.Utf8 as U8
Data/Text/Encoding/Utf8.hs+19−5
@@ -1,4 +1,4 @@
1−{-# LANGUAGE MagicHash #-}
1+{-# LANGUAGE CPP, MagicHash #-}
2
2
3-- |
3-- |
4-- Module : Data.Text.Encoding.Utf16
4-- Module : Data.Text.Encoding.Utf16
@@ -30,9 +30,11 @@ module Data.Text.Encoding.Utf8
30 , validate4
30 , validate4
31 ) where
31 ) where
32
32
33+#if defined(ASSERTS)
33import Control.Exception (assert)
34import Control.Exception (assert)
34−import Data.Char (ord)
35+#endif
35import Data.Bits ((.&.))
36import Data.Bits ((.&.))
37+import Data.Text.UnsafeChar (ord)
36import Data.Text.UnsafeShift (shiftR)
38import Data.Text.UnsafeShift (shiftR)
37import GHC.Exts
39import GHC.Exts
38import GHC.Word (Word8(..))
40import GHC.Word (Word8(..))
@@ -47,14 +49,22 @@ between x y z = x >= y && x <= z
47{-# INLINE between #-}
49{-# INLINE between #-}
48
50
49ord2 :: Char -> (Word8,Word8)
51ord2 :: Char -> (Word8,Word8)
52+ord2 c =
53+#if defined(ASSERTS)
50−ord2 c = assert (n >= 0x80 && n <= 0x07ff) (x1,x2)
54+ assert (n >= 0x80 && n <= 0x07ff)
55+#endif
56+ (x1,x2)
51 where
57 where
52 n = ord c
58 n = ord c
53 x1 = fromIntegral $ (n `shiftR` 6) + 0xC0
59 x1 = fromIntegral $ (n `shiftR` 6) + 0xC0
54 x2 = fromIntegral $ (n .&. 0x3F) + 0x80
60 x2 = fromIntegral $ (n .&. 0x3F) + 0x80
55
61
56ord3 :: Char -> (Word8,Word8,Word8)
62ord3 :: Char -> (Word8,Word8,Word8)
63+ord3 c =
64+#if defined(ASSERTS)
57−ord3 c = assert (n >= 0x0800 && n <= 0xffff) (x1,x2,x3)
65+ assert (n >= 0x0800 && n <= 0xffff)
66+#endif
67+ (x1,x2,x3)
58 where
68 where
59 n = ord c
69 n = ord c
60 x1 = fromIntegral $ (n `shiftR` 12) + 0xE0
70 x1 = fromIntegral $ (n `shiftR` 12) + 0xE0
@@ -62,7 +72,11 @@ ord3 c = assert (n >= 0x0800 && n <= 0xffff) (x1,x2,x3)
62 x3 = fromIntegral $ (n .&. 0x3F) + 0x80
72 x3 = fromIntegral $ (n .&. 0x3F) + 0x80
63
73
64ord4 :: Char -> (Word8,Word8,Word8,Word8)
74ord4 :: Char -> (Word8,Word8,Word8,Word8)
75+ord4 c =
76+#if defined(ASSERTS)
65−ord4 c = assert (n >= 0x10000) (x1,x2,x3,x4)
77+ assert (n >= 0x10000)
78+#endif
79+ (x1,x2,x3,x4)
66 where
80 where
67 n = ord c
81 n = ord c
68 x1 = fromIntegral $ (n `shiftR` 18) + 0xF0
82 x1 = fromIntegral $ (n `shiftR` 18) + 0xF0
Data/Text/Foreign.hs+9−2
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns #-}
1+{-# LANGUAGE BangPatterns, CPP #-}
2-- |
2-- |
3-- Module : Data.Text.Foreign
3-- Module : Data.Text.Foreign
4-- Copyright : (c) Bryan O'Sullivan 2009
4-- Copyright : (c) Bryan O'Sullivan 2009
@@ -25,7 +25,9 @@ module Data.Text.Foreign
25 , unsafeCopyToPtr
25 , unsafeCopyToPtr
26 ) where
26 ) where
27
27
28+#if defined(ASSERTS)
28import Control.Exception (assert)
29import Control.Exception (assert)
30+#endif
29import Control.Monad.ST (unsafeIOToST)
31import Control.Monad.ST (unsafeIOToST)
30import Data.Text.Internal (Text(..), empty)
32import Data.Text.Internal (Text(..), empty)
31import qualified Data.Text.Array as A
33import qualified Data.Text.Array as A
@@ -53,7 +55,11 @@ fromPtr :: Ptr Word16 -- ^ source array
53 -> Int -- ^ length of source array (in 'Word16' units)
55 -> Int -- ^ length of source array (in 'Word16' units)
54 -> IO Text
56 -> IO Text
55fromPtr _ 0 = return empty
57fromPtr _ 0 = return empty
58+fromPtr ptr len =
59+#if defined(ASSERTS)
60+ assert (len > 0) $
61+#endif
56−fromPtr ptr len = assert (len > 0) $ return (Text arr 0 len)
62+ return $! Text arr 0 len
57 where
63 where
58 arr = A.run (A.unsafeNew len >>= copy)
64 arr = A.run (A.unsafeNew len >>= copy)
59 copy marr = loop ptr 0
65 copy marr = loop ptr 0
@@ -68,6 +74,7 @@ fromPtr ptr len = assert (len > 0) $ return (Text arr 0 len)
68-- 'unsafeCopyToPtr'.
74-- 'unsafeCopyToPtr'.
69lengthWord16 :: Text -> Int
75lengthWord16 :: Text -> Int
70lengthWord16 (Text _arr _off len) = len
76lengthWord16 (Text _arr _off len) = len
77+{-# INLINE lengthWord16 #-}
71
78
72-- | /O(n)/ Copy a 'Text' to an array. The array is assumed to be big
79-- | /O(n)/ Copy a 'Text' to an array. The array is assumed to be big
73-- enough to hold the contents of the entire 'Text'.
80-- enough to hold the contents of the entire 'Text'.
Data/Text/Fusion.hs+1−2
@@ -47,9 +47,8 @@ import Prelude (Bool(..), Char, Maybe(..), Monad(..), Int,
47 Num(..), Ord(..), ($), (&&),
47 Num(..), Ord(..), ($), (&&),
48 fromIntegral, otherwise)
48 fromIntegral, otherwise)
49import Data.Bits ((.&.))
49import Data.Bits ((.&.))
50−import Data.Char (ord)
51import Data.Text.Internal (Text(..))
50import Data.Text.Internal (Text(..))
52−import Data.Text.UnsafeChar (unsafeChr, unsafeWrite)
51+import Data.Text.UnsafeChar (ord, unsafeChr, unsafeWrite)
53import Data.Text.UnsafeShift (shiftL, shiftR)
52import Data.Text.UnsafeShift (shiftL, shiftR)
54import qualified Data.Text.Array as A
53import qualified Data.Text.Array as A
55import qualified Data.Text.Fusion.Common as S
54import qualified Data.Text.Fusion.Common as S
Data/Text/Fusion/Size.hs+13−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1{-# OPTIONS_GHC -fno-warn-missing-methods #-}
2{-# OPTIONS_GHC -fno-warn-missing-methods #-}
2-- |
3-- |
3-- Module : Data.Text.Fusion.Internal
4-- Module : Data.Text.Fusion.Internal
@@ -26,7 +27,9 @@ module Data.Text.Fusion.Size
26 , isEmpty
27 , isEmpty
27 ) where
28 ) where
28
29
30+#if defined(ASSERTS)
29import Control.Exception (assert)
31import Control.Exception (assert)
32+#endif
30
33
31data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
34data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
32 | Max {-# UNPACK #-} !Int -- ^ Upper bound on size.
35 | Max {-# UNPACK #-} !Int -- ^ Upper bound on size.
@@ -34,11 +37,19 @@ data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
34 deriving (Eq, Show)
37 deriving (Eq, Show)
35
38
36exactSize :: Int -> Size
39exactSize :: Int -> Size
37−exactSize n = assert (n >= 0) Exact n
40+exactSize n =
41+#if defined(ASSERTS)
42+ assert (n >= 0)
43+#endif
44+ Exact n
38{-# INLINE exactSize #-}
45{-# INLINE exactSize #-}
39
46
40maxSize :: Int -> Size
47maxSize :: Int -> Size
41−maxSize n = assert (n >= 0) Max n
48+maxSize n =
49+#if defined(ASSERTS)
50+ assert (n >= 0)
51+#endif
52+ Max n
42{-# INLINE maxSize #-}
53{-# INLINE maxSize #-}
43
54
44unknownSize :: Size
55unknownSize :: Size
Data/Text/Internal.hs+12−8
@@ -1,4 +1,4 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
1+{-# LANGUAGE CPP, DeriveDataTypeable #-}
2
2
3-- |
3-- |
4-- Module : Data.Text.Internal
4-- Module : Data.Text.Internal
@@ -28,7 +28,9 @@ module Data.Text.Internal
28 , showText
28 , showText
29 ) where
29 ) where
30
30
31+#if defined(ASSERTS)
31import Control.Exception (assert)
32import Control.Exception (assert)
33+#endif
32import qualified Data.Text.Array as A
34import qualified Data.Text.Array as A
33import Data.Typeable (Typeable)
35import Data.Typeable (Typeable)
34
36
@@ -42,13 +44,15 @@ data Text = Text
42-- | Smart constructor.
44-- | Smart constructor.
43text :: A.Array -> Int -> Int -> Text
45text :: A.Array -> Int -> Int -> Text
44text arr off len =
46text arr off len =
47+#if defined(ASSERTS)
48+ let c = A.unsafeIndex arr off
49+ alen = A.length arr
45− assert (len >= 0) .
50+ in assert (len >= 0) .
46− assert (off >= 0) .
51+ assert (off >= 0) .
47− assert (alen == 0 || len == 0 || off < alen) .
52+ assert (alen == 0 || len == 0 || off < alen) .
48− assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $
53+ assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $
54+#endif
49− Text arr off len
55+ Text arr off len
50− where c = A.unsafeIndex arr off
51− alen = A.length arr
52{-# INLINE text #-}
56{-# INLINE text #-}
53
57
54-- | /O(1)/ The empty 'Text'.
58-- | /O(1)/ The empty 'Text'.
Data/Text/Lazy/Builder.hs+13−5
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, Rank2Types #-}
1+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
2
2
3-----------------------------------------------------------------------------
3-----------------------------------------------------------------------------
4-- |
4-- |
@@ -29,7 +29,9 @@ module Data.Text.Lazy.Builder
29 , flush
29 , flush
30 ) where
30 ) where
31
31
32+#if defined(ASSERTS)
32import Control.Exception (assert)
33import Control.Exception (assert)
34+#endif
33import Control.Monad.ST (ST, runST)
35import Control.Monad.ST (ST, runST)
34import Data.Bits ((.&.))
36import Data.Bits ((.&.))
35import Data.Char (ord)
37import Data.Char (ord)
@@ -259,8 +261,10 @@ newBuffer size = do
259-- | Unsafely copy the elements of an array.
261-- | Unsafely copy the elements of an array.
260unsafeCopy :: A.Array -> Int -> A.MArray s -> Int -> Int -> ST s ()
262unsafeCopy :: A.Array -> Int -> A.MArray s -> Int -> Int -> ST s ()
261unsafeCopy src sidx dest didx count =
263unsafeCopy src sidx dest didx count =
264+#if defined(ASSERTS)
262 assert (sidx + count <= A.length src) .
265 assert (sidx + count <= A.length src) .
263 assert (didx + count <= A.length dest) $
266 assert (didx + count <= A.length dest) $
267+#endif
264 copy_loop sidx didx 0
268 copy_loop sidx didx 0
265 where
269 where
266 copy_loop !i !j !c
270 copy_loop !i !j !c
@@ -274,12 +278,16 @@ unsafeCopy src sidx dest didx count =
274unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
278unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
275unsafeWrite marr i c
279unsafeWrite marr i c
276 | n < 0x10000 = do
280 | n < 0x10000 = do
281+#if defined(ASSERTS)
277− assert (i >= 0) . assert (i < A.length marr) $
282+ assert (i >= 0) . assert (i < A.length marr) $ return ()
283+#endif
278− A.unsafeWrite marr i (fromIntegral n)
284+ A.unsafeWrite marr i (fromIntegral n)
279 return 1
285 return 1
280 | otherwise = do
286 | otherwise = do
287+#if defined(ASSERTS)
281− assert (i >= 0) . assert (i < A.length marr - 1) $
288+ assert (i >= 0) . assert (i < A.length marr - 1) $ return ()
289+#endif
282− A.unsafeWrite marr i lo
290+ A.unsafeWrite marr i lo
283 A.unsafeWrite marr (i+1) hi
291 A.unsafeWrite marr (i+1) hi
284 return 2
292 return 2
285 where n = ord c
293 where n = ord c
Data/Text/Lazy/Encoding/Fusion.hs+8−2
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, Rank2Types #-}
1+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
2
2
3-- |
3-- |
4-- Module : Data.Text.Lazy.Encoding.Fusion
4-- Module : Data.Text.Lazy.Encoding.Fusion
@@ -43,7 +43,9 @@ import System.IO.Unsafe (unsafePerformIO)
43import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
43import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
44import Foreign.Storable (pokeByteOff)
44import Foreign.Storable (pokeByteOff)
45import Data.ByteString.Internal (mallocByteString, memcpy)
45import Data.ByteString.Internal (mallocByteString, memcpy)
46+#if defined(ASSERTS)
46import Control.Exception (assert)
47import Control.Exception (assert)
48+#endif
47import qualified Data.ByteString.Internal as B
49import qualified Data.ByteString.Internal as B
48
50
49data S = S0
51data S = S0
@@ -123,7 +125,11 @@ unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 (upperBound 4 len0)
123 loop n' (off+1) s fp'
125 loop n' (off+1) s fp'
124 trimUp fp off = B.PS fp 0 off
126 trimUp fp off = B.PS fp 0 off
125 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
127 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
126− copy0 !src !srcLen !destLen = assert (srcLen <= destLen) $ do
128+ copy0 !src !srcLen !destLen =
129+#if defined(ASSERTS)
130+ assert (srcLen <= destLen) $
131+#endif
132+ do
127 dest <- mallocByteString destLen
133 dest <- mallocByteString destLen
128 withForeignPtr src $ \src' ->
134 withForeignPtr src $ \src' ->
129 withForeignPtr dest $ \dest' ->
135 withForeignPtr dest $ \dest' ->
Data/Text/Unsafe.hs+25−20
@@ -21,7 +21,9 @@ module Data.Text.Unsafe
21 , unsafeTail
21 , unsafeTail
22 ) where
22 ) where
23
23
24+#if defined(ASSERTS)
24import Control.Exception (assert)
25import Control.Exception (assert)
26+#endif
25import Data.Text.Encoding.Utf16 (chr2)
27import Data.Text.Encoding.Utf16 (chr2)
26import Data.Text.Internal (Text(..))
28import Data.Text.Internal (Text(..))
27import Data.Text.UnsafeChar (unsafeChr)
29import Data.Text.UnsafeChar (unsafeChr)
@@ -40,11 +42,11 @@ import GHC.Base (realWorld#)
40-- omits the check for the empty case, so there is an obligation on
42-- omits the check for the empty case, so there is an obligation on
41-- the programmer to provide a proof that the 'Text' is non-empty.
43-- the programmer to provide a proof that the 'Text' is non-empty.
42unsafeHead :: Text -> Char
44unsafeHead :: Text -> Char
43−unsafeHead (Text arr off len)
45+unsafeHead (Text arr off _len)
44 | m < 0xD800 || m > 0xDBFF = unsafeChr m
46 | m < 0xD800 || m > 0xDBFF = unsafeChr m
45 | otherwise = chr2 m n
47 | otherwise = chr2 m n
46− where m = assert (len > 0) $ A.unsafeIndex arr off
48+ where m = A.unsafeIndex arr off
47− n = assert (len > 1) $ A.unsafeIndex arr (off+1)
49+ n = A.unsafeIndex arr (off+1)
48{-# INLINE unsafeHead #-}
50{-# INLINE unsafeHead #-}
49
51
50-- | /O(1)/ A variant of 'tail' for non-empty 'Text'. 'unsafeHead'
52-- | /O(1)/ A variant of 'tail' for non-empty 'Text'. 'unsafeHead'
@@ -52,42 +54,45 @@ unsafeHead (Text arr off len)
52-- the programmer to provide a proof that the 'Text' is non-empty.
54-- the programmer to provide a proof that the 'Text' is non-empty.
53unsafeTail :: Text -> Text
55unsafeTail :: Text -> Text
54unsafeTail t@(Text arr off len) =
56unsafeTail t@(Text arr off len) =
57+#if defined(ASSERTS)
58+ assert (d <= len) $
59+#endif
55− assert (d <= len) $ Text arr (off+d) (len-d)
60+ Text arr (off+d) (len-d)
56 where d = iter_ t 0
61 where d = iter_ t 0
57{-# INLINE unsafeTail #-}
62{-# INLINE unsafeTail #-}
58
63
59−-- | /O(1)/ Iterate one step forwards through a UTF-16 array,
64+-- | /O(1)/ Iterate (unsafely) one step forwards through a UTF-16
60−-- returning the current character and the delta to add to give the
65+-- array, returning the current character and the delta to add to give
61−-- next offset to iterate at.
66+-- the next offset to iterate at.
62iter :: Text -> Int -> (Char,Int)
67iter :: Text -> Int -> (Char,Int)
63−iter (Text arr off len) i
68+iter (Text arr off _len) i
64 | m < 0xD800 || m > 0xDBFF = (unsafeChr m, 1)
69 | m < 0xD800 || m > 0xDBFF = (unsafeChr m, 1)
65 | otherwise = (chr2 m n, 2)
70 | otherwise = (chr2 m n, 2)
66− where m = assert (i < len) $ A.unsafeIndex arr j
71+ where m = A.unsafeIndex arr j
67− n = assert (i + 1 < len) $ A.unsafeIndex arr k
72+ n = A.unsafeIndex arr k
68− j = assert (i >= 0) $ off + i
73+ j = off + i
69− k = j + 1
74+ k = j + 1
70{-# INLINE iter #-}
75{-# INLINE iter #-}
71
76
72-- | /O(1)/ Iterate one step through a UTF-16 array, returning the
77-- | /O(1)/ Iterate one step through a UTF-16 array, returning the
73-- delta to add to give the next offset to iterate at.
78-- delta to add to give the next offset to iterate at.
74iter_ :: Text -> Int -> Int
79iter_ :: Text -> Int -> Int
75−iter_ (Text arr off len) i | m < 0xD800 || m > 0xDBFF = 1
80+iter_ (Text arr off _len) i | m < 0xD800 || m > 0xDBFF = 1
76− | otherwise = 2
81+ | otherwise = 2
77− where m = assert (i >= 0 && i < len) $ A.unsafeIndex arr (off+i)
82+ where m = A.unsafeIndex arr (off+i)
78{-# INLINE iter_ #-}
83{-# INLINE iter_ #-}
79
84
80-- | /O(1)/ Iterate one step backwards through a UTF-16 array,
85-- | /O(1)/ Iterate one step backwards through a UTF-16 array,
81-- returning the current character and the delta to add (i.e. a
86-- returning the current character and the delta to add (i.e. a
82-- negative number) to give the next offset to iterate at.
87-- negative number) to give the next offset to iterate at.
83reverseIter :: Text -> Int -> (Char,Int)
88reverseIter :: Text -> Int -> (Char,Int)
84−reverseIter (Text arr off len) i
89+reverseIter (Text arr off _len) i
85 | m < 0xDC00 || m > 0xDFFF = (unsafeChr m, -1)
90 | m < 0xDC00 || m > 0xDFFF = (unsafeChr m, -1)
86 | otherwise = (chr2 n m, -2)
91 | otherwise = (chr2 n m, -2)
87− where m = assert (i < len) $ A.unsafeIndex arr j
92+ where m = A.unsafeIndex arr j
88− n = assert (i - 1 >= 0) $ A.unsafeIndex arr k
93+ n = A.unsafeIndex arr k
89− j = assert (i >= 0) $ off + i
94+ j = off + i
90− k = j - 1
95+ k = j - 1
91{-# INLINE reverseIter #-}
96{-# INLINE reverseIter #-}
92
97
93-- | Just like unsafePerformIO, but we inline it. Big performance gains as
98-- | Just like unsafePerformIO, but we inline it. Big performance gains as
Data/Text/UnsafeChar.hs+18−8
@@ -1,4 +1,4 @@
1−{-# LANGUAGE MagicHash #-}
1+{-# LANGUAGE CPP, MagicHash #-}
2
2
3-- |
3-- |
4-- Module : Data.Text.UnsafeChar
4-- Module : Data.Text.UnsafeChar
@@ -15,22 +15,28 @@
15-- Fast character manipulation functions.
15-- Fast character manipulation functions.
16module Data.Text.UnsafeChar
16module Data.Text.UnsafeChar
17 (
17 (
18+ ord
18− unsafeChr
19+ , unsafeChr
19 , unsafeChr8
20 , unsafeChr8
20 , unsafeChr32
21 , unsafeChr32
21 , unsafeWrite
22 , unsafeWrite
22 -- , unsafeWriteRev
23 -- , unsafeWriteRev
23 ) where
24 ) where
24
25
26+#ifdef ASSERTS
25import Control.Exception (assert)
27import Control.Exception (assert)
28+#endif
26import Control.Monad.ST (ST)
29import Control.Monad.ST (ST)
27import Data.Bits ((.&.))
30import Data.Bits ((.&.))
28−import Data.Char (ord)
29import Data.Text.UnsafeShift (shiftR)
31import Data.Text.UnsafeShift (shiftR)
30−import GHC.Exts (Char(..), chr#, word2Int#)
32+import GHC.Exts (Char(..), Int(..), chr#, ord#, word2Int#)
31import GHC.Word (Word8(..), Word16(..), Word32(..))
33import GHC.Word (Word8(..), Word16(..), Word32(..))
32import qualified Data.Text.Array as A
34import qualified Data.Text.Array as A
33
35
36+ord :: Char -> Int
37+ord (C# c#) = I# (ord# c#)
38+{-# INLINE ord #-}
39+
34unsafeChr :: Word16 -> Char
40unsafeChr :: Word16 -> Char
35unsafeChr (W16# w#) = C# (chr# (word2Int# w#))
41unsafeChr (W16# w#) = C# (chr# (word2Int# w#))
36{-# INLINE unsafeChr #-}
42{-# INLINE unsafeChr #-}
@@ -46,12 +52,16 @@ unsafeChr32 (W32# w#) = C# (chr# (word2Int# w#))
46unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
52unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
47unsafeWrite marr i c
53unsafeWrite marr i c
48 | n < 0x10000 = do
54 | n < 0x10000 = do
55+#if defined(ASSERTS)
49− assert (i >= 0) . assert (i < A.length marr) $
56+ assert (i >= 0) . assert (i < A.length marr) $ return ()
57+#endif
50− A.unsafeWrite marr i (fromIntegral n)
58+ A.unsafeWrite marr i (fromIntegral n)
51 return $! i+1
59 return $! i+1
52 | otherwise = do
60 | otherwise = do
61+#if defined(ASSERTS)
53− assert (i >= 0) . assert (i < A.length marr - 1) $
62+ assert (i >= 0) . assert (i < A.length marr - 1) $ return ()
63+#endif
54− A.unsafeWrite marr i lo
64+ A.unsafeWrite marr i lo
55 A.unsafeWrite marr (i+1) hi
65 A.unsafeWrite marr (i+1) hi
56 return $! i+2
66 return $! i+2
57 where n = ord c
67 where n = ord c
text.cabal+1
@@ -85,3 +85,4 @@ library
85 ghc-options: -fwarn-tabs
85 ghc-options: -fwarn-tabs
86 if flag(developer)
86 if flag(developer)
87 ghc-options: -Werror
87 ghc-options: -Werror
88+ cpp-options: -DASSERTS