on master help sign in
Add sliceBeginWith, tests and benchmarks
fb9f05eAnurag Hooda
benchmark/Streamly/Benchmark/Data/Parser.hs+5
@@ -72,6 +72,10 @@ takeEQ value = IP.parse (PR.takeEQ value FL.drain)
72drainWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
72drainWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
73drainWhile value = IP.parse (PR.drainWhile (<= value))
73drainWhile value = IP.parse (PR.drainWhile (<= value))
74
74
75+{-# INLINE sliceBeginWith #-}
76+sliceBeginWith :: MonadCatch m => Int -> SerialT m Int -> m ()
77+sliceBeginWith value = IP.parse (PR.sliceBeginWith (>= value) FL.drain)
78+
75{-# INLINE takeWhile #-}
79{-# INLINE takeWhile #-}
76takeWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
80takeWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
77takeWhile value = IP.parse (PR.takeWhile (<= value) FL.drain)
81takeWhile value = IP.parse (PR.takeWhile (<= value) FL.drain)
@@ -284,6 +288,7 @@ o_1_space_serial value =
284 , benchIOSink value "takeEQ" $ takeEQ value
288 , benchIOSink value "takeEQ" $ takeEQ value
285 , benchIOSink value "takeWhile" $ takeWhile value
289 , benchIOSink value "takeWhile" $ takeWhile value
286 , benchIOSink value "drainWhile" $ drainWhile value
290 , benchIOSink value "drainWhile" $ drainWhile value
291+ , benchIOSink value "sliceBeginWith" $ sliceBeginWith value
287 , benchIOSink value "groupBy" $ groupBy
292 , benchIOSink value "groupBy" $ groupBy
288 , benchIOSink value "groupByRolling" $ groupByRolling
293 , benchIOSink value "groupByRolling" $ groupByRolling
289 , benchIOSink value "wordBy" $ wordBy value
294 , benchIOSink value "wordBy" $ wordBy value
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+5
@@ -63,6 +63,10 @@ benchIOSink value name f =
63drainWhile :: MonadThrow m => (a -> Bool) -> PR.Parser m a ()
63drainWhile :: MonadThrow m => (a -> Bool) -> PR.Parser m a ()
64drainWhile p = PR.takeWhile p FL.drain
64drainWhile p = PR.takeWhile p FL.drain
65
65
66+{-# INLINE sliceBeginWith #-}
67+sliceBeginWith :: MonadCatch m => Int -> SerialT m Int -> m()
68+sliceBeginWith value = IP.parseD (PR.sliceBeginWith (>= value) FL.drain)
69+
66{-# INLINE takeWhile #-}
70{-# INLINE takeWhile #-}
67takeWhile :: MonadThrow m => Int -> SerialT m Int -> m ()
71takeWhile :: MonadThrow m => Int -> SerialT m Int -> m ()
68takeWhile value = IP.parseD (drainWhile (<= value))
72takeWhile value = IP.parseD (drainWhile (<= value))
@@ -216,6 +220,7 @@ moduleName = "Data.Parser.ParserD"
216o_1_space_serial :: Int -> [Benchmark]
220o_1_space_serial :: Int -> [Benchmark]
217o_1_space_serial value =
221o_1_space_serial value =
218 [ benchIOSink value "takeWhile" $ takeWhile value
222 [ benchIOSink value "takeWhile" $ takeWhile value
223+ , benchIOSink value "sliceBeginWith" $ sliceBeginWith value
219 , benchIOSink value "groupBy" $ groupBy
224 , benchIOSink value "groupBy" $ groupBy
220 , benchIOSink value "groupByRolling" $ groupByRolling
225 , benchIOSink value "groupByRolling" $ groupByRolling
221 , benchIOSink value "wordBy" $ wordBy value
226 , benchIOSink value "wordBy" $ wordBy value
src/Streamly/Internal/Data/Parser.hs+25−6
@@ -507,22 +507,41 @@ sliceSepWith _cond = undefined -- K.toParserK . D.sliceSepBy cond
507
507
508-- | Collect stream elements until an elements passes the predicate, return the
508-- | Collect stream elements until an elements passes the predicate, return the
509-- last element on which the predicate succeeded back to the input stream. If
509-- last element on which the predicate succeeded back to the input stream. If
510−-- the predicate succeeds on the first element itself then it is kept in the
510+-- the predicate succeeds on the first element itself then the parser does not
511−-- stream and we continue collecting. The succeeding element is treated as a
511+-- terminate there. The succeeding element in the leading position
512−-- prefix separator which is kept in the output segement.
512+-- is treated as a prefix separator which is kept in the output segment.
513--
513--
514-- * Stops - when the predicate succeeds in non-leading position.
514-- * Stops - when the predicate succeeds in non-leading position.
515-- * Fails - never.
515-- * Fails - never.
516--
516--
517-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
517-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
518--
518--
519−-- /Unimplemented/
519+-- Examples: -
520+--
521+-- @
522+-- sliceBeginWithOdd ls = S.parse prsr (S.fromList ls)
523+-- where prsr = P.sliceBeginWith odd FL.toList
524+-- @
525+--
526+-- >>> sliceBeginWithOdd [2, 4, 6, 3]
527+-- > [2,4,6]
528+--
529+-- >>> sliceBeginWithOdd [3, 5, 7, 4]
530+-- > [3]
531+--
532+-- >>> sliceBeginWithOdd [3, 4, 6, 8, 5]
533+-- > [3,4,6,8]
534+--
535+-- >>> sliceBeginWithOdd []
536+-- > []
537+--
538+-- /Internal/
520--
539--
521{-# INLINABLE sliceBeginWith #-}
540{-# INLINABLE sliceBeginWith #-}
522sliceBeginWith ::
541sliceBeginWith ::
523− -- Monad m =>
542+ MonadCatch m =>
524 (a -> Bool) -> Fold m a b -> Parser m a b
543 (a -> Bool) -> Fold m a b -> Parser m a b
525−sliceBeginWith = undefined
544+sliceBeginWith cond = K.toParserK . D.sliceBeginWith cond
526
545
527-- | Like 'sliceSepBy' but the separator elements can be escaped using an
546-- | Like 'sliceSepBy' but the separator elements can be escaped using an
528-- escape char determined by the second predicate.
547-- escape char determined by the second predicate.
src/Streamly/Internal/Data/Parser/ParserD.hs+29−6
@@ -535,13 +535,36 @@ sliceSepByP cond (Parser pstep pinitial pextract) =
535
535
536-- | See 'Streamly.Internal.Data.Parser.sliceBeginWith'.
536-- | See 'Streamly.Internal.Data.Parser.sliceBeginWith'.
537--
537--
538−-- /Unimplemented/
538+-- /Internal/
539--
539--
540+data SliceBeginWithState s = Left' s | Right' s
541+
540−{-# INLINABLE sliceBeginWith #-}
542+{-# INLINE sliceBeginWith #-}
541−sliceBeginWith ::
542− -- Monad m =>
543− (a -> Bool) -> Fold m a b -> Parser m a b
543+sliceBeginWith :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
544−sliceBeginWith = undefined
544+sliceBeginWith cond (Fold fstep finitial fextract) =
545+
546+ Parser step initial extract
547+
548+ where
549+
550+ initial = Left' <$> finitial
551+
552+ {-# INLINE process #-}
553+ process s a = do
554+ res <- fstep s a
555+ return
556+ $ case res of
557+ FL.Partial s1 -> Partial 0 (Right' s1)
558+ FL.Done b -> Done 0 b
559+
560+ step (Left' s) a = process s a
561+ step (Right' s) a =
562+ if not (cond a)
563+ then process s a
564+ else Done 1 <$> fextract s
565+
566+ extract (Left' s) = fextract s
567+ extract (Right' s) = fextract s
545
568
546data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
569data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
547
570
test/Streamly/Test/Data/Parser.hs+19
@@ -323,6 +323,23 @@ sliceSepByP =
323 prsr = P.many FL.toList (P.satisfy (const True))
323 prsr = P.many FL.toList (P.satisfy (const True))
324 tkwhl ls = Prelude.takeWhile (not . predicate) ls
324 tkwhl ls = Prelude.takeWhile (not . predicate) ls
325
325
326+sliceBeginWith :: Property
327+sliceBeginWith =
328+ forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
329+ case S.parse parser (S.fromList ls) of
330+ Right parsed_list ->
331+ if not $ Prelude.null ls
332+ then
333+ let tls = Prelude.takeWhile (not . predicate) (tail ls)
334+ in checkListEqual parsed_list $
335+ if predicate (head ls)
336+ then head ls : tls
337+ else Prelude.takeWhile (not . predicate) ls
338+ else property $ Prelude.null parsed_list
339+ Left _ -> property False
340+ where
341+ predicate = odd
342+ parser = P.sliceBeginWith predicate FL.toList
326
343
327takeWhile :: Property
344takeWhile :: Property
328takeWhile =
345takeWhile =
@@ -696,6 +713,8 @@ main =
696 -- prop "Fail when stream length exceeded" lookAheadFail
713 -- prop "Fail when stream length exceeded" lookAheadFail
697 -- prop "lookAhead . take n >> lookAhead . take n = lookAhead . take n, else fail" lookAhead
714 -- prop "lookAhead . take n >> lookAhead . take n = lookAhead . take n, else fail" lookAhead
698 prop "P.sliceSepByP test" Main.sliceSepByP
715 prop "P.sliceSepByP test" Main.sliceSepByP
716+ prop ("P.sliceBeginWith pred = head : Prelude.takeWhile (not . pred)"
717+ ++ " tail") sliceBeginWith
699 prop "P.takeWhile = Prelude.takeWhile" Main.takeWhile
718 prop "P.takeWhile = Prelude.takeWhile" Main.takeWhile
700 prop ("P.takeWhile1 = Prelude.takeWhile if taken something,"
719 prop ("P.takeWhile1 = Prelude.takeWhile if taken something,"
701 ++ " else check why failed") takeWhile1
720 ++ " else check why failed") takeWhile1
test/Streamly/Test/Data/Parser/ParserD.hs−1
@@ -292,7 +292,6 @@ lookAhead =
292 where
292 where
293 list_length = Prelude.length ls
293 list_length = Prelude.length ls
294
294
295−
296takeWhile :: Property
295takeWhile :: Property
297takeWhile =
296takeWhile =
298 forAll (listOf (chooseInt (0, 1))) $ \ ls ->
297 forAll (listOf (chooseInt (0, 1))) $ \ ls ->