module Data.Hash.Rolling (
RollingHash,
rollingHash, addAndRoll,
currentHash, lastHashes, windowSize
)
where
import Data.Hash.Base
import Data.Hash.Instances
import Data.Bits
import qualified Data.Sequence as S
import Data.Foldable
import Text.Show.Functions ()
data RollingHash a = RH {
RollingHash a -> Hash
currentHash :: Hash
,RollingHash a -> Int
windowSize :: Int
,RollingHash a -> Seq Hash
hseq :: S.Seq Hash
,RollingHash a -> RollingHash a -> Hash -> RollingHash a
addHashImpl :: RollingHash a -> Hash -> RollingHash a
} deriving Int -> RollingHash a -> ShowS
[RollingHash a] -> ShowS
RollingHash a -> String
(Int -> RollingHash a -> ShowS)
-> (RollingHash a -> String)
-> ([RollingHash a] -> ShowS)
-> Show (RollingHash a)
forall a. Int -> RollingHash a -> ShowS
forall a. [RollingHash a] -> ShowS
forall a. RollingHash a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RollingHash a] -> ShowS
$cshowList :: forall a. [RollingHash a] -> ShowS
show :: RollingHash a -> String
$cshow :: forall a. RollingHash a -> String
showsPrec :: Int -> RollingHash a -> ShowS
$cshowsPrec :: forall a. Int -> RollingHash a -> ShowS
Show
rollingHash :: Int -> RollingHash a
rollingHash :: Int -> RollingHash a
rollingHash Int
n
| Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = String -> RollingHash a
forall a. HasCallStack => String -> a
error (String -> RollingHash a) -> String -> RollingHash a
forall a b. (a -> b) -> a -> b
$ String
"rollingHash: invalid window size " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n
| Bool
otherwise = RH :: forall a.
Hash
-> Int
-> Seq Hash
-> (RollingHash a -> Hash -> RollingHash a)
-> RollingHash a
RH {
currentHash :: Hash
currentHash = Hash
initial_hash
,windowSize :: Int
windowSize = Int
n
,hseq :: Seq Hash
hseq = Hash -> Seq Hash
forall a. a -> Seq a
S.singleton Hash
initial_hash
,addHashImpl :: RollingHash a -> Hash -> RollingHash a
addHashImpl = Int -> RollingHash a -> Hash -> RollingHash a
forall a. Int -> RollingHash a -> Hash -> RollingHash a
accumulateNext (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
}
where initial_hash :: Hash
initial_hash = () -> Hash
forall a. Hashable a => a -> Hash
hash () Hash -> Hash -> Hash
`combine` Int -> Hash
forall a. Hashable a => a -> Hash
hash Int
n
defaultAddHash :: RollingHash a -> Hash -> RollingHash a
defaultAddHash :: RollingHash a -> Hash -> RollingHash a
defaultAddHash RollingHash a
rh Hash
hv = RollingHash a
rh { currentHash :: Hash
currentHash = (RollingHash a -> Hash
forall a. RollingHash a -> Hash
currentHash RollingHash a
rh) Hash -> Hash -> Hash
`combine` (Word64 -> Hash
Hash (Word64 -> Hash) -> Word64 -> Hash
forall a b. (a -> b) -> a -> b
$ Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
rotate Word64
c1 Int
k Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64
ck)
, hseq :: Seq Hash
hseq = (Int -> Seq Hash -> Seq Hash
forall a. Int -> Seq a -> Seq a
S.drop Int
1 (Seq Hash -> Seq Hash) -> Seq Hash -> Seq Hash
forall a b. (a -> b) -> a -> b
$ RollingHash a -> Seq Hash
forall a. RollingHash a -> Seq Hash
hseq RollingHash a
rh) Seq Hash -> Hash -> Seq Hash
forall a. Seq a -> a -> Seq a
S.|> Hash
hv
}
where ck :: Word64
ck = Hash -> Word64
asWord64 Hash
hv
c1 :: Word64
c1 = Hash -> Word64
asWord64 (Hash -> Word64) -> Hash -> Word64
forall a b. (a -> b) -> a -> b
$ Seq Hash -> Int -> Hash
forall a. Seq a -> Int -> a
S.index (RollingHash a -> Seq Hash
forall a. RollingHash a -> Seq Hash
hseq RollingHash a
rh) Int
0
k :: Int
k = Seq Hash -> Int
forall a. Seq a -> Int
S.length (Seq Hash -> Int) -> Seq Hash -> Int
forall a b. (a -> b) -> a -> b
$ RollingHash a -> Seq Hash
forall a. RollingHash a -> Seq Hash
hseq RollingHash a
rh
addAndRoll :: Hashable a => RollingHash a -> a -> RollingHash a
addAndRoll :: RollingHash a -> a -> RollingHash a
addAndRoll RollingHash a
r a
a = (RollingHash a -> RollingHash a -> Hash -> RollingHash a
forall a. RollingHash a -> RollingHash a -> Hash -> RollingHash a
addHashImpl RollingHash a
r) RollingHash a
r (a -> Hash
forall a. Hashable a => a -> Hash
hash a
a)
accumulateNext :: Int -> RollingHash a -> Hash -> RollingHash a
accumulateNext :: Int -> RollingHash a -> Hash -> RollingHash a
accumulateNext Int
n | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = \RollingHash a
rh Hash
h -> RollingHash a
rh {
currentHash :: Hash
currentHash = RollingHash a -> Hash
forall a. RollingHash a -> Hash
currentHash RollingHash a
rh Hash -> Hash -> Hash
`combine` Hash
h,
hseq :: Seq Hash
hseq = (RollingHash a -> Seq Hash
forall a. RollingHash a -> Seq Hash
hseq RollingHash a
rh) Seq Hash -> Hash -> Seq Hash
forall a. Seq a -> a -> Seq a
S.|> Hash
h,
addHashImpl :: RollingHash a -> Hash -> RollingHash a
addHashImpl = Int -> RollingHash a -> Hash -> RollingHash a
forall a. Int -> RollingHash a -> Hash -> RollingHash a
accumulateNext (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
}
| Bool
otherwise = RollingHash a -> Hash -> RollingHash a
forall a. RollingHash a -> Hash -> RollingHash a
defaultAddHash
lastHashes :: RollingHash a -> [Hash]
lastHashes :: RollingHash a -> [Hash]
lastHashes = Seq Hash -> [Hash]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Seq Hash -> [Hash])
-> (RollingHash a -> Seq Hash) -> RollingHash a -> [Hash]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RollingHash a -> Seq Hash
forall a. RollingHash a -> Seq Hash
hseq