@@ -34,7 +34,7 @@ module Data.Text.Lazy.Search
3434
3535import qualified Data.Text.Array as A
3636import Data.Int (Int64)
37−import Data.Word (Word64)
37+import Data.Word (Word16, Word64)
3838import qualified Data.Text.Internal as T
3939import Data.Text.Fusion.Internal (PairS(..))
4040import Data.Text.Lazy.Internal (Text(..))
@@ -49,7 +49,48 @@ import Data.Text.UnsafeShift (shiftL)
4949indices :: Text -- ^ Substring to search for (@needle@)
5050 -> Text -- ^ Text to search in (@haystack@)
5151 -> [Int64]
52−indices = undefined
52+indices needle Empty = []
53+indices needle@(Chunk n ns) haystack@(Chunk c cs)
54+ | nlen <= 0 || ldiff < 0 = []
55+ | otherwise = scan 0 0 c cs
56+ where
57+ scan !g !i x@(T.Text harr hoff l) xs
58+ | g > ldiff = []
59+ | i >= m = case xs of
60+ Empty -> []
61+ Chunk y ys -> scan g (i-m) y ys
62+ | c == z && candidateMatch 0 = g : scan (g+nlen) (i+nlen) x xs
63+ | otherwise = scan (g+delta) (i+delta) x xs
64+ where
65+ m = fromIntegral l
66+ c = hindex (i + nlast)
67+ delta | nextInPattern = nlen + 1
68+ | c == z = skip + 1
69+ | otherwise = 1
70+ nextInPattern = mask .&. swizzle (hindex (i+nlen)) == 0
71+ candidateMatch !j
72+ | j >= nlast = True
73+ | hindex (i+j) /= nindex j = False
74+ | otherwise = candidateMatch (j+1)
75+ hindex = index x xs
76+ ldiff = hlen - nlen
77+ hlen = wordLength haystack
78+ nlen = wordLength needle
79+ nlast = nlen - 1
80+ nindex = index n ns
81+ z = foldChunks fin 0 needle
82+ where fin _ (T.Text narr noff nlen) = A.unsafeIndex narr (noff+nlen-1)
83+ mask :*: skip = buildTable needle
84+
85+index :: T.Text -> Text -> Int64 -> Word16
86+index (T.Text arr off len) xs i
87+ | j <= len = A.unsafeIndex arr (off+j)
88+ | otherwise = case xs of
89+ Empty -> error "empty"
90+ Chunk c cs -> index c cs (i-fromIntegral len)
91+ where j = fromIntegral i
92+
93+swizzle k = 1 `shiftL` (fromIntegral k .&. 0x3f)
5394
5495foldChunks :: (a -> T.Text -> a) -> a -> Text -> a
5596foldChunks _ z Empty = z
@@ -73,7 +114,6 @@ buildTable needle@(Chunk c cs) = outer c cs 0 0 (nlen-2)
73114 where c = A.unsafeIndex xarr (xoff+i)
74115 skip' | c == z = nlen - fromIntegral i - 2
75116 | otherwise = skip
76− swizzle k = 1 `shiftL` (fromIntegral k .&. 0x3f)
77117 nlen = wordLength needle
78118 z = foldChunks fin 0 needle
79119 where fin _ (T.Text narr noff nlen) = A.unsafeIndex narr (noff+nlen-1)