@@ -36,6 +36,7 @@ import qualified Data.Text.Array as A
36import Data.Int (Int64)
36import Data.Int (Int64)
37import Data.Word (Word16, Word64)
37import Data.Word (Word16, Word64)
38import qualified Data.Text.Internal as T
38import qualified Data.Text.Internal as T
39+import qualified Data.Text as T
39import Data.Text.Fusion.Internal (PairS(..))
40import Data.Text.Fusion.Internal (PairS(..))
40import Data.Text.Lazy.Internal (Text(..))
41import Data.Text.Lazy.Internal (Text(..))
41import Data.Bits ((.|.), (.&.))
42import Data.Bits ((.|.), (.&.))
@@ -49,12 +50,12 @@ import Data.Text.UnsafeShift (shiftL)
49indices :: Text -- ^ Substring to search for (@needle@)
50indices :: Text -- ^ Substring to search for (@needle@)
50 -> Text -- ^ Text to search in (@haystack@)
51 -> Text -- ^ Text to search in (@haystack@)
51 -> [Int64]
52 -> [Int64]
52−indices needle Empty = []
53−indices needle@(Chunk n ns) haystack@(Chunk c cs)
53+indices needle@(Chunk n ns) haystack@(Chunk k ks)
54 | nlen <= 0 || ldiff < 0 = []
54 | nlen <= 0 || ldiff < 0 = []
55+ | nlen == 1 = scanOne (nindex 0) 0 k ks
55− | otherwise = scan 0 0 c cs
56+ | otherwise = scan 0 0 k ks
57− scan !g !i x@(T.Text harr hoff l) xs
58+ scan !g !i x@(T.Text _ _ l) xs
58 | g > ldiff = []
59 | g > ldiff = []
59 | i >= m = case xs of
60 | i >= m = case xs of
60 Empty -> []
61 Empty -> []
@@ -79,17 +80,28 @@ indices needle@(Chunk n ns) haystack@(Chunk c cs)
79 nlast = nlen - 1
80 nlast = nlen - 1
80 nindex = index n ns
81 nindex = index n ns
81 z = foldChunks fin 0 needle
82 z = foldChunks fin 0 needle
82− where fin _ (T.Text narr noff nlen) = A.unsafeIndex narr (noff+nlen-1)
83+ where fin _ (T.Text farr foff flen) = A.unsafeIndex farr (foff+flen-1)
83 mask :*: skip = buildTable needle
84 mask :*: skip = buildTable needle
85+ scanOne c i (T.Text oarr ooff olen) os = go 0
87+ go h | h >= olen = case os of
89+ Chunk y ys -> scanOne c (i+fromIntegral olen) y ys
90+ | on == c = i + fromIntegral h : go (h+1)
91+ | otherwise = go (h+1)
92+ where on = A.unsafeIndex oarr (ooff+h)
85index :: T.Text -> Text -> Int64 -> Word16
95index :: T.Text -> Text -> Int64 -> Word16
86index (T.Text arr off len) xs i
96index (T.Text arr off len) xs i
87− | j <= len = A.unsafeIndex arr (off+j)
97+ | j < len = A.unsafeIndex arr (off+j)
88 | otherwise = case xs of
98 | otherwise = case xs of
99+ Empty | j == len -> 0
89− Empty -> error "empty"
100+ | otherwise -> error "empty"
90 Chunk c cs -> index c cs (i-fromIntegral len)
101 Chunk c cs -> index c cs (i-fromIntegral len)
91 where j = fromIntegral i
102 where j = fromIntegral i
104+swizzle :: Word16 -> Word64
93swizzle k = 1 `shiftL` (fromIntegral k .&. 0x3f)
105swizzle k = 1 `shiftL` (fromIntegral k .&. 0x3f)
95foldChunks :: (a -> T.Text -> a) -> a -> Text -> a
107foldChunks :: (a -> T.Text -> a) -> a -> Text -> a
@@ -97,23 +109,25 @@ foldChunks _ z Empty = z
97foldChunks f z (Chunk c cs) = let z' = f z c
109foldChunks f z (Chunk c cs) = let z' = f z c
98 in z' `seq` foldChunks f z' cs
110 in z' `seq` foldChunks f z' cs
112+wordLength :: Text -> Int64
100wordLength = foldChunks sumLength 0
113wordLength = foldChunks sumLength 0
101 where sumLength i (T.Text _ _ l) = i + fromIntegral l
114 where sumLength i (T.Text _ _ l) = i + fromIntegral l
103buildTable :: Text -> PairS Word64 Int64
116buildTable :: Text -> PairS Word64 Int64
104buildTable Empty = 0 :*: 0
117buildTable Empty = 0 :*: 0
105−buildTable needle@(Chunk c cs) = outer c cs 0 0 (nlen-2)
118+buildTable needle@(Chunk k ks) = outer k ks 0 0 0 (nlen-2)
107− outer x@(T.Text xarr xoff xlen) xs = go
120+ outer (T.Text xarr xoff xlen) xs = go
109− go !i !mask !skip
122+ go !(g::Int64) !i !mask !skip
110− | i >= xlen = case xs of
123+ | i >= xlast = case xs of
111− Empty -> (mask .|. swizzle z) :*: skip
124+ Empty -> (mask .|. swizzle z) :*: skip
112− Chunk y ys -> outer y ys 0 mask skip
125+ Chunk y ys -> outer y ys g 0 mask skip
113− | otherwise = go (i+1) (mask .|. swizzle c) skip'
126+ | otherwise = go (g+1) (i+1) (mask .|. swizzle c) skip'
114 where c = A.unsafeIndex xarr (xoff+i)
127 where c = A.unsafeIndex xarr (xoff+i)
115− skip' | c == z = nlen - fromIntegral i - 2
128+ skip' | c == z = nlen - fromIntegral g - 2
116 | otherwise = skip
129 | otherwise = skip
117 nlen = wordLength needle
131 nlen = wordLength needle
118 z = foldChunks fin 0 needle
132 z = foldChunks fin 0 needle
119− where fin _ (T.Text narr noff nlen) = A.unsafeIndex narr (noff+nlen-1)
133+ where fin _ (T.Text farr foff flen) = A.unsafeIndex farr (foff+flen-1)