{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP          #-}
{-# LANGUAGE MagicHash    #-}

{-|

A hash table using the cuckoo strategy. (See
<http://en.wikipedia.org/wiki/Cuckoo_hashing>). Use this hash table if you...

  * want the fastest possible inserts, and very fast lookups.

  * are conscious of memory usage; this table has less space overhead than
    "Data.HashTable.ST.Basic" or "Data.HashTable.ST.Linear".

  * don't care that a table resize might pause for a long time to rehash all
    of the key-value mappings.


/Details:/

The basic idea of cuckoo hashing, first introduced by Pagh and Rodler in 2001,
is to use /d/ hash functions instead of only one; in this implementation d=2
and the strategy we use is to split up a flat array of slots into @k@ buckets,
each cache-line-sized:

@
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+----------+
|x0|x1|x2|x3|x4|x5|x6|x7|y0|y1|y2|y3|y4|y5|y6|y7|z0|z1|z2........|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+----------+
[  ^^^  bucket 0  ^^^  ][  ^^^  bucket 1  ^^^  ]...
@

There are actually three parallel arrays: one unboxed array of 'Int's for hash
codes, one boxed array for keys, and one boxed array for values. When looking
up a key-value mapping, we hash the key using two hash functions and look in
both buckets in the hash code array for the key. Each bucket is cache-line
sized, with its keys in no particular order. Because the hash code array is
unboxed, we can search it for the key using a highly-efficient branchless
strategy in C code, using SSE instructions if available.

On insert, if both buckets are full, we knock out a randomly-selected entry
from one of the buckets (using a random walk ensures that \"key cycles\" are
broken with maximum probability) and try to repeat the insert procedure. This
process may not succeed; if all items have not successfully found a home after
some number of tries, we give up and rehash all of the elements into a larger
table.

/Space overhead: experimental results/

The implementation of cuckoo hash given here is almost as fast for lookups as
the basic open-addressing hash table using linear probing, and on average is
more space-efficient: in randomized testing on my 64-bit machine (see
@test\/compute-overhead\/ComputeOverhead.hs@ in the source distribution), mean
overhead is 0.77 machine words per key-value mapping, with a standard deviation
of 0.29 words, and 1.23 words per mapping at the 95th percentile.

/References:/

  * A. Pagh and F. Rodler. Cuckoo hashing. In /Proceedings of the 9th
    Annual European Symposium on Algorithms/, pp. 121-133, 2001.
-}


module Data.HashTable.ST.Cuckoo
  ( HashTable
  , new
  , newSized
  , delete
  , lookup
  , insert
  , mutate
  , mutateST
  , mapM_
  , foldM
  , lookupIndex
  , nextByIndex
  ) where


------------------------------------------------------------------------------
#if !MIN_VERSION_base(4,8,0)
import           Control.Applicative
#endif
import           Control.Monad                                      hiding
                                                                     (foldM,
                                                                     mapM_)
import           Control.Monad.ST                                   (ST)
import           Data.Bits
import           Data.Hashable                                      hiding
                                                                     (hash)
import qualified Data.Hashable                                      as H
import           Data.Int
import           Data.Maybe
import           Data.Primitive.Array
import           Data.STRef
import           GHC.Exts
import           Prelude                                            hiding
                                                                     (lookup,
                                                                     mapM_,
                                                                     read)
------------------------------------------------------------------------------
import qualified Data.HashTable.Class                               as C
import           Data.HashTable.Internal.CacheLine
import           Data.HashTable.Internal.CheapPseudoRandomBitStream
import           Data.HashTable.Internal.IntArray                   (Elem)
import qualified Data.HashTable.Internal.IntArray                   as U
import           Data.HashTable.Internal.Utils

#ifdef DEBUG
import           System.IO
#endif


------------------------------------------------------------------------------
-- | A cuckoo hash table.
newtype HashTable s k v = HT (STRef s (HashTable_ s k v))

data HashTable_ s k v = HashTable
    { HashTable_ s k v -> Int
_size        :: {-# UNPACK #-} !Int     -- ^ in buckets, total size is
                                              --   numElemsInCacheLine * _size
    , HashTable_ s k v -> BitStream s
_rng         :: {-# UNPACK #-} !(BitStream s)
    , HashTable_ s k v -> IntArray s
_hashes      :: {-# UNPACK #-} !(U.IntArray s)
    , HashTable_ s k v -> MutableArray s k
_keys        :: {-# UNPACK #-} !(MutableArray s k)
    , HashTable_ s k v -> MutableArray s v
_values      :: {-# UNPACK #-} !(MutableArray s v)
    , HashTable_ s k v -> Int
_maxAttempts :: {-# UNPACK #-} !Int
    }


------------------------------------------------------------------------------
instance C.HashTable HashTable where
    new :: ST s (HashTable s k v)
new             = ST s (HashTable s k v)
forall s k v. ST s (HashTable s k v)
new
    newSized :: Int -> ST s (HashTable s k v)
newSized        = Int -> ST s (HashTable s k v)
forall s k v. Int -> ST s (HashTable s k v)
newSized
    insert :: HashTable s k v -> k -> v -> ST s ()
insert          = HashTable s k v -> k -> v -> ST s ()
forall k s v.
(Eq k, Hashable k) =>
HashTable s k v -> k -> v -> ST s ()
insert
    delete :: HashTable s k v -> k -> ST s ()
delete          = HashTable s k v -> k -> ST s ()
forall k s v. (Hashable k, Eq k) => HashTable s k v -> k -> ST s ()
delete
    lookup :: HashTable s k v -> k -> ST s (Maybe v)
lookup          = HashTable s k v -> k -> ST s (Maybe v)
forall k s v.
(Eq k, Hashable k) =>
HashTable s k v -> k -> ST s (Maybe v)
lookup
    foldM :: (a -> (k, v) -> ST s a) -> a -> HashTable s k v -> ST s a
foldM           = (a -> (k, v) -> ST s a) -> a -> HashTable s k v -> ST s a
forall a k v s.
(a -> (k, v) -> ST s a) -> a -> HashTable s k v -> ST s a
foldM
    mapM_ :: ((k, v) -> ST s b) -> HashTable s k v -> ST s ()
mapM_           = ((k, v) -> ST s b) -> HashTable s k v -> ST s ()
forall k v s b. ((k, v) -> ST s b) -> HashTable s k v -> ST s ()
mapM_
    lookupIndex :: HashTable s k v -> k -> ST s (Maybe Word)
lookupIndex     = HashTable s k v -> k -> ST s (Maybe Word)
forall k s v.
(Hashable k, Eq k) =>
HashTable s k v -> k -> ST s (Maybe Word)
lookupIndex
    nextByIndex :: HashTable s k v -> Word -> ST s (Maybe (Word, k, v))
nextByIndex     = HashTable s k v -> Word -> ST s (Maybe (Word, k, v))
forall s k v. HashTable s k v -> Word -> ST s (Maybe (Word, k, v))
nextByIndex
    computeOverhead :: HashTable s k v -> ST s Double
computeOverhead = HashTable s k v -> ST s Double
forall s k v. HashTable s k v -> ST s Double
computeOverhead
    mutate :: HashTable s k v -> k -> (Maybe v -> (Maybe v, a)) -> ST s a
mutate          = HashTable s k v -> k -> (Maybe v -> (Maybe v, a)) -> ST s a
forall k s v a.
(Eq k, Hashable k) =>
HashTable s k v -> k -> (Maybe v -> (Maybe v, a)) -> ST s a
mutate
    mutateST :: HashTable s k v -> k -> (Maybe v -> ST s (Maybe v, a)) -> ST s a
mutateST        = HashTable s k v -> k -> (Maybe v -> ST s (Maybe v, a)) -> ST s a
forall k s v a.
(Eq k, Hashable k) =>
HashTable s k v -> k -> (Maybe v -> ST s (Maybe v, a)) -> ST s a
mutateST


------------------------------------------------------------------------------
instance Show (HashTable s k v) where
    show :: HashTable s k v -> String
show HashTable s k v
_ = String
"<HashTable>"


------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.new'.
new :: ST s (HashTable s k v)
new :: ST s (HashTable s k v)
new = Int -> ST s (HashTable_ s k v)
forall s k v. Int -> ST s (HashTable_ s k v)
newSizedReal Int
2 ST s (HashTable_ s k v)
-> (HashTable_ s k v -> ST s (HashTable s k v))
-> ST s (HashTable s k v)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashTable_ s k v -> ST s (HashTable s k v)
forall s k v. HashTable_ s k v -> ST s (HashTable s k v)
newRef
{-# INLINE new #-}


------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.newSized'.
newSized :: Int -> ST s (HashTable s k v)
newSized :: Int -> ST s (HashTable s k v)
newSized Int
n = do
    let n' :: Int
n' = (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
numElemsInCacheLine Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
numElemsInCacheLine
    let k :: Int
k = Int -> Int
nextBestPrime (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Double -> Int
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double -> Int) -> Double -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n' Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
maxLoad
    Int -> ST s (HashTable_ s k v)
forall s k v. Int -> ST s (HashTable_ s k v)
newSizedReal Int
k ST s (HashTable_ s k v)
-> (HashTable_ s k v -> ST s (HashTable s k v))
-> ST s (HashTable s k v)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashTable_ s k v -> ST s (HashTable s k v)
forall s k v. HashTable_ s k v -> ST s (HashTable s k v)
newRef
{-# INLINE newSized #-}


------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.insert'.
insert :: (Eq k, Hashable k) => HashTable s k v -> k -> v -> ST s ()
insert :: HashTable s k v -> k -> v -> ST s ()
insert HashTable s k v
ht !k
k !v
v = HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
ht ST s (HashTable_ s k v) -> (HashTable_ s k v -> ST s ()) -> ST s ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \HashTable_ s k v
h -> HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
insert' HashTable_ s k v
h k
k v
v ST s (HashTable_ s k v) -> (HashTable_ s k v -> ST s ()) -> ST s ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashTable s k v -> HashTable_ s k v -> ST s ()
forall s k v. HashTable s k v -> HashTable_ s k v -> ST s ()
writeRef HashTable s k v
ht


------------------------------------------------------------------------------
mutate :: (Eq k, Hashable k) =>
          HashTable s k v
       -> k
       -> (Maybe v -> (Maybe v, a))
       -> ST s a
mutate :: HashTable s k v -> k -> (Maybe v -> (Maybe v, a)) -> ST s a
mutate HashTable s k v
htRef !k
k !Maybe v -> (Maybe v, a)
f = HashTable s k v -> k -> (Maybe v -> ST s (Maybe v, a)) -> ST s a
forall k s v a.
(Eq k, Hashable k) =>
HashTable s k v -> k -> (Maybe v -> ST s (Maybe v, a)) -> ST s a
mutateST HashTable s k v
htRef k
k ((Maybe v, a) -> ST s (Maybe v, a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Maybe v, a) -> ST s (Maybe v, a))
-> (Maybe v -> (Maybe v, a)) -> Maybe v -> ST s (Maybe v, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe v -> (Maybe v, a)
f)
{-# INLINE mutate #-}


------------------------------------------------------------------------------
mutateST :: (Eq k, Hashable k) =>
            HashTable s k v
         -> k
         -> (Maybe v -> ST s (Maybe v, a))
         -> ST s a
mutateST :: HashTable s k v -> k -> (Maybe v -> ST s (Maybe v, a)) -> ST s a
mutateST HashTable s k v
htRef !k
k !Maybe v -> ST s (Maybe v, a)
f = do
    HashTable_ s k v
ht <- HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef
    (HashTable_ s k v
newHt, a
a) <- HashTable_ s k v
-> k
-> (Maybe v -> ST s (Maybe v, a))
-> ST s (HashTable_ s k v, a)
forall k s v a.
(Eq k, Hashable k) =>
HashTable_ s k v
-> k
-> (Maybe v -> ST s (Maybe v, a))
-> ST s (HashTable_ s k v, a)
mutate' HashTable_ s k v
ht k
k Maybe v -> ST s (Maybe v, a)
f
    HashTable s k v -> HashTable_ s k v -> ST s ()
forall s k v. HashTable s k v -> HashTable_ s k v -> ST s ()
writeRef HashTable s k v
htRef HashTable_ s k v
newHt
    a -> ST s a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
{-# INLINE mutateST #-}


------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.computeOverhead'.
computeOverhead :: HashTable s k v -> ST s Double
computeOverhead :: HashTable s k v -> ST s Double
computeOverhead HashTable s k v
htRef = HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef ST s (HashTable_ s k v)
-> (HashTable_ s k v -> ST s Double) -> ST s Double
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashTable_ s k v -> ST s Double
forall b s k v. Fractional b => HashTable_ s k v -> ST s b
work
  where
    work :: HashTable_ s k v -> ST s b
work (HashTable Int
sz BitStream s
_ IntArray s
_ MutableArray s k
_ MutableArray s v
_ Int
_) = do
        Int
nFilled <- (Int -> (k, v) -> ST s Int) -> Int -> HashTable s k v -> ST s Int
forall a k v s.
(a -> (k, v) -> ST s a) -> a -> HashTable s k v -> ST s a
foldM Int -> (k, v) -> ST s Int
forall (m :: * -> *) a p. (Monad m, Num a) => a -> p -> m a
f Int
0 HashTable s k v
htRef

        let oh :: Int
oh = (Int
totSz Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
hashCodesPerWord)  -- one half or quarter word
                                                 -- per element in hashes
               Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
totSz Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
nFilled)           -- two words per non-filled entry
               Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
12                              -- fixed overhead

        b -> ST s b
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> ST s b) -> b -> ST s b
forall a b. (a -> b) -> a -> b
$! Int -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
oh::Int) b -> b -> b
forall a. Fractional a => a -> a -> a
/ Int -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nFilled

      where
        hashCodesPerWord :: Int
hashCodesPerWord = (Int -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize (Int
0 :: Int)) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
16
        totSz :: Int
totSz = Int
numElemsInCacheLine Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
sz

        f :: a -> p -> m a
f !a
a p
_ = a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> m a) -> a -> m a
forall a b. (a -> b) -> a -> b
$! a
aa -> a -> a
forall a. Num a => a -> a -> a
+a
1


------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.delete'.
delete :: (Hashable k, Eq k) =>
          HashTable s k v
       -> k
       -> ST s ()
delete :: HashTable s k v -> k -> ST s ()
delete HashTable s k v
htRef k
k = HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef ST s (HashTable_ s k v) -> (HashTable_ s k v -> ST s ()) -> ST s ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashTable_ s k v -> ST s ()
forall s v. HashTable_ s k v -> ST s ()
go
  where
    go :: HashTable_ s k v -> ST s ()
go ht :: HashTable_ s k v
ht@(HashTable Int
sz BitStream s
_ IntArray s
_ MutableArray s k
_ MutableArray s v
_ Int
_) = do
        (Int, Elem)
_ <- HashTable_ s k v
-> Bool -> k -> Int -> Int -> Int -> Int -> ST s (Int, Elem)
forall k s v.
(Hashable k, Eq k) =>
HashTable_ s k v
-> Bool -> k -> Int -> Int -> Int -> Int -> ST s (Int, Elem)
delete' HashTable_ s k v
ht Bool
False k
k Int
b1 Int
b2 Int
h1 Int
h2
        () -> ST s ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

      where
        h1 :: Int
h1 = k -> Int
forall k. Hashable k => k -> Int
hash1 k
k
        h2 :: Int
h2 = k -> Int
forall k. Hashable k => k -> Int
hash2 k
k

        b1 :: Int
b1 = Int -> Int -> Int
whichLine Int
h1 Int
sz
        b2 :: Int
b2 = Int -> Int -> Int
whichLine Int
h2 Int
sz


------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.lookup'.
lookup :: (Eq k, Hashable k) =>
          HashTable s k v
       -> k
       -> ST s (Maybe v)
lookup :: HashTable s k v -> k -> ST s (Maybe v)
lookup HashTable s k v
htRef k
k = do
    HashTable_ s k v
ht <- HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef
    HashTable_ s k v -> k -> ST s (Maybe v)
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> k -> ST s (Maybe v)
lookup' HashTable_ s k v
ht k
k
{-# INLINE lookup #-}


------------------------------------------------------------------------------
lookup' :: (Eq k, Hashable k) =>
           HashTable_ s k v
        -> k
        -> ST s (Maybe v)
lookup' :: HashTable_ s k v -> k -> ST s (Maybe v)
lookup' (HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) !k
k = do
    -- Unlike the write case, prefetch doesn't seem to help here for lookup.
    -- prefetchRead hashes b2
    Int
idx1 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b1 Elem
he1

    if Int
idx1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
      then do
        v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx1
        Maybe v -> ST s (Maybe v)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe v -> ST s (Maybe v)) -> Maybe v -> ST s (Maybe v)
forall a b. (a -> b) -> a -> b
$! v -> Maybe v
forall a. a -> Maybe a
Just v
v
      else do
        Int
idx2 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b2 Elem
he2
        if Int
idx2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
          then do
            v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx2
            Maybe v -> ST s (Maybe v)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe v -> ST s (Maybe v)) -> Maybe v -> ST s (Maybe v)
forall a b. (a -> b) -> a -> b
$! v -> Maybe v
forall a. a -> Maybe a
Just v
v
          else
            Maybe v -> ST s (Maybe v)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe v
forall a. Maybe a
Nothing

  where
    h1 :: Int
h1 = k -> Int
forall k. Hashable k => k -> Int
hash1 k
k
    h2 :: Int
h2 = k -> Int
forall k. Hashable k => k -> Int
hash2 k
k

    he1 :: Elem
he1 = Int -> Elem
hashToElem Int
h1
    he2 :: Elem
he2 = Int -> Elem
hashToElem Int
h2

    b1 :: Int
b1 = Int -> Int -> Int
whichLine Int
h1 Int
sz
    b2 :: Int
b2 = Int -> Int -> Int
whichLine Int
h2 Int
sz
{-# INLINE lookup' #-}


------------------------------------------------------------------------------
searchOne :: (Eq k) =>
             MutableArray s k
          -> U.IntArray s
          -> k
          -> Int
          -> Elem
          -> ST s Int
searchOne :: MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne !MutableArray s k
keys !IntArray s
hashes !k
k !Int
b0 !Elem
h = Int -> ST s Int
go Int
b0
  where
    go :: Int -> ST s Int
go !Int
b = do
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"searchOne: go/" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"/" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Elem -> String
forall a. Show a => a -> String
show Elem
h
        Int
idx <- IntArray s -> Int -> Elem -> ST s Int
forall s. IntArray s -> Int -> Elem -> ST s Int
cacheLineSearch IntArray s
hashes Int
b Elem
h
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"searchOne: cacheLineSearch returned " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
idx

        case Int
idx of
          -1 -> Int -> ST s Int
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
          Int
_  -> do
              k
k' <- MutableArray (PrimState (ST s)) k -> Int -> ST s k
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
idx
              if k
k k -> k -> Bool
forall a. Eq a => a -> a -> Bool
== k
k'
                then Int -> ST s Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
idx
                else do
                  let !idx' :: Int
idx' = Int
idx Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
                  if Int -> Bool
isCacheLineAligned Int
idx'
                    then Int -> ST s Int
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
                    else Int -> ST s Int
go Int
idx'
{-# INLINE searchOne #-}



------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.foldM'.
foldM :: (a -> (k,v) -> ST s a)
      -> a
      -> HashTable s k v
      -> ST s a
foldM :: (a -> (k, v) -> ST s a) -> a -> HashTable s k v -> ST s a
foldM a -> (k, v) -> ST s a
f a
seed0 HashTable s k v
htRef = HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef ST s (HashTable_ s k v) -> (HashTable_ s k v -> ST s a) -> ST s a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (a -> (k, v) -> ST s a) -> a -> HashTable_ s k v -> ST s a
forall a k v s.
(a -> (k, v) -> ST s a) -> a -> HashTable_ s k v -> ST s a
foldMWork a -> (k, v) -> ST s a
f a
seed0
{-# INLINE foldM #-}


------------------------------------------------------------------------------
foldMWork :: (a -> (k,v) -> ST s a)
          -> a
          -> HashTable_ s k v
          -> ST s a
foldMWork :: (a -> (k, v) -> ST s a) -> a -> HashTable_ s k v -> ST s a
foldMWork a -> (k, v) -> ST s a
f a
seed0 (HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) = Int -> a -> ST s a
go Int
0 a
seed0
  where
    totSz :: Int
totSz = Int
numElemsInCacheLine Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
sz

    go :: Int -> a -> ST s a
go !Int
i !a
seed | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
totSz = a -> ST s a
forall (m :: * -> *) a. Monad m => a -> m a
return a
seed
                | Bool
otherwise  = do
        Elem
h <- IntArray s -> Int -> ST s Elem
forall s. IntArray s -> Int -> ST s Elem
U.readArray IntArray s
hashes Int
i
        if Elem
h Elem -> Elem -> Bool
forall a. Eq a => a -> a -> Bool
/= Elem
emptyMarker
          then do
            k
k <- MutableArray (PrimState (ST s)) k -> Int -> ST s k
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
i
            v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
i
            !a
seed' <- a -> (k, v) -> ST s a
f a
seed (k
k,v
v)
            Int -> a -> ST s a
go (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) a
seed'

          else
            Int -> a -> ST s a
go (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) a
seed
{-# INLINE foldMWork #-}


------------------------------------------------------------------------------
-- | See the documentation for this function in
-- 'Data.HashTable.Class.mapM_'.
mapM_ :: ((k,v) -> ST s a)
      -> HashTable s k v
      -> ST s ()
mapM_ :: ((k, v) -> ST s a) -> HashTable s k v -> ST s ()
mapM_ (k, v) -> ST s a
f HashTable s k v
htRef = HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef ST s (HashTable_ s k v) -> (HashTable_ s k v -> ST s ()) -> ST s ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ((k, v) -> ST s a) -> HashTable_ s k v -> ST s ()
forall k v s a. ((k, v) -> ST s a) -> HashTable_ s k v -> ST s ()
mapMWork (k, v) -> ST s a
f
{-# INLINE mapM_ #-}


------------------------------------------------------------------------------
mapMWork :: ((k,v) -> ST s a)
         -> HashTable_ s k v
         -> ST s ()
mapMWork :: ((k, v) -> ST s a) -> HashTable_ s k v -> ST s ()
mapMWork (k, v) -> ST s a
f (HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) = Int -> ST s ()
go Int
0
  where
    totSz :: Int
totSz = Int
numElemsInCacheLine Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
sz

    go :: Int -> ST s ()
go !Int
i | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
totSz = () -> ST s ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
          | Bool
otherwise  = do
        Elem
h <- IntArray s -> Int -> ST s Elem
forall s. IntArray s -> Int -> ST s Elem
U.readArray IntArray s
hashes Int
i
        if Elem
h Elem -> Elem -> Bool
forall a. Eq a => a -> a -> Bool
/= Elem
emptyMarker
          then do
            k
k <- MutableArray (PrimState (ST s)) k -> Int -> ST s k
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
i
            v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
i
            a
_ <- (k, v) -> ST s a
f (k
k,v
v)
            Int -> ST s ()
go (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
          else
            Int -> ST s ()
go (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
{-# INLINE mapMWork #-}


---------------------------------
-- Private declarations follow --
---------------------------------


------------------------------------------------------------------------------
newSizedReal :: Int -> ST s (HashTable_ s k v)
newSizedReal :: Int -> ST s (HashTable_ s k v)
newSizedReal Int
nbuckets = do
    let !ntotal :: Int
ntotal   = Int
nbuckets Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
numElemsInCacheLine
    let !maxAttempts :: Int
maxAttempts = Int
12 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Word -> Int
log2 (Word -> Int) -> Word -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Word
forall a. Enum a => Int -> a
toEnum Int
nbuckets)

    String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"creating cuckoo hash table with " String -> ShowS
forall a. [a] -> [a] -> [a]
++
            Int -> String
forall a. Show a => a -> String
show Int
nbuckets String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" buckets having " String -> ShowS
forall a. [a] -> [a] -> [a]
++
            Int -> String
forall a. Show a => a -> String
show Int
ntotal String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" total slots"

    BitStream s
rng    <- ST s (BitStream s)
forall s. ST s (BitStream s)
newBitStream
    IntArray s
hashes <- Int -> ST s (IntArray s)
forall s. Int -> ST s (IntArray s)
U.newArray Int
ntotal
    MutableArray s k
keys   <- Int -> k -> ST s (MutableArray (PrimState (ST s)) k)
forall (m :: * -> *) a.
PrimMonad m =>
Int -> a -> m (MutableArray (PrimState m) a)
newArray Int
ntotal k
forall a. HasCallStack => a
undefined
    MutableArray s v
values <- Int -> v -> ST s (MutableArray (PrimState (ST s)) v)
forall (m :: * -> *) a.
PrimMonad m =>
Int -> a -> m (MutableArray (PrimState m) a)
newArray Int
ntotal v
forall a. HasCallStack => a
undefined

    HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return (HashTable_ s k v -> ST s (HashTable_ s k v))
-> HashTable_ s k v -> ST s (HashTable_ s k v)
forall a b. (a -> b) -> a -> b
$! Int
-> BitStream s
-> IntArray s
-> MutableArray s k
-> MutableArray s v
-> Int
-> HashTable_ s k v
forall s k v.
Int
-> BitStream s
-> IntArray s
-> MutableArray s k
-> MutableArray s v
-> Int
-> HashTable_ s k v
HashTable Int
nbuckets BitStream s
rng IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
maxAttempts


insert' :: (Eq k, Hashable k) =>
           HashTable_ s k v
        -> k
        -> v
        -> ST s (HashTable_ s k v)
insert' :: HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
insert' HashTable_ s k v
ht k
k v
v = do
    String -> ST s ()
forall s. String -> ST s ()
debug String
"insert': begin"
    Maybe (k, v)
mbX <- HashTable_ s k v -> k -> v -> ST s (Maybe (k, v))
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> k -> v -> ST s (Maybe (k, v))
updateOrFail HashTable_ s k v
ht k
k v
v
    HashTable_ s k v
z <- ST s (HashTable_ s k v)
-> ((k, v) -> ST s (HashTable_ s k v))
-> Maybe (k, v)
-> ST s (HashTable_ s k v)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
ht)
               (\(k
k',v
v') -> HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
grow HashTable_ s k v
ht k
k' v
v')
               Maybe (k, v)
mbX
    String -> ST s ()
forall s. String -> ST s ()
debug String
"insert': end"
    HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
z
{-# INLINE insert #-}


------------------------------------------------------------------------------
mutate' :: (Eq k, Hashable k) =>
           HashTable_ s k v
        -> k
        -> (Maybe v -> ST s (Maybe v, a))
        -> ST s (HashTable_ s k v, a)
mutate' :: HashTable_ s k v
-> k
-> (Maybe v -> ST s (Maybe v, a))
-> ST s (HashTable_ s k v, a)
mutate' ht :: HashTable_ s k v
ht@(HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) !k
k !Maybe v -> ST s (Maybe v, a)
f = do
    !(Maybe v
maybeVal, Int
idx, Int
_hashCode) <- ST s (Maybe v, Int, Int)
lookupSlot
    !(Maybe v, a)
fRes <- Maybe v -> ST s (Maybe v, a)
f Maybe v
maybeVal
    case (Maybe v
maybeVal, (Maybe v, a)
fRes) of
        (Maybe v
Nothing, (Maybe v
Nothing, a
a)) -> (HashTable_ s k v, a) -> ST s (HashTable_ s k v, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (HashTable_ s k v
ht, a
a)
        (Just v
_v, (Just v
v', a
a)) -> do
            MutableArray (PrimState (ST s)) v -> Int -> v -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx v
v'
            (HashTable_ s k v, a) -> ST s (HashTable_ s k v, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (HashTable_ s k v
ht, a
a)
        (Just v
_v, (Maybe v
Nothing, a
a)) -> do
            HashTable_ s k v -> Int -> ST s ()
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> Int -> ST s ()
deleteFromSlot HashTable_ s k v
ht Int
idx
            (HashTable_ s k v, a) -> ST s (HashTable_ s k v, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (HashTable_ s k v
ht, a
a)
        (Maybe v
Nothing, (Just v
v', a
a)) -> do
            HashTable_ s k v
newHt <- v -> ST s (HashTable_ s k v)
insertNew v
v'
            (HashTable_ s k v, a) -> ST s (HashTable_ s k v, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (HashTable_ s k v
newHt, a
a)

  where
    h1 :: Int
h1 = k -> Int
forall k. Hashable k => k -> Int
hash1 k
k
    h2 :: Int
h2 = k -> Int
forall k. Hashable k => k -> Int
hash2 k
k

    b1 :: Int
b1 = Int -> Int -> Int
whichLine Int
h1 Int
sz
    b2 :: Int
b2 = Int -> Int -> Int
whichLine Int
h2 Int
sz

    he1 :: Elem
he1 = Int -> Elem
hashToElem Int
h1
    he2 :: Elem
he2 = Int -> Elem
hashToElem Int
h2

    lookupSlot :: ST s (Maybe v, Int, Int)
lookupSlot = do
        Int
idx1 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b1 Elem
he1
        if Int
idx1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
          then do
            v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx1
            (Maybe v, Int, Int) -> ST s (Maybe v, Int, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (v -> Maybe v
forall a. a -> Maybe a
Just v
v, Int
idx1, Int
h1)
          else do
            Int
idx2 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b2 Elem
he2
            if Int
idx2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
              then do
                v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx2
                (Maybe v, Int, Int) -> ST s (Maybe v, Int, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (v -> Maybe v
forall a. a -> Maybe a
Just v
v, Int
idx2, Int
h2)
              else do
                (Maybe v, Int, Int) -> ST s (Maybe v, Int, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe v
forall a. Maybe a
Nothing, -Int
1, -Int
1)

    insertNew :: v -> ST s (HashTable_ s k v)
insertNew v
v = do
        Int
idxE1 <- IntArray s -> Int -> Elem -> ST s Int
forall s. IntArray s -> Int -> Elem -> ST s Int
cacheLineSearch IntArray s
hashes Int
b1 Elem
emptyMarker
        if Int
idxE1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
          then do
            HashTable_ s k v -> Int -> Elem -> k -> v -> ST s ()
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> Int -> Elem -> k -> v -> ST s ()
insertIntoSlot HashTable_ s k v
ht Int
idxE1 Elem
he1 k
k v
v
            HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
ht
          else do
            Int
idxE2 <- IntArray s -> Int -> Elem -> ST s Int
forall s. IntArray s -> Int -> Elem -> ST s Int
cacheLineSearch IntArray s
hashes Int
b2 Elem
emptyMarker
            if Int
idxE2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
              then do
                HashTable_ s k v -> Int -> Elem -> k -> v -> ST s ()
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> Int -> Elem -> k -> v -> ST s ()
insertIntoSlot HashTable_ s k v
ht Int
idxE2 Elem
he2 k
k v
v
                HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
ht
              else do
                Maybe (k, v)
result <- HashTable_ s k v
-> Int -> Int -> Int -> Int -> k -> v -> ST s (Maybe (k, v))
forall k s v.
(Hashable k, Eq k) =>
HashTable_ s k v
-> Int -> Int -> Int -> Int -> k -> v -> ST s (Maybe (k, v))
cuckooOrFail HashTable_ s k v
ht Int
h1 Int
h2 Int
b1 Int
b2 k
k v
v
                ST s (HashTable_ s k v)
-> ((k, v) -> ST s (HashTable_ s k v))
-> Maybe (k, v)
-> ST s (HashTable_ s k v)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
ht)
                      (\(k
k', v
v') -> do
                          HashTable_ s k v
newHt <- HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
grow HashTable_ s k v
ht k
k' v
v'
                          HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
newHt)
                      Maybe (k, v)
result
{-# INLINE mutate' #-}


------------------------------------------------------------------------------
deleteFromSlot :: (Eq k, Hashable k) =>
                  HashTable_ s k v
               -> Int
               -> ST s ()
deleteFromSlot :: HashTable_ s k v -> Int -> ST s ()
deleteFromSlot _ht :: HashTable_ s k v
_ht@(HashTable Int
_ BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) Int
idx = do
    IntArray s -> Int -> Elem -> ST s ()
forall s. IntArray s -> Int -> Elem -> ST s ()
U.writeArray IntArray s
hashes Int
idx Elem
emptyMarker
    MutableArray (PrimState (ST s)) k -> Int -> k -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
idx k
forall a. HasCallStack => a
undefined
    MutableArray (PrimState (ST s)) v -> Int -> v -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx v
forall a. HasCallStack => a
undefined
{-# INLINE deleteFromSlot #-}


------------------------------------------------------------------------------
insertIntoSlot :: (Eq k, Hashable k) =>
                  HashTable_ s k v
               -> Int
               -> Elem
               -> k
               -> v
               -> ST s ()
insertIntoSlot :: HashTable_ s k v -> Int -> Elem -> k -> v -> ST s ()
insertIntoSlot _ht :: HashTable_ s k v
_ht@(HashTable Int
_ BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) Int
idx Elem
he k
k v
v = do
    IntArray s -> Int -> Elem -> ST s ()
forall s. IntArray s -> Int -> Elem -> ST s ()
U.writeArray IntArray s
hashes Int
idx Elem
he
    MutableArray (PrimState (ST s)) k -> Int -> k -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
idx k
k
    MutableArray (PrimState (ST s)) v -> Int -> v -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx v
v
{-# INLINE insertIntoSlot #-}



------------------------------------------------------------------------------
updateOrFail :: (Eq k, Hashable k) =>
                HashTable_ s k v
             -> k
             -> v
             -> ST s (Maybe (k,v))
updateOrFail :: HashTable_ s k v -> k -> v -> ST s (Maybe (k, v))
updateOrFail ht :: HashTable_ s k v
ht@(HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) k
k v
v = do
    String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"updateOrFail: begin: sz = " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
sz
    String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"   h1=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h1 String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
", h2=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h2
            String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
", b1=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b1 String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
", b2=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b2
    (Int
didx, Elem
hashCode) <- HashTable_ s k v
-> Bool -> k -> Int -> Int -> Int -> Int -> ST s (Int, Elem)
forall k s v.
(Hashable k, Eq k) =>
HashTable_ s k v
-> Bool -> k -> Int -> Int -> Int -> Int -> ST s (Int, Elem)
delete' HashTable_ s k v
ht Bool
True k
k Int
b1 Int
b2 Int
h1 Int
h2

    String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"delete' returned (" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
didx String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"," String -> ShowS
forall a. [a] -> [a] -> [a]
++ Elem -> String
forall a. Show a => a -> String
show Elem
hashCode String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"

    if Int
didx Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
      then do
        IntArray s -> Int -> Elem -> ST s ()
forall s. IntArray s -> Int -> Elem -> ST s ()
U.writeArray IntArray s
hashes Int
didx Elem
hashCode
        MutableArray (PrimState (ST s)) k -> Int -> k -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
didx k
k
        MutableArray (PrimState (ST s)) v -> Int -> v -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
didx v
v
        Maybe (k, v) -> ST s (Maybe (k, v))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (k, v)
forall a. Maybe a
Nothing
      else ST s (Maybe (k, v))
cuckoo

  where
    h1 :: Int
h1 = k -> Int
forall k. Hashable k => k -> Int
hash1 k
k
    h2 :: Int
h2 = k -> Int
forall k. Hashable k => k -> Int
hash2 k
k

    b1 :: Int
b1 = Int -> Int -> Int
whichLine Int
h1 Int
sz
    b2 :: Int
b2 = Int -> Int -> Int
whichLine Int
h2 Int
sz

    cuckoo :: ST s (Maybe (k, v))
cuckoo = do
        String -> ST s ()
forall s. String -> ST s ()
debug String
"cuckoo: calling cuckooOrFail"
        Maybe (k, v)
result <- HashTable_ s k v
-> Int -> Int -> Int -> Int -> k -> v -> ST s (Maybe (k, v))
forall k s v.
(Hashable k, Eq k) =>
HashTable_ s k v
-> Int -> Int -> Int -> Int -> k -> v -> ST s (Maybe (k, v))
cuckooOrFail HashTable_ s k v
ht Int
h1 Int
h2 Int
b1 Int
b2 k
k v
v
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"cuckoo: cuckooOrFail returned " String -> ShowS
forall a. [a] -> [a] -> [a]
++
                  (if Maybe (k, v) -> Bool
forall a. Maybe a -> Bool
isJust Maybe (k, v)
result then String
"Just _" else String
"Nothing")

        -- if cuckoo failed we need to grow the table.
        ST s (Maybe (k, v))
-> ((k, v) -> ST s (Maybe (k, v)))
-> Maybe (k, v)
-> ST s (Maybe (k, v))
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Maybe (k, v) -> ST s (Maybe (k, v))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (k, v)
forall a. Maybe a
Nothing)
              (Maybe (k, v) -> ST s (Maybe (k, v))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (k, v) -> ST s (Maybe (k, v)))
-> ((k, v) -> Maybe (k, v)) -> (k, v) -> ST s (Maybe (k, v))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (k, v) -> Maybe (k, v)
forall a. a -> Maybe a
Just)
              Maybe (k, v)
result
{-# INLINE updateOrFail #-}


------------------------------------------------------------------------------
-- Returns either (-1, 0) (not found, and both buckets full ==> trigger
-- cuckoo), or the slot in the array where it would be safe to write the given
-- key, and the hashcode to use there
delete' :: (Hashable k, Eq k) =>
           HashTable_ s k v     -- ^ hash table
        -> Bool                 -- ^ are we updating?
        -> k                    -- ^ key
        -> Int                  -- ^ cache line start address 1
        -> Int                  -- ^ cache line start address 2
        -> Int                  -- ^ hash1
        -> Int                  -- ^ hash2
        -> ST s (Int, Elem)
delete' :: HashTable_ s k v
-> Bool -> k -> Int -> Int -> Int -> Int -> ST s (Int, Elem)
delete' (HashTable Int
_ BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) !Bool
updating !k
k Int
b1 Int
b2 Int
h1 Int
h2 = do
    String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"delete' b1=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b1
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" b2=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b2
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" h1=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h1
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" h2=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h2
    IntArray s -> Int -> ST s ()
forall s. IntArray s -> Int -> ST s ()
prefetchWrite IntArray s
hashes Int
b2
    let !he1 :: Elem
he1 = Int -> Elem
hashToElem Int
h1
    let !he2 :: Elem
he2 = Int -> Elem
hashToElem Int
h2
    Int
idx1 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b1 Elem
he1
    if Int
idx1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0
      then do
        Int
idx2 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b2 Elem
he2
        if Int
idx2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0
          then if Bool
updating
                 then do
                   String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"delete': looking for empty element"
                   -- if we're updating, we look for an empty element
                   Int
idxE1 <- IntArray s -> Int -> Elem -> ST s Int
forall s. IntArray s -> Int -> Elem -> ST s Int
cacheLineSearch IntArray s
hashes Int
b1 Elem
emptyMarker
                   String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"delete': idxE1 was " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
idxE1
                   if Int
idxE1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
                     then (Int, Elem) -> ST s (Int, Elem)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
idxE1, Elem
he1)
                     else do
                       Int
idxE2 <- IntArray s -> Int -> Elem -> ST s Int
forall s. IntArray s -> Int -> Elem -> ST s Int
cacheLineSearch IntArray s
hashes Int
b2 Elem
emptyMarker
                       String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"delete': idxE2 was " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
idxE1
                       if Int
idxE2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
                         then (Int, Elem) -> ST s (Int, Elem)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
idxE2, Elem
he2)
                         else (Int, Elem) -> ST s (Int, Elem)
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1, Elem
0)
                 else (Int, Elem) -> ST s (Int, Elem)
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1, Elem
0)
          else Int -> Elem -> ST s (Int, Elem)
forall b. Int -> b -> ST s (Int, b)
deleteIt Int
idx2 Elem
he2
      else Int -> Elem -> ST s (Int, Elem)
forall b. Int -> b -> ST s (Int, b)
deleteIt Int
idx1 Elem
he1

  where
    deleteIt :: Int -> b -> ST s (Int, b)
deleteIt !Int
idx !b
h = do
        if Bool -> Bool
not Bool
updating
          then do
            IntArray s -> Int -> Elem -> ST s ()
forall s. IntArray s -> Int -> Elem -> ST s ()
U.writeArray IntArray s
hashes Int
idx Elem
emptyMarker
            MutableArray (PrimState (ST s)) k -> Int -> k -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
idx k
forall a. HasCallStack => a
undefined
            MutableArray (PrimState (ST s)) v -> Int -> v -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx v
forall a. HasCallStack => a
undefined
          else () -> ST s ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        (Int, b) -> ST s (Int, b)
forall (m :: * -> *) a. Monad m => a -> m a
return ((Int, b) -> ST s (Int, b)) -> (Int, b) -> ST s (Int, b)
forall a b. (a -> b) -> a -> b
$! (Int
idx, b
h)
{-# INLINE delete' #-}


------------------------------------------------------------------------------
cuckooOrFail :: (Hashable k, Eq k) =>
                HashTable_ s k v  -- ^ hash table
             -> Int               -- ^ hash code 1
             -> Int               -- ^ hash code 2
             -> Int               -- ^ cache line 1
             -> Int               -- ^ cache line 2
             -> k                 -- ^ key
             -> v                 -- ^ value
             -> ST s (Maybe (k,v))
cuckooOrFail :: HashTable_ s k v
-> Int -> Int -> Int -> Int -> k -> v -> ST s (Maybe (k, v))
cuckooOrFail (HashTable Int
sz BitStream s
rng IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
maxAttempts0)
                 !Int
h1_0 !Int
h2_0 !Int
b1_0 !Int
b2_0 !k
k0 !v
v0 = do
    -- at this point we know:
    --
    --   * there is no empty slot in either cache line
    --
    --   * the key doesn't already exist in the table
    --
    -- next things to do:
    --
    --   * decide which element to bump
    --
    --   * read that element, and write (k,v) in there
    --
    --   * attempt to write the bumped element into its other cache slot
    --
    --   * if it fails, recurse.

    String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"cuckooOrFail h1_0=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h1_0
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" h2_0=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h2_0
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" b1_0=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b1_0
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" b2_0=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b2_0

    !Word
lineChoice <- BitStream s -> ST s Word
forall s. BitStream s -> ST s Word
getNextBit BitStream s
rng

    String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"chose line " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word -> String
forall a. Show a => a -> String
show Word
lineChoice
    let (!Int
b, !Int
h) = if Word
lineChoice Word -> Word -> Bool
forall a. Eq a => a -> a -> Bool
== Word
0 then (Int
b1_0, Int
h1_0) else (Int
b2_0, Int
h2_0)
    Int -> Int -> k -> v -> Int -> ST s (Maybe (k, v))
forall a.
(Eq a, Num a) =>
Int -> Int -> k -> v -> a -> ST s (Maybe (k, v))
go Int
b Int
h k
k0 v
v0 Int
maxAttempts0


  where
    randomIdx :: b -> ST s b
randomIdx !b
b = do
        !Word
z <- Int -> BitStream s -> ST s Word
forall s. Int -> BitStream s -> ST s Word
getNBits Int
cacheLineIntBits BitStream s
rng
        b -> ST s b
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> ST s b) -> b -> ST s b
forall a b. (a -> b) -> a -> b
$! b
b b -> b -> b
forall a. Num a => a -> a -> a
+ Word -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
z

    bumpIdx :: Int -> Int -> k -> v -> ST s (Elem, k, v)
bumpIdx !Int
idx !Int
h !k
k !v
v = do
        let !he :: Elem
he = Int -> Elem
hashToElem Int
h
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"bumpIdx idx=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
idx String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" h=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h
                  String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" he=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Elem -> String
forall a. Show a => a -> String
show Elem
he
        !Elem
he' <- IntArray s -> Int -> ST s Elem
forall s. IntArray s -> Int -> ST s Elem
U.readArray IntArray s
hashes Int
idx
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"bumpIdx: he' was " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Elem -> String
forall a. Show a => a -> String
show Elem
he'
        !k
k' <- MutableArray (PrimState (ST s)) k -> Int -> ST s k
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
idx
        v
v'  <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx
        IntArray s -> Int -> Elem -> ST s ()
forall s. IntArray s -> Int -> Elem -> ST s ()
U.writeArray IntArray s
hashes Int
idx Elem
he
        MutableArray (PrimState (ST s)) k -> Int -> k -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
idx k
k
        MutableArray (PrimState (ST s)) v -> Int -> v -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx v
v
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"bumped key with he'=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Elem -> String
forall a. Show a => a -> String
show Elem
he'
        (Elem, k, v) -> ST s (Elem, k, v)
forall (m :: * -> *) a. Monad m => a -> m a
return ((Elem, k, v) -> ST s (Elem, k, v))
-> (Elem, k, v) -> ST s (Elem, k, v)
forall a b. (a -> b) -> a -> b
$! (Elem
he', k
k', v
v')

    otherHash :: Elem -> k -> Int
otherHash Elem
he k
k = if Int -> Elem
hashToElem Int
h1 Elem -> Elem -> Bool
forall a. Eq a => a -> a -> Bool
== Elem
he then Int
h2 else Int
h1
      where
        h1 :: Int
h1 = k -> Int
forall k. Hashable k => k -> Int
hash1 k
k
        h2 :: Int
h2 = k -> Int
forall k. Hashable k => k -> Int
hash2 k
k

    tryWrite :: Int -> Int -> k -> v -> a -> ST s (Maybe (k, v))
tryWrite !Int
b !Int
h k
k v
v a
maxAttempts = do
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"tryWrite b=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" h=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
h
        Int
idx <- IntArray s -> Int -> Elem -> ST s Int
forall s. IntArray s -> Int -> Elem -> ST s Int
cacheLineSearch IntArray s
hashes Int
b Elem
emptyMarker
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"cacheLineSearch returned " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
idx

        if Int
idx Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
          then do
            IntArray s -> Int -> Elem -> ST s ()
forall s. IntArray s -> Int -> Elem -> ST s ()
U.writeArray IntArray s
hashes Int
idx (Elem -> ST s ()) -> Elem -> ST s ()
forall a b. (a -> b) -> a -> b
$! Int -> Elem
hashToElem Int
h
            MutableArray (PrimState (ST s)) k -> Int -> k -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
idx k
k
            MutableArray (PrimState (ST s)) v -> Int -> v -> ST s ()
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
writeArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
idx v
v
            Maybe (k, v) -> ST s (Maybe (k, v))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (k, v)
forall a. Maybe a
Nothing
          else Int -> Int -> k -> v -> a -> ST s (Maybe (k, v))
go Int
b Int
h k
k v
v (a -> ST s (Maybe (k, v))) -> a -> ST s (Maybe (k, v))
forall a b. (a -> b) -> a -> b
$! a
maxAttempts a -> a -> a
forall a. Num a => a -> a -> a
- a
1

    go :: Int -> Int -> k -> v -> a -> ST s (Maybe (k, v))
go !Int
b !Int
h !k
k v
v !a
maxAttempts | a
maxAttempts a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = Maybe (k, v) -> ST s (Maybe (k, v))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (k, v) -> ST s (Maybe (k, v)))
-> Maybe (k, v) -> ST s (Maybe (k, v))
forall a b. (a -> b) -> a -> b
$! (k, v) -> Maybe (k, v)
forall a. a -> Maybe a
Just (k
k,v
v)
                               | Bool
otherwise = do
        Int
idx <- Int -> ST s Int
forall b. Num b => b -> ST s b
randomIdx Int
b
        (!Elem
he0', !k
k', v
v') <- Int -> Int -> k -> v -> ST s (Elem, k, v)
bumpIdx Int
idx Int
h k
k v
v
        let !h' :: Int
h' = Elem -> k -> Int
forall k. Hashable k => Elem -> k -> Int
otherHash Elem
he0' k
k'
        let !b' :: Int
b' = Int -> Int -> Int
whichLine Int
h' Int
sz

        Int -> Int -> k -> v -> a -> ST s (Maybe (k, v))
tryWrite Int
b' Int
h' k
k' v
v' a
maxAttempts


------------------------------------------------------------------------------
grow :: (Eq k, Hashable k) =>
        HashTable_ s k v
     -> k
     -> v
     -> ST s (HashTable_ s k v)
grow :: HashTable_ s k v -> k -> v -> ST s (HashTable_ s k v)
grow (HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_) k
k0 v
v0 = do
    HashTable_ s k v
newHt <- Int -> ST s (HashTable_ s k v)
grow' (Int -> ST s (HashTable_ s k v)) -> Int -> ST s (HashTable_ s k v)
forall a b. (a -> b) -> a -> b
$! Double -> Int -> Int
bumpSize Double
bumpFactor Int
sz

    Maybe (k, v)
mbR <- HashTable_ s k v -> k -> v -> ST s (Maybe (k, v))
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> k -> v -> ST s (Maybe (k, v))
updateOrFail HashTable_ s k v
newHt k
k0 v
v0
    ST s (HashTable_ s k v)
-> ((k, v) -> ST s (HashTable_ s k v))
-> Maybe (k, v)
-> ST s (HashTable_ s k v)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
newHt)
          (\(k, v)
_ -> Int -> ST s (HashTable_ s k v)
grow' (Int -> ST s (HashTable_ s k v)) -> Int -> ST s (HashTable_ s k v)
forall a b. (a -> b) -> a -> b
$ Double -> Int -> Int
bumpSize Double
bumpFactor (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ HashTable_ s k v -> Int
forall s k v. HashTable_ s k v -> Int
_size HashTable_ s k v
newHt)
          Maybe (k, v)
mbR

  where
    grow' :: Int -> ST s (HashTable_ s k v)
grow' Int
newSz = do
        String -> ST s ()
forall s. String -> ST s ()
debug (String -> ST s ()) -> String -> ST s ()
forall a b. (a -> b) -> a -> b
$ String
"growing table, oldsz = " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
sz String -> ShowS
forall a. [a] -> [a] -> [a]
++
                String
", newsz=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
newSz
        HashTable_ s k v
newHt <- Int -> ST s (HashTable_ s k v)
forall s k v. Int -> ST s (HashTable_ s k v)
newSizedReal Int
newSz
        Int -> HashTable_ s k v -> ST s (HashTable_ s k v)
rehash Int
newSz HashTable_ s k v
newHt


    rehash :: Int -> HashTable_ s k v -> ST s (HashTable_ s k v)
rehash !Int
newSz !HashTable_ s k v
newHt = Int -> ST s (HashTable_ s k v)
go Int
0
      where
        totSz :: Int
totSz = Int
numElemsInCacheLine Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
sz

        go :: Int -> ST s (HashTable_ s k v)
go !Int
i | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
totSz = HashTable_ s k v -> ST s (HashTable_ s k v)
forall (m :: * -> *) a. Monad m => a -> m a
return HashTable_ s k v
newHt
              | Bool
otherwise  = do
            Elem
h <- IntArray s -> Int -> ST s Elem
forall s. IntArray s -> Int -> ST s Elem
U.readArray IntArray s
hashes Int
i
            if (Elem
h Elem -> Elem -> Bool
forall a. Eq a => a -> a -> Bool
/= Elem
emptyMarker)
              then do
                k
k <- MutableArray (PrimState (ST s)) k -> Int -> ST s k
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
i
                v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
i

                Maybe (k, v)
mbR <- HashTable_ s k v -> k -> v -> ST s (Maybe (k, v))
forall k s v.
(Eq k, Hashable k) =>
HashTable_ s k v -> k -> v -> ST s (Maybe (k, v))
updateOrFail HashTable_ s k v
newHt k
k v
v
                ST s (HashTable_ s k v)
-> ((k, v) -> ST s (HashTable_ s k v))
-> Maybe (k, v)
-> ST s (HashTable_ s k v)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Int -> ST s (HashTable_ s k v)
go (Int -> ST s (HashTable_ s k v)) -> Int -> ST s (HashTable_ s k v)
forall a b. (a -> b) -> a -> b
$ Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
                      (\(k, v)
_ -> Int -> ST s (HashTable_ s k v)
grow' (Int -> ST s (HashTable_ s k v)) -> Int -> ST s (HashTable_ s k v)
forall a b. (a -> b) -> a -> b
$ Double -> Int -> Int
bumpSize Double
bumpFactor Int
newSz)
                      Maybe (k, v)
mbR
              else Int -> ST s (HashTable_ s k v)
go (Int -> ST s (HashTable_ s k v)) -> Int -> ST s (HashTable_ s k v)
forall a b. (a -> b) -> a -> b
$ Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1


------------------------------------------------------------------------------
hashPrime :: Int
hashPrime :: Int
hashPrime = if Int
wordSize Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
32 then Int
hashPrime32 else Int
hashPrime64
  where
    hashPrime32 :: Int
hashPrime32 = Int
0xedf2a025
    hashPrime64 :: Int
hashPrime64 = Int
0x3971ca9c8b3722e9


------------------------------------------------------------------------------
hash1 :: Hashable k => k -> Int
hash1 :: k -> Int
hash1 = k -> Int
forall k. Hashable k => k -> Int
H.hash
{-# INLINE hash1 #-}


hash2 :: Hashable k => k -> Int
hash2 :: k -> Int
hash2 = Int -> k -> Int
forall a. Hashable a => Int -> a -> Int
H.hashWithSalt Int
hashPrime
{-# INLINE hash2 #-}


------------------------------------------------------------------------------
hashToElem :: Int -> Elem
hashToElem :: Int -> Elem
hashToElem !Int
h = Elem
out
  where
    !(I# Int#
lo#) = Int
h Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
U.elemMask

    !m# :: Word#
m#  = Int# -> Int# -> Word#
maskw# Int#
lo# Int#
0#
    !nm# :: Word#
nm# = Word# -> Word#
not# Word#
m#

    !r# :: Word#
r#  = ((Int# -> Word#
int2Word# Int#
1#) Word# -> Word# -> Word#
`and#` Word#
m#) Word# -> Word# -> Word#
`or#` (Int# -> Word#
int2Word# Int#
lo# Word# -> Word# -> Word#
`and#` Word#
nm#)
    !out :: Elem
out = Word# -> Elem
U.primWordToElem Word#
r#
{-# INLINE hashToElem #-}


------------------------------------------------------------------------------
emptyMarker :: Elem
emptyMarker :: Elem
emptyMarker = Elem
0


------------------------------------------------------------------------------
maxLoad :: Double
maxLoad :: Double
maxLoad = Double
0.88


------------------------------------------------------------------------------
bumpFactor :: Double
bumpFactor :: Double
bumpFactor = Double
0.73


------------------------------------------------------------------------------
debug :: String -> ST s ()
#ifdef DEBUG
debug s = unsafeIOToST (putStrLn s >> hFlush stdout)
#else
debug :: String -> ST s ()
debug String
_ = () -> ST s ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
#endif
{-# INLINE debug #-}


------------------------------------------------------------------------------
whichLine :: Int -> Int -> Int
whichLine :: Int -> Int -> Int
whichLine !Int
h !Int
sz = Int -> Int -> Int
whichBucket Int
h Int
sz Int -> Int -> Int
`iShiftL` Int
cacheLineIntBits
{-# INLINE whichLine #-}


------------------------------------------------------------------------------
newRef :: HashTable_ s k v -> ST s (HashTable s k v)
newRef :: HashTable_ s k v -> ST s (HashTable s k v)
newRef = (STRef s (HashTable_ s k v) -> HashTable s k v)
-> ST s (STRef s (HashTable_ s k v)) -> ST s (HashTable s k v)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM STRef s (HashTable_ s k v) -> HashTable s k v
forall s k v. STRef s (HashTable_ s k v) -> HashTable s k v
HT (ST s (STRef s (HashTable_ s k v)) -> ST s (HashTable s k v))
-> (HashTable_ s k v -> ST s (STRef s (HashTable_ s k v)))
-> HashTable_ s k v
-> ST s (HashTable s k v)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashTable_ s k v -> ST s (STRef s (HashTable_ s k v))
forall a s. a -> ST s (STRef s a)
newSTRef
{-# INLINE newRef #-}

writeRef :: HashTable s k v -> HashTable_ s k v -> ST s ()
writeRef :: HashTable s k v -> HashTable_ s k v -> ST s ()
writeRef (HT STRef s (HashTable_ s k v)
ref) HashTable_ s k v
ht = STRef s (HashTable_ s k v) -> HashTable_ s k v -> ST s ()
forall s a. STRef s a -> a -> ST s ()
writeSTRef STRef s (HashTable_ s k v)
ref HashTable_ s k v
ht
{-# INLINE writeRef #-}

readRef :: HashTable s k v -> ST s (HashTable_ s k v)
readRef :: HashTable s k v -> ST s (HashTable_ s k v)
readRef (HT STRef s (HashTable_ s k v)
ref) = STRef s (HashTable_ s k v) -> ST s (HashTable_ s k v)
forall s a. STRef s a -> ST s a
readSTRef STRef s (HashTable_ s k v)
ref
{-# INLINE readRef #-}


------------------------------------------------------------------------------

-- | Find index of given key in the hashtable.
lookupIndex :: (Hashable k, Eq k) => HashTable s k v -> k -> ST s (Maybe Word)
lookupIndex :: HashTable s k v -> k -> ST s (Maybe Word)
lookupIndex HashTable s k v
htRef k
k =
  do HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
_ Int
_ <- HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef

     let !h1 :: Int
h1  = k -> Int
forall k. Hashable k => k -> Int
hash1 k
k
         !h2 :: Int
h2  = k -> Int
forall k. Hashable k => k -> Int
hash2 k
k
         !he1 :: Elem
he1 = Int -> Elem
hashToElem Int
h1
         !he2 :: Elem
he2 = Int -> Elem
hashToElem Int
h2
         !b1 :: Int
b1  = Int -> Int -> Int
whichLine Int
h1 Int
sz
         !b2 :: Int
b2  = Int -> Int -> Int
whichLine Int
h2 Int
sz

     Int
idx1 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b1 Elem
he1
     if Int
idx1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
       then Maybe Word -> ST s (Maybe Word)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Word -> ST s (Maybe Word))
-> Maybe Word -> ST s (Maybe Word)
forall a b. (a -> b) -> a -> b
$! (Word -> Maybe Word
forall a. a -> Maybe a
Just (Word -> Maybe Word) -> Word -> Maybe Word
forall a b. (a -> b) -> a -> b
$! Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
idx1)
       else do Int
idx2 <- MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
forall k s.
Eq k =>
MutableArray s k -> IntArray s -> k -> Int -> Elem -> ST s Int
searchOne MutableArray s k
keys IntArray s
hashes k
k Int
b2 Elem
he2
               if Int
idx2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
                 then Maybe Word -> ST s (Maybe Word)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Word -> ST s (Maybe Word))
-> Maybe Word -> ST s (Maybe Word)
forall a b. (a -> b) -> a -> b
$! (Word -> Maybe Word
forall a. a -> Maybe a
Just (Word -> Maybe Word) -> Word -> Maybe Word
forall a b. (a -> b) -> a -> b
$! Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
idx2)
                 else Maybe Word -> ST s (Maybe Word)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Word
forall a. Maybe a
Nothing

-- | Find the next entry in the hashtable starting at the given index.
nextByIndex :: HashTable s k v -> Word -> ST s (Maybe (Word,k,v))
nextByIndex :: HashTable s k v -> Word -> ST s (Maybe (Word, k, v))
nextByIndex HashTable s k v
htRef Word
i0 =
  do HashTable Int
sz BitStream s
_ IntArray s
hashes MutableArray s k
keys MutableArray s v
values Int
_ <- HashTable s k v -> ST s (HashTable_ s k v)
forall s k v. HashTable s k v -> ST s (HashTable_ s k v)
readRef HashTable s k v
htRef
     let totSz :: Int
totSz = Int
numElemsInCacheLine Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
sz
         go :: Int -> ST s (Maybe (a, k, v))
go Int
i
           | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
totSz = Maybe (a, k, v) -> ST s (Maybe (a, k, v))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (a, k, v)
forall a. Maybe a
Nothing
           | Bool
otherwise =
               do Elem
h <- IntArray s -> Int -> ST s Elem
forall s. IntArray s -> Int -> ST s Elem
U.readArray IntArray s
hashes Int
i
                  if Elem
h Elem -> Elem -> Bool
forall a. Eq a => a -> a -> Bool
== Elem
emptyMarker
                    then Int -> ST s (Maybe (a, k, v))
go (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
                    else do k
k <- MutableArray (PrimState (ST s)) k -> Int -> ST s k
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s k
MutableArray (PrimState (ST s)) k
keys Int
i
                            v
v <- MutableArray (PrimState (ST s)) v -> Int -> ST s v
forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> m a
readArray MutableArray s v
MutableArray (PrimState (ST s)) v
values Int
i
                            let !i' :: a
i' = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i
                            Maybe (a, k, v) -> ST s (Maybe (a, k, v))
forall (m :: * -> *) a. Monad m => a -> m a
return ((a, k, v) -> Maybe (a, k, v)
forall a. a -> Maybe a
Just (a
i',k
k,v
v))

     Int -> ST s (Maybe (Word, k, v))
forall a. Num a => Int -> ST s (Maybe (a, k, v))
go (Word -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
i0)