on master help sign in
Merge pull request #135 from paulcapron/master

Implement takeWhileEnd

commit8aef850cfd87a3df3785e527befe1ff61b23e249 authorBryan O'Sullivan <bos@serpentine.com> dateTue 22 Dec 2015, 11:08 (11 years ago) parent52f09467534f3c
3 files changed+43
Data/Text.hs+22 Data/Text/Lazy.hs+15 tests/Tests/Properties.hs+6
Data/Text.hs+22
@@ -129,6 +129,7 @@ module Data.Text
129129 , drop
130130 , dropEnd
131131 , takeWhile
132+ , takeWhileEnd
132133 , dropWhile
133134 , dropWhileEnd
134135 , dropAround
@@ -1144,6 +1145,27 @@ takeWhile p t@(Text arr off len) = loop 0
11441145 unstream (S.takeWhile p (stream t)) = takeWhile p t
11451146 #-}
11461147
1148+-- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',
1149+-- returns the longest suffix (possibly empty) of elements that
1150+-- satisfy @p@. Subject to fusion.
1151+-- Examples:
1152+--
1153+-- > takeWhileEnd (=='o') "foo" == "oo"
1154+takeWhileEnd :: (Char -> Bool) -> Text -> Text
1155+takeWhileEnd p t@(Text arr off len) = loop (len-1) len
1156+ where loop !i !l | l <= 0 = t
1157+ | p c = loop (i+d) (l+d)
1158+ | otherwise = text arr (off+l) (len-l)
1159+ where (c,d) = reverseIter t i
1160+{-# INLINE [1] takeWhileEnd #-}
1161+
1162+{-# RULES
1163+"TEXT takeWhileEnd -> fused" [~1] forall p t.
1164+ takeWhileEnd p t = S.reverse (S.takeWhile p (S.reverseStream t))
1165+"TEXT takeWhileEnd -> unfused" [1] forall p t.
1166+ S.reverse (S.takeWhile p (S.reverseStream t)) = takeWhileEnd p t
1167+ #-}
1168+
11471169-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after
11481170-- 'takeWhile' @p@ @t@. Subject to fusion.
11491171dropWhile :: (Char -> Bool) -> Text -> Text
Data/Text/Lazy.hs+15
@@ -140,6 +140,7 @@ module Data.Text.Lazy
140140 , drop
141141 , dropEnd
142142 , takeWhile
143+ , takeWhileEnd
143144 , dropWhile
144145 , dropWhileEnd
145146 , dropAround
@@ -1139,6 +1140,20 @@ takeWhile p t0 = takeWhile' t0
11391140"LAZY TEXT takeWhile -> unfused" [1] forall p t.
11401141 unstream (S.takeWhile p (stream t)) = takeWhile p t
11411142 #-}
1143+-- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',
1144+-- returns the longest suffix (possibly empty) of elements that
1145+-- satisfy @p@.
1146+-- Examples:
1147+--
1148+-- > takeWhileEnd (=='o') "foo" == "oo"
1149+takeWhileEnd :: (Char -> Bool) -> Text -> Text
1150+takeWhileEnd p = takeChunk empty . L.reverse . toChunks
1151+ where takeChunk acc [] = acc
1152+ takeChunk acc (t:ts) = if T.length t' < T.length t
1153+ then (Chunk t' acc)
1154+ else takeChunk (Chunk t' acc) ts
1155+ where t' = T.takeWhileEnd p t
1156+{-# INLINE takeWhileEnd #-}
11421157
11431158-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after
11441159-- 'takeWhile' @p@ @t@. Subject to fusion.
tests/Tests/Properties.hs+6
@@ -516,6 +516,10 @@ sf_takeWhile q p = (L.takeWhile p . L.filter q) `eqP`
516516 (unpackS . S.takeWhile p . S.filter q)
517517t_takeWhile p = L.takeWhile p `eqP` (unpackS . T.takeWhile p)
518518tl_takeWhile p = L.takeWhile p `eqP` (unpackS . TL.takeWhile p)
519+t_takeWhileEnd p = (L.reverse . L.takeWhile p . L.reverse) `eqP`
520+ (unpackS . T.takeWhileEnd p)
521+tl_takeWhileEnd p = (L.reverse . L.takeWhile p . L.reverse) `eqP`
522+ (unpackS . TL.takeWhileEnd p)
519523s_dropWhile p = L.dropWhile p `eqP` (unpackS . S.dropWhile p)
520524s_dropWhile_s p = L.dropWhile p `eqP` (unpackS . S.unstream . S.dropWhile p)
521525sf_dropWhile q p = (L.dropWhile p . L.filter q) `eqP`
@@ -1142,6 +1146,8 @@ tests =
11421146 testProperty "sf_takeWhile" sf_takeWhile,
11431147 testProperty "t_takeWhile" t_takeWhile,
11441148 testProperty "tl_takeWhile" tl_takeWhile,
1149+ testProperty "t_takeWhileEnd" t_takeWhileEnd,
1150+ testProperty "tl_takeWhileEnd" tl_takeWhileEnd,
11451151 testProperty "sf_dropWhile" sf_dropWhile,
11461152 testProperty "s_dropWhile" s_dropWhile,
11471153 testProperty "s_dropWhile_s" s_dropWhile_s,