{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TypeFamilies #-}

module Data.Monoid.RollingHash where

import Data.Char
import Data.Coerce
import qualified Data.Foldable as F
import Data.Monoid
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Generic.Mutable as GM
import qualified Data.Vector.Unboxed as U
import GHC.Exts
import GHC.TypeLits

import Data.Monoid.Affine
import Data.RollingHash

{- |
@b@ should be a primitive root of @2^61-1@

>>> :set -XDataKinds -XOverloadedStrings
>>> runRollingHashBuilder @2047 $ "abc" <> "def"
1182147938584434692
>>> runRollingHashBuilder @2047 "abcdef"
1182147938584434692
>>> mempty @(RollingHashBuilder 2047)
Affine {getAffine1 = 1, getAffine0 = 0}
-}
newtype RollingHashBuilder b = RHB (Affine (RollingHash b))
  deriving newtype (RollingHashBuilder b -> RollingHashBuilder b -> Bool
(RollingHashBuilder b -> RollingHashBuilder b -> Bool)
-> (RollingHashBuilder b -> RollingHashBuilder b -> Bool)
-> Eq (RollingHashBuilder b)
forall (b :: Nat).
RollingHashBuilder b -> RollingHashBuilder b -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall (b :: Nat).
RollingHashBuilder b -> RollingHashBuilder b -> Bool
== :: RollingHashBuilder b -> RollingHashBuilder b -> Bool
$c/= :: forall (b :: Nat).
RollingHashBuilder b -> RollingHashBuilder b -> Bool
/= :: RollingHashBuilder b -> RollingHashBuilder b -> Bool
Eq, Int -> RollingHashBuilder b -> ShowS
[RollingHashBuilder b] -> ShowS
RollingHashBuilder b -> String
(Int -> RollingHashBuilder b -> ShowS)
-> (RollingHashBuilder b -> String)
-> ([RollingHashBuilder b] -> ShowS)
-> Show (RollingHashBuilder b)
forall (b :: Nat). Int -> RollingHashBuilder b -> ShowS
forall (b :: Nat). [RollingHashBuilder b] -> ShowS
forall (b :: Nat). RollingHashBuilder b -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall (b :: Nat). Int -> RollingHashBuilder b -> ShowS
showsPrec :: Int -> RollingHashBuilder b -> ShowS
$cshow :: forall (b :: Nat). RollingHashBuilder b -> String
show :: RollingHashBuilder b -> String
$cshowList :: forall (b :: Nat). [RollingHashBuilder b] -> ShowS
showList :: [RollingHashBuilder b] -> ShowS
Show)
  deriving (NonEmpty (RollingHashBuilder b) -> RollingHashBuilder b
RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
(RollingHashBuilder b
 -> RollingHashBuilder b -> RollingHashBuilder b)
-> (NonEmpty (RollingHashBuilder b) -> RollingHashBuilder b)
-> (forall b.
    Integral b =>
    b -> RollingHashBuilder b -> RollingHashBuilder b)
-> Semigroup (RollingHashBuilder b)
forall (b :: Nat).
NonEmpty (RollingHashBuilder b) -> RollingHashBuilder b
forall (b :: Nat).
RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
forall (b :: Nat) b.
Integral b =>
b -> RollingHashBuilder b -> RollingHashBuilder b
forall b.
Integral b =>
b -> RollingHashBuilder b -> RollingHashBuilder b
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: forall (b :: Nat).
RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
<> :: RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
$csconcat :: forall (b :: Nat).
NonEmpty (RollingHashBuilder b) -> RollingHashBuilder b
sconcat :: NonEmpty (RollingHashBuilder b) -> RollingHashBuilder b
$cstimes :: forall (b :: Nat) b.
Integral b =>
b -> RollingHashBuilder b -> RollingHashBuilder b
stimes :: forall b.
Integral b =>
b -> RollingHashBuilder b -> RollingHashBuilder b
Semigroup, Semigroup (RollingHashBuilder b)
RollingHashBuilder b
Semigroup (RollingHashBuilder b) =>
RollingHashBuilder b
-> (RollingHashBuilder b
    -> RollingHashBuilder b -> RollingHashBuilder b)
-> ([RollingHashBuilder b] -> RollingHashBuilder b)
-> Monoid (RollingHashBuilder b)
[RollingHashBuilder b] -> RollingHashBuilder b
RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
forall (b :: Nat). Semigroup (RollingHashBuilder b)
forall (b :: Nat). RollingHashBuilder b
forall (b :: Nat). [RollingHashBuilder b] -> RollingHashBuilder b
forall (b :: Nat).
RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
$cmempty :: forall (b :: Nat). RollingHashBuilder b
mempty :: RollingHashBuilder b
$cmappend :: forall (b :: Nat).
RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
mappend :: RollingHashBuilder b
-> RollingHashBuilder b -> RollingHashBuilder b
$cmconcat :: forall (b :: Nat). [RollingHashBuilder b] -> RollingHashBuilder b
mconcat :: [RollingHashBuilder b] -> RollingHashBuilder b
Monoid) via Dual (Affine (RollingHash b))

instance (KnownNat b) => IsString (RollingHashBuilder b) where
  fromString :: String -> RollingHashBuilder b
fromString = (Char -> RollingHashBuilder b) -> String -> RollingHashBuilder b
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
F.foldMap' (Int -> RollingHashBuilder b
forall (b :: Nat). KnownNat b => Int -> RollingHashBuilder b
singletonRHB (Int -> RollingHashBuilder b)
-> (Char -> Int) -> Char -> RollingHashBuilder b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord)

newtype instance U.MVector s (RollingHashBuilder b)
  = MV_RollingHashBuilder (U.MVector s (Affine (RollingHash b)))
newtype instance U.Vector (RollingHashBuilder b)
  = V_RollingHashBuilder (U.Vector (Affine (RollingHash b)))
deriving newtype instance GM.MVector U.MVector (RollingHashBuilder b)
deriving newtype instance G.Vector U.Vector (RollingHashBuilder b)
instance U.Unbox (RollingHashBuilder b)

runRollingHashBuilder :: RollingHashBuilder b -> RollingHash b
runRollingHashBuilder :: forall (b :: Nat). RollingHashBuilder b -> RollingHash b
runRollingHashBuilder (RHB (Affine RollingHash b
_ RollingHash b
h)) = RollingHash b
h

{- |
>>> :set -XDataKinds
>>> singletonRHB @2047 123
Affine {getAffine1 = 2047, getAffine0 = 123}
-}
singletonRHB :: forall b. (KnownNat b) => Int -> RollingHashBuilder b
singletonRHB :: forall (b :: Nat). KnownNat b => Int -> RollingHashBuilder b
singletonRHB Int
x = Affine (RollingHash Any) -> RollingHashBuilder b
forall a b. Coercible a b => a -> b
coerce (RollingHash Any -> RollingHash Any -> Affine (RollingHash Any)
forall a. a -> a -> Affine a
Affine (Int -> RollingHash Any
forall (b :: Nat). Int -> RollingHash b
RollingHash Int
b) (Int -> RollingHash Any
forall (b :: Nat). Int -> RollingHash b
RollingHash Int
x))
  where
    b :: Int
b = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat). KnownNat n => Proxy# n -> Integer
natVal' @b Proxy# b
forall {k} (a :: k). Proxy# a
proxy#)