content: {-# LANGUAGE BangPatterns #-}
  {-# LANGUAGE CPP          #-}
  #ifdef UNSAFETRICKS
  {-# LANGUAGE MagicHash    #-}
  #endif
  
  module Data.HashTable.Internal.UnsafeTricks
    ( Key
    , toKey
    , fromKey
    , emptyRecord
    , deletedRecord
    , keyIsEmpty
    , keyIsDeleted
    , writeDeletedElement
    , makeEmptyVector
    ) where
  
  import Prelude
  
  import           Control.Monad.Primitive
  import           Data.Vector.Mutable (MVector)
  import qualified Data.Vector.Mutable as M
  #ifdef UNSAFETRICKS
  import           GHC.Exts
  import           Unsafe.Coerce
  
  #if __GLASGOW_HASKELL__ >= 808
  -- Nothing to do here.
  #elif __GLASGOW_HASKELL__ >= 707
  import           GHC.Exts                         (isTrue#)
  #else
  isTrue# :: Bool -> Bool
  isTrue# = id
  #endif
  
  #endif
  
  
  ------------------------------------------------------------------------------
  #ifdef UNSAFETRICKS
  type Key a = Any
  
  #else
  data Key a = Key !a
             | EmptyElement
             | DeletedElement
    deriving (Show)
  #endif
  
  
  ------------------------------------------------------------------------------
  -- Type signatures
  emptyRecord :: Key a
  deletedRecord :: Key a
  keyIsEmpty :: Key a -> Bool
  keyIsDeleted :: Key a -> Bool
  makeEmptyVector :: PrimMonad m => Int -> m (MVector (PrimState m) (Key a))
  writeDeletedElement :: PrimMonad m =>
                         MVector (PrimState m) (Key a) -> Int -> m ()
  toKey :: a -> Key a
  fromKey :: Key a -> a
  
  
  #ifdef UNSAFETRICKS
  data TombStone = EmptyElement
                 | DeletedElement
  
  {-# NOINLINE emptyRecord #-}
  emptyRecord = unsafeCoerce EmptyElement
  
  {-# NOINLINE deletedRecord #-}
  deletedRecord = unsafeCoerce DeletedElement
  
  {-# INLINE keyIsEmpty #-}
  keyIsEmpty a = isTrue# (x# ==# 1#)
    where
      !x# = reallyUnsafePtrEquality# a emptyRecord
  
  {-# INLINE keyIsDeleted #-}
  keyIsDeleted a = isTrue# (x# ==# 1#)
    where
      !x# = reallyUnsafePtrEquality# a deletedRecord
  
  {-# INLINE toKey #-}
  toKey = unsafeCoerce
  
  {-# INLINE fromKey #-}
  fromKey = unsafeCoerce
  
  #else
  
  emptyRecord = EmptyElement
  
  deletedRecord = DeletedElement
  
  keyIsEmpty EmptyElement = True
  keyIsEmpty _            = False
  
  keyIsDeleted DeletedElement = True
  keyIsDeleted _              = False
  
  toKey = Key
  
  fromKey (Key x) = x
  fromKey _ = error "impossible"
  
  #endif
  
  
  ------------------------------------------------------------------------------
  {-# INLINE makeEmptyVector #-}
  makeEmptyVector m = M.replicate m emptyRecord
  
  ------------------------------------------------------------------------------
  {-# INLINE writeDeletedElement #-}
  writeDeletedElement v i = M.unsafeWrite v i deletedRecord
  