packages feed

hashes-0.1.0.0: src/Data/Hash/Utils.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UnboxedTuples #-}

-- |
-- Module: Data.Hash.Utils
-- Copyright: Copyright © 2021 Lars Kuhtz <lakuhtz@gmail.com>
-- License: MIT
-- Maintainer: Lars Kuhtz <lakuhtz@gmail.com>
-- Stability: experimental
--
module Data.Hash.Utils
(
-- * Pure API
  hashStorable
, hashStorable_
, hashByteString
, hashByteString_
, hashByteArray
, hashByteArray_
, hashPtr
, hashPtr_

-- * IO API
, hashStorableIO
, hashStorableIO_
, hashByteStringIO
, hashByteStringIO_
, hashByteArrayIO
, hashByteArrayIO_
) where

import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B
import Data.Word

import Foreign.Marshal.Utils
import Foreign.Ptr
import Foreign.Storable

import GHC.Exts
import GHC.IO
import Foreign.Marshal.Alloc

-- -------------------------------------------------------------------------- --
-- Pure API

-- Storable

hashStorable :: Storable a => (Ptr Word8 -> Int -> IO b) -> a -> b
hashStorable f = unsafeDupablePerformIO . hashStorableIO f
{-# INLINE hashStorable #-}

hashStorable_ :: Storable a => (Ptr Word8 -> Int -> b -> IO b) -> a -> b -> b
hashStorable_ f a = unsafeDupablePerformIO . hashStorableIO_ f a
{-# INLINE hashStorable_ #-}

-- ByteString

hashByteString :: (Ptr Word8 -> Int -> IO b) -> B.ByteString -> b
hashByteString f = unsafeDupablePerformIO . hashByteStringIO f
{-# INLINE hashByteString #-}

hashByteString_ :: (Ptr Word8 -> Int -> b -> IO b) -> B.ByteString -> b -> b
hashByteString_ f a = unsafeDupablePerformIO . hashByteStringIO_ f a
{-# INLINE hashByteString_ #-}

-- ByteArray

hashByteArray :: (Ptr Word8 -> Int -> IO b) -> ByteArray# -> b
hashByteArray f a# = unsafeDupablePerformIO $! hashByteArrayIO f a#
{-# INLINE hashByteArray #-}

hashByteArray_ :: (Ptr Word8 -> Int -> b -> IO b) -> ByteArray# -> b -> b
hashByteArray_ f a# = unsafeDupablePerformIO . hashByteArrayIO_ f a#
{-# INLINE hashByteArray_ #-}

-- Ptr

hashPtr :: (Ptr Word8 -> Int -> IO b) -> Ptr Word8 -> Int -> b
hashPtr f ptr = unsafeDupablePerformIO . f ptr
{-# INLINE hashPtr #-}

hashPtr_ :: (Ptr Word8 -> Int -> b -> IO b) -> Ptr Word8 -> Int -> b -> b
hashPtr_ f ptr l = unsafeDupablePerformIO . f ptr l
{-# INLINE hashPtr_ #-}

-- -------------------------------------------------------------------------- --
-- IO API

-- Storable

hashStorableIO :: Storable a => (Ptr Word8 -> Int -> IO b) -> a -> IO b
hashStorableIO f a = with a $ \ptr -> f (castPtr ptr) (sizeOf a)
{-# INLINE hashStorableIO #-}

hashStorableIO_ :: Storable a => (Ptr Word8 -> Int -> b -> IO b) -> a -> b -> IO b
hashStorableIO_ f a b = with a $ \ptr -> f (castPtr ptr) (sizeOf a) b
{-# INLINE hashStorableIO_ #-}

-- ByteString

hashByteStringIO :: (Ptr Word8 -> Int -> IO b) -> B.ByteString -> IO b
hashByteStringIO f a = B.unsafeUseAsCStringLen a $ \(!p, !l) -> f (castPtr p) l
{-# INLINE hashByteStringIO #-}

hashByteStringIO_ :: (Ptr Word8 -> Int -> b -> IO b) -> B.ByteString -> b -> IO b
hashByteStringIO_ f a b = B.unsafeUseAsCStringLen a $ \(!p, !l) -> f (castPtr p) l b
{-# INLINE hashByteStringIO_ #-}

-- ByteArray

hashByteArrayIO :: (Ptr Word8 -> Int -> IO b) -> ByteArray# -> IO b
hashByteArrayIO f a# = case isByteArrayPinned# a# of
    -- Pinned ByteArray
    1# -> f (Ptr (byteArrayContents# a#)) (I# size#)

    -- Unpinned ByteArray, copy content to newly allocated pinned ByteArray
    _ -> allocaBytes (I# size#) $ \ptr@(Ptr addr#) -> IO $ \s0 ->
        case copyByteArrayToAddr# a# 0# addr# size# s0 of
            s1 -> case f ptr (I# size#) of
                IO run -> run s1
  where
    size# = sizeofByteArray# a#
{-# INLINE hashByteArrayIO #-}


hashByteArrayIO_ :: (Ptr Word8 -> Int -> b -> IO b) -> ByteArray# -> b -> IO b
hashByteArrayIO_ f a# b = case isByteArrayPinned# a# of
    -- Pinned ByteArray
    1# -> f (Ptr (byteArrayContents# a#)) (I# size#) b

    -- Unpinned ByteArray, copy content to newly allocated pinned ByteArray
    _ -> allocaBytes (I# size#) $ \ptr@(Ptr addr#) -> IO $ \s0 ->
        case copyByteArrayToAddr# a# 0# addr# size# s0 of
            s1 -> case f ptr (I# size#) b of
                IO run -> run s1
  where
    size# = sizeofByteArray# a#
{-# INLINE hashByteArrayIO_ #-}