on master help sign in
Reorganize exports, add unimplemented signatures

Also, cleanup the higher level mutable array module, use the lower level module directly.

commitd86e6041208b4ec09dfbaa4d88042ccf0fb08df1 authorHarendra Kumar <harendra@composewell.com> dateSat 16 Oct 2021, 16:16 (5 years ago) parent33b7aaf
2 files changed+309−183
src/Streamly/Internal/Data/Array/Foreign/Mut.hs+1−114 src/Streamly/Internal/Data/Array/Foreign/Mut/Type.hs+308−69
src/Streamly/Internal/Data/Array/Foreign/Mut.hs+1−114
@@ -24,123 +24,10 @@
2424
2525module Streamly.Internal.Data.Array.Foreign.Mut
2626 (
27− -- * Type
28− Array
29− -- , writeIndex
30− -- , writeFrom -- start writing at the given position
31− -- , writeFromRev
32− -- , writeTo -- write from beginning up to the given position
33− -- , writeToRev
34− -- , writeFromTo
35− -- , writeFromThenTo
36− --
37− -- , writeChunksOfFrom
38− -- , ...
39−
40− -- * Mutation
41− , writeIndex
42− , snoc
43−
44− --, writeIndices
45− --, writeRanges
46−
47− -- -- * In-pace mutation (for Mutable Array type)
48− -- , partitionBy
49− -- , shuffleBy
50− -- , foldtWith
51− -- , foldbWith
52−
53− -- * Folding
54− , foldl'
55− , foldr
56−
57− -- * Composable Folds
58− , writeN
59− , write
60−
61− -- * Unfolds
62− , read
63−
64− -- * To containers
65− , toList
66−
67− -- * Combining
68− , splice
69− , spliceExp
70− , spliceCopy
71−
72− -- * Splitting
73− , breakOn
74− , splitAt
27+ module Streamly.Internal.Data.Array.Foreign.Mut.Type
7528 )
7629where
7730
78−import Control.Monad.IO.Class (MonadIO(..))
79−import Foreign.Storable (Storable(..))
80−import Streamly.Internal.BaseCompat (unsafeWithForeignPtr)
81−
8231import Prelude hiding (foldr, length, read, splitAt)
8332
8433import Streamly.Internal.Data.Array.Foreign.Mut.Type
85−
86−-- | /O(1)/ Write the given element at the given index in the array.
87−-- Performs in-place mutation of the array.
88−--
89−-- /Pre-release/
90−{-# INLINE writeIndex #-}
91−writeIndex :: (MonadIO m, Storable a) => Array a -> Int -> a -> m ()
92−writeIndex arr i a = do
93− let maxIndex = length arr - 1
94− if i < 0
95− then error "writeIndex: negative array index"
96− else if i > maxIndex
97− then error $ "writeIndex: specified array index " ++ show i
98− ++ " is beyond the maximum index " ++ show maxIndex
99− else
100− liftIO $ unsafeWithForeignPtr (aStart arr) $ \p ->
101− pokeElemOff p i a
102−
103−{-
104−
105−-------------------------------------------------------------------------------
106−-- In-place mutation APIs
107−-------------------------------------------------------------------------------
108−
109−-- | Partition an array into two halves using a partitioning predicate. The
110−-- first half retains values where the predicate is 'False' and the second half
111−-- retains values where the predicate is 'True'.
112−{-# INLINE partitionBy #-}
113−partitionBy :: (a -> Bool) -> Array a -> (Array a, Array a)
114−partitionBy f arr = undefined
115−
116−-- | Shuffle corresponding elements from two arrays using a shuffle function.
117−-- If the shuffle function returns 'False' then do nothing otherwise swap the
118−-- elements. This can be used in a bottom up fold to shuffle or reorder the
119−-- elements.
120−shuffleBy :: (a -> a -> m Bool) -> Array a -> Array a -> m (Array a)
121−shuffleBy f arr1 arr2 = undefined
122−
123−-- XXX we can also make the folds partial by stopping at a certain level.
124−--
125−-- | Perform a top down hierarchical recursive partitioning fold of items in
126−-- the container using the given function as the partition function.
127−--
128−-- This will perform a quick sort if the partition function is
129−-- 'partitionBy (< pivot)'.
130−--
131−-- @since 0.7.0
132−{-# INLINABLE foldtWith #-}
133−foldtWith :: Int -> (Array a -> Array a -> m (Array a)) -> Array a -> m (Array a)
134−foldtWith level f = undefined
135−
136−-- | Perform a pairwise bottom up fold recursively merging the pairs. Level
137−-- indicates the level in the tree where the fold would stop.
138−--
139−-- This will perform a random shuffle if the shuffle function is random.
140−-- If we stop at level 0 and repeatedly apply the function then we can do a
141−-- bubble sort.
142−foldbWith :: Int -> (Array a -> Array a -> m (Array a)) -> Array a -> m (Array a)
143−foldbWith level f = undefined
144−-}
145−
146−-- XXX consider the bulk update/accumulation/permutation APIs from vector.
src/Streamly/Internal/Data/Array/Foreign/Mut/Type.hs+308−69
@@ -17,46 +17,128 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
1717 -- $arrayNotes
1818 Array (..)
1919
20− -- * Construction
21− , fromForeignPtrUnsafe
22− , withNewArrayUnsafe
20+ -- * Constructing and Writing
21+ -- ** Construction
22+ -- , nil
23+
24+ -- *** Uninitialized Arrays
2325 , newArray
2426 , newArrayAligned
2527 , newArrayAlignedUnmanaged
2628 , newArrayWith
2729
28− -- * From containers
29− , fromList
30+ -- *** Initialized Arrays
31+ , withNewArrayUnsafe
32+
33+ -- *** From streams
34+ , ArrayUnsafe (..)
35+ , writeNWithUnsafe
36+ , writeNWith
37+ , writeNUnsafe
38+ , writeN
39+ , writeNAligned
40+ , writeNAlignedUnmanaged
41+
42+ , writeWith
43+ , write
44+
45+ -- , writeRevN
46+ -- , writeRev
47+
48+ -- ** From containers
49+ , fromForeignPtrUnsafe
3050 , fromListN
51+ , fromList
3152 , fromStreamDN
3253 , fromStreamD
3354
34− -- * Resizing
55+ -- * Random writes
56+ , putIndex
57+ , putIndexUnsafe
58+ , putIndices
59+ -- , putFromThenTo
60+ -- , putFrom -- start writing at the given position
61+ -- , putUpto -- write from beginning up to the given position
62+ -- , putFromTo
63+ -- , putFromRev
64+ -- , putUptoRev
65+ , modifyIndexUnsafe
66+ , modifyIndex
67+ , modifyIndices
68+ , modify
69+ , swapIndices
70+
71+ -- * Growing and Shrinking
72+ -- Arrays grow only at the end, though it is possible to grow on both sides
73+ -- and therefore have a cons as well as snoc. But that will require two
74+ -- bounds in the array representation.
75+
76+ -- ** Appending elements
77+ , snocWith
78+ , snoc
79+ , snocLinear
80+ , snocMay
81+ , snocUnsafe
82+
83+ -- ** Appending streams
84+ , appendNUnsafe
85+ , appendN
86+ , appendWith
87+ , append
88+
89+ -- ** Truncation
90+ -- These are not the same as slicing the array at the beginning, they may
91+ -- reduce the length as well as the capacity of the array.
92+ , truncateWith
93+ , truncate
94+ , truncateExp
95+
96+ -- * Eliminating and Reading
97+
98+ -- ** To streams
99+ , ReadUState
100+ , read
101+ , readRev
102+
103+ -- ** To containers
104+ , toStreamD
105+ , toStreamDRev
106+ , toStreamK
107+ , toStreamKRev
108+ , toList
109+
110+ -- experimental
111+ , producer
112+
113+ -- ** Random reads
114+ , getIndex
115+ , getIndexUnsafe
116+ , getIndices
117+ -- , getFromThenTo
118+ , getIndexRev
119+
120+ -- * Memory Management
121+ , blockSize
122+ , arrayChunkSize
35123 , realloc
124+ , resize
125+ , resizeExp
36126 , rightSize
37127
38128 -- * Size
39129 , length
40130 , byteLength
131+ -- , capacity
41132 , byteCapacity
42133 , bytesFree
43134
44− -- * Random access
45− , getIndexUnsafe
46− , getIndex
47− , getIndexRev
48− , getIndices
49−
50− -- * Mutation
51− , putIndexUnsafe
52− , putIndex
53− , modifyIndexUnsafe
54− , modifyIndex
55− , snocUnsafe
56− , snocWith
57− , snoc
58− , snocLinear
59− , snocMay
135+ -- * In-place Mutation Algorithms
136+ , reverse
137+ , permute
138+ , partitionBy
139+ , shuffleBy
140+ , divideBy
141+ , mergeBy
60142
61143 -- * Casting
62144 , cast
@@ -64,61 +146,45 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
64146 , asBytes
65147 , asPtrUnsafe
66148
67− -- * Subarrays
68− , getSliceUnsafe
69− , getSlice
70−
71149 -- * Folding
72150 , foldl'
73151 , foldr
74152 , cmp
75153
76− -- * Composable Folds
77− -- XXX These should be Refolds
78− , appendNUnsafe
79− , appendN
80− , appendWith
81− , append
154+ -- * Arrays of arrays
155+ -- We can add dimensionality parameter to the array type to get
156+ -- multidimensional arrays. Multidimensional arrays would just be a
157+ -- convenience wrapper on top of single dimensional arrays.
82158
83− , writeWith
84− , writeNWithUnsafe
85− , writeNWith
86− , writeN
87− , writeNUnsafe
88− , ArrayUnsafe (..)
89− , writeNAligned
90− , writeNAlignedUnmanaged
91− , write
159+ -- | Operations dealing with multiple arrays, streams of arrays or
160+ -- multidimensional array representations.
92161
93− -- * Unfolds
94− , ReadUState
95− , read
96− , readRev
97− , producer
162+ -- ** Construct from streams
163+ , arraysOf
164+ , arrayStreamKFromStreamD
165+ , writeChunks
166+
167+ -- ** Eliminate to streams
98168 , flattenArrays
99169 , flattenArraysRev
170+ , fromArrayStreamK
100171
101− -- * To containers
102− , toStreamD
103− , toStreamDRev
104− , toStreamK
105− , toStreamKRev
106− , toList
172+ -- ** Construct from arrays
173+ -- get chunks without copying
174+ , getSliceUnsafe
175+ , getSlice
176+ -- , getSlicesFromLenN
177+ , splitAt -- XXX should be able to express using getSlice
178+ , breakOn
107179
108− -- * Combining
180+ -- ** Appending arrays
181+ , spliceCopy
109182 , spliceWith
110183 , splice
111184 , spliceExp
112− , spliceCopy
113−
114− -- * Splitting
115− , breakOn
116− , splitAt
117−
118− -- * Stream of arrays
119− , arraysOf
120− , writeChunks
121− , fromArrayStreamK
185+ -- , putSlice
186+ -- , appendSlice
187+ -- , appendSliceFrom
122188
123189 -- * Utilities
124190 , bytesToElemCount
@@ -135,7 +201,7 @@ import Control.DeepSeq (NFData(..))
135201import Control.Monad (when, void)
136202import Control.Monad.IO.Class (MonadIO(..))
137203import Data.Bits ((.&.))
138−import Data.Functor.Identity (runIdentity)
204+import Data.Functor.Identity (Identity(runIdentity))
139205#if __GLASGOW_HASKELL__ < 808
140206import Data.Semigroup (Semigroup(..))
141207#endif
@@ -172,7 +238,8 @@ import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
172238import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
173239import qualified Streamly.Internal.Foreign.Malloc as Malloc
174240
175−import Prelude hiding (length, foldr, read, unlines, splitAt)
241+import Prelude hiding
242+ (length, foldr, read, unlines, splitAt, reverse, truncate)
176243
177244#if MIN_VERSION_base(4,10,0)
178245import Foreign.ForeignPtr (plusForeignPtr)
@@ -205,7 +272,8 @@ foreign import ccall unsafe "string.h memcmp" c_memcmp
205272 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
206273
207274-- | Given a 'Storable' type (unused first arg) and a number of bytes, return
208−-- how many elements of that type are required to hold those bytes.
275+-- how many elements of that type will fit in after rounding the bytes up to
276+-- the element size.
209277{-# INLINE bytesToElemCount #-}
210278bytesToElemCount :: Storable a => a -> Int -> Int
211279bytesToElemCount x n =
@@ -298,6 +366,10 @@ fromForeignPtrUnsafe fp end bound =
298366-- XXX Change the names to use "new" instead of "newArray". That way we can use
299367-- the same names for managed file system objects as well. For unmanaged ones
300368-- we can use open/create etc as usual.
369+--
370+-- A new array is similar to "touch" creating a zero length file. An mmapped
371+-- array would be similar to a sparse file with holes. TBD: support mmapped
372+-- files and arrays.
301373
302374-- GHC always guarantees word-aligned memory, alignment is important only when
303375-- we need more than that. See stg_newAlignedPinnedByteArrayzh and
@@ -379,6 +451,14 @@ withNewArrayUnsafe count f = do
379451-- Random writes
380452-------------------------------------------------------------------------------
381453
454+-- | Write an input stream of (index, value) pairs to an array. Throws an
455+-- error if any index is out of bounds.
456+--
457+-- /Unimplemented/
458+{-# INLINE putIndices #-}
459+putIndices :: Array a -> Fold m (Int, a) ()
460+putIndices = undefined
461+
382462-- | Write the given element to the given index of the array. Does not check if
383463-- the index is out of bounds of the array.
384464--
@@ -411,6 +491,8 @@ putIndexPtr ptr end i x = do
411491-- Performs in-place mutation of the array.
412492--
413493-- >>> putIndex arr ix val = Array.modifyIndex arr ix (const (val, ()))
494+-- >>> f = Array.putIndices
495+-- >>> putIndex arr ix val = Stream.fold (f arr) (Stream.fromPure (ix, val))
414496--
415497-- /Pre-release/
416498{-# INLINE putIndex #-}
@@ -450,6 +532,27 @@ modifyIndex Array{..} i f = do
450532 return res
451533 else invalidIndex "modifyIndex" i
452534
535+-- | Modify the array indices generated by the supplied unfold.
536+--
537+-- /Pre-release/
538+modifyIndices :: -- forall m a b. (MonadIO m, Storable a) =>
539+ Unfold m (Array a) Int -> Array a -> (a -> a) -> m ()
540+modifyIndices = undefined
541+
542+-- | Modify each element of an array using the supplied modifier function.
543+--
544+-- /Unimplemented/
545+modify :: -- forall m a b. (MonadIO m, Storable a) =>
546+ Array a -> (a -> a) -> m ()
547+modify = undefined
548+
549+-- | Swap the elements at two indices.
550+--
551+-- /Pre-release/
552+swapIndices :: -- (MonadIO m, Storable a) =>
553+ Array a -> Int -> Int -> m ()
554+swapIndices = undefined
555+
453556-------------------------------------------------------------------------------
454557-- Rounding
455558-------------------------------------------------------------------------------
@@ -497,6 +600,16 @@ arrayChunkSize = mkChunkSize 1024
497600-- Snoc
498601-------------------------------------------------------------------------------
499602
603+-- XXX We can possibly use a smallMutableByteArray to hold the start, end,
604+-- bound pointers. Or we can use the first 16 bytes of the allocation to store
605+-- the end, bound pointers. Using fully mutable handle will ensure that we do
606+-- not have multiple references to the same array of different lengths lying
607+-- around and potentially misused. In that case "snoc" need not return a new
608+-- array (snoc :: Array a -> a -> m ()), it will just modify the old reference.
609+-- The array length will be mutable. This means the length function would also
610+-- be monadic. Mutable arrays would behave more like files that grow in that
611+-- case.
612+
500613-- | Snoc using a 'Ptr'. Low level reusable function.
501614--
502615-- /Internal/
@@ -653,7 +766,6 @@ reallocAligned elemSize alignSize newSize Array{..} = do
653766 , aBound = pNew `plusPtr` newSize
654767 }
655768
656−-- XXX can unaligned allocation be more efficient when alignment is not needed?
657769{-# INLINABLE realloc #-}
658770realloc :: forall m a. (MonadIO m, Storable a) => Int -> Array a -> m (Array a)
659771realloc i arr =
@@ -661,8 +773,30 @@ realloc i arr =
661773 $ reallocAligned
662774 (sizeOf (undefined :: a)) (alignment (undefined :: a)) i arr
663775
664−-- | Drop any reserved free space at the end of the array and reallocate it to
665−-- reduce wastage.
776+-- | Change the reserved memory of the array so that it is enough to hold the
777+-- specified number of elements. Nothing is done if the specified capacity is
778+-- less than the length of the array.
779+--
780+-- If the capacity is more than 'largeObjectThreshold' then it is rounded up to
781+-- the block size (4K).
782+--
783+-- /Unimplemented/
784+{-# INLINE resize #-}
785+resize :: -- (MonadIO m, Storable a) =>
786+ Int -> Array a -> m (Array a)
787+resize = undefined
788+
789+-- | Like 'resize' but if the capacity is more than 'largeObjectThreshold' then
790+-- it is rounded up to the closest power of 2.
791+--
792+-- /Unimplemented/
793+{-# INLINE resizeExp #-}
794+resizeExp :: -- (MonadIO m, Storable a) =>
795+ Int -> Array a -> m (Array a)
796+resizeExp = undefined
797+
798+-- | Resize the allocated memory to drop any reserved free space at the end of
799+-- the array and reallocate it to reduce wastage.
666800--
667801-- Up to 25% wastage is allowed to avoid reallocations. If the capacity is
668802-- more than 'largeObjectThreshold' then free space up to the 'blockSize' is
@@ -686,7 +820,39 @@ rightSize arr@Array{..} = do
686820 else return arr
687821
688822-------------------------------------------------------------------------------
823+-- Reducing the length
824+-------------------------------------------------------------------------------
825+
826+-- | Drop the last n elements of the array to reduce the length by n. The
827+-- capacity is reallocated using the user supplied function.
689828--
829+-- /Unimplemented/
830+{-# INLINE truncateWith #-}
831+truncateWith :: -- (MonadIO m, Storable a) =>
832+ Int -> (Int -> Int) -> Array a -> m (Array a)
833+truncateWith = undefined
834+
835+-- | Drop the last n elements of the array to reduce the length by n.
836+--
837+-- The capacity is rounded to 1K or 4K if the length is more than the GHC large
838+-- block threshold.
839+--
840+-- /Unimplemented/
841+{-# INLINE truncate #-}
842+truncate :: -- (MonadIO m, Storable a) =>
843+ Int -> Array a -> m (Array a)
844+truncate = undefined
845+
846+-- | Like 'truncate' but the capacity is rounded to the closest power of 2.
847+--
848+-- /Unimplemented/
849+{-# INLINE truncateExp #-}
850+truncateExp :: -- (MonadIO m, Storable a) =>
851+ Int -> Array a -> m (Array a)
852+truncateExp = undefined
853+
854+-------------------------------------------------------------------------------
855+-- Random reads
690856-------------------------------------------------------------------------------
691857
692858-- | Return the element at the specified index without checking the bounds.
@@ -772,6 +938,8 @@ getIndices (Unfold stepi injecti) = Unfold step inject
772938-- Subarrays
773939-------------------------------------------------------------------------------
774940
941+-- XXX We can also get immutable slices.
942+
775943-- | /O(1)/ Slice an array in constant time.
776944--
777945-- Unsafe: The bounds of the slice are not checked.
@@ -811,6 +979,77 @@ getSlice index len (Array fp e _) =
811979 $ "getSlice: invalid slice, index "
812980 ++ show index ++ " length " ++ show len
813981
982+-------------------------------------------------------------------------------
983+-- In-place mutation algorithms
984+-------------------------------------------------------------------------------
985+
986+-- XXX consider the bulk update/accumulation/permutation APIs from vector.
987+
988+-- | You may not need to reverse an array because you can consume it in reverse
989+-- using 'readRev'. To reverse large arrays you can read in reverse and write
990+-- to another array. However, in-place reverse can be useful to take adavantage
991+-- of cache locality and when you do not want to allocate additional memory.
992+--
993+-- /Unimplemented/
994+{-# INLINE reverse #-}
995+reverse :: Array a -> m Bool
996+reverse = undefined
997+
998+-- | Generate the next permutation of the sequence, returns False if this is
999+-- the last permutation.
1000+--
1001+-- /Unimplemented/
1002+{-# INLINE permute #-}
1003+permute :: Array a -> m Bool
1004+permute = undefined
1005+
1006+-- | Partition an array into two halves using a partitioning predicate. The
1007+-- first half retains values where the predicate is 'False' and the second half
1008+-- retains values where the predicate is 'True'.
1009+--
1010+-- /Unimplemented/
1011+{-# INLINE partitionBy #-}
1012+partitionBy :: (a -> Bool) -> Array a -> m (Array a, Array a)
1013+partitionBy = undefined
1014+
1015+-- | Shuffle corresponding elements from two arrays using a shuffle function.
1016+-- If the shuffle function returns 'False' then do nothing otherwise swap the
1017+-- elements. This can be used in a bottom up fold to shuffle or reorder the
1018+-- elements.
1019+--
1020+-- /Unimplemented/
1021+{-# INLINE shuffleBy #-}
1022+shuffleBy :: (a -> a -> m Bool) -> Array a -> Array a -> m (Array a)
1023+shuffleBy = undefined
1024+
1025+-- XXX we can also make the folds partial by stopping at a certain level.
1026+--
1027+-- | @divideBy level partition array@ performs a top down hierarchical
1028+-- recursive partitioning fold of items in the container using the given
1029+-- function as the partition function. Level indicates the level in the tree
1030+-- where the fold would stop.
1031+--
1032+-- This performs a quick sort if the partition function is
1033+-- 'partitionBy (< pivot)'.
1034+--
1035+-- /Unimplemented/
1036+{-# INLINABLE divideBy #-}
1037+divideBy ::
1038+ Int -> (Array a -> Array a -> m (Array a)) -> Array a -> m (Array a)
1039+divideBy = undefined
1040+
1041+-- | @mergeBy level merge array@ performs a pairwise bottom up fold recursively
1042+-- merging the pairs using the supplied merge function. Level indicates the
1043+-- level in the tree where the fold would stop.
1044+--
1045+-- This performs a random shuffle if the shuffle function is random. If we
1046+-- stop at level 0 and repeatedly apply the function then we can do a bubble
1047+-- sort.
1048+--
1049+-- /Unimplemented/
1050+mergeBy :: Int -> (Array a -> Array a -> m (Array a)) -> Array a -> m (Array a)
1051+mergeBy = undefined
1052+
8141053-------------------------------------------------------------------------------
8151054-- Size
8161055-------------------------------------------------------------------------------