packages feed

discrimination 0.1 → 0.2.1

raw patch · 8 files changed

+675/−72 lines, 8 filesdep +criteriondep +discriminationdep +hashabledep ~basedep ~containersdep ~deepseqPVP ok

version bump matches the API change (PVP)

Dependencies added: criterion, discrimination, hashable, transformers-compat, unordered-containers

Dependency ranges changed: base, containers, deepseq, primitive, promises, transformers, vector

API changes (from Hackage documentation)

- Data.Discrimination: getGroup :: Group a -> forall m b. PrimMonad m => (b -> m (b -> m ())) -> m (a -> b -> m ())
- Data.Discrimination: runSort :: Sort a -> forall b. [(a, b)] -> [[b]]
- Data.Discrimination.Class: instance Discriminating Group
- Data.Discrimination.Class: instance Discriminating Sort
- Data.Discrimination.Grouping: getGroup :: Group a -> forall m b. PrimMonad m => (b -> m (b -> m ())) -> m (a -> b -> m ())
- Data.Discrimination.Grouping: groupingNat :: Int -> Group Int
- Data.Discrimination.Grouping: instance (Grouping a, Grouping b) => Grouping (Either a b)
- Data.Discrimination.Grouping: instance (Grouping a, Grouping b) => Grouping (a, b)
- Data.Discrimination.Grouping: instance (Grouping a, Grouping b) => Grouping1 ((,,) a b)
- Data.Discrimination.Grouping: instance (Grouping a, Grouping b, Grouping c) => Grouping (a, b, c)
- Data.Discrimination.Grouping: instance (Grouping a, Grouping b, Grouping c) => Grouping1 ((,,,) a b c)
- Data.Discrimination.Grouping: instance (Grouping a, Grouping b, Grouping c, Grouping d) => Grouping (a, b, c, d)
- Data.Discrimination.Grouping: instance (Grouping a, Integral a) => Grouping (Ratio a)
- Data.Discrimination.Grouping: instance (Grouping1 f, Grouping1 g) => Grouping1 (Compose f g)
- Data.Discrimination.Grouping: instance (Grouping1 f, Grouping1 g, Grouping a) => Grouping (Compose f g a)
- Data.Discrimination.Grouping: instance Contravariant Group
- Data.Discrimination.Grouping: instance Decidable Group
- Data.Discrimination.Grouping: instance Divisible Group
- Data.Discrimination.Grouping: instance Grouping Bool
- Data.Discrimination.Grouping: instance Grouping Int
- Data.Discrimination.Grouping: instance Grouping Int16
- Data.Discrimination.Grouping: instance Grouping Int32
- Data.Discrimination.Grouping: instance Grouping Int64
- Data.Discrimination.Grouping: instance Grouping Int8
- Data.Discrimination.Grouping: instance Grouping Void
- Data.Discrimination.Grouping: instance Grouping Word
- Data.Discrimination.Grouping: instance Grouping Word16
- Data.Discrimination.Grouping: instance Grouping Word32
- Data.Discrimination.Grouping: instance Grouping Word64
- Data.Discrimination.Grouping: instance Grouping Word8
- Data.Discrimination.Grouping: instance Grouping a => Grouping (Complex a)
- Data.Discrimination.Grouping: instance Grouping a => Grouping (Maybe a)
- Data.Discrimination.Grouping: instance Grouping a => Grouping [a]
- Data.Discrimination.Grouping: instance Grouping a => Grouping1 ((,) a)
- Data.Discrimination.Grouping: instance Grouping a => Grouping1 (Either a)
- Data.Discrimination.Grouping: instance Grouping1 Complex
- Data.Discrimination.Grouping: instance Grouping1 Maybe
- Data.Discrimination.Grouping: instance Grouping1 []
- Data.Discrimination.Grouping: instance Monoid (Group a)
- Data.Discrimination.Grouping: instance Typeable Group
- Data.Discrimination.Sorting: instance (Sorting a, Sorting b) => Sorting (Either a b)
- Data.Discrimination.Sorting: instance (Sorting a, Sorting b) => Sorting (a, b)
- Data.Discrimination.Sorting: instance (Sorting a, Sorting b, Sorting c) => Sorting (a, b, c)
- Data.Discrimination.Sorting: instance (Sorting a, Sorting b, Sorting c, Sorting d) => Sorting (a, b, c, d)
- Data.Discrimination.Sorting: instance (Sorting1 f, Sorting1 g) => Sorting1 (Compose f g)
- Data.Discrimination.Sorting: instance (Sorting1 f, Sorting1 g, Sorting a) => Sorting (Compose f g a)
- Data.Discrimination.Sorting: instance Contravariant Sort
- Data.Discrimination.Sorting: instance Decidable Sort
- Data.Discrimination.Sorting: instance Divisible Sort
- Data.Discrimination.Sorting: instance Monoid (Sort a)
- Data.Discrimination.Sorting: instance Sorting Bool
- Data.Discrimination.Sorting: instance Sorting Int
- Data.Discrimination.Sorting: instance Sorting Int16
- Data.Discrimination.Sorting: instance Sorting Int32
- Data.Discrimination.Sorting: instance Sorting Int64
- Data.Discrimination.Sorting: instance Sorting Int8
- Data.Discrimination.Sorting: instance Sorting Void
- Data.Discrimination.Sorting: instance Sorting Word
- Data.Discrimination.Sorting: instance Sorting Word16
- Data.Discrimination.Sorting: instance Sorting Word32
- Data.Discrimination.Sorting: instance Sorting Word64
- Data.Discrimination.Sorting: instance Sorting Word8
- Data.Discrimination.Sorting: instance Sorting a => Sorting (Maybe a)
- Data.Discrimination.Sorting: instance Sorting a => Sorting [a]
- Data.Discrimination.Sorting: instance Sorting a => Sorting1 (Either a)
- Data.Discrimination.Sorting: instance Sorting1 Maybe
- Data.Discrimination.Sorting: instance Sorting1 []
- Data.Discrimination.Sorting: instance Typeable Sort
- Data.Discrimination.Sorting: runSort :: Sort a -> forall b. [(a, b)] -> [[b]]
+ Data.Discrimination: [getGroup] :: Group a -> forall m b. PrimMonad m => (b -> m (b -> m ())) -> m (a -> b -> m ())
+ Data.Discrimination: [runSort] :: Sort a -> forall b. [(a, b)] -> [[b]]
+ Data.Discrimination.Class: instance Data.Discrimination.Class.Discriminating Data.Discrimination.Grouping.Group
+ Data.Discrimination.Class: instance Data.Discrimination.Class.Discriminating Data.Discrimination.Sorting.Sort
+ Data.Discrimination.Grouping: [getGroup] :: Group a -> forall m b. PrimMonad m => (b -> m (b -> m ())) -> m (a -> b -> m ())
+ Data.Discrimination.Grouping: hashing :: Hashable a => Group a
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping a, Data.Discrimination.Grouping.Grouping b) => Data.Discrimination.Grouping.Grouping (Data.Either.Either a b)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping a, Data.Discrimination.Grouping.Grouping b) => Data.Discrimination.Grouping.Grouping (a, b)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping a, Data.Discrimination.Grouping.Grouping b) => Data.Discrimination.Grouping.Grouping1 ((,,) a b)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping a, Data.Discrimination.Grouping.Grouping b, Data.Discrimination.Grouping.Grouping c) => Data.Discrimination.Grouping.Grouping (a, b, c)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping a, Data.Discrimination.Grouping.Grouping b, Data.Discrimination.Grouping.Grouping c) => Data.Discrimination.Grouping.Grouping1 ((,,,) a b c)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping a, Data.Discrimination.Grouping.Grouping b, Data.Discrimination.Grouping.Grouping c, Data.Discrimination.Grouping.Grouping d) => Data.Discrimination.Grouping.Grouping (a, b, c, d)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping a, GHC.Real.Integral a) => Data.Discrimination.Grouping.Grouping (GHC.Real.Ratio a)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping1 f, Data.Discrimination.Grouping.Grouping1 g) => Data.Discrimination.Grouping.Grouping1 (Data.Functor.Compose.Compose f g)
+ Data.Discrimination.Grouping: instance (Data.Discrimination.Grouping.Grouping1 f, Data.Discrimination.Grouping.Grouping1 g, Data.Discrimination.Grouping.Grouping a) => Data.Discrimination.Grouping.Grouping (Data.Functor.Compose.Compose f g a)
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping Data.Void.Void
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Int.Int16
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Int.Int32
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Int.Int64
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Int.Int8
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Types.Bool
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Types.Char
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Types.Int
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Types.Word
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Word.Word16
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Word.Word32
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Word.Word64
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping GHC.Word.Word8
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping a => Data.Discrimination.Grouping.Grouping (Data.Complex.Complex a)
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping a => Data.Discrimination.Grouping.Grouping (GHC.Base.Maybe a)
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping a => Data.Discrimination.Grouping.Grouping [a]
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping a => Data.Discrimination.Grouping.Grouping1 ((,) a)
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping a => Data.Discrimination.Grouping.Grouping1 (Data.Either.Either a)
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping1 Data.Complex.Complex
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping1 GHC.Base.Maybe
+ Data.Discrimination.Grouping: instance Data.Discrimination.Grouping.Grouping1 []
+ Data.Discrimination.Grouping: instance Data.Functor.Contravariant.Contravariant Data.Discrimination.Grouping.Group
+ Data.Discrimination.Grouping: instance Data.Functor.Contravariant.Divisible.Decidable Data.Discrimination.Grouping.Group
+ Data.Discrimination.Grouping: instance Data.Functor.Contravariant.Divisible.Divisible Data.Discrimination.Grouping.Group
+ Data.Discrimination.Grouping: instance Data.Semigroup.Semigroup (Data.Discrimination.Grouping.Group a)
+ Data.Discrimination.Grouping: instance GHC.Base.Monoid (Data.Discrimination.Grouping.Group a)
+ Data.Discrimination.Internal.SmallArray: SmallArray :: (SmallArray# a) -> SmallArray a
+ Data.Discrimination.Internal.SmallArray: SmallMutableArray :: (SmallMutableArray# s a) -> SmallMutableArray s a
+ Data.Discrimination.Internal.SmallArray: cloneSmallArray :: SmallArray a -> Int -> Int -> SmallArray a
+ Data.Discrimination.Internal.SmallArray: cloneSmallMutableArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> Int -> m (SmallMutableArray (PrimState m) a)
+ Data.Discrimination.Internal.SmallArray: copySmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> SmallArray a -> Int -> Int -> m ()
+ Data.Discrimination.Internal.SmallArray: copySmallMutableArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> SmallMutableArray (PrimState m) a -> Int -> Int -> m ()
+ Data.Discrimination.Internal.SmallArray: data SmallArray a
+ Data.Discrimination.Internal.SmallArray: data SmallMutableArray s a
+ Data.Discrimination.Internal.SmallArray: indexSmallArray :: SmallArray a -> Int -> a
+ Data.Discrimination.Internal.SmallArray: indexSmallArrayM :: Monad m => SmallArray a -> Int -> m a
+ Data.Discrimination.Internal.SmallArray: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Data.Discrimination.Internal.SmallArray.SmallArray a)
+ Data.Discrimination.Internal.SmallArray: instance Data.Foldable.Foldable Data.Discrimination.Internal.SmallArray.SmallArray
+ Data.Discrimination.Internal.SmallArray: instance Data.Traversable.Traversable Data.Discrimination.Internal.SmallArray.SmallArray
+ Data.Discrimination.Internal.SmallArray: instance GHC.Base.Functor Data.Discrimination.Internal.SmallArray.SmallArray
+ Data.Discrimination.Internal.SmallArray: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Discrimination.Internal.SmallArray.SmallArray a)
+ Data.Discrimination.Internal.SmallArray: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Discrimination.Internal.SmallArray.SmallArray a)
+ Data.Discrimination.Internal.SmallArray: instance GHC.Exts.IsList (Data.Discrimination.Internal.SmallArray.SmallArray a)
+ Data.Discrimination.Internal.SmallArray: instance GHC.Read.Read a => GHC.Read.Read (Data.Discrimination.Internal.SmallArray.SmallArray a)
+ Data.Discrimination.Internal.SmallArray: instance GHC.Show.Show a => GHC.Show.Show (Data.Discrimination.Internal.SmallArray.SmallArray a)
+ Data.Discrimination.Internal.SmallArray: newSmallArray :: PrimMonad m => Int -> a -> m (SmallMutableArray (PrimState m) a)
+ Data.Discrimination.Internal.SmallArray: readSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> m a
+ Data.Discrimination.Internal.SmallArray: sameSmallMutableArray :: SmallMutableArray s a -> SmallMutableArray s a -> Bool
+ Data.Discrimination.Internal.SmallArray: unsafeFreezeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> m (SmallArray a)
+ Data.Discrimination.Internal.SmallArray: unsafeThawSmallArray :: PrimMonad m => SmallArray a -> m (SmallMutableArray (PrimState m) a)
+ Data.Discrimination.Internal.SmallArray: writeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> a -> m ()
+ Data.Discrimination.Internal.WordMap: data WordMap v
+ Data.Discrimination.Internal.WordMap: empty :: WordMap a
+ Data.Discrimination.Internal.WordMap: fromList :: [(Word64, v)] -> WordMap v
+ Data.Discrimination.Internal.WordMap: insert :: Key -> v -> WordMap v -> WordMap v
+ Data.Discrimination.Internal.WordMap: instance Control.DeepSeq.NFData v => Control.DeepSeq.NFData (Data.Discrimination.Internal.WordMap.WordMap v)
+ Data.Discrimination.Internal.WordMap: instance Data.Foldable.Foldable Data.Discrimination.Internal.WordMap.WordMap
+ Data.Discrimination.Internal.WordMap: instance Data.Traversable.Traversable Data.Discrimination.Internal.WordMap.WordMap
+ Data.Discrimination.Internal.WordMap: instance GHC.Base.Functor Data.Discrimination.Internal.WordMap.WordMap
+ Data.Discrimination.Internal.WordMap: instance GHC.Show.Show v => GHC.Show.Show (Data.Discrimination.Internal.WordMap.WordMap v)
+ Data.Discrimination.Internal.WordMap: lookup :: Key -> WordMap v -> Maybe v
+ Data.Discrimination.Internal.WordMap: member :: Key -> WordMap v -> Bool
+ Data.Discrimination.Internal.WordMap: singleton :: Key -> v -> WordMap v
+ Data.Discrimination.Sorting: [runSort] :: Sort a -> forall b. [(a, b)] -> [[b]]
+ Data.Discrimination.Sorting: instance (Data.Discrimination.Sorting.Sorting a, Data.Discrimination.Sorting.Sorting b) => Data.Discrimination.Sorting.Sorting (Data.Either.Either a b)
+ Data.Discrimination.Sorting: instance (Data.Discrimination.Sorting.Sorting a, Data.Discrimination.Sorting.Sorting b) => Data.Discrimination.Sorting.Sorting (a, b)
+ Data.Discrimination.Sorting: instance (Data.Discrimination.Sorting.Sorting a, Data.Discrimination.Sorting.Sorting b, Data.Discrimination.Sorting.Sorting c) => Data.Discrimination.Sorting.Sorting (a, b, c)
+ Data.Discrimination.Sorting: instance (Data.Discrimination.Sorting.Sorting a, Data.Discrimination.Sorting.Sorting b, Data.Discrimination.Sorting.Sorting c, Data.Discrimination.Sorting.Sorting d) => Data.Discrimination.Sorting.Sorting (a, b, c, d)
+ Data.Discrimination.Sorting: instance (Data.Discrimination.Sorting.Sorting1 f, Data.Discrimination.Sorting.Sorting1 g) => Data.Discrimination.Sorting.Sorting1 (Data.Functor.Compose.Compose f g)
+ Data.Discrimination.Sorting: instance (Data.Discrimination.Sorting.Sorting1 f, Data.Discrimination.Sorting.Sorting1 g, Data.Discrimination.Sorting.Sorting a) => Data.Discrimination.Sorting.Sorting (Data.Functor.Compose.Compose f g a)
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting Data.Void.Void
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Int.Int16
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Int.Int32
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Int.Int64
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Int.Int8
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Types.Bool
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Types.Char
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Types.Int
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Types.Word
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Word.Word16
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Word.Word32
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Word.Word64
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting GHC.Word.Word8
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting a => Data.Discrimination.Sorting.Sorting (GHC.Base.Maybe a)
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting a => Data.Discrimination.Sorting.Sorting [a]
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting a => Data.Discrimination.Sorting.Sorting1 (Data.Either.Either a)
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting1 GHC.Base.Maybe
+ Data.Discrimination.Sorting: instance Data.Discrimination.Sorting.Sorting1 []
+ Data.Discrimination.Sorting: instance Data.Functor.Contravariant.Contravariant Data.Discrimination.Sorting.Sort
+ Data.Discrimination.Sorting: instance Data.Functor.Contravariant.Divisible.Decidable Data.Discrimination.Sorting.Sort
+ Data.Discrimination.Sorting: instance Data.Functor.Contravariant.Divisible.Divisible Data.Discrimination.Sorting.Sort
+ Data.Discrimination.Sorting: instance Data.Semigroup.Semigroup (Data.Discrimination.Sorting.Sort a)
+ Data.Discrimination.Sorting: instance GHC.Base.Monoid (Data.Discrimination.Sorting.Sort a)

Files

CHANGELOG.markdown view
@@ -1,3 +1,15 @@+## 0.2.1++* `promises` 0.3 support+* `vector` 0.11 support+* `transformers` 0.5 support+* `transformers-compat` support+* ghc 8 support++## 0.2++* `grouping` is now much more efficient.+ ## 0.1  * `grouping` is now productive. This means it can start spitting out results as it goes! To do this I created the `promises` package and switched to using it behind the scenes for many combinators that consume a `Group`. This has a bunch of knock-on effects:
README.markdown view
@@ -1,7 +1,7 @@ discrimination ============== -[![Build Status](https://secure.travis-ci.org/ekmett/discrimination.png?branch=master)](http://travis-ci.org/ekmett/discrimination)+[![Hackage](https://img.shields.io/hackage/v/discrimination.svg)](https://hackage.haskell.org/package/discrimination) [![Build Status](https://secure.travis-ci.org/ekmett/discrimination.png?branch=master)](http://travis-ci.org/ekmett/discrimination)  This package provides linear time sorting, partitioning, and joins for a wide array of Haskell data types. This work is based on a "final encoding" of the ideas presented in [multiple](http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011a.pdf) [papers](http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011c.pdf) and [talks](https://www.youtube.com/watch?v=sz9ZlZIRDAg) by [Fritz Henglein](http://www.diku.dk/hjemmesider/ansatte/henglein/).
+ benchmarks/wordmap.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+{-# OPTIONS_GHC -Wall -funbox-strict-fields -fno-warn-orphans -fno-warn-type-defaults -O2 #-}+{-# OPTIONS_GHC -fno-full-laziness #-}+module Main where++import Control.DeepSeq+import Control.Exception (evaluate)+import Criterion.Main+import Criterion.Types+import Data.Discrimination.Internal.WordMap+import Data.Foldable+import Data.HashMap.Lazy (HashMap)+import Data.Maybe (fromMaybe)+import Data.Word+import Prelude hiding (lookup, length, foldr)+import qualified Data.IntMap as M+import qualified Data.HashMap.Lazy as H++main :: IO ()+main = do+    evaluate $ rnf [denseM, sparseM, sparseM']+    evaluate $ rnf [denseW, sparseW, sparseW']+    evaluate $ rnf [denseH, sparseH, sparseH']+    evaluate $ rnf [elems,  sElems,  sElemsSearch]+    evaluate $ rnf [keys,   sKeys, sKeysSearch]+    evaluate $ rnf [values, sValues]+    evaluate $ rnf [welems,  wsElems,  wsElemsSearch]+    evaluate $ rnf [wkeys,   wsKeys, wsKeysSearch]+    evaluate $ rnf [wvalues, wsValues]+    defaultMainWith (defaultConfig { timeLimit = 1 })+        [ bgroup "lookup"+            [ bgroup "present"+                [ bench "IntMap"  $ whnf (\m -> foldl' (\n k -> fromMaybe n (M.lookup k m)) 0 keys) denseM+                , bench "WordMap" $ whnf (\m -> foldl' (\n k -> fromMaybe n (lookup k m)) 0 wkeys) denseW+                , bench "HashMap" $ whnf (\m -> foldl' (\n k -> fromMaybe n (H.lookup k m)) 0 wkeys) denseH+                ]+            , bgroup "absent"+                [ bench "IntMap"  $ whnf (\m -> foldl' (\n k -> fromMaybe n (M.lookup k m)) 0 sKeysSearch) sparseM+                , bench "WordMap" $ whnf (\m -> foldl' (\n k -> fromMaybe n (lookup k m)) 0 wsKeysSearch) sparseW+                , bench "HashMap" $ whnf (\m -> foldl' (\n k -> fromMaybe n (H.lookup k m)) 0 wsKeysSearch) sparseH+                ]+            ]+        , bgroup "insert"+            [ bgroup "present"+                [ bench "IntMap"  $ whnf (\m0 -> foldl' (\m (k, v) -> M.insert k v m) m0 elems) denseM+                , bench "WordMap" $ whnf (\m0 -> foldl' (\m (k, v) -> insert k v m) m0 welems) denseW+                , bench "HashMap" $ whnf (\m0 -> foldl' (\m (k, v) -> H.insert k v m) m0 welems) denseH+                ]+            , bgroup "absent"+                [ bench "IntMap" $ whnf (\m0 -> foldl' (\m (k, v) -> M.insert k v m) m0 sElemsSearch) sparseM+                , bench "WordMap" $ whnf (\m0 -> foldl' (\m (k, v) -> insert k v m) m0 wsElemsSearch) sparseW+                , bench "HashMap" $ whnf (\m0 -> foldl' (\m (k, v) -> H.insert k v m) m0 wsElemsSearch) sparseH+                ]+            ]+        , bgroup "member"+            [ bgroup "present"+                [ bench "IntMap"  $ whnf (\m -> foldl' (\n x -> if M.member x m then n + 1 else n) (0 :: Int) keys) denseM+                , bench "WordMap" $ whnf (\m -> foldl' (\n x -> if member x m then n + 1 else n) (0 :: Int) wkeys) denseW+                , bench "HashMap" $ whnf (\m -> foldl' (\n x -> if H.member x m then n + 1 else n) (0 :: Int) wkeys) denseH+                ]+            , bgroup "absent"+                [ bench "IntMap"  $ whnf (\m -> foldl' (\n x -> if M.member x m then n + 1 else n) (0 :: Int) sKeysSearch) sparseM+                , bench "WordMap" $ whnf (\m -> foldl' (\n x -> if member x m then n + 1 else n) (0 :: Int) wsKeysSearch) sparseW+                , bench "HashMap" $ whnf (\m -> foldl' (\n x -> if H.member x m then n + 1 else n) (0 :: Int) wsKeysSearch) sparseH+                ]+            ]+        ]+  where+    denseM = M.fromAscList elems :: M.IntMap Int+    denseW = fromList welems :: WordMap Word64+    denseH = H.fromList welems :: HashMap Word64 Word64+    sparseM = M.fromAscList sElems :: M.IntMap Int+    sparseW = fromList wsElems :: WordMap Word64+    sparseH = H.fromList wsElems :: HashMap Word64 Word64+    sparseM' = M.fromAscList sElemsSearch :: M.IntMap Int+    sparseW' = fromList wsElemsSearch :: WordMap Word64+    sparseH' = H.fromList wsElemsSearch :: HashMap Word64 Word64++    elems = zip keys values+    keys = [1..2^12]+    values = [1..2^12]+    sElems = zip sKeys sValues+    sElemsSearch = zip sKeysSearch sValues+    sKeys = [1,3..2^12]+    sKeysSearch = [2,4..2^12]+    sValues = [1,3..2^12]++    welems = zip wkeys wvalues+    wkeys = [1..2^12]+    wvalues = [1..2^12]+    wsElems = zip wsKeys wsValues+    wsElemsSearch = zip wsKeysSearch wsValues+    wsKeys = [1,3..2^12]+    wsKeysSearch = [2,4..2^12]+    wsValues = [1,3..2^12]
discrimination.cabal view
@@ -1,8 +1,8 @@ name:          discrimination category:      Data, Sorting-version:       0.1+version:       0.2.1 license:       BSD3-cabal-version: >= 1.10+cabal-version: >= 1.22 license-file:  LICENSE author:        Edward A. Kmett maintainer:    Edward A. Kmett <ekmett@gmail.com>@@ -11,7 +11,7 @@ bug-reports:   http://github.com/ekmett/discrimination/issues copyright:     Copyright (C) 2014-2015 Edward A. Kmett build-type:    Simple-tested-with:   GHC == 7.8.4+tested-with:   GHC == 7.10.1 synopsis:      Fast generic linear-time sorting, joins and container construction. description:   This package provides fast, generic, linear-time discrimination and sorting.@@ -38,6 +38,8 @@     Data.Discrimination.Class     Data.Discrimination.Grouping     Data.Discrimination.Internal+    Data.Discrimination.Internal.SmallArray+    Data.Discrimination.Internal.WordMap     Data.Discrimination.Sorting    build-depends:@@ -47,10 +49,28 @@     contravariant >= 1.3.1  && < 2,     deepseq       >= 1.3    && < 1.5,     ghc-prim,+    hashable      >= 1.2    && < 1.3,     primitive     >= 0.6    && < 0.7,     profunctors   >= 5      && < 6,-    promises      >= 0.2    && < 0.3,+    promises      >= 0.2    && < 0.4,     semigroups    >= 0.16.2 && < 1,-    transformers  >= 0.2    && < 0.5,-    vector        >= 0.10   && < 0.11,+    transformers  >= 0.2    && < 0.6,+    transformers-compat >= 0.3 && < 1,+    vector        >= 0.10   && < 0.12,     void          >= 0.5    && < 1++benchmark wordmap+  type:             exitcode-stdio-1.0+  main-is:          wordmap.hs+  ghc-options:      -Wall -O2 -threaded +  hs-source-dirs:   benchmarks+  default-language: Haskell2010+  build-depends:+    base >= 4.8,+    containers,+    criterion,+    deepseq,+    discrimination,+    ghc-prim,+    unordered-containers,+    primitive
src/Data/Discrimination/Grouping.hs view
@@ -24,27 +24,27 @@   , groupingEq   , runGroup   -- * Internals-  , groupingNat+  , hashing   ) where  import Control.Monad hiding (mapM_) import Control.Monad.Primitive import Control.Monad.ST-import Data.Bits import Data.Complex+import Data.Discrimination.Internal.WordMap as WordMap import Data.Foldable hiding (concat) import Data.Functor.Compose import Data.Functor.Contravariant import Data.Functor.Contravariant.Divisible import Data.Functor.Contravariant.Generic+import Data.Hashable import Data.Int-import Data.Monoid hiding (Any)+import Data.Semigroup hiding (Any) import Data.Primitive.MutVar import Data.Promise import Data.Proxy import Data.Ratio import Data.Typeable-import qualified Data.Vector.Mutable as UM import Data.Void import Data.Word import Prelude hiding (read, concat, mapM_)@@ -83,21 +83,35 @@    lose k = Group $ \_ -> return (absurd . k) +instance Semigroup (Group a) where+  (<>) = divide (\a -> (a,a))+ instance Monoid (Group a) where   mempty = conquer-  mappend = divide (\a -> (a,a))+  mappend = (<>)  -------------------------------------------------------------------------------- -- Primitives -------------------------------------------------------------------------------- -groupingNat :: Int -> Group Int-groupingNat = \ n -> Group $ \k -> do-  t <- UM.replicate n Nothing-  return $ \ a b -> UM.read t a >>= \case-    Nothing -> k b >>= UM.write t a . Just-    Just k' -> k' b+groupingWord64 :: Group Word64+groupingWord64 = Group $ \k -> do+  mt <- newMutVar WordMap.empty+  return $ \a b -> readMutVar mt >>= \m -> case WordMap.lookup a m of+    Nothing -> k b >>= \p -> writeMutVar mt (insert a p m)+    Just n -> n b +-- | This may be useful for pragmatically accelerating a grouping structure by+-- preclassifying by a hash function+--+-- Semantically,+--+-- @+-- grouping = hashing <> grouping+-- @+hashing :: Hashable a => Group a+hashing = contramap hash grouping+ -------------------------------------------------------------------------------- -- * Unordered Discrimination (for partitioning) --------------------------------------------------------------------------------@@ -119,52 +133,17 @@ instance Grouping Void where   grouping = lose id -instance Grouping Word8 where-  grouping = contramap fromIntegral (groupingNat 256)--instance Grouping Word16 where-  grouping = divide (\x -> (fromIntegral (unsafeShiftR x 8), fromIntegral x .&. 0xff)) (groupingNat 256) (groupingNat 256)--instance Grouping Word32 where-  grouping = divide (\x -> ( (fromIntegral (unsafeShiftR x 24)        , fromIntegral (unsafeShiftR x 16) .&. 0xff)-                           , (fromIntegral (unsafeShiftR x 8) .&. 0xff, fromIntegral x                   .&. 0xff)-                           )-                    )-    (divide id (groupingNat 256) (groupingNat 256))-    (divide id (groupingNat 256) (groupingNat 256))--instance Grouping Word64 where-  grouping = divide (\x ->-      ( ( (fromIntegral (unsafeShiftR x 56)         , fromIntegral (unsafeShiftR x 48) .&. 0xff)-        , (fromIntegral (unsafeShiftR x 40) .&. 0xff, fromIntegral (unsafeShiftR x 32) .&. 0xff)-        ),-        ( (fromIntegral (unsafeShiftR x 24) .&. 0xff, fromIntegral (unsafeShiftR x 16) .&. 0xff)-        , (fromIntegral (unsafeShiftR x 8)  .&. 0xff, fromIntegral x                   .&. 0xff)-        )-      )-    )-    (divide id (divide id (groupingNat 256) (groupingNat 256)) (divide id (groupingNat 256) (groupingNat 256)))-    (divide id (divide id (groupingNat 256) (groupingNat 256)) (divide id (groupingNat 256) (groupingNat 256)))--instance Grouping Word where-  grouping-    | (maxBound :: Word) == 4294967295 = contramap (fromIntegral :: Word -> Word32) grouping-    | otherwise                        = contramap (fromIntegral :: Word -> Word64) grouping--instance Grouping Int8 where-  grouping = contramap (\x -> fromIntegral x + 128) (groupingNat 256)--instance Grouping Int16 where-  grouping = contramap (\x -> fromIntegral (x - minBound) :: Word16) grouping--instance Grouping Int32 where-  grouping = contramap (\x -> fromIntegral (x - minBound) :: Word32) grouping--instance Grouping Int64 where-  grouping = contramap (\x -> fromIntegral (x - minBound) :: Word64) grouping--instance Grouping Int where-  grouping = contramap (\x -> fromIntegral (x - minBound) :: Word) grouping+instance Grouping Word8 where grouping = contramap fromIntegral groupingWord64+instance Grouping Word16 where grouping = contramap fromIntegral groupingWord64+instance Grouping Word32 where grouping = contramap fromIntegral groupingWord64+instance Grouping Word64 where grouping = groupingWord64+instance Grouping Word where grouping = contramap fromIntegral groupingWord64+instance Grouping Int8 where grouping = contramap fromIntegral groupingWord64+instance Grouping Int16 where grouping = contramap fromIntegral groupingWord64+instance Grouping Int32 where grouping = contramap fromIntegral groupingWord64+instance Grouping Int64 where grouping = contramap fromIntegral groupingWord64+instance Grouping Int where grouping = contramap fromIntegral groupingWord64+instance Grouping Char where grouping = contramap (fromIntegral . fromEnum) groupingWord64  instance Grouping Bool instance (Grouping a, Grouping b) => Grouping (a, b)@@ -208,7 +187,7 @@   k a ()   k b ()   n <- readMutVar rn-  return $ n == 2+  return $ n == 1 {-# INLINE groupingEq #-}  runGroup :: Group a -> [(a,b)] -> [[b]]@@ -237,7 +216,7 @@ -- -- This combinator still operates in linear time, at the expense of storing history. ----- The result equivalence classes are _not_ sorted, but the grouping is stable.+-- The result equivalence classes are __not__ sorted, but the grouping is stable. -- -- @ -- 'group' = 'groupWith' 'id'@@ -247,7 +226,7 @@  -- | /O(n)/. This is a replacement for 'GHC.Exts.groupWith' using discrimination. ----- The result equivalence classes are _not_ sorted, but the grouping is stable.+-- The result equivalence classes are __not__ sorted, but the grouping is stable. groupWith :: Grouping b => (a -> b) -> [a] -> [[a]] groupWith f as = runGroup grouping [(f a, a) | a <- as] 
+ src/Data/Discrimination/Internal/SmallArray.hs view
@@ -0,0 +1,232 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE DeriveDataTypeable #-}+--------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Edward Kmett 2015+-- License     : BSD-style+-- Maintainer  : Edward Kmett <ekmett@gmail.com>+-- Portability : non-portable+--+-- Small primitive boxed arrays+--+--------------------------------------------------------------------------------+module Data.Discrimination.Internal.SmallArray (+  SmallArray(..), SmallMutableArray(..),+  newSmallArray, readSmallArray, writeSmallArray, indexSmallArray, indexSmallArrayM,+  unsafeFreezeSmallArray, unsafeThawSmallArray, sameSmallMutableArray,+  copySmallArray, copySmallMutableArray,+  cloneSmallArray, cloneSmallMutableArray+) where++import Control.DeepSeq+import Control.Monad.Primitive+import Data.Foldable as Foldable+import GHC.Exts+import GHC.ST++-- | Boxed arrays+data SmallArray a = SmallArray (SmallArray# a)++-- | Mutable boxed arrays associated with a primitive state token.+data SmallMutableArray s a = SmallMutableArray (SmallMutableArray# s a)++-- | Create a new mutable array of the specified size and initialise all+-- elements with the given value.+newSmallArray :: PrimMonad m => Int -> a -> m (SmallMutableArray (PrimState m) a)+{-# INLINE newSmallArray #-}+newSmallArray (I# n#) x = primitive+   (\s# -> case newSmallArray# n# x s# of+             (# s'#, arr# #) -> (# s'#, SmallMutableArray arr# #))++-- | Read a value from the array at the given index.+readSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> m a+{-# INLINE readSmallArray #-}+readSmallArray (SmallMutableArray arr#) (I# i#) = primitive (readSmallArray# arr# i#)++-- | Write a value to the array at the given index.+writeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> a -> m ()+{-# INLINE writeSmallArray #-}+writeSmallArray (SmallMutableArray arr#) (I# i#) x = primitive_ (writeSmallArray# arr# i# x)++-- | Read a value from the immutable array at the given index.+indexSmallArray :: SmallArray a -> Int -> a+{-# INLINE indexSmallArray #-}+indexSmallArray (SmallArray arr#) (I# i#) = case indexSmallArray# arr# i# of (# x #) -> x++-- | Monadically read a value from the immutable array at the given index.+-- This allows us to be strict in the array while remaining lazy in the read+-- element which is very useful for collective operations. Suppose we want to+-- copy an array. We could do something like this:+--+-- > copy marr arr ... = do ...+-- >                        writeSmallArray marr i (indexSmallArray arr i) ...+-- >                        ...+--+-- But since primitive arrays are lazy, the calls to 'indexSmallArray' will not be+-- evaluated. Rather, @marr@ will be filled with thunks each of which would+-- retain a reference to @arr@. This is definitely not what we want!+--+-- With 'indexSmallArrayM', we can instead write+--+-- > copy marr arr ... = do ...+-- >                        x <- indexSmallArrayM arr i+-- >                        writeSmallArray marr i x+-- >                        ...+--+-- Now, indexing is executed immediately although the returned element is+-- still not evaluated.+--+indexSmallArrayM :: Monad m => SmallArray a -> Int -> m a+{-# INLINE indexSmallArrayM #-}+indexSmallArrayM (SmallArray arr#) (I# i#)+  = case indexSmallArray# arr# i# of (# x #) -> return x++-- | Convert a mutable array to an immutable one without copying. The+-- array should not be modified after the conversion.+unsafeFreezeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> m (SmallArray a)+{-# INLINE unsafeFreezeSmallArray #-}+unsafeFreezeSmallArray (SmallMutableArray arr#)+  = primitive (\s# -> case unsafeFreezeSmallArray# arr# s# of+                        (# s'#, arr'# #) -> (# s'#, SmallArray arr'# #))++-- | Convert an immutable array to an mutable one without copying. The+-- immutable array should not be used after the conversion.+unsafeThawSmallArray :: PrimMonad m => SmallArray a -> m (SmallMutableArray (PrimState m) a)+{-# INLINE unsafeThawSmallArray #-}+unsafeThawSmallArray (SmallArray arr#)+  = primitive (\s# -> case unsafeThawSmallArray# arr# s# of+                        (# s'#, arr'# #) -> (# s'#, SmallMutableArray arr'# #))++-- | Check whether the two arrays refer to the same memory block.+sameSmallMutableArray :: SmallMutableArray s a -> SmallMutableArray s a -> Bool+{-# INLINE sameSmallMutableArray #-}+sameSmallMutableArray (SmallMutableArray arr#) (SmallMutableArray brr#)+  = isTrue# (sameSmallMutableArray# arr# brr#)++-- | Copy a slice of an immutable array to a mutable array.+copySmallArray :: PrimMonad m+          => SmallMutableArray (PrimState m) a    -- ^ destination array+          -> Int                             -- ^ offset into destination array+          -> SmallArray a                         -- ^ source array+          -> Int                             -- ^ offset into source array+          -> Int                             -- ^ number of elements to copy+          -> m ()+{-# INLINE copySmallArray #-}+copySmallArray (SmallMutableArray dst#) (I# doff#) (SmallArray src#) (I# soff#) (I# len#)+  = primitive_ (copySmallArray# src# soff# dst# doff# len#)++-- | Copy a slice of a mutable array to another array. The two arrays may+-- not be the same.+copySmallMutableArray :: PrimMonad m+          => SmallMutableArray (PrimState m) a    -- ^ destination array+          -> Int                             -- ^ offset into destination array+          -> SmallMutableArray (PrimState m) a    -- ^ source array+          -> Int                             -- ^ offset into source array+          -> Int                             -- ^ number of elements to copy+          -> m ()+{-# INLINE copySmallMutableArray #-}+-- NOTE: copySmallArray# and copySmallMutableArray# are slightly broken in GHC 7.6.* and earlier+copySmallMutableArray (SmallMutableArray dst#) (I# doff#)+                 (SmallMutableArray src#) (I# soff#) (I# len#)+  = primitive_ (copySmallMutableArray# src# soff# dst# doff# len#)++-- | Return a newly allocated SmallArray with the specified subrange of the+-- provided SmallArray. The provided SmallArray should contain the full subrange+-- specified by the two Ints, but this is not checked.+cloneSmallArray :: SmallArray a -- ^ source array+           -> Int     -- ^ offset into destination array+           -> Int     -- ^ number of elements to copy+           -> SmallArray a+{-# INLINE cloneSmallArray #-}+cloneSmallArray (SmallArray arr#) (I# off#) (I# len#) +  = case cloneSmallArray# arr# off# len# of arr'# -> SmallArray arr'#++-- | Return a newly allocated SmallMutableArray. with the specified subrange of+-- the provided SmallMutableArray. The provided SmallMutableArray should contain the+-- full subrange specified by the two Ints, but this is not checked.+cloneSmallMutableArray :: PrimMonad m+        => SmallMutableArray (PrimState m) a -- ^ source array+        -> Int                          -- ^ offset into destination array+        -> Int                          -- ^ number of elements to copy+        -> m (SmallMutableArray (PrimState m) a)+{-# INLINE cloneSmallMutableArray #-}+cloneSmallMutableArray (SmallMutableArray arr#) (I# off#) (I# len#) = primitive+   (\s# -> case cloneSmallMutableArray# arr# off# len# s# of+             (# s'#, arr'# #) -> (# s'#, SmallMutableArray arr'# #))++instance IsList (SmallArray a) where+  type Item (SmallArray a) = a+  toList = Foldable.toList+  fromListN n xs0 = runST $ do+    arr <- newSmallArray n undefined+    let go !_ []     = return ()+        go k (x:xs) = writeSmallArray arr k x >> go (k+1) xs+    go 0 xs0+    unsafeFreezeSmallArray arr+  fromList xs = fromListN (Prelude.length xs) xs++instance Functor SmallArray where+  fmap f !i = runST $ do+    let n = length i+    o <- newSmallArray n undefined+    let go !k+          | k == n = return ()+          | otherwise = do+            a <- indexSmallArrayM i k+            writeSmallArray o k (f a)+            go (k+1)+    go 0+    unsafeFreezeSmallArray o++instance Foldable SmallArray where+  foldr f z arr = go 0 where+    n = length arr+    go !k+      | k == n    = z+      | otherwise = f (indexSmallArray arr k) (go (k+1))++  foldl f z arr = go (length arr - 1) where+    go !k+      | k < 0 = z+      | otherwise = f (go (k-1)) (indexSmallArray arr k)++  foldr' f z arr = go 0 where+    n = length arr+    go !k+      | k == n    = z+      | r <- indexSmallArray arr k = r `seq` f r (go (k+1))++  foldl' f z arr = go (length arr - 1) where+    go !k+      | k < 0 = z+      | r <- indexSmallArray arr k = r `seq` f (go (k-1)) r++  length (SmallArray ary) = I# (sizeofSmallArray# ary)+  {-# INLINE length #-}++instance Traversable SmallArray where+  traverse f a = fromListN (length a) <$> traverse f (Foldable.toList a)++instance Show a => Show (SmallArray a) where+  showsPrec d as = showParen (d > 10) $+    showString "fromList " . showsPrec 11 (Foldable.toList as)++instance Read a => Read (SmallArray a) where+  readsPrec d = readParen (d > 10) $ \s -> [(fromList m, u) | ("fromList", t) <- lex s, (m,u) <- readsPrec 11 t]++instance Ord a => Ord (SmallArray a) where+  compare as bs = compare (Foldable.toList as) (Foldable.toList bs)++instance Eq a => Eq (SmallArray a) where+  as == bs = Foldable.toList as == Foldable.toList bs++instance NFData a => NFData (SmallArray a) where+  rnf a0 = go a0 (length a0) 0 where+    go !a !n !i+      | i >= n = ()+      | otherwise = rnf (indexSmallArray a i) `seq` go a n (i+1)+  {-# INLINE rnf #-}
+ src/Data/Discrimination/Internal/WordMap.hs view
@@ -0,0 +1,249 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+{-# OPTIONS_GHC -Wall -funbox-strict-fields -fno-warn-orphans -fno-warn-type-defaults -O2 #-}+#ifdef ST_HACK+{-# OPTIONS_GHC -fno-full-laziness #-}+#endif+--------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Edward Kmett 2015+-- License     : BSD-style+-- Maintainer  : Edward Kmett <ekmett@gmail.com>+-- Portability : non-portable+--+-- This module suppose a Word64-based array-mapped PATRICIA Trie.+--+-- The most significant nybble is isolated by using techniques based on+-- <https://www.fpcomplete.com/user/edwardk/revisiting-matrix-multiplication/part-4>+-- but modified to work nybble-by-nybble rather than bit-by-bit.+--+--------------------------------------------------------------------------------+module Data.Discrimination.Internal.WordMap+  ( WordMap+  , singleton+  , empty+  , insert+  , lookup+  , member+  , fromList+  ) where++import Control.Applicative hiding (empty)+import Control.DeepSeq+import Control.Monad.ST hiding (runST)+import Data.Bits+import Data.Discrimination.Internal.SmallArray+import Data.Foldable+import Data.Functor+import Data.Monoid+import Data.Traversable+import Data.Word+import qualified GHC.Exts as Exts+import Prelude hiding (lookup, length, foldr)+import GHC.Types+import GHC.ST++type Key = Word64+type Mask = Word16+type Offset = Int++ptrEq :: a -> a -> Bool+ptrEq x y = isTrue# (Exts.reallyUnsafePtrEquality# x y Exts.==# 1#)+{-# INLINEABLE ptrEq #-}++ptrNeq :: a -> a -> Bool+ptrNeq x y = isTrue# (Exts.reallyUnsafePtrEquality# x y Exts./=# 1#)+{-# INLINEABLE ptrNeq #-}++data WordMap v+  = Full !Key !Offset !(SmallArray (WordMap v))+  | Node !Key !Offset !Mask !(SmallArray (WordMap v))+  | Tip  !Key v+  | Nil+  deriving Show++node :: Key -> Offset -> Mask -> SmallArray (WordMap v) -> WordMap v+node k o 0xffff a = Full k o a+node k o m a      = Node k o m a+{-# INLINE node #-}++instance NFData v => NFData (WordMap v) where+  rnf (Full _ _ a)   = rnf a+  rnf (Node _ _ _ a) = rnf a+  rnf (Tip _ v) = rnf v+  rnf Nil = ()++instance Functor WordMap where+  fmap f = go where+    go (Full k o a) = Full k o (fmap go a)+    go (Node k o m a) = Node k o m (fmap go a)+    go (Tip k v) = Tip k (f v)+    go Nil = Nil+  {-# INLINEABLE fmap #-}++instance Foldable WordMap where+  foldMap f = go where+    go (Full _ _ a) = foldMap go a+    go (Node _ _ _ a) = foldMap go a+    go (Tip _ v) = f v+    go Nil = mempty+  {-# INLINEABLE foldMap #-}++instance Traversable WordMap where+  traverse f = go where+    go (Full k o a) = Full k o <$> traverse go a+    go (Node k o m a) = Node k o m <$> traverse go a+    go (Tip k v) = Tip k <$> f v+    go Nil = pure Nil+  {-# INLINEABLE traverse #-}++-- Note: 'level 0' will return a negative shift, don't use it+level :: Key -> Int+level w = 60 - (countLeadingZeros w .&. 0x7c)+{-# INLINE level #-}++maskBit :: Key -> Offset -> Int+maskBit k o = fromIntegral (unsafeShiftR k o .&. 0xf)+{-# INLINE maskBit #-}++mask :: Key -> Offset -> Word16+mask k o = unsafeShiftL 1 (maskBit k o)+{-# INLINE mask #-}++-- offset :: Int -> Word16 -> Int+-- offset k w = popCount $ w .&. (unsafeShiftL 1 k - 1)+-- {-# INLINE offset #-}++fork :: Int -> Key -> WordMap v -> Key -> WordMap v -> WordMap v+fork o k n ok on = Node (k .&. unsafeShiftL 0xfffffffffffffff0 o) o (mask k o .|. mask ok o) $ runST $ do+  arr <- newSmallArray 2 n+  writeSmallArray arr (fromEnum (k < ok)) on+  unsafeFreezeSmallArray arr++insert :: Key -> v -> WordMap v -> WordMap v+insert !k v xs0 = go xs0 where+  go on@(Full ok n as)+    | wd > 0xf = fork (level okk) k (Tip k v) ok on+    | !oz <- indexSmallArray as d+    , !z <- go oz+    , ptrNeq z oz = Full ok n (update16 d z as)+    | otherwise = on+    where+      okk = xor ok k+      wd  = unsafeShiftR okk n+      d   = fromIntegral wd+  go on@(Node ok n m as)+    | wd > 0xf = fork (level okk) k (Tip k v) ok on+    | m .&. b == 0 = node ok n (m .|. b) (insertSmallArray odm (Tip k v) as)+    | !oz <- indexSmallArray as odm+    , !z <- go oz+    , ptrNeq z oz = Node ok n m (updateSmallArray odm z as)+    | otherwise = on+    where+      okk = xor ok k+      wd  = unsafeShiftR okk n+      d   = fromIntegral wd+      b   = unsafeShiftL 1 d+      odm = popCount $ m .&. (b - 1)+  go on@(Tip ok ov)+    | k /= ok    = fork (level (xor ok k)) k (Tip k v) ok on+    | ptrEq v ov = on+    | otherwise  = Tip k v+  go Nil = Tip k v+{-# INLINEABLE insert #-}+++lookup :: Key -> WordMap v -> Maybe v+lookup !k (Full ok o a)+  | z <- unsafeShiftR (xor k ok) o, z <= 0xf = lookup k $ indexSmallArray a (fromIntegral z)+  | otherwise = Nothing+lookup k (Node ok o m a)+  | z <= 0xf && m .&. b /= 0 = lookup k (indexSmallArray a (popCount (m .&. (b - 1))))+  | otherwise = Nothing+  where+    z = unsafeShiftR (xor k ok) o+    b = unsafeShiftL 1 (fromIntegral z)+lookup k (Tip ok ov)+  | k == ok   = Just ov+  | otherwise = Nothing+lookup _ Nil = Nothing+{-# INLINEABLE lookup #-}++member :: Key -> WordMap v -> Bool+member !k (Full ok o a)+  | z <- unsafeShiftR (xor k ok) o = z <= 0xf && member k (indexSmallArray a (fromIntegral z))+member k (Node ok o m a)+  | z <- unsafeShiftR (xor k ok) o+  = z <= 0xf && let b = unsafeShiftL 1 (fromIntegral z) in+    m .&. b /= 0 && member k (indexSmallArray a (popCount (m .&. (b - 1))))+member k (Tip ok _) = k == ok+member _ Nil = False+{-# INLINEABLE member #-}++updateSmallArray :: Int -> a -> SmallArray a -> SmallArray a+updateSmallArray !k a i = runST $ do+  let n = length i+  o <- newSmallArray n undefined+  copySmallArray o 0 i 0 n+  writeSmallArray o k a+  unsafeFreezeSmallArray o+{-# INLINEABLE updateSmallArray #-}++update16 :: Int -> a -> SmallArray a -> SmallArray a+update16 !k a i = runST $ do+  o <- clone16 i+  writeSmallArray o k a+  unsafeFreezeSmallArray o+{-# INLINEABLE update16 #-}++insertSmallArray :: Int -> a -> SmallArray a -> SmallArray a+insertSmallArray !k a i = runST $ do+  let n = length i+  o <- newSmallArray (n + 1) a+  copySmallArray  o 0 i 0 k+  copySmallArray  o (k+1) i k (n-k)+  unsafeFreezeSmallArray o+{-# INLINEABLE insertSmallArray #-}++clone16 :: SmallArray a -> ST s (SmallMutableArray s a)+clone16 i = do+  o <- newSmallArray 16 undefined+  indexSmallArrayM i 0 >>= writeSmallArray o 0+  indexSmallArrayM i 1 >>= writeSmallArray o 1+  indexSmallArrayM i 2 >>= writeSmallArray o 2+  indexSmallArrayM i 3 >>= writeSmallArray o 3+  indexSmallArrayM i 4 >>= writeSmallArray o 4+  indexSmallArrayM i 5 >>= writeSmallArray o 5+  indexSmallArrayM i 6 >>= writeSmallArray o 6+  indexSmallArrayM i 7 >>= writeSmallArray o 7+  indexSmallArrayM i 8 >>= writeSmallArray o 8+  indexSmallArrayM i 9 >>= writeSmallArray o 9+  indexSmallArrayM i 10 >>= writeSmallArray o 10+  indexSmallArrayM i 11 >>= writeSmallArray o 11+  indexSmallArrayM i 12 >>= writeSmallArray o 12+  indexSmallArrayM i 13 >>= writeSmallArray o 13+  indexSmallArrayM i 14 >>= writeSmallArray o 14+  indexSmallArrayM i 15 >>= writeSmallArray o 15+  return o+{-# INLINE clone16 #-}++-- | Build a singleton WordMap+singleton :: Key -> v -> WordMap v+singleton !k v = Tip k v+{-# INLINE singleton #-}++fromList :: [(Word64,v)] -> WordMap v+fromList xs = foldl' (\r (k,v) -> insert k v r) Nil xs+{-# INLINE fromList #-}++empty :: WordMap a+empty = Nil+{-# INLINE empty #-}
src/Data/Discrimination/Sorting.hs view
@@ -2,7 +2,6 @@ {-# LANGUAGE MagicHash #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-}-{-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE RoleAnnotations #-}@@ -51,8 +50,8 @@ import Data.IntSet as IntSet import qualified Data.List as List import Data.Map as Map-import Data.Monoid hiding (Any) import Data.Proxy+import Data.Semigroup hiding (Any) import Data.Set as Set import Data.Typeable import Data.Void@@ -84,14 +83,17 @@  instance Decidable Sort where   lose k = Sort $ fmap (absurd.k.fst)-  choose f (Sort l) (Sort r) = Sort $ \xs -> let +  choose f (Sort l) (Sort r) = Sort $ \xs -> let       ys = fmap (first f) xs     in l [ (k,v) | (Left k, v) <- ys]     ++ r [ (k,v) | (Right k, v) <- ys] +instance Semigroup (Sort a) where+  Sort l <> Sort r = Sort $ \xs -> l [ (fst x, x) | x <- xs ] >>= r+ instance Monoid (Sort a) where   mempty = conquer-  mappend (Sort l) (Sort r) = Sort $ \xs -> l [ (fst x, x) | x <- xs ] >>= r+  mappend = (<>)  -------------------------------------------------------------------------------- -- * Ordered Discrimination@@ -150,6 +152,11 @@ instance Sorting Int where   sorting = contramap (\x -> fromIntegral (x - minBound) :: Word) sorting +instance Sorting Char where+  sorting = Sort (runs <=< runSort (sortingNat 1087) . join . runSort (sortingNat 1024) . fmap radices) where+    radices (c,b) = (x .&. 0x3ff, (unsafeShiftR x 10, (x,b))) where+      x = fromEnum c+ -- TODO: Integer and Natural?  instance Sorting Void@@ -239,7 +246,7 @@ sort :: Sorting a => [a] -> [a] sort as = List.concat $ runSort sorting [ (a,a) | a <- as ] --- | /O(n)/. Sort a list with a Schwartzian transformation by using discrimination. +-- | /O(n)/. Sort a list with a Schwartzian transformation by using discrimination. -- -- This linear time replacement for 'GHC.Exts.sortWith' and 'Data.List.sortOn' uses discrimination. sortWith :: Sorting b => (a -> b) -> [a] -> [a]