packages feed

cgrep-8.0.0: src/CGrep/Search.hs

--
-- Copyright (c) 2013-2023 Nicola Bonelli <nicola@larthia.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
--

module CGrep.Search ( searchStringIndices
                    , searchStringTaggedIndices
                    , eligibleForSearch
                    , TaggedIx(..)
                    ) where

import CGrep.Types ( Text8 )
import Data.Int ( Int64 )
import GHC.Exts ( groupWith )

import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Search as BM
import qualified Data.ByteString.Search.DFA as DFA

import qualified Data.ByteString.Lazy.Search as LBM
import qualified Data.ByteString.Lazy.Search.DFA as LDFA
import Data.List.Extra ( notNull )


findIndices :: Text8 -> Text8 -> [Int]
findIndices p = if C.length p <= 3
    then DFA.indices p
    else BM.indices p
{-# INLINE findIndices #-}


searchStringIndices :: [Text8] -> Text8 -> [[Int64]]
searchStringIndices ps text =  ps >>= \p -> [fromIntegral <$> p `findIndices` text]
{-# INLINE searchStringIndices #-}


data TaggedIx a = TaggedIx {
      index :: {-# UNPACK #-} !Int
    , tags  :: [a]
} deriving stock (Show)

instance Eq (TaggedIx a) where
    (TaggedIx i1 _) == (TaggedIx i2 _) = i1 == i2

instance Ord (TaggedIx a) where
    compare (TaggedIx i1 _) (TaggedIx i2 _) = compare i1 i2

-- >>> searchStringTaggedIndices [("a",2),("b",1),("a",0), ("he", 42)] "aheba"
-- [TaggedIx {index = 0, tags = [2,0]},TaggedIx {index = 1, tags = [42]},TaggedIx {index = 3, tags = [1]},TaggedIx {index = 4, tags = [2,0]}]

searchStringTaggedIndices :: [(Text8, a)] -> Text8 -> [TaggedIx a]
searchStringTaggedIndices ps text =
    let res = ps >>= \p -> let pat = fst p
                               tag = snd p
                               ids = findIndices pat text
                                in (\i -> TaggedIx (fromIntegral i) [tag]) <$> ids
        in fuseGroup <$> groupWith index res
    where {-# INLINE fuseGroup #-}
          fuseGroup :: [TaggedIx a] -> TaggedIx a
          fuseGroup xs = TaggedIx (index $ head xs) $ concatMap tags xs

eligibleForSearch :: [a] -> [[Int64]] -> Bool
eligibleForSearch [_] = all notNull
eligibleForSearch _   = any notNull
{-# INLINE eligibleForSearch #-}