Skip to content

Commit a83eac1

Browse files
committed
Add RULES for break, span, takeWhile, dropWhile on single character
1 parent c0b11ac commit a83eac1

2 files changed

Lines changed: 64 additions & 6 deletions

File tree

src/Data/Text.hs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ import Prelude (Char, Bool(..), Int, Maybe(..), String,
228228
Eq, (==), (/=), Ord(..), Ordering(..), (++),
229229
Monad(..), pure, Read(..), Show,
230230
(&&), (||), (+), (-), (.), ($), ($!), (>>),
231-
not, return, otherwise, quot)
231+
fst, not, return, otherwise, quot, snd)
232232
import Control.DeepSeq (NFData(rnf))
233233
#if defined(ASSERTS)
234234
import Control.Exception (assert)
@@ -273,7 +273,7 @@ import qualified Data.Text.Lazy as L
273273
#endif
274274
import Data.Word (Word8)
275275
import Foreign.C.Types
276-
import GHC.Base (eqInt, neInt, gtInt, geInt, ltInt, leInt)
276+
import GHC.Base (eqChar, neChar, eqInt, neInt, gtInt, geInt, ltInt, leInt)
277277
import qualified GHC.Exts as Exts
278278
import GHC.Int (Int8)
279279
import GHC.Stack (HasCallStack)
@@ -1522,6 +1522,13 @@ takeWhile p t@(Text arr off len) = loop 0
15221522
where Iter c d = iter t i
15231523
{-# INLINE [1] takeWhile #-}
15241524

1525+
{-# RULES
1526+
"TEXT takeWhile (c `neChar`) -> fst . breakOn (singleton c)" forall c.
1527+
takeWhile (c `neChar`) = fst . breakOn (singleton c)
1528+
"TEXT takeWhile (`neChar` c) -> fst . breakOn (singleton c)" forall c.
1529+
takeWhile (`neChar` c) = fst . breakOn (singleton c)
1530+
#-}
1531+
15251532
-- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',
15261533
-- returns the longest suffix (possibly empty) of elements that
15271534
-- satisfy @p@.
@@ -1549,6 +1556,13 @@ dropWhile p t@(Text arr off len) = loop 0 0
15491556
where Iter c d = iter t i
15501557
{-# INLINE [1] dropWhile #-}
15511558

1559+
{-# RULES
1560+
"TEXT dropWhile (c `neChar`) -> snd . breakOn (singleton c)" forall c.
1561+
dropWhile (c `neChar`) = snd . breakOn (singleton c)
1562+
"TEXT dropWhile (`neChar` c) -> snd . breakOn (singleton c)" forall c.
1563+
dropWhile (`neChar` c) = snd . breakOn (singleton c)
1564+
#-}
1565+
15521566
-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after
15531567
-- dropping characters that satisfy the predicate @p@ from the end of
15541568
-- @t@.
@@ -1615,7 +1629,14 @@ splitAt n t@(Text arr off len)
16151629
span :: (Char -> Bool) -> Text -> (Text, Text)
16161630
span p t = case span_ p t of
16171631
(# hd,tl #) -> (hd,tl)
1618-
{-# INLINE span #-}
1632+
{-# INLINE [1] span #-}
1633+
1634+
{-# RULES
1635+
"TEXT span (c `neChar`) -> breakOn (singleton c)" forall c.
1636+
span (c `neChar`) = breakOn (singleton c)
1637+
"TEXT span (`neChar` c) -> breakOn (singleton c)" forall c.
1638+
span (`neChar` c) = breakOn (singleton c)
1639+
#-}
16191640

16201641
-- | /O(n)/ 'break' is like 'span', but the prefix returned is
16211642
-- over elements that fail the predicate @p@.
@@ -1624,7 +1645,14 @@ span p t = case span_ p t of
16241645
-- ("180","cm")
16251646
break :: (Char -> Bool) -> Text -> (Text, Text)
16261647
break p = span (not . p)
1627-
{-# INLINE break #-}
1648+
{-# INLINE [1] break #-}
1649+
1650+
{-# RULES
1651+
"TEXT break (c `eqChar`) -> breakOn (singleton c)" forall c.
1652+
break (c `eqChar`) = breakOn (singleton c)
1653+
"TEXT break (`eqChar` c) -> breakOn (singleton c)" forall c.
1654+
break (`eqChar` c) = breakOn (singleton c)
1655+
#-}
16281656

16291657
spanEnd :: (Char -> Bool) -> Text -> (Text, Text)
16301658
spanEnd = coerce (spanEndM :: (Char -> Identity Bool) -> Text -> Identity (Text, Text))

src/Data/Text/Lazy.hs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ import Prelude (Char, Bool(..), Maybe(..), String,
219219
Eq, (==), Ord(..), Ordering(..), Read(..), Show(showsPrec),
220220
Monad(..), pure, (<$>),
221221
(&&), (+), (-), (.), ($), (++),
222-
error, flip, fmap, fromIntegral, not, otherwise, quot)
222+
error, fst, flip, fmap, fromIntegral, not, otherwise, quot, snd)
223223
import qualified Prelude as P
224224
import Control.Arrow (first)
225225
import Control.DeepSeq (NFData(..))
@@ -253,6 +253,7 @@ import Data.Text.Lazy.Encoding (decodeUtf8', encodeUtf8Builder)
253253
import Data.Text.Internal.Lazy.Search (indices)
254254
import qualified GHC.CString as GHC
255255
import qualified GHC.Exts as Exts
256+
import GHC.Char (eqChar, neChar)
256257
import GHC.Prim (Addr#)
257258
import GHC.Stack (HasCallStack)
258259
#if __GLASGOW_HASKELL__ >= 914
@@ -1230,6 +1231,13 @@ takeWhile p t0 = takeWhile' t0
12301231
Nothing -> Chunk t (takeWhile' ts)
12311232
{-# INLINE [1] takeWhile #-}
12321233

1234+
{-# RULES
1235+
"TEXT takeWhile (c `neChar`) -> fst . breakOn (singleton c)" forall c.
1236+
takeWhile (c `neChar`) = fst . breakOn (singleton c)
1237+
"TEXT takeWhile (`neChar` c) -> fst . breakOn (singleton c)" forall c.
1238+
takeWhile (`neChar` c) = fst . breakOn (singleton c)
1239+
#-}
1240+
12331241
-- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',
12341242
-- returns the longest suffix (possibly empty) of elements that
12351243
-- satisfy @p@.
@@ -1259,6 +1267,13 @@ dropWhile p t0 = dropWhile' t0
12591267
Nothing -> dropWhile' ts
12601268
{-# INLINE [1] dropWhile #-}
12611269

1270+
{-# RULES
1271+
"TEXT dropWhile (c `neChar`) -> snd . breakOn (singleton c)" forall c.
1272+
dropWhile (c `neChar`) = snd . breakOn (singleton c)
1273+
"TEXT dropWhile (`neChar` c) -> snd . breakOn (singleton c)" forall c.
1274+
dropWhile (`neChar` c) = snd . breakOn (singleton c)
1275+
#-}
1276+
12621277
-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after
12631278
-- dropping characters that satisfy the predicate @p@ from the end of
12641279
-- @t@.
@@ -1435,6 +1450,14 @@ break p t0 = break' t0
14351450
Just n | n == 0 -> (Empty, c)
14361451
| otherwise -> let (a,b) = T.splitAt n t
14371452
in (Chunk a Empty, Chunk b ts)
1453+
{-# INLINE [1] break #-}
1454+
1455+
{-# RULES
1456+
"TEXT break (c `eqChar`) -> breakOn (singleton c)" forall c.
1457+
break (c `eqChar`) = breakOn (singleton c)
1458+
"TEXT break (`eqChar` c) -> breakOn (singleton c)" forall c.
1459+
break (`eqChar` c) = breakOn (singleton c)
1460+
#-}
14381461

14391462
-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns
14401463
-- a pair whose first element is the longest prefix (possibly empty)
@@ -1445,7 +1468,14 @@ break p t0 = break' t0
14451468
-- ("000","AB")
14461469
span :: (Char -> Bool) -> Text -> (Text, Text)
14471470
span p = break (not . p)
1448-
{-# INLINE span #-}
1471+
{-# INLINE [1] span #-}
1472+
1473+
{-# RULES
1474+
"TEXT span (c `neChar`) -> breakOn (singleton c)" forall c.
1475+
span (c `neChar`) = breakOn (singleton c)
1476+
"TEXT span (`neChar` c) -> breakOn (singleton c)" forall c.
1477+
span (`neChar` c) = breakOn (singleton c)
1478+
#-}
14491479

14501480
-- | /O(length of prefix)/ 'spanM', applied to a monadic predicate @p@,
14511481
-- a text @t@, returns a pair @(t1, t2)@ where @t1@ is the longest prefix of

0 commit comments

Comments
 (0)