on master help sign in
Redo Data.Text.find's type and behaviour
f50288bBryan O'Sullivan
Data/Text.hs+14−18
@@ -1086,34 +1086,30 @@ breakEnd pat src = let (a,b) = break (reverse pat) (reverse src)
1086{-# INLINE breakEnd #-}
1086{-# INLINE breakEnd #-}
1087
1087
1088-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
1088-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
1089−-- @haystack@. The first element of the returned pair is the prefix
1089+-- @haystack@. Each element of the returned list consists of a triple:
1090−-- of @haystack@ prior to any matches of @needle@. The second is a
1091−-- list of pairs.
1092--
1090--
1093−-- The first element of each pair in the list is a span from the
1091+-- * The entire string prior to the /k/th match
1094−-- beginning of a match to the beginning of the next match, while the
1092+--
1095−-- second is a span from the beginning of the match to the end of the
1093+-- * The /k/th match
1096−-- input.
1094+--
1095+-- * The entire string following the /k/th match
1097--
1096--
1098-- Examples:
1097-- Examples:
1099--
1098--
1100-- > find "::" ""
1099-- > find "::" ""
1101−-- > ==> ("", [])
1100+-- > ==> []
1102−-- > find "/" "a/b/c/d"
1101+-- > find "/" "a/b/c/"
1103−-- > ==> ("a", [("/b","/b/c/d"), ("/c","/c/d"), ("/d","/d")])
1102+-- > ==> [("a", "/", "b/c/"), ("a/b", "/", "c/"), ("a/b/c", "/", "")]
1104--
1103--
1105-- In (unlikely) bad cases, this function's time complexity degrades
1104-- In (unlikely) bad cases, this function's time complexity degrades
1106-- towards /O(n*m)/.
1105-- towards /O(n*m)/.
1107−find :: Text -> Text -> (Text, [(Text, Text)])
1106+find :: Text -> Text -> [(Text, Text, Text)]
1108−find pat src@(Text arr off len)
1107+find pat@(Text _ _ plen) src@(Text arr off slen)
1109 | null pat = emptyError "find"
1108 | null pat = emptyError "find"
1110− | otherwise = case indices pat src of
1109+ | otherwise = L.map step (indices pat src)
1111− [] -> (src, [])
1112− (x:xs) -> (chunk 0 x, go x xs)
1113 where
1110 where
1114− go !s (x:xs) = (chunk s (x-s), chunk s (len-s)) : go x xs
1111+ step x = (chunk 0 x, chunk x plen, chunk (x+plen) (stop-x))
1115− go s _ = let c = chunk s (len-s)
1112+ stop = slen - plen
1116− in [(c,c)]
1117 chunk !n !l = textP arr (n+off) l
1113 chunk !n !l = textP arr (n+off) l
1118{-# INLINE find #-}
1114{-# INLINE find #-}
1119
1115
tests/Properties.hs+5−6
@@ -408,11 +408,9 @@ t_inits = L.inits `eqP` (map unpackS . T.inits)
408tl_inits = L.inits `eqP` (map unpackS . TL.inits)
408tl_inits = L.inits `eqP` (map unpackS . TL.inits)
409t_tails = L.tails `eqP` (map unpackS . T.tails)
409t_tails = L.tails `eqP` (map unpackS . T.tails)
410tl_tails = L.tails `eqP` (map unpackS . TL.tails)
410tl_tails = L.tails `eqP` (map unpackS . TL.tails)
411−
411+t_findConcat (NotEmpty s) t = all (==t) $ map conc (T.find s t)
412−t_findSplit s t = (T.split s `eq` splitty) u
413− where splitty v = case T.find s v of
414− (x,xs) -> x : L.map (T.drop (T.length s) . fst) xs
415− u = T.concat [t,s,t]
412+ where conc (a,b,c) = T.concat [a,b,c]
413+t_findCount s = (L.length . T.find s) `eq` T.count s
416tl_findSplit s t = (TL.split s `eq` splitty) u
414tl_findSplit s t = (TL.split s `eq` splitty) u
417 where splitty v = case TL.find s v of
415 where splitty v = case TL.find s v of
418 (x,xs) -> x : L.map (TL.drop (TL.length s) . fst) xs
416 (x,xs) -> x : L.map (TL.drop (TL.length s) . fst) xs
@@ -812,7 +810,8 @@ tests = [
812 ],
810 ],
813
811
814 testGroup "breaking many" [
812 testGroup "breaking many" [
815− testProperty "t_findSplit" t_findSplit,
813+ testProperty "t_findConcat" t_findConcat,
814+ testProperty "t_findCount" t_findCount,
816 testProperty "tl_findSplit" tl_findSplit,
815 testProperty "tl_findSplit" tl_findSplit,
817 testProperty "t_split_split" t_split_split,
816 testProperty "t_split_split" t_split_split,
818 testProperty "tl_split_split" tl_split_split,
817 testProperty "tl_split_split" tl_split_split,