Skip to content

Commit

Permalink
Use CApiFFI, small tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
phadej committed Aug 23, 2021
1 parent 585240c commit 3e3d4c5
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 34 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
See also https://pvp.haskell.org/faq

## Version 1.3.3.0

* `Text` hashing uses 64-bit FNV prime
* Don't truncate Text hashvalues on 64bit Windows:
https://github.com/haskell-unordered-containers/hashable/pull/211

## Version 1.3.2.0

* Add `Hashable (Fixed a)` for `base <4.7` versions.
Expand Down
17 changes: 3 additions & 14 deletions cbits/fnv.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,14 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "MachDeps.h"
#include <stdint.h>

#if WORD_SIZE_IN_BITS == 64
#define FNV_PRIME 1099511628211
#define FNV_SIGNED int64_t
#define FNV_UNSIGNED uint64_t
#else
#define FNV_PRIME 16777619
#define FNV_SIGNED int32_t
#define FNV_UNSIGNED uint32_t
#endif
#include "HsHashable.h"

/* FNV-1 hash
*
* The FNV-1 hash description: http://isthe.com/chongo/tech/comp/fnv/
* The FNV-1 hash is public domain: http://isthe.com/chongo/tech/comp/fnv/#public_domain
*/
FNV_SIGNED hashable_fnv_hash(const unsigned char* str, FNV_SIGNED len, FNV_SIGNED salt) {
FNV_UNSIGNED hashable_fnv_hash(const unsigned char* str, FNV_SIGNED len, FNV_UNSIGNED salt) {

FNV_UNSIGNED hash = salt;
while (len--) {
Expand All @@ -62,6 +51,6 @@ FNV_SIGNED hashable_fnv_hash(const unsigned char* str, FNV_SIGNED len, FNV_SIGNE
/* Used for ByteArray#s. We can't treat them like pointers in
native Haskell, but we can in unsafe FFI calls.
*/
FNV_SIGNED hashable_fnv_hash_offset(const unsigned char* str, FNV_SIGNED offset, FNV_SIGNED len, FNV_SIGNED salt) {
FNV_UNSIGNED hashable_fnv_hash_offset(const unsigned char* str, FNV_SIGNED offset, FNV_SIGNED len, FNV_UNSIGNED salt) {
return hashable_fnv_hash(str + offset, len, salt);
}
9 changes: 6 additions & 3 deletions hashable-bench/hashable-bench.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ tested-with:
|| ==8.10.4
|| ==9.0.1

extra-source-files: benchmarks/cbits/*.h
extra-source-files:
benchmarks/cbits/*.h
include/HsHashable.h

flag integer-gmp
description:
Expand Down Expand Up @@ -61,6 +63,7 @@ library
Data.Hashable.Generic.Instances

c-sources: cbits/fnv.c
include-dirs: include
hs-source-dirs: src
build-depends:
base >=4.5 && <4.16
Expand Down Expand Up @@ -113,12 +116,12 @@ benchmark hashable-benchmark
, siphash
, text

if impl(ghc -any)
if impl(ghc)
build-depends:
ghc-prim
, text >=0.11.0.5

if (impl(ghc -any) && flag(integer-gmp))
if (impl(ghc) && flag(integer-gmp))
build-depends: integer-gmp >=0.2

if impl(ghc >=7.2.1)
Expand Down
1 change: 1 addition & 0 deletions hashable-bench/include
5 changes: 3 additions & 2 deletions hashable.cabal
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
cabal-version: 1.12
name: hashable
version: 1.3.2.0
x-revision: 1
version: 1.3.3.0
synopsis: A class for types that can be converted to a hash value
description:
This package defines a class, 'Hashable', for types that
Expand Down Expand Up @@ -43,6 +42,7 @@ tested-with:
extra-source-files:
CHANGES.md
README.md
include/HsHashable.h

flag integer-gmp
description:
Expand Down Expand Up @@ -71,6 +71,7 @@ library
Data.Hashable.Generic.Instances

c-sources: cbits/fnv.c
include-dirs: include
hs-source-dirs: src
build-depends:
base >=4.5 && <4.17
Expand Down
22 changes: 22 additions & 0 deletions include/HsHashable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef HS_HASHABLE_H
#define HS_HASHABLE_H

#include "MachDeps.h"
#include <stdint.h>

#if WORD_SIZE_IN_BITS == 64
#define FNV_PRIME 1099511628211
#define FNV_SIGNED int64_t
#define FNV_UNSIGNED uint64_t
#else
#define FNV_PRIME 16777619
#define FNV_SIGNED int32_t
#define FNV_UNSIGNED uint32_t
#endif

uint64_t hs_hashable_init();

FNV_UNSIGNED hashable_fnv_hash(const unsigned char* str, FNV_SIGNED len, FNV_UNSIGNED salt);
FNV_UNSIGNED hashable_fnv_hash_offset(const unsigned char* str, FNV_SIGNED offset, FNV_SIGNED len, FNV_UNSIGNED salt);

#endif
27 changes: 13 additions & 14 deletions src/Data/Hashable/Class.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{-# LANGUAGE BangPatterns, CPP, MagicHash,
ScopedTypeVariables, UnliftedFFITypes, DeriveDataTypeable,
DefaultSignatures, FlexibleContexts, TypeFamilies,
MultiParamTypeClasses #-}
MultiParamTypeClasses, CApiFFI #-}

{-# LANGUAGE Trustworthy #-}

Expand Down Expand Up @@ -121,11 +121,7 @@ import Data.Typeable.Internal (Typeable, TypeRep (..))
import GHC.Fingerprint.Type(Fingerprint(..))
#endif

#if MIN_VERSION_base(4,5,0)
import Foreign.C.Types (CInt(..))
#else
import Foreign.C.Types (CInt)
#endif

#if !(MIN_VERSION_base(4,8,0))
import Data.Word (Word)
Expand Down Expand Up @@ -208,7 +204,7 @@ initialSeed :: Word64
initialSeed = unsafePerformIO initialSeedC
{-# NOINLINE initialSeed #-}

foreign import ccall "hs_hashable_init" initialSeedC :: IO Word64
foreign import capi "HsHashable.h hs_hashable_init" initialSeedC :: IO Word64
#endif

-- | A default salt used in the implementation of 'hash'.
Expand Down Expand Up @@ -721,6 +717,7 @@ instance Hashable TL.Text where
hashThreadId :: ThreadId -> Int
hashThreadId (ThreadId t) = hash (fromIntegral (getThreadId t) :: Int)

-- this cannot be capi, as GHC panics.
foreign import ccall unsafe "rts_getThreadId" getThreadId
:: ThreadId# -> CInt

Expand Down Expand Up @@ -814,12 +811,11 @@ hashPtrWithSalt p len salt =
fromIntegral `fmap` c_hashCString (castPtr p) (fromIntegral len)
(fromIntegral salt)

foreign import capi unsafe "HsHashable.h hashable_fnv_hash" c_hashCString
#if WORD_SIZE_IN_BITS == 64
foreign import ccall unsafe "hashable_fnv_hash" c_hashCString
:: CString -> Int64 -> Int64 -> IO Int64
:: CString -> Int64 -> Int64 -> IO Word64
#else
foreign import ccall unsafe "hashable_fnv_hash" c_hashCString
:: CString -> Int32 -> Int32 -> IO Int32
:: CString -> Int32 -> Int32 -> IO Word32
#endif

-- | Compute a hash value for the content of this 'ByteArray#',
Expand Down Expand Up @@ -847,12 +843,15 @@ hashByteArrayWithSalt ba !off !len !h =
fromIntegral $ c_hashByteArray ba (fromIntegral off) (fromIntegral len)
(fromIntegral h)

#if WORD_SIZE_IN_BITS == 64
foreign import ccall unsafe "hashable_fnv_hash_offset" c_hashByteArray
:: ByteArray# -> Int64 -> Int64 -> Int64 -> Int64
#if __GLASGOW_HASKELL__ >= 802
foreign import capi unsafe "HsHashable.h hashable_fnv_hash_offset" c_hashByteArray
#else
foreign import ccall unsafe "hashable_fnv_hash_offset" c_hashByteArray
:: ByteArray# -> Int32 -> Int32 -> Int32 -> Int32
#endif
#if WORD_SIZE_IN_BITS == 64
:: ByteArray# -> Int64 -> Int64 -> Int64 -> Word64
#else
:: ByteArray# -> Int32 -> Int32 -> Int32 -> Word32
#endif

-- | Combine two given hash values. 'combine' has zero as a left
Expand Down
2 changes: 1 addition & 1 deletion tests/Regress.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ regressions = [] ++
hs @=? nub hs
#if WORD_SIZE_IN_BITS == 64
, testCase "64 bit Text" $ do
hash ("hello world" :: Text) @=? 6567282331143050109
hash ("hello world" :: Text) @=? 2668910425102664189
#endif
]
where
Expand Down

0 comments on commit 3e3d4c5

Please sign in to comment.