hw-streams (empty) → 0.0.0.1
raw patch · 18 files changed
+602/−0 lines, 18 filesdep +QuickCheckdep +basedep +bytestringsetup-changed
Dependencies added: QuickCheck, base, bytestring, criterion, directory, exceptions, ghc-prim, hedgehog, hspec, hw-bits, hw-hspec-hedgehog, hw-prim, hw-streams, mmap, primitive, semigroups, transformers, vector
Files
- LICENSE +30/−0
- README.md +10/−0
- Setup.hs +2/−0
- bench/Baseline/Data/Streams/Vector/Storable.hs +9/−0
- bench/Main.hs +63/−0
- bench/Reference/Data/Streams/Vector/Storable.hs +8/−0
- hw-streams.cabal +123/−0
- src/HaskellWorks/Data/Streams/Internal.hs +5/−0
- src/HaskellWorks/Data/Streams/Internal/Bundle.hs +13/−0
- src/HaskellWorks/Data/Streams/Internal/Chunk.hs +12/−0
- src/HaskellWorks/Data/Streams/Size.hs +7/−0
- src/HaskellWorks/Data/Streams/Stream.hs +103/−0
- src/HaskellWorks/Data/Streams/Stream/Ops.hs +41/−0
- src/HaskellWorks/Data/Streams/Vector.hs +46/−0
- src/HaskellWorks/Data/Streams/Vector/Storable.hs +84/−0
- test/HaskellWorks/Data/Stream/Vector/StorableSpec.hs +33/−0
- test/Spec.hs +1/−0
- test/Test/Gen.hs +12/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright John Ky (c) 2016++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 Author name here 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,10 @@+# hw-streams++[](https://circleci.com/gh/haskell-works/hw-streams/tree/master)+[](https://travis-ci.org/haskell-works/hw-streams)++Pure streaming library.++This is a reproduction of the work in [Exploiting Vector Instructions with Generalized Stream Fusion][1]++[1]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/haskell-beats-C.pdf
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bench/Baseline/Data/Streams/Vector/Storable.hs view
@@ -0,0 +1,9 @@+module Baseline.Data.Streams.Vector.Storable where++import qualified Data.Vector.Storable as DVS+import qualified HaskellWorks.Data.Streams.Vector.Storable as DVS++-- | Version of map that does not do fusion+map :: (DVS.Storable a, DVS.Storable b) => (a -> b) -> DVS.Vector a -> DVS.Vector b+map f = DVS.unstream . fmap f . DVS.stream+{-# INLINE map #-}
+ bench/Main.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main where++import Control.Monad (join)+import Criterion.Main+import Data.Word++import qualified Baseline.Data.Streams.Vector.Storable as USDVS+import qualified Data.Vector.Storable as DVS+import qualified HaskellWorks.Data.Streams.Stream as S+import qualified HaskellWorks.Data.Streams.Vector.Storable as SDVS+import qualified Reference.Data.Streams.Vector.Storable as DVS++mkReplicateVector :: IO (DVS.Vector Word64)+mkReplicateVector = do+ let !v = DVS.replicate 100000 (0 :: Word64)+ return v++mkEnumVector :: IO (DVS.Vector Word64)+mkEnumVector = do+ let !v = SDVS.enumFromStepN 0 1 100000+ return v++mkEnumVector2 :: IO (DVS.Vector Word64, DVS.Vector Word64)+mkEnumVector2 = do+ let !v = SDVS.enumFromStepN 0 1 100000+ let !w = SDVS.enumFromStepN 0 1 100000+ return (v, w)++sumall :: DVS.Vector Word64 -> Word64+sumall = S.foldl (+) 123 . SDVS.stream . SDVS.map (+1) . SDVS.map (+1) . SDVS.map (+1)++runMap :: DVS.Vector Word64 -> DVS.Vector Word64+runMap = SDVS.map (+123) . SDVS.map (+123) . SDVS.map (+123)++runMapUnfused :: DVS.Vector Word64 -> DVS.Vector Word64+runMapUnfused = USDVS.map (+123) . USDVS.map (+123) . USDVS.map (+123)++benchThings :: [Benchmark]+benchThings = join $+ [ [ env mkReplicateVector $ \v -> bgroup "mkReplicateVector"+ [ bench "DVS.map" (whnf runMap v)+ , bench "DVS.mapUnfused" (whnf runMapUnfused v)+ ]+ ]+ , [ env mkEnumVector $ \v -> bgroup "mkEnumVector"+ [ bench "DVS.map" (whnf runMap v)+ , bench "DVS.mapUnfused" (whnf runMapUnfused v)+ , bench "DVS.sumall" (whnf sumall v)+ , bench "DVS.foldl" (whnf (SDVS.foldl (+) 0) v)+ ]+ ]+ , [ env mkEnumVector2 $ \ ~(v, w) -> bgroup "mkEnumVector2"+ [ bench "SDVS.dotp" (whnf (SDVS.dotp v) w)+ , bench "DVS.dotp" (whnf (DVS.dotp v) w)+ ]+ ]+ ]++main :: IO ()+main = defaultMain benchThings
+ bench/Reference/Data/Streams/Vector/Storable.hs view
@@ -0,0 +1,8 @@+module Reference.Data.Streams.Vector.Storable where++import Data.Vector.Storable (Storable)++import qualified Data.Vector.Storable as DVS++dotp :: (Storable a, Num a) => DVS.Vector a -> DVS.Vector a -> a+dotp v w = DVS.sum (DVS.zipWith (*) v w)
+ hw-streams.cabal view
@@ -0,0 +1,123 @@+-- This file has been generated from package.yaml by hpack version 0.18.1.+--+-- see: https://github.com/sol/hpack++name: hw-streams+version: 0.0.0.1+synopsis: Primitive functions and data types+description: Primitive functions and data types.+category: Data+stability: Experimental+homepage: http://github.com/haskell-works/hw-streams#readme+bug-reports: https://github.com/haskell-works/hw-streams/issues+author: John Ky+maintainer: newhoggy@gmail.com+copyright: 2016-2018 John Ky+license: BSD3+license-file: LICENSE+tested-with: GHC == 8.4.2, GHC == 8.2.2, GHC == 8.0.2, GHC == 7.10.3+build-type: Simple+cabal-version: >= 1.10++extra-source-files:+ README.md++source-repository head+ type: git+ location: https://github.com/haskell-works/hw-streams++flag bounds-checking-enabled+ description: Enable bmi2 instruction set+ manual: False+ default: False++library+ hs-source-dirs:+ src+ other-extensions: AllowAmbiguousTypes+ ghc-options: -Wall -O2 -msse4.2+ build-depends:+ base >= 4.8 && < 5+ , bytestring >= 0.9 && < 0.11+ , ghc-prim >= 0.5.1.1 && < 0.6+ , hw-bits >= 0.7.0.3 && < 0.8+ , hw-prim >= 0.6.2.17 && < 0.7+ , mmap >= 0.5 && < 0.6+ , primitive >= 0.6.3.0 && < 0.7+ , vector >= 0.12 && < 0.13+ , semigroups >= 0.8.4 && < 0.19+ , transformers >= 0.4 && < 0.6+ if flag(bounds-checking-enabled)+ cpp-options: -DBOUNDS_CHECKING_ENABLED+ exposed-modules:+ HaskellWorks.Data.Streams.Internal+ HaskellWorks.Data.Streams.Internal.Bundle+ HaskellWorks.Data.Streams.Internal.Chunk+ HaskellWorks.Data.Streams.Size+ HaskellWorks.Data.Streams.Stream+ HaskellWorks.Data.Streams.Stream.Ops+ HaskellWorks.Data.Streams.Vector+ HaskellWorks.Data.Streams.Vector.Storable+ other-modules:+ Paths_hw_streams+ default-language: Haskell2010++test-suite hw-streams-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs:+ test+ other-extensions: AllowAmbiguousTypes+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >= 4.8 && < 5+ , bytestring >= 0.9 && < 0.11+ , ghc-prim >= 0.5.1.1 && < 0.6+ , hw-bits >= 0.7.0.3 && < 0.8+ , hw-prim >= 0.6.2.17 && < 0.7+ , mmap >= 0.5 && < 0.6+ , primitive >= 0.6.3.0 && < 0.7+ , vector >= 0.12 && < 0.13+ , semigroups >= 0.8.4 && < 0.19+ , transformers >= 0.4 && < 0.6+ , QuickCheck >= 2.10 && < 2.12+ , directory >= 1.2 && < 1.4+ , exceptions >= 0.8 && < 0.11+ , hedgehog >= 0.5 && < 0.7+ , hspec >= 2.4 && < 2.6+ , hw-hspec-hedgehog >= 0.1 && < 0.2+ , hw-streams+ if flag(bounds-checking-enabled)+ cpp-options: -DBOUNDS_CHECKING_ENABLED+ other-modules:+ HaskellWorks.Data.Stream.Vector.StorableSpec+ Test.Gen+ default-language: Haskell2010++benchmark bench+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs:+ bench+ other-extensions: AllowAmbiguousTypes+ ghc-options: -Wall -O2 -msse4.2+ build-depends:+ base >= 4.8 && < 5+ , bytestring >= 0.9 && < 0.11+ , ghc-prim >= 0.5.1.1 && < 0.6+ , hw-bits >= 0.7.0.3 && < 0.8+ , hw-prim >= 0.6.2.17 && < 0.7+ , mmap >= 0.5 && < 0.6+ , primitive >= 0.6.3.0 && < 0.7+ , vector >= 0.12 && < 0.13+ , semigroups >= 0.8.4 && < 0.19+ , transformers >= 0.4 && < 0.6+ , criterion >= 1.2 && < 1.6+ , hw-streams+ , mmap >= 0.5 && < 0.6+ if flag(bounds-checking-enabled)+ cpp-options: -DBOUNDS_CHECKING_ENABLED+ other-modules:+ Baseline.Data.Streams.Vector.Storable+ Reference.Data.Streams.Vector.Storable+ default-language: Haskell2010
+ src/HaskellWorks/Data/Streams/Internal.hs view
@@ -0,0 +1,5 @@+module HaskellWorks.Data.Streams.Internal where++inplace :: a -> a+inplace = id+{-# INLINE [1] inplace #-}
+ src/HaskellWorks/Data/Streams/Internal/Bundle.hs view
@@ -0,0 +1,13 @@+module HaskellWorks.Data.Streams.Internal.Bundle where++import HaskellWorks.Data.Streams.Internal.Chunk (Chunk)++import qualified HaskellWorks.Data.Streams.Stream as S++type Size = Int++data Bundle a = Bundle+ { bundleSize :: Size+ , bundleElems :: S.Stream a+ , bundleChunks :: S.Stream (Chunk a)+ }
+ src/HaskellWorks/Data/Streams/Internal/Chunk.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE RankNTypes #-}++module HaskellWorks.Data.Streams.Internal.Chunk where++import Control.Monad.Primitive++import qualified Data.Vector.Storable as DVS++data Chunk a = Chunk+ { chunkSize :: Int+ , chunkWrite :: forall m. PrimMonad m => DVS.MVector (PrimState m) a -> m ()+ }
+ src/HaskellWorks/Data/Streams/Size.hs view
@@ -0,0 +1,7 @@+module HaskellWorks.Data.Streams.Size+ ( Size(..)+ , smaller+ , larger+ ) where++import Data.Vector.Fusion.Bundle.Size
+ src/HaskellWorks/Data/Streams/Stream.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE GADTs #-}++module HaskellWorks.Data.Streams.Stream where++import Data.Bool+import HaskellWorks.Data.Streams.Size++import Prelude hiding (drop, zipWith)++data Stream a where+ Stream :: ()+ => (s -> Step s a)+ -> s+ -> Size+ -> Stream a++instance Functor Stream where+ fmap f (Stream step s i) = Stream (fmap f <$> step) s i+ {-# INLINE fmap #-}++data Step s a+ = Yield a s+ | Skip s+ | Done++instance Functor (Step s) where+ fmap f (Yield a s) = Yield (f a) s+ fmap _ (Skip s) = Skip s+ fmap _ Done = Done+ {-# INLINE fmap #-}++zipWith :: (a -> b -> c) -> Stream a -> Stream b -> Stream c+zipWith f (Stream stepa sa na) (Stream stepb sb nb) = Stream step (sa, sb, Nothing) (smaller na nb)+ where step (ta, tb, Nothing) = case stepa ta of+ Yield xa ta0 -> Skip (ta0, tb, Just xa)+ Skip ta0 -> Skip (ta0, tb, Nothing)+ Done -> Done+ step (ta, tb, Just xa) = case stepb tb of+ Yield y tb0 -> Yield (f xa y) (ta, tb0, Nothing)+ Skip tb0 -> Skip (ta, tb0, Just xa)+ Done -> Done+ {-# INLINE [0] step #-}+{-# INLINE [1] zipWith #-}++zipWithState :: (a -> b -> s -> (c, s)) -> s -> Stream a -> Stream b -> Stream c+zipWithState f state (Stream stepa sa na) (Stream stepb sb nb) = Stream step (sa, sb, Nothing, state) (smaller na nb)+ where step (ta, tb, Nothing, oldState) = case stepa ta of+ Yield xa ta0 -> Skip (ta0, tb, Just xa, oldState)+ Skip ta0 -> Skip (ta0, tb, Nothing, oldState)+ Done -> Done+ step (ta, tb, Just xa, oldState) = case stepb tb of+ Yield y tb0 -> let (newValue, newState) = f xa y state in Yield newValue (ta, tb0, Nothing, newState)+ Skip tb0 -> Skip (ta, tb0, Just xa, oldState)+ Done -> Done+ {-# INLINE [0] step #-}+{-# INLINE [1] zipWithState #-}++enumFromStepN :: Num a => a -> a -> Int -> Stream a+enumFromStepN x y n = x `seq` y `seq` n `seq` Stream step (x, n) (Exact n)+ where step (w, m) | m > 0 = Yield w (w + y, m - 1)+ | otherwise = Done+ {-# INLINE [0] step #-}+{-# INLINE [1] enumFromStepN #-}++foldl :: (a -> b -> a) -> a -> Stream b -> a+foldl f z (Stream step s _) = loop z s+ where loop za sa = za `seq` case step sa of+ Yield x sb -> loop (f za x) sb+ Skip sb -> loop za sb+ Done -> za+{-# INLINE [1] foldl #-}++drop :: Int -> Stream a -> Stream a+drop n s@(Stream step state size) = if n > 0+ then case step state of+ Yield _ newState -> drop (n - 1) $ Stream step newState (size - 1)+ Skip newState -> drop n $ Stream step newState size+ Done -> s+ else s++{-# RULES+ "zipWith xs xs [Vector.Stream]" forall f xs. zipWith f xs xs = fmap (\x -> f x x) xs #-}++append :: Stream a -> Stream a -> Stream a+append (Stream stepa ta na) (Stream stepb tb nb) = Stream step (Left ta) (na + nb)+ where step (Left sa) = case stepa sa of+ Yield x sa' -> Yield x (Left sa')+ Skip sa' -> Skip (Left sa')+ Done -> Skip (Right tb)+ step (Right sb) = case stepb sb of+ Yield x sb' -> Yield x (Right sb')+ Skip sb' -> Skip (Right sb')+ Done -> Done+ {-# INLINE step #-}+{-# INLINE append #-}++singleton :: a -> Stream a+singleton a = Stream (bool Done (Yield a False)) True 1++repeat :: Int -> a -> Stream a+repeat n a = Stream step n 1+ where step i = if i > 0 then Yield a (i - 1) else Done
+ src/HaskellWorks/Data/Streams/Stream/Ops.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE MagicHash #-}++module HaskellWorks.Data.Streams.Stream.Ops where++import Data.Word+import GHC.Int+import GHC.Prim+import GHC.Word hiding (ltWord)+import HaskellWorks.Data.Bits.BitWise ((.&.), (.<.), (.>.), (.^.), (.|.))+import HaskellWorks.Data.Positioning+import HaskellWorks.Data.Streams.Stream++import qualified HaskellWorks.Data.Bits.BitWise as BW+import qualified HaskellWorks.Data.Streams.Stream as HW++ltWord :: Word64 -> Word64 -> Word64+ltWord (W64# a#) (W64# b#) = fromIntegral (I64# (ltWord# a# b#))+{-# INLINE ltWord #-}++comp :: Stream Word64 -> Stream Word64+comp = fmap BW.comp++bitwiseAnd :: Stream Word64 -> Stream Word64 -> Stream Word64+bitwiseAnd = HW.zipWith (.&.)++bitwiseOr :: Stream Word64 -> Stream Word64 -> Stream Word64+bitwiseOr = HW.zipWith (.|.)++bitwiseXor :: Stream Word64 -> Stream Word64 -> Stream Word64+bitwiseXor = HW.zipWith (.^.)++bitwiseShiftDown :: Count -> Stream Word64 -> Stream Word64+bitwiseShiftDown n as = HW.zipWith splice bs (HW.drop 1 bs `append` HW.singleton 0)+ where bs = HW.drop i as `append` HW.repeat i 0+ o = n `mod` 64+ i = fromIntegral (n `div` 64)+ splice :: Word64 -> Word64 -> Word64+ splice a b = (a .>. o) .|. (b .<. (64 - o))++add :: Stream Word64 -> Stream Word64 -> Stream Word64+add = HW.zipWithState (\a b c -> let d = a + b in (c + d, d `ltWord` a)) 0
+ src/HaskellWorks/Data/Streams/Vector.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Streams.Vector where++import Control.Monad+import Control.Monad.ST+import HaskellWorks.Data.Streams.Internal+import HaskellWorks.Data.Streams.Size+import HaskellWorks.Data.Streams.Stream++import qualified Data.Vector as DV+import qualified Data.Vector.Mutable as DVM+import qualified HaskellWorks.Data.Streams.Stream as HW++unstream :: forall a. HW.Stream a -> DV.Vector a+unstream (HW.Stream step initialState size) = runST $ do+ v <- case size of+ Exact n -> DVM.unsafeNew n+ Max n -> DVM.unsafeNew n+ Unknown -> DVM.unsafeNew (32 * 1024)+ loop step v 0 initialState+ where loop :: (s -> Step s a) -> DVM.MVector t a -> Int -> s -> ST t (DV.Vector a)+ loop g v i s = case g s of+ Yield a s' -> do+ when (i >= DVM.length v) $ void $ DVM.unsafeGrow v (i * 2)+ DVM.unsafeWrite v i a+ loop g v (i + 1) s'+ Skip s0 -> loop g v i s0+ Done -> DV.freeze v+{-# INLINE [1] unstream #-}++stream :: forall a. DV.Vector a -> Stream a+stream v = Stream step 0 (Exact len)+ where len = DV.length v+ step i = if i >= len+ then Done+ else Yield (DV.unsafeIndex v i) (i + 1)+{-# INLINE [1] stream #-}++map :: (a -> b) -> DV.Vector a -> DV.Vector b+map f = unstream . inplace (fmap f) . stream+{-# INLINE map #-}++{-# RULES+ "stream/unstream" forall f. stream (unstream f) = f+ #-}
+ src/HaskellWorks/Data/Streams/Vector/Storable.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Streams.Vector.Storable+ ( stream+ , unstream++ , map+ , zipWith++ , enumFromStepN+ , foldl++ , dotp+ , sum+ ) where++import Control.Monad+import Control.Monad.ST+import Data.Vector.Storable (Storable)+import HaskellWorks.Data.Streams.Internal (inplace)+import HaskellWorks.Data.Streams.Size+import HaskellWorks.Data.Streams.Stream (Step (..), Stream (..))+import Prelude hiding (foldl, map, sum, zipWith)++import qualified Data.Vector.Storable as DVS+import qualified Data.Vector.Storable.Mutable as DVSM+import qualified HaskellWorks.Data.Streams.Stream as S++unstream :: forall a. Storable a => S.Stream a -> DVS.Vector a+unstream (S.Stream step initialState size) = runST $ do+ v <- case size of+ Exact n -> DVSM.unsafeNew n+ Max n -> DVSM.unsafeNew n+ Unknown -> DVSM.unsafeNew (32 * 1024)+ loop step v 0 initialState+ where loop :: (s -> Step s a) -> DVSM.MVector t a -> Int -> s -> ST t (DVS.Vector a)+ loop g v i s = case g s of+ Yield a s' -> do+ when (i >= DVSM.length v) $ void $ DVSM.unsafeGrow v (i * 2)+ DVSM.unsafeWrite v i a+ loop g v (i + 1) s'+ Skip s0 -> loop g v i s0+ Done -> DVS.freeze v+{-# INLINE [1] unstream #-}++stream :: forall a. Storable a => DVS.Vector a -> Stream a+stream v = Stream step 0 (Exact len)+ where len = DVS.length v+ step i = if i >= len+ then Done+ else Yield (DVS.unsafeIndex v i) (i + 1)+{-# INLINE [1] stream #-}++map :: (Storable a, Storable b)+ => (a -> b)+ -> DVS.Vector a+ -> DVS.Vector b+map f = unstream . inplace (fmap f) . stream+{-# INLINE map #-}++zipWith :: (Storable a, Storable b, Storable c)+ => (a -> b -> c)+ -> DVS.Vector a+ -> DVS.Vector b+ -> DVS.Vector c+zipWith f v w = unstream (S.zipWith f (stream v) (stream w))++enumFromStepN :: (Num a, Storable a) => a -> a -> Int -> DVS.Vector a+enumFromStepN x y = unstream . inplace (S.enumFromStepN x y)+{-# INLINE [1] enumFromStepN #-}++foldl :: Storable b => (a -> b -> a) -> a -> DVS.Vector b -> a+foldl f z = inplace (S.foldl f z) . stream+{-# INLINE [1] foldl #-}++sum :: (Storable a, Num a) => DVS.Vector a -> a+sum = foldl (+) 0++dotp :: (Storable a, Num a) => DVS.Vector a -> DVS.Vector a -> a+dotp v w = sum (zipWith (*) v w)++{-# RULES+ "stream/unstream" forall f. stream (unstream f) = f+ #-}
+ test/HaskellWorks/Data/Stream/Vector/StorableSpec.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Stream.Vector.StorableSpec+ ( spec+ ) where++import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec++import qualified Data.Vector.Storable as DVS+import qualified HaskellWorks.Data.Streams.Vector.Storable as SDVS+import qualified Hedgehog.Gen as G+import qualified Hedgehog.Range as R+import qualified Test.Gen as G++{-# ANN module ("HLint: Ignore Redundant do" :: String) #-}++spec :: Spec+spec = describe "HaskellWorks.Data.Stream.Vector.StorableSpec" $ do+ it "map" $ requireProperty $ do+ v <- forAll $ G.vector (R.linear 0 100) (G.word64 (R.constantBounded))++ DVS.map (+ 1) v === SDVS.map (+ 1) v+ it "foldl" $ requireProperty $ do+ v <- forAll $ G.vector (R.linear 0 100) (G.word64 (R.constantBounded))++ DVS.foldl (+) 0 v === SDVS.foldl (+) 0 v+ it "sum" $ requireProperty $ do+ v <- forAll $ G.vector (R.linear 0 100) (G.word64 (R.constantBounded))++ DVS.sum v === SDVS.sum v
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/Test/Gen.hs view
@@ -0,0 +1,12 @@+module Test.Gen where++import Data.Vector.Storable (Storable)+import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec++import qualified Data.Vector.Storable as DVS+import qualified Hedgehog.Gen as G++vector :: (MonadGen m, Storable a) => Range Int -> m a -> m (DVS.Vector a)+vector r g = DVS.fromList <$> G.list r g