on master help sign in
Do not force the entire haystack before searching it.
51fc7e0Bryan O'Sullivan
Data/Text/Lazy/Internal.hs+1
@@ -91,6 +91,7 @@ foldlChunks f z = go z
91defaultChunkSize :: Int
91defaultChunkSize :: Int
92defaultChunkSize = 32 * k - chunkOverhead
92defaultChunkSize = 32 * k - chunkOverhead
93 where k = 1024 `div` sizeOf (undefined :: Word16)
93 where k = 1024 `div` sizeOf (undefined :: Word16)
94+{-# INLINE defaultChunkSize #-}
94
95
95-- | Currently set to 4k, less the memory management overhead.
96-- | Currently set to 4k, less the memory management overhead.
96smallChunkSize :: Int
97smallChunkSize :: Int
Data/Text/Lazy/Search.hs+27−16
@@ -13,8 +13,6 @@
13-- Fast substring search for lazy 'Text', based on work by Boyer,
13-- Fast substring search for lazy 'Text', based on work by Boyer,
14-- Moore, Horspool, Sunday, and Lundh. Adapted from the strict
14-- Moore, Horspool, Sunday, and Lundh. Adapted from the strict
15-- implementation.
15-- implementation.
16−--
17−-- /Note/: this is currently too strict!
18
16
19module Data.Text.Lazy.Search
17module Data.Text.Lazy.Search
20 (
18 (
@@ -34,23 +32,26 @@ import Data.Text.UnsafeShift (shiftL)
34-- | /O(n+m)/ Find the offsets of all non-overlapping indices of
32-- | /O(n+m)/ Find the offsets of all non-overlapping indices of
35-- @needle@ within @haystack@.
33-- @needle@ within @haystack@.
36--
34--
35+-- This function is strict in @needle@, and lazy (as far as possible)
36+-- in the chunks of @haystack@.
37+--
37-- In (unlikely) bad cases, this algorithm's complexity degrades
38-- In (unlikely) bad cases, this algorithm's complexity degrades
38-- towards /O(n*m)/.
39-- towards /O(n*m)/.
39indices :: Text -- ^ Substring to search for (@needle@)
40indices :: Text -- ^ Substring to search for (@needle@)
40 -> Text -- ^ Text to search in (@haystack@)
41 -> Text -- ^ Text to search in (@haystack@)
41 -> [Int64]
42 -> [Int64]
42−indices needle@(Chunk n ns) haystack@(Chunk k ks)
43+indices needle@(Chunk n ns) _haystack@(Chunk k ks)
43− | nlen <= 0 || ldiff < 0 = []
44+ | nlen <= 0 = []
44− | nlen == 1 = scanOne (nindex 0) 0 k ks
45+ | nlen == 1 = scanOne (nindex 0) 0 k ks
45− | otherwise = scan 0 0 k ks
46+ | otherwise = scan 0 0 k ks
46 where
47 where
47 scan !g !i x@(T.Text _ _ l) xs
48 scan !g !i x@(T.Text _ _ l) xs
48− | g > ldiff = []
49− | i >= m = case xs of
49+ | i >= m = case xs of
50− Empty -> []
50+ Empty -> []
51− Chunk y ys -> scan g (i-m) y ys
51+ Chunk y ys -> scan g (i-m) y ys
52+ | lackingHay (i + nlen) x xs = []
52− | c == z && candidateMatch 0 = g : scan (g+nlen) (i+nlen) x xs
53+ | c == z && candidateMatch 0 = g : scan (g+nlen) (i+nlen) x xs
53− | otherwise = scan (g+delta) (i+delta) x xs
54+ | otherwise = scan (g+delta) (i+delta) x xs
54 where
55 where
55 m = fromIntegral l
56 m = fromIntegral l
56 c = hindex (i + nlast)
57 c = hindex (i + nlast)
@@ -62,8 +63,7 @@ indices needle@(Chunk n ns) haystack@(Chunk k ks)
62 | j >= nlast = True
63 | j >= nlast = True
63 | hindex (i+j) /= nindex j = False
64 | hindex (i+j) /= nindex j = False
64 | otherwise = candidateMatch (j+1)
65 | otherwise = candidateMatch (j+1)
65− hindex = index x xs
66+ hindex = index x xs
66− ldiff = wordLength haystack - nlen
67 nlen = wordLength needle
67 nlen = wordLength needle
68 nlast = nlen - 1
68 nlast = nlen - 1
69 nindex = index n ns
69 nindex = index n ns
@@ -90,6 +90,14 @@ indices needle@(Chunk n ns) haystack@(Chunk k ks)
90 | on == c = i + fromIntegral h : go (h+1)
90 | on == c = i + fromIntegral h : go (h+1)
91 | otherwise = go (h+1)
91 | otherwise = go (h+1)
92 where on = A.unsafeIndex oarr (ooff+h)
92 where on = A.unsafeIndex oarr (ooff+h)
93+ -- | Check whether an attempt to index into the haystack at the
94+ -- given offset will fail.
95+ lackingHay q = go 0
96+ where
97+ go p (T.Text _ _ l) ps = p' < q && case ps of
98+ Empty -> True
99+ Chunk r rs -> go p' r rs
100+ where p' = p + fromIntegral l
93indices _ _ = []
101indices _ _ = []
94
102
95-- | Fast index into a partly unpacked 'Text'. We take into account
103-- | Fast index into a partly unpacked 'Text'. We take into account
@@ -99,8 +107,11 @@ index :: T.Text -> Text -> Int64 -> Word16
99index (T.Text arr off len) xs i
107index (T.Text arr off len) xs i
100 | j < len = A.unsafeIndex arr (off+j)
108 | j < len = A.unsafeIndex arr (off+j)
101 | otherwise = case xs of
109 | otherwise = case xs of
110+ Empty
102− Empty | j == len -> 0 -- out of bounds, but legal
111+ -- out of bounds, but legal
112+ | j == len -> 0
113+ -- should never happen, due to lackingHay above
103− | otherwise -> emptyError "index"
114+ | otherwise -> emptyError "index"
104 Chunk c cs -> index c cs (i-fromIntegral len)
115 Chunk c cs -> index c cs (i-fromIntegral len)
105 where j = fromIntegral i
116 where j = fromIntegral i
106
117