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

module Data.HashTable.Internal.Utils
  ( whichBucket
  , nextBestPrime
  , bumpSize
  , shiftL
  , shiftRL
  , iShiftL
  , iShiftRL
  , nextHighestPowerOf2
  , log2
  , highestBitMask
  , wordSize
  , cacheLineSize
  , numElemsInCacheLine
  , cacheLineIntMask
  , cacheLineIntBits
  , forceSameType
  , unsafeIOToST
  ) where

import           Data.Bits                        hiding (shiftL)
import           Data.HashTable.Internal.IntArray (Elem)
import           Data.Vector                      (Vector)
import qualified Data.Vector                      as V
#if __GLASGOW_HASKELL__ >= 503
import           GHC.Exts
#else
import qualified Data.Bits
import           Data.Word
#endif

#if MIN_VERSION_base(4,4,0)
import           Control.Monad.ST.Unsafe          (unsafeIOToST)
#else
import           Control.Monad.ST                 (unsafeIOToST)
#endif

------------------------------------------------------------------------------
wordSize :: Int
wordSize :: Int
wordSize = Int -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize (0::Int)


cacheLineSize :: Int
cacheLineSize :: Int
cacheLineSize = 64


numElemsInCacheLine :: Int
numElemsInCacheLine :: Int
numElemsInCacheLine = Int
z
  where
    !z :: Int
z = Int
cacheLineSize Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` (Elem -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize (0::Elem) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 8)


-- | What you have to mask an integer index by to tell if it's
-- cacheline-aligned
cacheLineIntMask :: Int
cacheLineIntMask :: Int
cacheLineIntMask = Int
z
  where
    !z :: Int
z = Int
numElemsInCacheLine Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1


cacheLineIntBits :: Int
cacheLineIntBits :: Int
cacheLineIntBits = Word -> Int
log2 (Word -> Int) -> Word -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Word
forall a. Enum a => Int -> a
toEnum Int
numElemsInCacheLine


------------------------------------------------------------------------------
{-# INLINE whichBucket #-}
whichBucket :: Int -> Int -> Int
whichBucket :: Int -> Int -> Int
whichBucket !Int
h !Int
sz = Int
o
  where
    !o :: Int
o = Int
h Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
sz


------------------------------------------------------------------------------
binarySearch :: (Ord e) => Vector e -> e -> Int
binarySearch :: Vector e -> e -> Int
binarySearch = (e -> e -> Ordering) -> Vector e -> e -> Int
forall e. (e -> e -> Ordering) -> Vector e -> e -> Int
binarySearchBy e -> e -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE binarySearch #-}


------------------------------------------------------------------------------
binarySearchBy :: (e -> e -> Ordering)
               -> Vector e
               -> e
               -> Int
binarySearchBy :: (e -> e -> Ordering) -> Vector e -> e -> Int
binarySearchBy cmp :: e -> e -> Ordering
cmp vec :: Vector e
vec e :: e
e = (e -> e -> Ordering) -> Vector e -> e -> Int -> Int -> Int
forall e.
(e -> e -> Ordering) -> Vector e -> e -> Int -> Int -> Int
binarySearchByBounds e -> e -> Ordering
cmp Vector e
vec e
e 0 (Vector e -> Int
forall a. Vector a -> Int
V.length Vector e
vec)
{-# INLINE binarySearchBy #-}


------------------------------------------------------------------------------
binarySearchByBounds :: (e -> e -> Ordering)
                     -> Vector e
                     -> e
                     -> Int
                     -> Int
                     -> Int
binarySearchByBounds :: (e -> e -> Ordering) -> Vector e -> e -> Int -> Int -> Int
binarySearchByBounds cmp :: e -> e -> Ordering
cmp vec :: Vector e
vec e :: e
e = Int -> Int -> Int
loop
 where
 loop :: Int -> Int -> Int
loop !Int
l !Int
u
   | Int
u Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
l    = Int
l
   | Bool
otherwise = let e' :: e
e' = Vector e -> Int -> e
forall a. Vector a -> Int -> a
V.unsafeIndex Vector e
vec Int
k
                 in case e -> e -> Ordering
cmp e
e' e
e of
                      LT -> Int -> Int -> Int
loop (Int
kInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) Int
u
                      EQ -> Int
k
                      GT -> Int -> Int -> Int
loop Int
l     Int
k
  where k :: Int
k = (Int
u Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
l) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` 1
{-# INLINE binarySearchByBounds #-}


------------------------------------------------------------------------------
primeSizes :: Vector Integer
primeSizes :: Vector Integer
primeSizes = [Integer] -> Vector Integer
forall a. [a] -> Vector a
V.fromList [ 19
                        , 31
                        , 37
                        , 43
                        , 47
                        , 53
                        , 61
                        , 67
                        , 79
                        , 89
                        , 97
                        , 107
                        , 113
                        , 127
                        , 137
                        , 149
                        , 157
                        , 167
                        , 181
                        , 193
                        , 211
                        , 233
                        , 257
                        , 281
                        , 307
                        , 331
                        , 353
                        , 389
                        , 409
                        , 421
                        , 443
                        , 467
                        , 503
                        , 523
                        , 563
                        , 593
                        , 631
                        , 653
                        , 673
                        , 701
                        , 733
                        , 769
                        , 811
                        , 877
                        , 937
                        , 1039
                        , 1117
                        , 1229
                        , 1367
                        , 1543
                        , 1637
                        , 1747
                        , 1873
                        , 2003
                        , 2153
                        , 2311
                        , 2503
                        , 2777
                        , 3079
                        , 3343
                        , 3697
                        , 5281
                        , 6151
                        , 7411
                        , 9901
                        , 12289
                        , 18397
                        , 24593
                        , 34651
                        , 49157
                        , 66569
                        , 73009
                        , 98317
                        , 118081
                        , 151051
                        , 196613
                        , 246011
                        , 393241
                        , 600011
                        , 786433
                        , 1050013
                        , 1572869
                        , 2203657
                        , 3145739
                        , 4000813
                        , 6291469
                        , 7801379
                        , 10004947
                        , 12582917
                        , 19004989
                        , 22752641
                        , 25165843
                        , 39351667
                        , 50331653
                        , 69004951
                        , 83004629
                        , 100663319
                        , 133004881
                        , 173850851
                        , 201326611
                        , 293954587
                        , 402653189
                        , 550001761
                        , 702952391
                        , 805306457
                        , 1102951999
                        , 1402951337
                        , 1610612741
                        , 1902802801
                        , 2147483647
                        , 3002954501
                        , 3902954959
                        , 4294967291
                        , 5002902979
                        , 6402754181
                        , 8589934583
                        , 17179869143
                        , 34359738337
                        , 68719476731
                        , 137438953447
                        , 274877906899 ]


------------------------------------------------------------------------------
nextBestPrime :: Int -> Int
nextBestPrime :: Int -> Int
nextBestPrime x :: Int
x = Integer -> Int
forall a. Enum a => a -> Int
fromEnum Integer
yi
  where
    xi :: Integer
xi  = Int -> Integer
forall a. Enum a => Int -> a
toEnum Int
x
    idx :: Int
idx = Vector Integer -> Integer -> Int
forall e. Ord e => Vector e -> e -> Int
binarySearch Vector Integer
primeSizes Integer
xi
    yi :: Integer
yi  = Vector Integer -> Int -> Integer
forall a. Vector a -> Int -> a
V.unsafeIndex Vector Integer
primeSizes Int
idx


------------------------------------------------------------------------------
bumpSize :: Double -> Int -> Int
bumpSize :: Double -> Int -> Int
bumpSize !Double
maxLoad !Int
s = 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 (Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
s Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
maxLoad)


------------------------------------------------------------------------------
shiftL :: Word -> Int -> Word
shiftRL :: Word -> Int -> Word
iShiftL  :: Int -> Int -> Int
iShiftRL  :: Int -> Int -> Int
#if __GLASGOW_HASKELL__
{--------------------------------------------------------------------
  GHC: use unboxing to get @shiftRL@ inlined.
--------------------------------------------------------------------}
{-# INLINE shiftL #-}
shiftL :: Word -> Int -> Word
shiftL (W# x :: Word#
x) (I# i :: Int#
i)
  = Word# -> Word
W# (Word# -> Int# -> Word#
shiftL# Word#
x Int#
i)

{-# INLINE shiftRL #-}
shiftRL :: Word -> Int -> Word
shiftRL (W# x :: Word#
x) (I# i :: Int#
i)
  = Word# -> Word
W# (Word# -> Int# -> Word#
shiftRL# Word#
x Int#
i)

{-# INLINE iShiftL #-}
iShiftL :: Int -> Int -> Int
iShiftL (I# x :: Int#
x) (I# i :: Int#
i)
  = Int# -> Int
I# (Int# -> Int# -> Int#
iShiftL# Int#
x Int#
i)

{-# INLINE iShiftRL #-}
iShiftRL :: Int -> Int -> Int
iShiftRL (I# x :: Int#
x) (I# i :: Int#
i)
  = Int# -> Int
I# (Int# -> Int# -> Int#
iShiftRL# Int#
x Int#
i)

#else
shiftL x i    = Data.Bits.shiftL x i
shiftRL x i   = shiftR x i
iShiftL x i   = shiftL x i
iShiftRL x i  = shiftRL x i
#endif


------------------------------------------------------------------------------
{-# INLINE nextHighestPowerOf2 #-}
nextHighestPowerOf2 :: Word -> Word
nextHighestPowerOf2 :: Word -> Word
nextHighestPowerOf2 w :: Word
w = Word -> Word
highestBitMask (Word
wWord -> Word -> Word
forall a. Num a => a -> a -> a
-1) Word -> Word -> Word
forall a. Num a => a -> a -> a
+ 1


------------------------------------------------------------------------------
log2 :: Word -> Int
log2 :: Word -> Int
log2 w :: Word
w = Word -> Int -> Int
forall t. Num t => Word -> t -> t
go (Word -> Word
nextHighestPowerOf2 Word
w) 0
  where
    go :: Word -> t -> t
go 0 !t
i  = t
it -> t -> t
forall a. Num a => a -> a -> a
-1
    go !Word
n !t
i = Word -> t -> t
go (Word -> Int -> Word
shiftRL Word
n 1) (t
it -> t -> t
forall a. Num a => a -> a -> a
+1)


------------------------------------------------------------------------------
{-# INLINE highestBitMask #-}
highestBitMask :: Word -> Word
highestBitMask :: Word -> Word
highestBitMask !Word
x0 = case (Word
x0 Word -> Word -> Word
forall a. Bits a => a -> a -> a
.|. Word -> Int -> Word
shiftRL Word
x0 1) of
                      x1 :: Word
x1 -> case (Word
x1 Word -> Word -> Word
forall a. Bits a => a -> a -> a
.|. Word -> Int -> Word
shiftRL Word
x1 2) of
                       x2 :: Word
x2 -> case (Word
x2 Word -> Word -> Word
forall a. Bits a => a -> a -> a
.|. Word -> Int -> Word
shiftRL Word
x2 4) of
                        x3 :: Word
x3 -> case (Word
x3 Word -> Word -> Word
forall a. Bits a => a -> a -> a
.|. Word -> Int -> Word
shiftRL Word
x3 8) of
                         x4 :: Word
x4 -> case (Word
x4 Word -> Word -> Word
forall a. Bits a => a -> a -> a
.|. Word -> Int -> Word
shiftRL Word
x4 16) of
                          x5 :: Word
x5 -> Word
x5 Word -> Word -> Word
forall a. Bits a => a -> a -> a
.|. Word -> Int -> Word
shiftRL Word
x5 32


------------------------------------------------------------------------------
forceSameType :: Monad m => a -> a -> m ()
forceSameType :: a -> a -> m ()
forceSameType _ _ = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
{-# INLINE forceSameType #-}