diff --git a/src/Data/Text.hs b/src/Data/Text.hs index 2b538d1f..7c3d6978 100644 --- a/src/Data/Text.hs +++ b/src/Data/Text.hs @@ -228,7 +228,7 @@ import Prelude (Char, Bool(..), Int, Maybe(..), String, Eq, (==), (/=), Ord(..), Ordering(..), (++), Monad(..), pure, Read(..), Show, (&&), (||), (+), (-), (.), ($), ($!), (>>), - not, return, otherwise, quot) + fst, not, return, otherwise, quot, snd) import Control.DeepSeq (NFData(rnf)) #if defined(ASSERTS) import Control.Exception (assert) @@ -273,7 +273,7 @@ import qualified Data.Text.Lazy as L #endif import Data.Word (Word8) import Foreign.C.Types -import GHC.Base (eqInt, neInt, gtInt, geInt, ltInt, leInt) +import GHC.Base (eqChar, neChar, eqInt, neInt, gtInt, geInt, ltInt, leInt) import qualified GHC.Exts as Exts import GHC.Int (Int8) import GHC.Stack (HasCallStack) @@ -1522,6 +1522,13 @@ takeWhile p t@(Text arr off len) = loop 0 where Iter c d = iter t i {-# INLINE [1] takeWhile #-} +{-# RULES +"TEXT takeWhile (c `neChar`) -> fst . breakOn (singleton c)" forall c. + takeWhile (c `neChar`) = fst . breakOn (singleton c) +"TEXT takeWhile (`neChar` c) -> fst . breakOn (singleton c)" forall c. + takeWhile (`neChar` c) = fst . breakOn (singleton c) + #-} + -- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text', -- returns the longest suffix (possibly empty) of elements that -- satisfy @p@. @@ -1549,6 +1556,13 @@ dropWhile p t@(Text arr off len) = loop 0 0 where Iter c d = iter t i {-# INLINE [1] dropWhile #-} +{-# RULES +"TEXT dropWhile (c `neChar`) -> snd . breakOn (singleton c)" forall c. + dropWhile (c `neChar`) = snd . breakOn (singleton c) +"TEXT dropWhile (`neChar` c) -> snd . breakOn (singleton c)" forall c. + dropWhile (`neChar` c) = snd . breakOn (singleton c) + #-} + -- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after -- dropping characters that satisfy the predicate @p@ from the end of -- @t@. @@ -1615,7 +1629,14 @@ splitAt n t@(Text arr off len) span :: (Char -> Bool) -> Text -> (Text, Text) span p t = case span_ p t of (# hd,tl #) -> (hd,tl) -{-# INLINE span #-} +{-# INLINE [1] span #-} + +{-# RULES +"TEXT span (c `neChar`) -> breakOn (singleton c)" forall c. + span (c `neChar`) = breakOn (singleton c) +"TEXT span (`neChar` c) -> breakOn (singleton c)" forall c. + span (`neChar` c) = breakOn (singleton c) + #-} -- | /O(n)/ 'break' is like 'span', but the prefix returned is -- over elements that fail the predicate @p@. @@ -1624,7 +1645,14 @@ span p t = case span_ p t of -- ("180","cm") break :: (Char -> Bool) -> Text -> (Text, Text) break p = span (not . p) -{-# INLINE break #-} +{-# INLINE [1] break #-} + +{-# RULES +"TEXT break (c `eqChar`) -> breakOn (singleton c)" forall c. + break (c `eqChar`) = breakOn (singleton c) +"TEXT break (`eqChar` c) -> breakOn (singleton c)" forall c. + break (`eqChar` c) = breakOn (singleton c) + #-} spanEnd :: (Char -> Bool) -> Text -> (Text, Text) spanEnd = coerce (spanEndM :: (Char -> Identity Bool) -> Text -> Identity (Text, Text)) diff --git a/src/Data/Text/Lazy.hs b/src/Data/Text/Lazy.hs index ff9859c6..879c9175 100644 --- a/src/Data/Text/Lazy.hs +++ b/src/Data/Text/Lazy.hs @@ -219,7 +219,7 @@ import Prelude (Char, Bool(..), Maybe(..), String, Eq, (==), Ord(..), Ordering(..), Read(..), Show(showsPrec), Monad(..), pure, (<$>), (&&), (+), (-), (.), ($), (++), - error, flip, fmap, fromIntegral, not, otherwise, quot) + error, fst, flip, fmap, fromIntegral, not, otherwise, quot, snd) import qualified Prelude as P import Control.Arrow (first) import Control.DeepSeq (NFData(..)) @@ -253,6 +253,7 @@ import Data.Text.Lazy.Encoding (decodeUtf8', encodeUtf8Builder) import Data.Text.Internal.Lazy.Search (indices) import qualified GHC.CString as GHC import qualified GHC.Exts as Exts +import GHC.Char (eqChar, neChar) import GHC.Prim (Addr#) import GHC.Stack (HasCallStack) #if __GLASGOW_HASKELL__ >= 914 @@ -1230,6 +1231,13 @@ takeWhile p t0 = takeWhile' t0 Nothing -> Chunk t (takeWhile' ts) {-# INLINE [1] takeWhile #-} +{-# RULES +"TEXT takeWhile (c `neChar`) -> fst . breakOn (singleton c)" forall c. + takeWhile (c `neChar`) = fst . breakOn (singleton c) +"TEXT takeWhile (`neChar` c) -> fst . breakOn (singleton c)" forall c. + takeWhile (`neChar` c) = fst . breakOn (singleton c) + #-} + -- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text', -- returns the longest suffix (possibly empty) of elements that -- satisfy @p@. @@ -1259,6 +1267,13 @@ dropWhile p t0 = dropWhile' t0 Nothing -> dropWhile' ts {-# INLINE [1] dropWhile #-} +{-# RULES +"TEXT dropWhile (c `neChar`) -> snd . breakOn (singleton c)" forall c. + dropWhile (c `neChar`) = snd . breakOn (singleton c) +"TEXT dropWhile (`neChar` c) -> snd . breakOn (singleton c)" forall c. + dropWhile (`neChar` c) = snd . breakOn (singleton c) + #-} + -- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after -- dropping characters that satisfy the predicate @p@ from the end of -- @t@. @@ -1435,6 +1450,14 @@ break p t0 = break' t0 Just n | n == 0 -> (Empty, c) | otherwise -> let (a,b) = T.splitAt n t in (Chunk a Empty, Chunk b ts) +{-# INLINE [1] break #-} + +{-# RULES +"TEXT break (c `eqChar`) -> breakOn (singleton c)" forall c. + break (c `eqChar`) = breakOn (singleton c) +"TEXT break (`eqChar` c) -> breakOn (singleton c)" forall c. + break (`eqChar` c) = breakOn (singleton c) + #-} -- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns -- a pair whose first element is the longest prefix (possibly empty) @@ -1445,7 +1468,14 @@ break p t0 = break' t0 -- ("000","AB") span :: (Char -> Bool) -> Text -> (Text, Text) span p = break (not . p) -{-# INLINE span #-} +{-# INLINE [1] span #-} + +{-# RULES +"TEXT span (c `neChar`) -> breakOn (singleton c)" forall c. + span (c `neChar`) = breakOn (singleton c) +"TEXT span (`neChar` c) -> breakOn (singleton c)" forall c. + span (`neChar` c) = breakOn (singleton c) + #-} -- | /O(length of prefix)/ 'spanM', applied to a monadic predicate @p@, -- a text @t@, returns a pair @(t1, t2)@ where @t1@ is the longest prefix of