on master help sign in
Implement Data.Parser.ParserD.wordBy
4d3f9b4Adithya Kumar
benchmark/Streamly/Benchmark/Data/Parser.hs+10
@@ -76,6 +76,14 @@ takeWhile value = IP.parse (PR.takeWhile (<= value) FL.drain)
76groupBy :: MonadCatch m => SerialT m Int -> m ()
76groupBy :: MonadCatch m => SerialT m Int -> m ()
77groupBy = IP.parse (PR.groupBy (<=) FL.drain)
77groupBy = IP.parse (PR.groupBy (<=) FL.drain)
78
78
79+{-# INLINE wordBy #-}
80+wordBy :: MonadCatch m => Int -> SerialT m Int -> m ()
81+wordBy value = IP.parse (PR.wordBy (>= value) FL.drain)
82+
83+{-# INLINE manyWordByEven #-}
84+manyWordByEven :: MonadCatch m => SerialT m Int -> m ()
85+manyWordByEven = IP.parse (PR.many FL.drain (PR.wordBy (Prelude.even) FL.drain))
86+
79{-# INLINE many #-}
87{-# INLINE many #-}
80many :: MonadCatch m => SerialT m Int -> m Int
88many :: MonadCatch m => SerialT m Int -> m Int
81many = IP.parse (PR.many FL.length (PR.satisfy (> 0)))
89many = IP.parse (PR.many FL.length (PR.satisfy (> 0)))
@@ -263,11 +271,13 @@ o_1_space_serial value =
263 , benchIOSink value "takeWhile" $ takeWhile value
271 , benchIOSink value "takeWhile" $ takeWhile value
264 , benchIOSink value "drainWhile" $ drainWhile value
272 , benchIOSink value "drainWhile" $ drainWhile value
265 , benchIOSink value "groupBy" $ groupBy
273 , benchIOSink value "groupBy" $ groupBy
274+ , benchIOSink value "wordBy" $ wordBy value
266 , benchIOSink value "splitAp" $ splitAp value
275 , benchIOSink value "splitAp" $ splitAp value
267 , benchIOSink value "splitApBefore" $ splitApBefore value
276 , benchIOSink value "splitApBefore" $ splitApBefore value
268 , benchIOSink value "splitApAfter" $ splitApAfter value
277 , benchIOSink value "splitApAfter" $ splitApAfter value
269 , benchIOSink value "splitWith" $ splitWith value
278 , benchIOSink value "splitWith" $ splitWith value
270 , benchIOSink value "many" many
279 , benchIOSink value "many" many
280+ , benchIOSink value "many (wordBy even)" $ manyWordByEven
271 , benchIOSink value "some" some
281 , benchIOSink value "some" some
272 , benchIOSink value "manyTill" $ manyTill value
282 , benchIOSink value "manyTill" $ manyTill value
273 , benchIOSink value "tee" $ teeAllAny value
283 , benchIOSink value "tee" $ teeAllAny value
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+11
@@ -71,6 +71,15 @@ takeWhile value = IP.parseD (drainWhile (<= value))
71groupBy :: MonadThrow m => SerialT m Int -> m ()
71groupBy :: MonadThrow m => SerialT m Int -> m ()
72groupBy = IP.parseD (PR.groupBy (<=) FL.drain)
72groupBy = IP.parseD (PR.groupBy (<=) FL.drain)
73
73
74+{-# INLINE wordBy #-}
75+wordBy :: MonadThrow m => Int -> SerialT m Int -> m ()
76+wordBy value = IP.parseD (PR.wordBy (>= value) FL.drain)
77+
78+{-# INLINE manyWordByEven #-}
79+manyWordByEven :: MonadCatch m => SerialT m Int -> m ()
80+manyWordByEven =
81+ IP.parseD (PR.many FL.drain (PR.wordBy (Prelude.even) FL.drain))
82+
74{-# INLINE many #-}
83{-# INLINE many #-}
75many :: MonadCatch m => SerialT m Int -> m Int
84many :: MonadCatch m => SerialT m Int -> m Int
76many = IP.parseD (PR.many FL.length (PR.satisfy (> 0)))
85many = IP.parseD (PR.many FL.length (PR.satisfy (> 0)))
@@ -200,8 +209,10 @@ o_1_space_serial :: Int -> [Benchmark]
200o_1_space_serial value =
209o_1_space_serial value =
201 [ benchIOSink value "takeWhile" $ takeWhile value
210 [ benchIOSink value "takeWhile" $ takeWhile value
202 , benchIOSink value "groupBy" $ groupBy
211 , benchIOSink value "groupBy" $ groupBy
212+ , benchIOSink value "wordBy" $ wordBy value
203 , benchIOSink value "split (all,any)" $ splitAllAny value
213 , benchIOSink value "split (all,any)" $ splitAllAny value
204 , benchIOSink value "many" many
214 , benchIOSink value "many" many
215+ , benchIOSink value "many (wordBy even)" $ manyWordByEven
205 , benchIOSink value "some" some
216 , benchIOSink value "some" some
206 , benchIOSink value "manyTill" $ manyTill value
217 , benchIOSink value "manyTill" $ manyTill value
207 , benchIOSink value "tee (all,any)" $ teeAllAny value
218 , benchIOSink value "tee (all,any)" $ teeAllAny value
src/Streamly/Internal/Data/Parser.hs+3−7
@@ -548,13 +548,9 @@ escapedFrameBy _begin _end _escape _p = undefined
548-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
548-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
549-- @
549-- @
550--
550--
551−-- /Unimplemented/
552−--
553−{-# INLINABLE wordBy #-}
551+{-# INLINE wordBy #-}
554−wordBy ::
555− -- Monad m =>
556− (a -> Bool) -> Fold m a b -> Parser m a b
552+wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
557−wordBy = undefined
553+wordBy f = K.toParserK . D.wordBy f
558
554
559-- | @groupBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
555-- | @groupBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
560-- first group, then if @a \`cmp` b@ is 'True' @b@ is also assigned to the same
556-- first group, then if @a \`cmp` b@ is 'True' @b@ is also assigned to the same
src/Streamly/Internal/Data/Parser/ParserD.hs+37−6
@@ -447,15 +447,46 @@ sliceBeginWith ::
447 (a -> Bool) -> Fold m a b -> Parser m a b
447 (a -> Bool) -> Fold m a b -> Parser m a b
448sliceBeginWith = undefined
448sliceBeginWith = undefined
449
449
450+data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
451+
450-- | See 'Streamly.Internal.Data.Parser.wordBy'.
452-- | See 'Streamly.Internal.Data.Parser.wordBy'.
451--
453--
452−-- /Unimplemented/
453--
454--
454−{-# INLINABLE wordBy #-}
455+{-# INLINE wordBy #-}
455−wordBy ::
456− -- Monad m =>
457− (a -> Bool) -> Fold m a b -> Parser m a b
456+wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
458−wordBy = undefined
457+wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
458+
459+ where
460+
461+ {-# INLINE worder #-}
462+ worder s a = do
463+ res <- fstep s a
464+ return
465+ $ case res of
466+ FL.Partial s1 -> Partial 0 $ WBWord s1
467+ FL.Done b -> Done 0 b
468+
469+ initial = WBLeft <$> finitial
470+
471+ step (WBLeft s) a =
472+ if not (predicate a)
473+ then worder s a
474+ else return $ Partial 0 $ WBLeft s
475+ step (WBWord s) a =
476+ if not (predicate a)
477+ then worder s a
478+ else do
479+ b <- fextract s
480+ return $ Partial 0 $ WBRight b
481+ step (WBRight b) a =
482+ return
483+ $ if not (predicate a)
484+ then Done 1 b
485+ else Partial 0 $ WBRight b
486+
487+ extract (WBLeft s) = fextract s
488+ extract (WBWord s) = fextract s
489+ extract (WBRight b) = return b
459
490
460data GroupByState a s
491data GroupByState a s
461 = GroupByInit !s
492 = GroupByInit !s
test/Streamly/Test/Data/Parser.hs+18
@@ -317,6 +317,23 @@ groupBy =
317 | null lst = []
317 | null lst = []
318 | otherwise = head $ List.groupBy cmp lst
318 | otherwise = head $ List.groupBy cmp lst
319
319
320+
321+wordBy :: Property
322+wordBy =
323+ forAll (listOf (elements [' ', 's']))
324+ $ \ls ->
325+ case S.parse parser (S.fromList ls) of
326+ Right parsed -> checkListEqual parsed (words' ls)
327+ Left _ -> property False
328+
329+ where
330+
331+ predicate = (== ' ')
332+ parser = P.many FL.toList (P.wordBy predicate FL.toList)
333+ words' lst =
334+ let wrds = words lst
335+ in if wrds == [] then [""] else wrds
336+
320-- splitWithPass :: Property
337-- splitWithPass :: Property
321-- splitWithPass =
338-- splitWithPass =
322-- forAll (listOf (chooseInt (0, 1))) $ \ls ->
339-- forAll (listOf (chooseInt (0, 1))) $ \ls ->
@@ -627,6 +644,7 @@ main =
627 prop "P.takeWhile = Prelude.takeWhile" Main.takeWhile
644 prop "P.takeWhile = Prelude.takeWhile" Main.takeWhile
628 prop "P.takeWhile1 = Prelude.takeWhile if taken something, else check why failed" takeWhile1
645 prop "P.takeWhile1 = Prelude.takeWhile if taken something, else check why failed" takeWhile1
629 prop "P.groupBy = Prelude.head . Prelude.groupBy" groupBy
646 prop "P.groupBy = Prelude.head . Prelude.groupBy" groupBy
647+ prop "many (P.wordBy ' ') = words'" wordBy
630 -- prop "" splitWithPass
648 -- prop "" splitWithPass
631 -- prop "" splitWithFailLeft
649 -- prop "" splitWithFailLeft
632 -- prop "" splitWithFailRight
650 -- prop "" splitWithFailRight
test/Streamly/Test/Data/Parser/ParserD.hs+18
@@ -323,6 +323,23 @@ sliceSepByMax =
323 where
323 where
324 predicate = (== 1)
324 predicate = (== 1)
325
325
326+wordBy :: Property
327+wordBy =
328+ forAll (listOf (elements [' ', 's']))
329+ $ \ls ->
330+ case S.parseD parser (S.fromList ls) of
331+ Right parsed -> checkListEqual parsed (words' ls)
332+ Left _ -> property False
333+
334+ where
335+
336+ predicate = (== ' ')
337+ parser = P.many FL.toList (P.wordBy predicate FL.toList)
338+ words' lst =
339+ let wrds = words lst
340+ in if wrds == [] then [""] else wrds
341+
342+
326splitWith :: Property
343splitWith :: Property
327splitWith =
344splitWith =
328 forAll (listOf (chooseInt (0, 1))) $ \ls ->
345 forAll (listOf (chooseInt (0, 1))) $ \ls ->
@@ -657,6 +674,7 @@ main =
657 prop "P.groupBy = Prelude.head . Prelude.groupBy" groupBy
674 prop "P.groupBy = Prelude.head . Prelude.groupBy" groupBy
658 prop "P.sliceSepBy = Prelude.takeWhile (not . predicate)" sliceSepBy
675 prop "P.sliceSepBy = Prelude.takeWhile (not . predicate)" sliceSepBy
659 prop "P.sliceSepByMax = Prelude.take n (Prelude.takeWhile (not . predicate)" sliceSepByMax
676 prop "P.sliceSepByMax = Prelude.take n (Prelude.takeWhile (not . predicate)" sliceSepByMax
677+ prop "many (P.wordBy ' ') = words'" wordBy
660 prop "parse 0, then 1, else fail" splitWith
678 prop "parse 0, then 1, else fail" splitWith
661 prop "fail due to die as left parser" splitWithFailLeft
679 prop "fail due to die as left parser" splitWithFailLeft
662 prop "fail due to die as right parser" splitWithFailRight
680 prop "fail due to die as right parser" splitWithFailRight