on master help sign in
Implement and test lazy elemIndex, elemIndices, and count
90c0aaaBryan O'Sullivan
Data/Text/Fusion.hs+3−17
@@ -217,31 +217,17 @@ findIndexOrEnd p (Stream next s0 _len) = loop_findIndex 0 s0
217-- element in the given stream which is equal to the query
217-- element in the given stream which is equal to the query
218-- element, or 'Nothing' if there is no such element.
218-- element, or 'Nothing' if there is no such element.
219elemIndex :: Char -> Stream Char -> Maybe Int
219elemIndex :: Char -> Stream Char -> Maybe Int
220−elemIndex a s = case elemIndices a s of
220+elemIndex = S.elemIndexI
221− (i:_) -> Just i
222− _ -> Nothing
223{-# INLINE [0] elemIndex #-}
221{-# INLINE [0] elemIndex #-}
224
222
225-- | /O(n)/ The 'elemIndices' function returns the index of every
223-- | /O(n)/ The 'elemIndices' function returns the index of every
226-- element in the given stream which is equal to the query element.
224-- element in the given stream which is equal to the query element.
227elemIndices :: Char -> Stream Char -> [Int]
225elemIndices :: Char -> Stream Char -> [Int]
228−elemIndices a (Stream next s0 _len) = loop 0 s0
226+elemIndices = S.elemIndicesI
229− where
230− loop !i !s = case next s of
231− Done -> []
232− Skip s' -> loop i s'
233− Yield x s' | a == x -> i : loop (i+1) s'
234− | otherwise -> loop (i+1) s'
235{-# INLINE [0] elemIndices #-}
227{-# INLINE [0] elemIndices #-}
236
228
237-- | /O(n)/ The 'count' function returns the number of times the query
229-- | /O(n)/ The 'count' function returns the number of times the query
238-- element appears in the given stream.
230-- element appears in the given stream.
239count :: Char -> Stream Char -> Int
231count :: Char -> Stream Char -> Int
240−count a (Stream next s0 _len) = loop 0 s0
232+count = S.countI
241− where
242− loop !i !s = case next s of
243− Done -> i
244− Skip s' -> loop i s'
245− Yield x s' | a == x -> loop (i+1) s'
246− | otherwise -> loop i s'
247{-# INLINE [0] count #-}
233{-# INLINE [0] count #-}
Data/Text/Fusion/Common.hs+36
@@ -82,6 +82,9 @@ module Data.Text.Fusion.Common
82 , indexI
82 , indexI
83 , findIndexI
83 , findIndexI
84 , findIndicesI
84 , findIndicesI
85+ , elemIndexI
86+ , elemIndicesI
87+ , countI
85
88
86 -- * Zipping and unzipping
89 -- * Zipping and unzipping
87 , zipWith
90 , zipWith
@@ -712,6 +715,39 @@ zipWith f (Stream next0 sa0 len1) (Stream next1 sb0 len2) = Stream next (sa0 :!:
712 Yield b sb' -> Yield (f a b) (sa' :!: sb' :!: Nothing)
715 Yield b sb' -> Yield (f a b) (sa' :!: sb' :!: Nothing)
713{-# INLINE [0] zipWith #-}
716{-# INLINE [0] zipWith #-}
714
717
718+-- | /O(n)/ The 'elemIndexI' function returns the index of the first
719+-- element in the given stream which is equal to the query
720+-- element, or 'Nothing' if there is no such element.
721+elemIndexI :: Integral a => Char -> Stream Char -> Maybe a
722+elemIndexI a s = case elemIndicesI a s of
723+ (i:_) -> Just i
724+ _ -> Nothing
725+{-# INLINE [0] elemIndexI #-}
726+
727+-- | /O(n)/ The 'elemIndicesI' function returns the index of every
728+-- element in the given stream which is equal to the query element.
729+elemIndicesI :: Integral a => Char -> Stream Char -> [a]
730+elemIndicesI a (Stream next s0 _len) = loop 0 s0
731+ where
732+ loop !i !s = case next s of
733+ Done -> []
734+ Skip s' -> loop i s'
735+ Yield x s' | a == x -> i : loop (i+1) s'
736+ | otherwise -> loop (i+1) s'
737+{-# INLINE [0] elemIndicesI #-}
738+
739+-- | /O(n)/ The 'count' function returns the number of times the query
740+-- element appears in the given stream.
741+countI :: Integral a => Char -> Stream Char -> a
742+countI a (Stream next s0 _len) = loop 0 s0
743+ where
744+ loop !i !s = case next s of
745+ Done -> i
746+ Skip s' -> loop i s'
747+ Yield x s' | a == x -> loop (i+1) s'
748+ | otherwise -> loop i s'
749+{-# INLINE [0] countI #-}
750+
715streamError :: String -> String -> a
751streamError :: String -> String -> a
716streamError func msg = P.error $ "Data.Text.Fusion.Common." ++ func ++ ": " ++ msg
752streamError func msg = P.error $ "Data.Text.Fusion.Common." ++ func ++ ": " ++ msg
717
753
Data/Text/Lazy.hs+25−3
@@ -136,9 +136,9 @@ module Data.Text.Lazy
136 , index
136 , index
137 , findIndex
137 , findIndex
138 , findIndices
138 , findIndices
139− -- , elemIndex
139+ , elemIndex
140− -- , elemIndices
140+ , elemIndices
141− -- , count
141+ , count
142
142
143 -- * Zipping and unzipping
143 -- * Zipping and unzipping
144 , zipWith
144 , zipWith
@@ -828,6 +828,28 @@ findIndices :: (Char -> Bool) -> Text -> [Int64]
828findIndices p t = S.findIndices p (stream t)
828findIndices p t = S.findIndices p (stream t)
829{-# INLINE findIndices #-}
829{-# INLINE findIndices #-}
830
830
831+-- | /O(n)/ The 'elemIndex' function returns the index of the first
832+-- element in the given 'Text' which is equal to the query element, or
833+-- 'Nothing' if there is no such element. This function is subject to
834+-- fusion.
835+elemIndex :: Char -> Text -> Maybe Int64
836+elemIndex c t = S.elemIndex c (stream t)
837+{-# INLINE elemIndex #-}
838+
839+-- | /O(n)/ The 'elemIndices' function returns the index of every
840+-- element in the given 'Text' which is equal to the query
841+-- element. This function is subject to fusion.
842+elemIndices :: Char -> Text -> [Int64]
843+elemIndices c t = S.elemIndices c (stream t)
844+{-# INLINE elemIndices #-}
845+
846+-- | /O(n)/ The 'count' function returns the number of times the query
847+-- element appears in the given 'Text'. This function is subject to
848+-- fusion.
849+count :: Char -> Text -> Int64
850+count c t = S.count c (stream t)
851+{-# INLINE count #-}
852+
831-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function
853-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function
832-- given as the first argument, instead of a tupling function.
854-- given as the first argument, instead of a tupling function.
833zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
855zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
Data/Text/Lazy/Fusion.hs+22
@@ -20,6 +20,9 @@ module Data.Text.Lazy.Fusion
20 , index
20 , index
21 , findIndex
21 , findIndex
22 , findIndices
22 , findIndices
23+ , elemIndex
24+ , elemIndices
25+ , count
23 ) where
26 ) where
24
27
25import Prelude hiding (length)
28import Prelude hiding (length)
@@ -115,3 +118,22 @@ findIndex = S.findIndexI
115findIndices :: (Char -> Bool) -> Stream Char -> [Int64]
118findIndices :: (Char -> Bool) -> Stream Char -> [Int64]
116findIndices = S.findIndicesI
119findIndices = S.findIndicesI
117{-# INLINE [0] findIndices #-}
120{-# INLINE [0] findIndices #-}
121+
122+-- | /O(n)/ The 'elemIndex' function returns the index of the first
123+-- element in the given stream which is equal to the query
124+-- element, or 'Nothing' if there is no such element.
125+elemIndex :: Char -> Stream Char -> Maybe Int64
126+elemIndex = S.elemIndexI
127+{-# INLINE [0] elemIndex #-}
128+
129+-- | /O(n)/ The 'elemIndices' function returns the index of every
130+-- element in the given stream which is equal to the query element.
131+elemIndices :: Char -> Stream Char -> [Int64]
132+elemIndices = S.elemIndicesI
133+{-# INLINE [0] elemIndices #-}
134+
135+-- | /O(n)/ The 'count' function returns the number of times the query
136+-- element appears in the given stream.
137+count :: Char -> Stream Char -> Int64
138+count = S.countI
139+{-# INLINE [0] count #-}
tests/Properties.hs+6
@@ -326,8 +326,11 @@ prop_TL_findIndex p = (fmap fromIntegral . L.findIndex p) `eqP` TL.findIndex
326prop_T_findIndices p = L.findIndices p `eqP` T.findIndices p
326prop_T_findIndices p = L.findIndices p `eqP` T.findIndices p
327prop_TL_findIndices p = (fmap fromIntegral . L.findIndices p) `eqP` TL.findIndices p
327prop_TL_findIndices p = (fmap fromIntegral . L.findIndices p) `eqP` TL.findIndices p
328prop_T_elemIndex c = L.elemIndex c `eqP` T.elemIndex c
328prop_T_elemIndex c = L.elemIndex c `eqP` T.elemIndex c
329+prop_TL_elemIndex c = (fmap fromIntegral . L.elemIndex c) `eqP` TL.elemIndex c
329prop_T_elemIndices c = L.elemIndices c`eqP` T.elemIndices c
330prop_T_elemIndices c = L.elemIndices c`eqP` T.elemIndices c
331+prop_TL_elemIndices c = (fmap fromIntegral . L.elemIndices c) `eqP` TL.elemIndices c
330prop_T_count c = (L.length . L.elemIndices c) `eqP` T.count c
332prop_T_count c = (L.length . L.elemIndices c) `eqP` T.count c
333+prop_TL_count c = (fromIntegral . L.length . L.elemIndices c) `eqP` TL.count c
331prop_T_zipWith c s = L.zipWith c s `eqP` (unpackT . T.zipWith c (packT s))
334prop_T_zipWith c s = L.zipWith c s `eqP` (unpackT . T.zipWith c (packT s))
332prop_TL_zipWith c s = L.zipWith c s `eqP` (unpackT . TL.zipWith c (packT s))
335prop_TL_zipWith c s = L.zipWith c s `eqP` (unpackT . TL.zipWith c (packT s))
333
336
@@ -531,8 +534,11 @@ tests = [
531 ("prop_T_findIndices", mytest prop_T_findIndices),
534 ("prop_T_findIndices", mytest prop_T_findIndices),
532 ("prop_TL_findIndices", mytest prop_TL_findIndices),
535 ("prop_TL_findIndices", mytest prop_TL_findIndices),
533 ("prop_T_elemIndex", mytest prop_T_elemIndex),
536 ("prop_T_elemIndex", mytest prop_T_elemIndex),
537+ ("prop_TL_elemIndex", mytest prop_TL_elemIndex),
534 ("prop_T_elemIndices", mytest prop_T_elemIndices),
538 ("prop_T_elemIndices", mytest prop_T_elemIndices),
539+ ("prop_TL_elemIndices", mytest prop_TL_elemIndices),
535 ("prop_T_count", mytest prop_T_count),
540 ("prop_T_count", mytest prop_T_count),
541+ ("prop_TL_count", mytest prop_TL_count),
536 ("prop_T_zipWith", mytest prop_T_zipWith),
542 ("prop_T_zipWith", mytest prop_T_zipWith),
537 ("prop_TL_zipWith", mytest prop_TL_zipWith),
543 ("prop_TL_zipWith", mytest prop_TL_zipWith),
538
544