on master help sign in
Implement and test lazy takeWhile and dropWhile
b15c35eBryan O'Sullivan
Data/Text/Lazy.hs+40−2
@@ -96,8 +96,8 @@ module Data.Text.Lazy
96 -- ** Breaking strings
96 -- ** Breaking strings
97 , take
97 , take
98 , drop
98 , drop
99− -- , takeWhile
99+ , takeWhile
100− -- , dropWhile
100+ , dropWhile
101 , splitAt
101 , splitAt
102 -- , span
102 -- , span
103 -- , break
103 -- , break
@@ -536,6 +536,44 @@ drop i t0
536 unstream (S.drop n (stream t)) = drop n t
536 unstream (S.drop n (stream t)) = drop n t
537 #-}
537 #-}
538
538
539+-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text', returns
540+-- the longest prefix (possibly empty) of elements that satisfy @p@.
541+-- This function is subject to array fusion.
542+takeWhile :: (Char -> Bool) -> Text -> Text
543+takeWhile p t0 = takeWhile' t0
544+ where takeWhile' Empty = Empty
545+ takeWhile' (Chunk t ts) =
546+ case T.findIndex (not . p) t of
547+ Just n | n > 0 -> Chunk (T.take n t) Empty
548+ | otherwise -> Empty
549+ Nothing -> Chunk t (takeWhile' ts)
550+{-# INLINE [1] takeWhile #-}
551+
552+{-# RULES
553+"LAZY TEXT takeWhile -> fused" [~1] forall p t.
554+ takeWhile p t = unstream (S.takeWhile p (stream t))
555+"LAZY TEXT takeWhile -> unfused" [1] forall p t.
556+ unstream (S.takeWhile p (stream t)) = takeWhile p t
557+ #-}
558+
559+-- | /O(n)/ 'dropWhile' @p@ @xs@ returns the suffix remaining after
560+-- 'takeWhile' @p@ @xs@. This function is subject to array fusion.
561+dropWhile :: (Char -> Bool) -> Text -> Text
562+dropWhile p t0 = dropWhile' t0
563+ where dropWhile' Empty = Empty
564+ dropWhile' (Chunk t ts) =
565+ case T.findIndex (not . p) t of
566+ Just n -> Chunk (T.drop n t) ts
567+ Nothing -> dropWhile' ts
568+{-# INLINE [1] dropWhile #-}
569+
570+{-# RULES
571+"LAZY TEXT dropWhile -> fused" [~1] forall p t.
572+ dropWhile p t = unstream (S.dropWhile p (stream t))
573+"LAZY TEXT dropWhile -> unfused" [1] forall p t.
574+ unstream (S.dropWhile p (stream t)) = dropWhile p t
575+ #-}
576+
539-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
577-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
540-- prefix of @t@ of length @n@, and whose second is the remainder of
578-- prefix of @t@ of length @n@, and whose second is the remainder of
541-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
579-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
tests/Properties.hs+8−4
@@ -221,10 +221,12 @@ prop_TL_take n = L.take n `eqP` (unpackT . TL.take (fromIntegral n)
221prop_S_drop n = L.drop n `eqP` (unpackT . S.drop n)
221prop_S_drop n = L.drop n `eqP` (unpackT . S.drop n)
222prop_T_drop n = L.drop n `eqP` (unpackT . T.drop n)
222prop_T_drop n = L.drop n `eqP` (unpackT . T.drop n)
223prop_TL_drop n = L.drop n `eqP` (unpackT . TL.drop n)
223prop_TL_drop n = L.drop n `eqP` (unpackT . TL.drop n)
224+prop_S_takeWhile p = L.takeWhile p `eqP` (unpackT . S.takeWhile p)
224prop_T_takeWhile p = L.takeWhile p `eqP` (unpackT . T.takeWhile p)
225prop_T_takeWhile p = L.takeWhile p `eqP` (unpackT . T.takeWhile p)
225−prop_T_takeWhileS p = L.takeWhile p `eqP` (unpackT . S.unstream . S.takeWhile p . S.stream)
226+prop_TL_takeWhile p = L.takeWhile p `eqP` (unpackT . TL.takeWhile p)
227+prop_S_dropWhile p = L.dropWhile p `eqP` (unpackT . S.dropWhile p)
226prop_T_dropWhile p = L.dropWhile p `eqP` (unpackT . T.dropWhile p)
228prop_T_dropWhile p = L.dropWhile p `eqP` (unpackT . T.dropWhile p)
227−prop_T_dropWhileS p = L.dropWhile p `eqP` (unpackT . S.unstream . S.dropWhile p . S.stream)
229+prop_TL_dropWhile p = L.dropWhile p `eqP` (unpackT . S.dropWhile p)
228prop_T_splitAt n = L.splitAt n `eqP` (unpack2 . T.splitAt n)
230prop_T_splitAt n = L.splitAt n `eqP` (unpack2 . T.splitAt n)
229prop_TL_splitAt n = L.splitAt n `eqP` (unpack2 . TL.splitAt n)
231prop_TL_splitAt n = L.splitAt n `eqP` (unpack2 . TL.splitAt n)
230prop_T_span p = L.span p `eqP` (unpack2 . T.span p)
232prop_T_span p = L.span p `eqP` (unpack2 . T.span p)
@@ -418,10 +420,12 @@ tests = [
418 ("prop_S_drop", mytest prop_S_drop),
420 ("prop_S_drop", mytest prop_S_drop),
419 ("prop_T_drop", mytest prop_T_drop),
421 ("prop_T_drop", mytest prop_T_drop),
420 ("prop_TL_drop", mytest prop_TL_drop),
422 ("prop_TL_drop", mytest prop_TL_drop),
423+ ("prop_S_takeWhile", mytest prop_S_takeWhile),
421 ("prop_T_takeWhile", mytest prop_T_takeWhile),
424 ("prop_T_takeWhile", mytest prop_T_takeWhile),
422− ("prop_T_takeWhileS", mytest prop_T_takeWhileS),
425+ ("prop_TL_takeWhile", mytest prop_TL_takeWhile),
426+ ("prop_S_dropWhile", mytest prop_S_dropWhile),
423 ("prop_T_dropWhile", mytest prop_T_dropWhile),
427 ("prop_T_dropWhile", mytest prop_T_dropWhile),
424− ("prop_T_dropWhileS", mytest prop_T_dropWhileS),
428+ ("prop_TL_dropWhile", mytest prop_TL_dropWhile),
425 ("prop_T_splitAt", mytest prop_T_splitAt),
429 ("prop_T_splitAt", mytest prop_T_splitAt),
426 ("prop_T_span", mytest prop_T_span),
430 ("prop_T_span", mytest prop_T_span),
427 ("prop_T_break", mytest prop_T_break),
431 ("prop_T_break", mytest prop_T_break),