on master help sign in
Implement partitionBy
commit21e948a59fa9b6db80ee54c71a143067600732a1 authorRanjeet Kumar Ranjan <ranjeetr@composewell.com> dateMon 27 Dec 2021, 21:09 (5 years ago) parent37d3c17
5 files changed+153−4
benchmark/Streamly/Benchmark/Data/Mut/Array.hs+96 benchmark/streamly-benchmarks.cabal+11 src/Streamly/Internal/Data/Array/Foreign/Mut/Type.hs+42−3 src/Streamly/Internal/Data/Array/Stream/Mut/Foreign.hs+3−1 streamly.cabal+1
benchmark/Streamly/Benchmark/Data/Mut/Array.hsnew file+96
@@ -0,0 +1,96 @@
1+-- |
2+-- Module : Streamly.Benchmark.Data.Mut.Array
3+-- Copyright : (c) 2020 Composewell Technologies
4+--
5+-- License : BSD-3-Clause
6+-- Maintainer : streamly@composewell.com
7+
8+{-# LANGUAGE CPP #-}
9+{-# LANGUAGE FlexibleContexts #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+
12+#ifdef __HADDOCK_VERSION__
13+#undef INSPECTION
14+#endif
15+
16+#ifdef INSPECTION
17+{-# LANGUAGE TemplateHaskell #-}
18+{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
19+#endif
20+
21+module Main
22+ (
23+ main
24+ ) where
25+
26+import Control.DeepSeq (NFData(..))
27+import System.Random (randomRIO)
28+import Prelude hiding ()
29+
30+import qualified Streamly.Prelude as Stream
31+import qualified Streamly.Internal.Data.Fold as Fold
32+import qualified Streamly.Internal.Data.Array.Stream.Mut.Foreign as MArray
33+
34+import Gauge hiding (env)
35+import Streamly.Prelude (SerialT, MonadAsync, IsStream)
36+import Streamly.Benchmark.Common
37+
38+#ifdef INSPECTION
39+import Foreign.Storable (Storable)
40+import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
41+import Test.Inspection
42+#endif
43+
44+-------------------------------------------------------------------------------
45+-- Utilities
46+-------------------------------------------------------------------------------
47+
48+{-# INLINE sourceUnfoldrM #-}
49+sourceUnfoldrM :: (IsStream t, MonadAsync m) => Int -> Int -> t m Int
50+sourceUnfoldrM value n = Stream.unfoldrM step n
51+ where
52+ step cnt =
53+ if cnt > n + value
54+ then return Nothing
55+ else return (Just (cnt, cnt + 1))
56+
57+{-# INLINE benchIO #-}
58+benchIO
59+ :: NFData b
60+ => String -> (Int -> t IO a) -> (t IO a -> IO b) -> Benchmark
61+benchIO name src sink =
62+ bench name $ nfIO $ randomRIO (1,1) >>= sink . src
63+
64+{-# INLINE partitionBy #-}
65+partitionBy :: Int -> SerialT IO (MArray.Array Int) -> IO ()
66+partitionBy value s = Stream.fold Fold.drain $ do
67+ a <- s
68+ MArray.partitionBy ( < value) a
69+
70+o_n_space_serial_marray ::
71+ Int -> [MArray.Array Int] -> [Benchmark]
72+o_n_space_serial_marray bound arrays =
73+ [ benchIO "partitionBy" (\_ -> Stream.fromList arrays)
74+ $ partitionBy bound
75+ ]
76+
77+-------------------------------------------------------------------------------
78+-- Driver
79+-------------------------------------------------------------------------------
80+
81+moduleName :: String
82+moduleName = "Data.Mut.Array"
83+
84+main :: IO ()
85+main = do
86+ runWithCLIOptsEnv defaultStreamSize alloc allBenchmarks
87+
88+ where
89+
90+ alloc value =
91+ Stream.toList $ MArray.arraysOf value $ sourceUnfoldrM value 0
92+
93+ allBenchmarks arrays value =
94+ [ bgroup (o_1_space_prefix moduleName) $
95+ o_n_space_serial_marray value arrays
96+ ]
benchmark/streamly-benchmarks.cabal+11
@@ -483,6 +483,17 @@ benchmark Data.Array.Foreign
483483 if flag(limit-build-mem)
484484 ghc-options: +RTS -M1000M -RTS
485485
486+benchmark Data.Mut.Array
487+ import: bench-options
488+ type: exitcode-stdio-1.0
489+ hs-source-dirs: Streamly/Benchmark/Data/Mut
490+ main-is: Array.hs
491+ if impl(ghcjs)
492+ buildable: False
493+ else
494+ buildable: True
495+ build-depends: exceptions >= 0.8 && < 0.11
496+
486497-------------------------------------------------------------------------------
487498-- Array Stream Benchmarks
488499-------------------------------------------------------------------------------
src/Streamly/Internal/Data/Array/Foreign/Mut/Type.hs+42−3
@@ -1206,10 +1206,49 @@ permute = undefined
12061206-- first half retains values where the predicate is 'False' and the second half
12071207-- retains values where the predicate is 'True'.
12081208--
1209−-- /Unimplemented/
1209+-- /Pre-release/
12101210{-# INLINE partitionBy #-}
1211−partitionBy :: (a -> Bool) -> Array a -> m (Array a, Array a)
1212−partitionBy = undefined
1211+partitionBy :: forall m a. (MonadIO m, Storable a)
1212+ => (a -> Bool) -> Array a -> m (Array a, Array a)
1213+partitionBy f arr = do
1214+ let low = 0
1215+ high = length arr - 1
1216+ swap low high arr
1217+
1218+ where
1219+
1220+ findL low = do
1221+ if length arr == low
1222+ then return low
1223+ else do
1224+ fw <- getIndex arr low
1225+ if not (f fw)
1226+ then findL (low + 1)
1227+ else return low
1228+
1229+ findR high = do
1230+ fw <- getIndex arr high
1231+ if f fw && high > 0
1232+ then findR (high - 1)
1233+ else return high
1234+
1235+ swap low high arr0 = do
1236+ if low < high
1237+ then do
1238+ left <- findL low
1239+ right <- findR high
1240+ if left < right
1241+ then do
1242+ unsafeSwapIndices arr0 left right
1243+ swap (left + 1) (right - 1) arr0
1244+ else do
1245+ let al = getSlice 0 left arr0
1246+ ar = getSlice left (length arr0 - left) arr0
1247+ return (al, ar)
1248+ else do
1249+ let al = getSlice 0 low arr0
1250+ ar = getSlice low (length arr0 - low) arr0
1251+ return (al, ar)
12131252
12141253-- | Shuffle corresponding elements from two arrays using a shuffle function.
12151254-- If the shuffle function returns 'False' then do nothing otherwise swap the
src/Streamly/Internal/Data/Array/Stream/Mut/Foreign.hs+3−1
@@ -21,6 +21,8 @@ module Streamly.Internal.Data.Array.Stream.Mut.Foreign
2121 , compactLE
2222 , compactEQ
2323 , compactGE
24+ , Array(..)
25+ , partitionBy
2426 )
2527where
2628
@@ -32,7 +34,7 @@ import Control.Monad (when)
3234import Control.Monad.Catch (MonadThrow)
3335import Data.Bifunctor (first)
3436import Foreign.Storable (Storable(..))
35−import Streamly.Internal.Data.Array.Foreign.Mut.Type (Array(..))
37+import Streamly.Internal.Data.Array.Foreign.Mut.Type (Array(..), partitionBy)
3638import Streamly.Internal.Data.Fold.Type (Fold(..))
3739import Streamly.Internal.Data.Stream.Serial (SerialT(..))
3840import Streamly.Internal.Data.Stream.IsStream.Type
streamly.cabal+1
@@ -63,6 +63,7 @@ extra-source-files:
6363 benchmark/Streamly/Benchmark/Data/Array/Prim.hs
6464 benchmark/Streamly/Benchmark/Data/Array/Prim/Pinned.hs
6565 benchmark/Streamly/Benchmark/Data/Array/Stream/Foreign.hs
66+ benchmark/Streamly/Benchmark/Data/Mut/Array.hs
6667 benchmark/Streamly/Benchmark/Data/Parser/*.hs
6768 benchmark/Streamly/Benchmark/Data/Stream/*.hs
6869 benchmark/Streamly/Benchmark/FileSystem/*.hs