{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
module Data.Text.BoyerMoore.Searcher
( Searcher
, automata
, build
, buildNeedleIdSearcher
, buildWithValues
, caseSensitivity
, containsAll
, containsAny
, needles
, numNeedles
, setSearcherCaseSensitivity
) where
import Control.DeepSeq (NFData)
import Data.Bifunctor (first)
import Data.Hashable (Hashable (hashWithSalt), Hashed, hashed, unhashed)
import Data.Text (Text)
import GHC.Generics (Generic)
import Data.Text.BoyerMoore.Automaton (Automaton, CaseSensitivity (..))
import qualified Data.Text.BoyerMoore.Automaton as BoyerMoore
data Searcher v = Searcher
{ Searcher v -> CaseSensitivity
searcherCaseSensitive :: CaseSensitivity
, Searcher v -> Hashed [(Text, v)]
searcherNeedles :: Hashed [(Text, v)]
, Searcher v -> Int
searcherNumNeedles :: Int
, Searcher v -> [(Automaton, v)]
searcherAutomata :: [(Automaton, v)]
} deriving ((forall x. Searcher v -> Rep (Searcher v) x)
-> (forall x. Rep (Searcher v) x -> Searcher v)
-> Generic (Searcher v)
forall x. Rep (Searcher v) x -> Searcher v
forall x. Searcher v -> Rep (Searcher v) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall v x. Rep (Searcher v) x -> Searcher v
forall v x. Searcher v -> Rep (Searcher v) x
$cto :: forall v x. Rep (Searcher v) x -> Searcher v
$cfrom :: forall v x. Searcher v -> Rep (Searcher v) x
Generic)
instance Show (Searcher v) where
show :: Searcher v -> String
show Searcher v
_ = String
"Searcher _ _ _"
instance Hashable v => Hashable (Searcher v) where
hashWithSalt :: Int -> Searcher v -> Int
hashWithSalt Int
salt Searcher v
searcher = Int -> Hashed [(Text, v)] -> Int
forall a. Hashable a => Int -> a -> Int
hashWithSalt Int
salt (Hashed [(Text, v)] -> Int) -> Hashed [(Text, v)] -> Int
forall a b. (a -> b) -> a -> b
$ Searcher v -> Hashed [(Text, v)]
forall v. Searcher v -> Hashed [(Text, v)]
searcherNeedles Searcher v
searcher
{-# INLINE hashWithSalt #-}
instance Eq v => Eq (Searcher v) where
Searcher CaseSensitivity
cx Hashed [(Text, v)]
xs Int
nx [(Automaton, v)]
_ == :: Searcher v -> Searcher v -> Bool
== Searcher CaseSensitivity
cy Hashed [(Text, v)]
ys Int
ny [(Automaton, v)]
_ = (CaseSensitivity
cx, Int
nx, Hashed [(Text, v)]
xs) (CaseSensitivity, Int, Hashed [(Text, v)])
-> (CaseSensitivity, Int, Hashed [(Text, v)]) -> Bool
forall a. Eq a => a -> a -> Bool
== (CaseSensitivity
cy, Int
ny, Hashed [(Text, v)]
ys)
{-# INLINE (==) #-}
instance NFData v => NFData (Searcher v)
build :: CaseSensitivity -> [Text] -> Searcher ()
{-# INLINABLE build #-}
build :: CaseSensitivity -> [Text] -> Searcher ()
build CaseSensitivity
case_ = CaseSensitivity -> [(Text, ())] -> Searcher ()
forall v.
Hashable v =>
CaseSensitivity -> [(Text, v)] -> Searcher v
buildWithValues CaseSensitivity
case_ ([(Text, ())] -> Searcher ())
-> ([Text] -> [(Text, ())]) -> [Text] -> Searcher ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text] -> [()] -> [(Text, ())]) -> [()] -> [Text] -> [(Text, ())]
forall a b c. (a -> b -> c) -> b -> a -> c
flip [Text] -> [()] -> [(Text, ())]
forall a b. [a] -> [b] -> [(a, b)]
zip (() -> [()]
forall a. a -> [a]
repeat ())
buildWithValues :: Hashable v => CaseSensitivity -> [(Text, v)] -> Searcher v
{-# INLINABLE buildWithValues #-}
buildWithValues :: CaseSensitivity -> [(Text, v)] -> Searcher v
buildWithValues CaseSensitivity
case_ [(Text, v)]
ns =
CaseSensitivity
-> Hashed [(Text, v)] -> Int -> [(Automaton, v)] -> Searcher v
forall v.
CaseSensitivity
-> Hashed [(Text, v)] -> Int -> [(Automaton, v)] -> Searcher v
Searcher CaseSensitivity
case_ ([(Text, v)] -> Hashed [(Text, v)]
forall a. Hashable a => a -> Hashed a
hashed [(Text, v)]
ns) ([(Text, v)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Text, v)]
ns) ([(Automaton, v)] -> Searcher v) -> [(Automaton, v)] -> Searcher v
forall a b. (a -> b) -> a -> b
$ ((Text, v) -> (Automaton, v)) -> [(Text, v)] -> [(Automaton, v)]
forall a b. (a -> b) -> [a] -> [b]
map ((Text -> Automaton) -> (Text, v) -> (Automaton, v)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Automaton
BoyerMoore.buildAutomaton) [(Text, v)]
ns
needles :: Searcher v -> [(Text, v)]
needles :: Searcher v -> [(Text, v)]
needles = Hashed [(Text, v)] -> [(Text, v)]
forall a. Hashed a -> a
unhashed (Hashed [(Text, v)] -> [(Text, v)])
-> (Searcher v -> Hashed [(Text, v)]) -> Searcher v -> [(Text, v)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Searcher v -> Hashed [(Text, v)]
forall v. Searcher v -> Hashed [(Text, v)]
searcherNeedles
automata :: Searcher v -> [(Automaton, v)]
automata :: Searcher v -> [(Automaton, v)]
automata = Searcher v -> [(Automaton, v)]
forall v. Searcher v -> [(Automaton, v)]
searcherAutomata
numNeedles :: Searcher v -> Int
numNeedles :: Searcher v -> Int
numNeedles = Searcher v -> Int
forall v. Searcher v -> Int
searcherNumNeedles
caseSensitivity :: Searcher v -> CaseSensitivity
caseSensitivity :: Searcher v -> CaseSensitivity
caseSensitivity = Searcher v -> CaseSensitivity
forall v. Searcher v -> CaseSensitivity
searcherCaseSensitive
setSearcherCaseSensitivity :: CaseSensitivity -> Searcher v -> Searcher v
setSearcherCaseSensitivity :: CaseSensitivity -> Searcher v -> Searcher v
setSearcherCaseSensitivity CaseSensitivity
case_ Searcher v
searcher = Searcher v
searcher{
searcherCaseSensitive :: CaseSensitivity
searcherCaseSensitive = CaseSensitivity
case_
}
{-# NOINLINE containsAny #-}
containsAny :: Searcher () -> Text -> Bool
containsAny :: Searcher () -> Text -> Bool
containsAny !Searcher ()
searcher !Text
text =
let
f :: p -> p -> Next Bool
f p
_acc p
_match = Bool -> Next Bool
forall a. a -> Next a
BoyerMoore.Done Bool
True
in
case Searcher () -> CaseSensitivity
forall v. Searcher v -> CaseSensitivity
caseSensitivity Searcher ()
searcher of
CaseSensitivity
CaseSensitive ->
((Automaton, ()) -> Bool) -> [(Automaton, ())] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\(Automaton
automaton, ()) -> Bool
-> (Bool -> CodeUnitIndex -> Next Bool)
-> Automaton
-> Text
-> Bool
forall a.
a -> (a -> CodeUnitIndex -> Next a) -> Automaton -> Text -> a
BoyerMoore.runText Bool
False Bool -> CodeUnitIndex -> Next Bool
forall p p. p -> p -> Next Bool
f Automaton
automaton Text
text) (Searcher () -> [(Automaton, ())]
forall v. Searcher v -> [(Automaton, v)]
automata Searcher ()
searcher)
CaseSensitivity
IgnoreCase ->
((Automaton, ()) -> Bool) -> [(Automaton, ())] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\(Automaton
automaton, ()) -> Bool
-> (Bool -> CodeUnitIndex -> Next Bool)
-> Automaton
-> Text
-> Bool
forall a.
a -> (a -> CodeUnitIndex -> Next a) -> Automaton -> Text -> a
BoyerMoore.runLower Bool
False Bool -> CodeUnitIndex -> Next Bool
forall p p. p -> p -> Next Bool
f Automaton
automaton Text
text) (Searcher () -> [(Automaton, ())]
forall v. Searcher v -> [(Automaton, v)]
automata Searcher ()
searcher)
buildNeedleIdSearcher :: CaseSensitivity -> [Text] -> Searcher Int
buildNeedleIdSearcher :: CaseSensitivity -> [Text] -> Searcher Int
buildNeedleIdSearcher !CaseSensitivity
case_ ![Text]
ns =
CaseSensitivity -> [(Text, Int)] -> Searcher Int
forall v.
Hashable v =>
CaseSensitivity -> [(Text, v)] -> Searcher v
buildWithValues CaseSensitivity
case_ ([(Text, Int)] -> Searcher Int) -> [(Text, Int)] -> Searcher Int
forall a b. (a -> b) -> a -> b
$ [Text] -> [Int] -> [(Text, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Text]
ns [Int
0..]
{-# NOINLINE containsAll #-}
containsAll :: Searcher Int -> Text -> Bool
containsAll :: Searcher Int -> Text -> Bool
containsAll !Searcher Int
searcher !Text
text =
let
f :: p -> p -> Next Bool
f p
_acc p
_match = Bool -> Next Bool
forall a. a -> Next a
BoyerMoore.Done Bool
True
in
case Searcher Int -> CaseSensitivity
forall v. Searcher v -> CaseSensitivity
caseSensitivity Searcher Int
searcher of
CaseSensitivity
CaseSensitive ->
((Automaton, Int) -> Bool) -> [(Automaton, Int)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\(Automaton
automaton, Int
_) -> Bool
-> (Bool -> CodeUnitIndex -> Next Bool)
-> Automaton
-> Text
-> Bool
forall a.
a -> (a -> CodeUnitIndex -> Next a) -> Automaton -> Text -> a
BoyerMoore.runText Bool
False Bool -> CodeUnitIndex -> Next Bool
forall p p. p -> p -> Next Bool
f Automaton
automaton Text
text) (Searcher Int -> [(Automaton, Int)]
forall v. Searcher v -> [(Automaton, v)]
automata Searcher Int
searcher)
CaseSensitivity
IgnoreCase ->
((Automaton, Int) -> Bool) -> [(Automaton, Int)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\(Automaton
automaton, Int
_) -> Bool
-> (Bool -> CodeUnitIndex -> Next Bool)
-> Automaton
-> Text
-> Bool
forall a.
a -> (a -> CodeUnitIndex -> Next a) -> Automaton -> Text -> a
BoyerMoore.runLower Bool
False Bool -> CodeUnitIndex -> Next Bool
forall p p. p -> p -> Next Bool
f Automaton
automaton Text
text) (Searcher Int -> [(Automaton, Int)]
forall v. Searcher v -> [(Automaton, v)]
automata Searcher Int
searcher)