hashable-accelerate (empty) → 0.1.0.0
raw patch · 6 files changed
+366/−0 lines, 6 filesdep +acceleratedep +basedep +template-haskellsetup-changed
Dependencies added: accelerate, base, template-haskell
Files
- CHANGELOG.md +14/−0
- LICENSE +30/−0
- README.md +25/−0
- Setup.hs +2/−0
- hashable-accelerate.cabal +40/−0
- src/Data/Array/Accelerate/Data/Hashable.hs +255/−0
+ CHANGELOG.md view
@@ -0,0 +1,14 @@+# Changelog for hashable-accelerate++Notable changes to the project will be documented in this file.++The format is based on [Keep a Changelog](http://keepachangelog.com/) and the+project adheres to the [Haskell Package Versioning+Policy (PVP)](https://pvp.haskell.org)++## [0.1.0.0] - 2020-08-28+### New+ * Initial version++[0.1.0.0]: https://github.com/tmcdonell/hashable-accelerate/compare/0b4e0893af766722836333776b9415e8e6e7941a...v0.1.0.0+
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Trevor L. McDonell (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Trevor L. McDonell nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,25 @@+<div align="center">+<img width="450" src="https://github.com/AccelerateHS/accelerate/raw/master/images/accelerate-logo-text-v.png?raw=true" alt="henlo, my name is Theia"/>++# hashable-accelerate++[](https://github.com/tmcdonell/hashable-accelerate/actions)+[](https://gitter.im/AccelerateHS/Lobby)+<br>+[](https://stackage.org/lts/package/hashable-accelerate)+[](https://stackage.org/nightly/package/hashable-accelerate)+[](https://hackage.haskell.org/package/hashable-accelerate)++</div>++A class for types which can be converted to a hash value. Based on the+[hashable][hashable] library. For details on Accelerate see the [main+repository][accelerate].++Contributions and bug reports are welcome!<br>+Please feel free to contact me through [GitHub][accelerate] or [gitter.im][gitter.im].++ [hashable]: http://hackage.haskell.org/package/hashable+ [accelerate]: https://github.com/AccelerateHS/accelerate+ [gitter.im]: https://gitter.im/AccelerateHS/Lobby+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hashable-accelerate.cabal view
@@ -0,0 +1,40 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.33.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 311ae20bdafe08bcf8608d32bb057d5525fb0e6d722f5426b94607f4142641cb++name: hashable-accelerate+version: 0.1.0.0+synopsis: A class for types which can be converted into a hash value+description: Please see the README on GitHub at <https://github.com/tmcdonell/hashable-accelerate#readme>+category: Accelerate, Data+homepage: https://github.com/tmcdonell/hashable-accelerate#readme+bug-reports: https://github.com/tmcdonell/hashable-accelerate/issues+author: Trevor L. McDonell+maintainer: Trevor L. McDonell <trevor.mcdonell@gmail.com>+license: BSD3+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md+ CHANGELOG.md++source-repository head+ type: git+ location: https://github.com/tmcdonell/hashable-accelerate++library+ exposed-modules:+ Data.Array.Accelerate.Data.Hashable+ other-modules:+ Paths_hashable_accelerate+ hs-source-dirs:+ src+ build-depends:+ accelerate >=1.3+ , base >=4.7 && <5+ , template-haskell+ default-language: Haskell2010
+ src/Data/Array/Accelerate/Data/Hashable.hs view
@@ -0,0 +1,255 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RebindableSyntax #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}+-- |+-- Module : Data.Array.Accelerate.Data.Hashable+-- Copyright : [2020] Trevor L. McDonell+-- License : BSD3+--+-- Maintainer : Trevor L. McDonell <trevor.mcdonell@gmail.com>+-- Stability : experimental+-- Portability : non-portable (GHC extensions)+--+-- This module defines a class 'Hashable', for types that can be converted+-- to a hash value.+--++module Data.Array.Accelerate.Data.Hashable (++ Hashable(..),+ hashUsing, defaultHashWithSalt,++) where++import Data.Array.Accelerate+import Data.Array.Accelerate.Data.Bits+import Data.Array.Accelerate.Data.Complex+import Data.Array.Accelerate.Data.Either+import Data.Array.Accelerate.Data.Maybe+import Data.Array.Accelerate.Data.Monoid+import Data.Array.Accelerate.Data.Ratio+import Data.Array.Accelerate.Data.Semigroup++import Prelude ( (<$>), id, concat )+import Control.Monad ( mapM )+import Language.Haskell.TH hiding ( Exp, match )+import qualified Prelude as P+import qualified Data.Bits as P+import qualified Data.List as P++#include "MachDeps.h"++infixl 0 `hashWithSalt`++-- | The class of types that can be converted to a hash value.+--+class Elt a => Hashable a where+ -- | Return a hash value for the argument, using the given salt.+ --+ -- The general contract of 'hashWithSalt' is:+ --+ -- * If two values are equal according to the '==' method, then+ -- applying the 'hashWithSalt' method on each of the two values+ -- /must/ produce the same integer result if the same salt is+ -- used in each case.+ --+ -- * It is /not/ required that if two values are unequal+ -- according to the '==' method, then applying the+ -- 'hashWithSalt' method on each of the two values must produce+ -- distinct integer results. However, the programmer should be+ -- aware that producing distinct integer results for unequal+ -- values may improve the performance of hashing-based data+ -- structures.+ --+ -- * This method can be used to compute different hash values for+ -- the same input by providing a different salt in each+ -- application of the method. This implies that any instance+ -- that defines 'hashWithSalt' /must/ make use of the salt in+ -- its implementation.+ --+ hashWithSalt :: Exp Int -> Exp a -> Exp Int++ -- | Like 'hashWithSalt', but no salt is used. The default+ -- implementation uses 'hashWithSalt' with some default salt.+ -- Instances might want to implement this method to provide a more+ -- efficient implementation than the default implementation.+ --+ hash :: Exp a -> Exp Int+ hash = hashWithSalt defaultSalt++-- | Transform a value into a 'Hashable' value, then hash the transformed+-- value using the given salt.+--+-- This is a useful shorthand in cases where a type can easily be mapped to+-- another type that is already an instance of 'Hashable'.+--+hashUsing+ :: Hashable b+ => (Exp a -> Exp b) -- ^ transformation function+ -> Exp Int -- ^ salt+ -> Exp a -- ^ value to transform+ -> Exp Int+hashUsing f salt x = hashWithSalt salt (f x)++-- | A default salt used in the implementation of 'hash'.+--+defaultSalt :: Exp Int+#if WORD_SIZE_IN_BITS == 64+defaultSalt = -2578643520546668380 -- 0xdc36d1615b7400a4+#else+defaultSalt = 0x087fc72c+#endif++defaultHashWithSalt :: Hashable a => Exp Int -> Exp a -> Exp Int+defaultHashWithSalt salt x = salt `combine` hash x++-- | Combine two given hash values. 'combine' has zero as a left identity.+--+combine :: Exp Int -> Exp Int -> Exp Int+combine h1 h2 = (h1 * 16777619) `xor` h2++instance Hashable Int where+ hash = id+ hashWithSalt = defaultHashWithSalt++instance Hashable Int8 where+ hash = fromIntegral+ hashWithSalt = defaultHashWithSalt++instance Hashable Int16 where+ hash = fromIntegral+ hashWithSalt = defaultHashWithSalt++instance Hashable Int32 where+ hash = fromIntegral+ hashWithSalt = defaultHashWithSalt++instance Hashable Int64 where+ hash x+ | P.finiteBitSize (undefined :: Int) P.== 64 = fromIntegral x+ | otherwise = fromIntegral (fromIntegral x `xor`+ (fromIntegral x `shiftR` 32 :: Exp Word64))+ hashWithSalt = defaultHashWithSalt++instance Hashable Word where+ hash = fromIntegral+ hashWithSalt = defaultHashWithSalt++instance Hashable Word8 where+ hash = fromIntegral+ hashWithSalt = defaultHashWithSalt++instance Hashable Word16 where+ hash = fromIntegral+ hashWithSalt = defaultHashWithSalt++instance Hashable Word32 where+ hash = fromIntegral+ hashWithSalt = defaultHashWithSalt++instance Hashable Word64 where+ hash x+ | P.finiteBitSize (undefined :: Int) P.== 64 = fromIntegral x+ | otherwise = fromIntegral (x `xor` (x `shiftR` 32))+ hashWithSalt = defaultHashWithSalt++instance Hashable () where+ hash _ = constant (P.fromEnum ())+ hashWithSalt = defaultHashWithSalt++instance Hashable Bool where+ hash = boolToInt+ hashWithSalt = defaultHashWithSalt++instance Hashable Char where+ hash = ord+ hashWithSalt = defaultHashWithSalt++instance Hashable Half where+ hash x =+ if x == 0.0 || x == -0.0+ then 0+ else hash (bitcast x :: Exp Word16)+ hashWithSalt = defaultHashWithSalt++instance Hashable Float where+ hash x =+ if x == 0.0 || x == -0.0+ then 0+ else hash (bitcast x :: Exp Word32)+ hashWithSalt = defaultHashWithSalt++instance Hashable Double where+ hash x =+ if x == 0.0 || x == -0.0+ then 0+ else hash (bitcast x :: Exp Word64)+ hashWithSalt = defaultHashWithSalt++instance Hashable a => Hashable (Complex a) where+ hash (r ::+ i) = hash r `hashWithSalt` i+ hashWithSalt s (r ::+ i) = s `hashWithSalt` r `hashWithSalt` i++instance Hashable a => Hashable (Ratio a) where+ hash a = hash (numerator a) `hashWithSalt` denominator a+ hashWithSalt s a = s `hashWithSalt` numerator a `hashWithSalt` denominator a++-- | A value with bit pattern (01)* (or 5* in hexa), for any size of Int.+-- It is used as data constructor distinguisher.+--+distinguisher :: Exp Int+distinguisher = fromIntegral $ (maxBound :: Exp Word) `quot` 3++instance Hashable a => Hashable (Maybe a) where+ hash = match \case+ Nothing_ -> 0+ Just_ x -> distinguisher `hashWithSalt` x+ hashWithSalt = defaultHashWithSalt++instance (Hashable a, Hashable b) => Hashable (Either a b) where+ hash = match \case+ Left_ x -> 0 `hashWithSalt` x+ Right_ x -> distinguisher `hashWithSalt` x+ hashWithSalt = defaultHashWithSalt++instance Hashable a => Hashable (Min a) where+ hashWithSalt s (Min_ a) = hashWithSalt s a++instance Hashable a => Hashable (Max a) where+ hashWithSalt s (Max_ a) = hashWithSalt s a++instance Hashable a => Hashable (Sum a) where+ hashWithSalt s (Sum_ a) = hashWithSalt s a++instance Hashable a => Hashable (Product a) where+ hashWithSalt s (Product_ a) = hashWithSalt s a++$(runQ $+ let+ tupT :: [TypeQ] -> TypeQ+ tupT tup =+ let n = P.length tup+ in P.foldl' (\ts t -> [t| $ts $t |]) (tupleT n) tup++ mkTup :: Int -> Q [Dec]+ mkTup n =+ let+ xs = [ mkName ('x':P.show i) | i <- [0 .. n-1] ]+ ctx = tupT (P.map (\x -> [t| Hashable $(varT x) |]) xs)+ res = tupT (P.map varT xs)+ pat = conP (mkName ('T':P.show n)) (P.map varP xs)+ in+ [d| instance $ctx => Hashable $res where+ hash $pat = $(P.foldl' (\vs v -> [| $vs `hashWithSalt` $v |]) [| hash $(varE (P.head xs))|] (P.map varE (P.tail xs)))+ hashWithSalt = defaultHashWithSalt+ |]++ in+ concat <$> mapM mkTup [2..16]+ )+