on master help sign in
Add sliceBeginWith, tests and benchmarks
commitfb9f05e4fba2632a63dccc175b75e1898088e3d7 authorAnurag Hooda <anuraghooda@composewell.com> dateSat 16 Jan 2021, 23:52 (6 years ago) parentb6a0752
6 files changed+83−13
benchmark/Streamly/Benchmark/Data/Parser.hs+5 benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+5 src/Streamly/Internal/Data/Parser.hs+25−6 src/Streamly/Internal/Data/Parser/ParserD.hs+29−6 test/Streamly/Test/Data/Parser.hs+19 test/Streamly/Test/Data/Parser/ParserD.hs−1
benchmark/Streamly/Benchmark/Data/Parser.hs+5
@@ -72,6 +72,10 @@ takeEQ value = IP.parse (PR.takeEQ value FL.drain)
7272drainWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
7373drainWhile value = IP.parse (PR.drainWhile (<= value))
7474
75+{-# INLINE sliceBeginWith #-}
76+sliceBeginWith :: MonadCatch m => Int -> SerialT m Int -> m ()
77+sliceBeginWith value = IP.parse (PR.sliceBeginWith (>= value) FL.drain)
78+
7579{-# INLINE takeWhile #-}
7680takeWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
7781takeWhile value = IP.parse (PR.takeWhile (<= value) FL.drain)
@@ -284,6 +288,7 @@ o_1_space_serial value =
284288 , benchIOSink value "takeEQ" $ takeEQ value
285289 , benchIOSink value "takeWhile" $ takeWhile value
286290 , benchIOSink value "drainWhile" $ drainWhile value
291+ , benchIOSink value "sliceBeginWith" $ sliceBeginWith value
287292 , benchIOSink value "groupBy" $ groupBy
288293 , benchIOSink value "groupByRolling" $ groupByRolling
289294 , benchIOSink value "wordBy" $ wordBy value
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+5
@@ -63,6 +63,10 @@ benchIOSink value name f =
6363drainWhile :: MonadThrow m => (a -> Bool) -> PR.Parser m a ()
6464drainWhile p = PR.takeWhile p FL.drain
6565
66+{-# INLINE sliceBeginWith #-}
67+sliceBeginWith :: MonadCatch m => Int -> SerialT m Int -> m()
68+sliceBeginWith value = IP.parseD (PR.sliceBeginWith (>= value) FL.drain)
69+
6670{-# INLINE takeWhile #-}
6771takeWhile :: MonadThrow m => Int -> SerialT m Int -> m ()
6872takeWhile value = IP.parseD (drainWhile (<= value))
@@ -216,6 +220,7 @@ moduleName = "Data.Parser.ParserD"
216220o_1_space_serial :: Int -> [Benchmark]
217221o_1_space_serial value =
218222 [ benchIOSink value "takeWhile" $ takeWhile value
223+ , benchIOSink value "sliceBeginWith" $ sliceBeginWith value
219224 , benchIOSink value "groupBy" $ groupBy
220225 , benchIOSink value "groupByRolling" $ groupByRolling
221226 , 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
507507
508508-- | Collect stream elements until an elements passes the predicate, return the
509509-- 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
511−-- stream and we continue collecting. The succeeding element is treated as a
512−-- prefix separator which is kept in the output segement.
510+-- the predicate succeeds on the first element itself then the parser does not
511+-- terminate there. The succeeding element in the leading position
512+-- is treated as a prefix separator which is kept in the output segment.
513513--
514514-- * Stops - when the predicate succeeds in non-leading position.
515515-- * Fails - never.
516516--
517517-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
518518--
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/
520539--
521540{-# INLINABLE sliceBeginWith #-}
522541sliceBeginWith ::
523− -- Monad m =>
542+ MonadCatch m =>
524543 (a -> Bool) -> Fold m a b -> Parser m a b
525−sliceBeginWith = undefined
544+sliceBeginWith cond = K.toParserK . D.sliceBeginWith cond
526545
527546-- | Like 'sliceSepBy' but the separator elements can be escaped using an
528547-- 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) =
535535
536536-- | See 'Streamly.Internal.Data.Parser.sliceBeginWith'.
537537--
538−-- /Unimplemented/
538+-- /Internal/
539539--
540−{-# INLINABLE sliceBeginWith #-}
541−sliceBeginWith ::
542− -- Monad m =>
543− (a -> Bool) -> Fold m a b -> Parser m a b
544−sliceBeginWith = undefined
540+data SliceBeginWithState s = Left' s | Right' s
541+
542+{-# INLINE sliceBeginWith #-}
543+sliceBeginWith :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
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
545568
546569data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
547570
test/Streamly/Test/Data/Parser.hs+19
@@ -323,6 +323,23 @@ sliceSepByP =
323323 prsr = P.many FL.toList (P.satisfy (const True))
324324 tkwhl ls = Prelude.takeWhile (not . predicate) ls
325325
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
326343
327344takeWhile :: Property
328345takeWhile =
@@ -696,6 +713,8 @@ main =
696713 -- prop "Fail when stream length exceeded" lookAheadFail
697714 -- prop "lookAhead . take n >> lookAhead . take n = lookAhead . take n, else fail" lookAhead
698715 prop "P.sliceSepByP test" Main.sliceSepByP
716+ prop ("P.sliceBeginWith pred = head : Prelude.takeWhile (not . pred)"
717+ ++ " tail") sliceBeginWith
699718 prop "P.takeWhile = Prelude.takeWhile" Main.takeWhile
700719 prop ("P.takeWhile1 = Prelude.takeWhile if taken something,"
701720 ++ " else check why failed") takeWhile1
test/Streamly/Test/Data/Parser/ParserD.hs−1
@@ -292,7 +292,6 @@ lookAhead =
292292 where
293293 list_length = Prelude.length ls
294294
295−
296295takeWhile :: Property
297296takeWhile =
298297 forAll (listOf (chooseInt (0, 1))) $ \ ls ->