• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lehins / massiv / 510

08 Jul 2025 08:14PM UTC coverage: 73.604% (+0.07%) from 73.539%
510

push

github

web-flow
Merge pull request #150 from lehins/fix-doctest-setup

Fix doctest setup

0 of 1 new or added line in 1 file covered. (0.0%)

146 existing lines in 7 files now uncovered.

4230 of 5747 relevant lines covered (73.6%)

1.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.89
/massiv/src/Data/Massiv/Array/Mutable.hs
1
{-# LANGUAGE BangPatterns #-}
2
{-# LANGUAGE FlexibleContexts #-}
3
{-# LANGUAGE LambdaCase #-}
4
{-# LANGUAGE MonoLocalBinds #-}
5
{-# LANGUAGE MultiParamTypeClasses #-}
6
{-# LANGUAGE RankNTypes #-}
7
{-# LANGUAGE ScopedTypeVariables #-}
8

9
-- |
10
-- Module      : Data.Massiv.Array.Mutable
11
-- Copyright   : (c) Alexey Kuleshevich 2018-2022
12
-- License     : BSD3
13
-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>
14
-- Stability   : experimental
15
-- Portability : non-portable
16
module Data.Massiv.Array.Mutable (
17
  -- ** Size
18
  sizeOfMArray,
19
  msize,
20
  resizeMArrayM,
21
  flattenMArray,
22
  outerSliceMArrayM,
23
  outerSlicesMArray,
24

25
  -- ** Element-wise mutation
26
  read,
27
  readM,
28
  write,
29
  write_,
30
  writeM,
31
  modify,
32
  modify_,
33
  modifyM,
34
  modifyM_,
35
  swap,
36
  swap_,
37
  swapM,
38
  swapM_,
39
  zipSwapM_,
40

41
  -- ** Operations on @MArray@
42

43
  -- *** Immutable conversion
44
  thaw,
45
  thawS,
46
  freeze,
47
  freezeS,
48

49
  -- *** Create mutable
50
  newMArray,
51
  newMArray',
52
  makeMArray,
53
  makeMArrayLinear,
54
  makeMArrayS,
55
  makeMArrayLinearS,
56

57
  -- *** Create pure
58
  createArray_,
59
  createArray,
60
  createArrayS_,
61
  createArrayS,
62
  createArrayST_,
63
  createArrayST,
64

65
  -- *** Generate
66
  generateArray,
67
  generateArrayLinear,
68
  generateArrayS,
69
  generateArrayLinearS,
70
  generateSplitSeedArray,
71

72
  -- *** Stateful worker threads
73
  generateArrayWS,
74
  generateArrayLinearWS,
75

76
  -- *** Unfold
77
  unfoldrPrimM_,
78
  iunfoldrPrimM_,
79
  unfoldrPrimM,
80
  iunfoldrPrimM,
81
  unfoldlPrimM_,
82
  iunfoldlPrimM_,
83
  unfoldlPrimM,
84
  iunfoldlPrimM,
85

86
  -- *** Mapping
87
  forPrimM,
88
  forPrimM_,
89
  iforPrimM,
90
  iforPrimM_,
91
  iforLinearPrimM,
92
  iforLinearPrimM_,
93
  for2PrimM_,
94
  ifor2PrimM_,
95

96
  -- *** Modify
97
  withMArray,
98
  withMArray_,
99
  withLoadMArray_,
100
  withMArrayS,
101
  withLoadMArrayS,
102
  withMArrayS_,
103
  withLoadMArrayS_,
104
  withMArrayST,
105
  withLoadMArrayST,
106
  withMArrayST_,
107
  withLoadMArrayST_,
108

109
  -- *** Initialize
110
  initialize,
111
  initializeNew,
112

113
  -- ** Computation
114
  Manifest,
115
  MArray,
116
  RealWorld,
117
  computeInto,
118
  loadArray,
119
  loadArrayS,
120
) where
121

122
-- TODO: add fromListM, et al.
123

124
import Control.Monad (unless, void, when, (>=>))
125
import Control.Monad.Primitive
126
import Control.Monad.ST
127
import Control.Scheduler
128
import Data.IORef
129
import Data.Massiv.Array.Delayed.Pull (D)
130
import Data.Massiv.Array.Mutable.Internal
131
import Data.Massiv.Core.Common
132
import Data.Maybe (fromMaybe)
133
import System.IO.Unsafe (unsafePerformIO)
134
import Prelude hiding (mapM, read)
135

136
-- | /O(1)/ - Change the size of a mutable array. Throws
137
-- `SizeElementsMismatchException` if total number of elements does not match
138
-- the supplied array.
139
--
140
-- @since 1.0.0
141
resizeMArrayM
142
  :: (Manifest r e, Index ix', Index ix, MonadThrow m)
143
  => Sz ix'
144
  -> MArray s r ix e
145
  -> m (MArray s r ix' e)
146
resizeMArrayM sz marr =
×
147
  unsafeResizeMArray sz marr <$ guardNumberOfElements (sizeOfMArray marr) sz
×
148
{-# INLINE resizeMArrayM #-}
149

150
-- | /O(1)/ - Change a mutable array to a mutable vector.
151
--
152
-- @since 1.0.0
153
flattenMArray :: (Manifest r e, Index ix) => MArray s r ix e -> MVector s r e
154
flattenMArray marr = unsafeResizeMArray (toLinearSz (sizeOfMArray marr)) marr
×
155
{-# INLINE flattenMArray #-}
156

157
-- | /O(1)/ - Slice a mutable array from the outside, while reducing its
158
-- dimensionality by one. Same as `Data.Massiv.Array.!?>` operator, but for
159
-- mutable arrays.
160
--
161
-- ====__Examples__
162
--
163
-- >>> import Data.Massiv.Array
164
-- >>> marr <- makeMArrayLinear @P Seq (Sz2 4 7) (pure . (+10))
165
-- >>> freezeS marr
166
-- Array P Seq (Sz (4 :. 7))
167
--   [ [ 10, 11, 12, 13, 14, 15, 16 ]
168
--   , [ 17, 18, 19, 20, 21, 22, 23 ]
169
--   , [ 24, 25, 26, 27, 28, 29, 30 ]
170
--   , [ 31, 32, 33, 34, 35, 36, 37 ]
171
--   ]
172
--
173
-- Let's say our goal is to swap row at index 0 with the one with index 2:
174
--
175
-- >>> row0 <- outerSliceMArrayM marr 0
176
-- >>> row2 <- outerSliceMArrayM marr 2
177
-- >>> zipSwapM_ 0 row0 row2
178
-- >>> freezeS marr
179
-- Array P Seq (Sz (4 :. 7))
180
--   [ [ 24, 25, 26, 27, 28, 29, 30 ]
181
--   , [ 17, 18, 19, 20, 21, 22, 23 ]
182
--   , [ 10, 11, 12, 13, 14, 15, 16 ]
183
--   , [ 31, 32, 33, 34, 35, 36, 37 ]
184
--   ]
185
--
186
-- @since 1.0.0
187
outerSliceMArrayM
188
  :: forall r ix e m s
189
   . (MonadThrow m, Index (Lower ix), Index ix, Manifest r e)
190
  => MArray s r ix e
191
  -> Ix1
192
  -> m (MArray s r (Lower ix) e)
193
outerSliceMArrayM !marr !i = do
2✔
194
  let (k, szL) = unconsSz (sizeOfMArray marr)
2✔
195
  unless (isSafeIndex k i) $ throwM $ IndexOutOfBoundsException k i
2✔
196
  pure $ unsafeResizeMArray szL $ unsafeLinearSliceMArray (i * totalElem szL) (toLinearSz szL) marr
2✔
197
{-# INLINE outerSliceMArrayM #-}
198

199
-- | /O(1)/ - Take all outer slices of a mutable array and construct a delayed
200
-- vector out of them. In other words it applies `outerSliceMArrayM` to each
201
-- outer index. Same as `Data.Massiv.Array.outerSlices` function, but for
202
-- mutable arrays.
203
--
204
-- ====__Examples__
205
--
206
-- >>> import Data.Massiv.Array as A
207
-- >>> arr <- resizeM (Sz2 4 7) $ makeArrayR P Seq (Sz1 28) (+10)
208
-- >>> arr
209
-- Array P Seq (Sz (4 :. 7))
210
--   [ [ 10, 11, 12, 13, 14, 15, 16 ]
211
--   , [ 17, 18, 19, 20, 21, 22, 23 ]
212
--   , [ 24, 25, 26, 27, 28, 29, 30 ]
213
--   , [ 31, 32, 33, 34, 35, 36, 37 ]
214
--   ]
215
--
216
-- Here is how we can get individual rows from a mutable matrix
217
--
218
-- >>> marr <- thawS arr
219
-- >>> import Control.Monad ((<=<))
220
-- >>> mapIO_ (print <=< freezeS)  $ outerSlicesMArray Seq marr
221
-- Array P Seq (Sz1 7)
222
--   [ 10, 11, 12, 13, 14, 15, 16 ]
223
-- Array P Seq (Sz1 7)
224
--   [ 17, 18, 19, 20, 21, 22, 23 ]
225
-- Array P Seq (Sz1 7)
226
--   [ 24, 25, 26, 27, 28, 29, 30 ]
227
-- Array P Seq (Sz1 7)
228
--   [ 31, 32, 33, 34, 35, 36, 37 ]
229
--
230
-- For the sake of example what if our goal was to mutate array in such a way
231
-- that rows from the top half were swapped with the bottom half:
232
--
233
-- >>> (top, bottom) <- splitAtM 1 2 $ outerSlicesMArray Seq marr
234
-- >>> mapIO_ (print <=< freezeS) top
235
-- Array P Seq (Sz1 7)
236
--   [ 10, 11, 12, 13, 14, 15, 16 ]
237
-- Array P Seq (Sz1 7)
238
--   [ 17, 18, 19, 20, 21, 22, 23 ]
239
-- >>> mapIO_ (print <=< freezeS) bottom
240
-- Array P Seq (Sz1 7)
241
--   [ 24, 25, 26, 27, 28, 29, 30 ]
242
-- Array P Seq (Sz1 7)
243
--   [ 31, 32, 33, 34, 35, 36, 37 ]
244
-- >>> szipWithM_ (zipSwapM_ 0) top bottom
245
-- >>> freezeS marr
246
-- Array P Seq (Sz (4 :. 7))
247
--   [ [ 24, 25, 26, 27, 28, 29, 30 ]
248
--   , [ 31, 32, 33, 34, 35, 36, 37 ]
249
--   , [ 10, 11, 12, 13, 14, 15, 16 ]
250
--   , [ 17, 18, 19, 20, 21, 22, 23 ]
251
--   ]
252
--
253
-- @since 1.0.0
254
outerSlicesMArray
255
  :: forall r ix e s
256
   . (Index (Lower ix), Index ix, Manifest r e)
257
  => Comp
258
  -> MArray s r ix e
259
  -> Vector D (MArray s r (Lower ix) e)
UNCOV
260
outerSlicesMArray comp marr =
×
261
  makeArray comp k (\i -> unsafeResizeMArray szL $ unsafeLinearSliceMArray (i * unSz kL) kL marr)
×
262
  where
UNCOV
263
    kL = toLinearSz szL
×
264
    (k, szL) = unconsSz $ sizeOfMArray marr
×
265
{-# INLINE outerSlicesMArray #-}
266

267
-- | /O(n)/ - Initialize a new mutable array. All elements will be set to some default value. For
268
-- boxed arrays it will be a thunk with `Uninitialized` exception, while for others it will be
269
-- simply zeros.
270
--
271
-- ==== __Examples__
272
--
273
-- >>> import Data.Massiv.Array
274
-- >>> marr <- newMArray' (Sz2 2 6) :: IO (MArray RealWorld P Ix2 Int)
275
-- >>> freeze Seq marr
276
-- Array P Seq (Sz (2 :. 6))
277
--   [ [ 0, 0, 0, 0, 0, 0 ]
278
--   , [ 0, 0, 0, 0, 0, 0 ]
279
--   ]
280
--
281
-- Or using @TypeApplications@:
282
--
283
-- >>> :seti -XTypeApplications
284
-- >>> newMArray' @P @Ix2 @Int (Sz2 2 6) >>= freezeS
285
-- Array P Seq (Sz (2 :. 6))
286
--   [ [ 0, 0, 0, 0, 0, 0 ]
287
--   , [ 0, 0, 0, 0, 0, 0 ]
288
--   ]
289
-- >>> newMArray' @B @_ @Int (Sz2 2 6) >>= freezeS
290
-- *** Exception: Uninitialized
291
-- ...
292
--
293
-- @since 0.6.0
294
newMArray'
295
  :: forall r ix e m
296
   . (Manifest r e, Index ix, PrimMonad m)
297
  => Sz ix
298
  -> m (MArray (PrimState m) r ix e)
299
newMArray' sz = unsafeNew sz >>= \ma -> ma <$ initialize ma
2✔
300
{-# INLINE newMArray' #-}
301

302
-- | /O(n)/ - Make a mutable copy of a pure array. Keep in mind that both `freeze` and `thaw` trigger a
303
-- copy of the full array.
304
--
305
-- ==== __Example__
306
--
307
-- >>> import Data.Massiv.Array
308
-- >>> :seti -XTypeApplications
309
-- >>> arr <- fromListsM @U @Ix2 @Double Par [[12,21],[13,31]]
310
-- >>> marr <- thaw arr
311
-- >>> modify marr (pure . (+ 10)) (1 :. 0)
312
-- Just 13.0
313
-- >>> freeze Par marr
314
-- Array U Par (Sz (2 :. 2))
315
--   [ [ 12.0, 21.0 ]
316
--   , [ 23.0, 31.0 ]
317
--   ]
318
--
319
-- @since 0.1.0
320
thaw
321
  :: forall r ix e m. (Manifest r e, Index ix, MonadIO m) => Array r ix e -> m (MArray RealWorld r ix e)
322
thaw arr =
2✔
323
  liftIO $ do
2✔
324
    let sz = size arr
2✔
325
        totalLength = totalElem sz
2✔
326
    marr <- unsafeNew sz
2✔
327
    withMassivScheduler_ (getComp arr) $ \scheduler ->
2✔
328
      splitLinearly (numWorkers scheduler) totalLength $ \chunkLength slackStart -> do
2✔
329
        loopA_ 0 (< slackStart) (+ chunkLength) $ \ !start ->
2✔
330
          scheduleWork_ scheduler $ unsafeArrayLinearCopy arr start marr start (SafeSz chunkLength)
2✔
331
        let slackLength = totalLength - slackStart
2✔
332
        when (slackLength > 0) $
2✔
333
          scheduleWork_ scheduler $
2✔
334
            unsafeArrayLinearCopy arr slackStart marr slackStart (SafeSz slackLength)
2✔
335
    pure marr
2✔
336
{-# INLINE thaw #-}
337

338
-- | Same as `thaw`, but restrict computation to sequential only.
339
--
340
-- ==== __Example__
341
--
342
-- >>> import Data.Massiv.Array
343
-- >>> :seti -XOverloadedLists
344
-- >>> thawS @P @Ix1 @Double [1..10]
345
-- >>> marr <- thawS @P @Ix1 @Double [1..10]
346
-- >>> writeM marr 5 100
347
-- >>> freezeS marr
348
-- Array P Seq (Sz1 10)
349
--   [ 1.0, 2.0, 3.0, 4.0, 5.0, 100.0, 7.0, 8.0, 9.0, 10.0 ]
350
--
351
-- @since 0.3.0
352
thawS
353
  :: forall r ix e m
354
   . (Manifest r e, Index ix, PrimMonad m)
355
  => Array r ix e
356
  -> m (MArray (PrimState m) r ix e)
357
thawS arr = do
2✔
358
  tmarr <- unsafeNew (size arr)
2✔
359
  unsafeArrayLinearCopy arr 0 tmarr 0 (SafeSz (totalElem (size arr)))
2✔
360
  pure tmarr
2✔
361
{-# INLINE thawS #-}
362

363
-- | /O(n)/ - Yield an immutable copy of the mutable array. Note that mutable representations
364
-- have to be the same.
365
--
366
-- ==== __Example__
367
--
368
-- >>> import Data.Massiv.Array
369
-- >>> marr <- newMArray @P (Sz2 2 6) (0 :: Int)
370
-- >>> forM_ (range Seq 0 (Ix2 1 4)) $ \ix -> write marr ix 9
371
-- >>> freeze Seq marr
372
-- Array P Seq (Sz (2 :. 6))
373
--   [ [ 9, 9, 9, 9, 0, 0 ]
374
--   , [ 0, 0, 0, 0, 0, 0 ]
375
--   ]
376
--
377
-- @since 0.1.0
378
freeze
379
  :: forall r ix e m
380
   . (Manifest r e, Index ix, MonadIO m)
381
  => Comp
382
  -> MArray RealWorld r ix e
383
  -> m (Array r ix e)
384
freeze comp smarr =
2✔
385
  liftIO $ do
2✔
386
    let sz = sizeOfMArray smarr
2✔
387
        totalLength = totalElem sz
2✔
388
    tmarr <- unsafeNew sz
2✔
389
    withMassivScheduler_ comp $ \scheduler ->
2✔
390
      splitLinearly (numWorkers scheduler) totalLength $ \chunkLength slackStart -> do
2✔
391
        loopA_ 0 (< slackStart) (+ chunkLength) $ \ !start ->
2✔
392
          scheduleWork_ scheduler $ unsafeLinearCopy smarr start tmarr start (SafeSz chunkLength)
2✔
393
        let slackLength = totalLength - slackStart
2✔
394
        when (slackLength > 0) $
2✔
395
          scheduleWork_ scheduler $
2✔
396
            unsafeLinearCopy smarr slackStart tmarr slackStart (SafeSz slackLength)
2✔
397
    unsafeFreeze comp tmarr
2✔
398
{-# INLINE freeze #-}
399

400
-- | Same as `freeze`, but do the copy of supplied muable array sequentially. Also, unlike `freeze`
401
-- that has to be done in `IO`, `freezeS` can be used with `ST`.
402
--
403
-- @since 0.3.0
404
freezeS
405
  :: forall r ix e m
406
   . (Manifest r e, Index ix, PrimMonad m)
407
  => MArray (PrimState m) r ix e
408
  -> m (Array r ix e)
409
freezeS smarr = do
2✔
410
  let sz = sizeOfMArray smarr
2✔
411
  tmarr <- unsafeNew sz
2✔
412
  unsafeLinearCopy smarr 0 tmarr 0 (SafeSz (totalElem sz))
2✔
413
  unsafeFreeze Seq tmarr
2✔
414
{-# INLINE freezeS #-}
415

416
unsafeNewUpper
417
  :: (Load r' ix e, Manifest r e, PrimMonad m) => Array r' ix e -> m (MArray (PrimState m) r Ix1 e)
418
unsafeNewUpper !arr = unsafeNew (fromMaybe zeroSz (maxLinearSize arr))
2✔
419
{-# INLINE unsafeNewUpper #-}
420

421
-- | Load sequentially a pure array into the newly created mutable array.
422
--
423
-- @since 0.3.0
424
loadArrayS
425
  :: forall r ix e r' m
426
   . (Load r' ix e, Manifest r e, PrimMonad m)
427
  => Array r' ix e
428
  -> m (MArray (PrimState m) r ix e)
429
loadArrayS arr = do
2✔
430
  marr <- unsafeNewUpper arr
2✔
431
  stToPrim $ unsafeLoadIntoST marr arr
2✔
432
{-# INLINE loadArrayS #-}
433

434
-- | Load a pure array into the newly created mutable array, while respecting computation startegy.
435
--
436
-- @since 0.3.0
437
loadArray
438
  :: forall r ix e r' m
439
   . (Load r' ix e, Manifest r e, MonadIO m)
440
  => Array r' ix e
441
  -> m (MArray RealWorld r ix e)
442
loadArray arr =
2✔
443
  liftIO $ do
2✔
444
    marr <- unsafeNewUpper arr
2✔
445
    unsafeLoadIntoIO marr arr
2✔
446
{-# INLINE loadArray #-}
447

448
-- | Compute an Array while loading the results into the supplied mutable target array. Number of
449
-- elements for arrays must agree, otherwise `SizeElementsMismatchException` exception is thrown.
450
--
451
-- @since 0.1.3
452
computeInto
453
  :: (Load r' ix' e, Manifest r e, Index ix, MonadIO m)
454
  => MArray RealWorld r ix e
455
  -- ^ Target Array
456
  -> Array r' ix' e
457
  -- ^ Array to load
458
  -> m ()
UNCOV
459
computeInto !mArr !arr =
×
UNCOV
460
  liftIO $ do
×
UNCOV
461
    let sz = outerSize arr
×
UNCOV
462
    unless (totalElem (sizeOfMArray mArr) == totalElem sz) $
×
463
      throwM $
×
464
        SizeElementsMismatchException (sizeOfMArray mArr) sz
×
465
    withMassivScheduler_ (getComp arr) $ \scheduler ->
×
466
      stToPrim $ iterArrayLinearST_ scheduler arr (unsafeLinearWrite mArr)
×
467
{-# INLINE computeInto #-}
468

469
-- | Create a mutable array using an index aware generating action.
470
--
471
-- @since 0.3.0
472
makeMArrayS
473
  :: forall r ix e m
474
   . (Manifest r e, Index ix, PrimMonad m)
475
  => Sz ix
476
  -- ^ Size of the create array
477
  -> (ix -> m e)
478
  -- ^ Element generating action
479
  -> m (MArray (PrimState m) r ix e)
UNCOV
480
makeMArrayS sz f = makeMArrayLinearS sz (f . fromLinearIndex sz)
×
481
{-# INLINE makeMArrayS #-}
482

483
-- | Same as `makeMArrayS`, but index supplied to the action is row-major linear index.
484
--
485
-- @since 0.3.0
486
makeMArrayLinearS
487
  :: forall r ix e m
488
   . (Manifest r e, Index ix, PrimMonad m)
489
  => Sz ix
490
  -> (Int -> m e)
491
  -> m (MArray (PrimState m) r ix e)
UNCOV
492
makeMArrayLinearS sz f = do
×
UNCOV
493
  marr <- unsafeNew sz
×
UNCOV
494
  loopA_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (\ !i -> f i >>= unsafeLinearWrite marr i)
×
UNCOV
495
  return marr
×
496
{-# INLINE makeMArrayLinearS #-}
497

498
-- | Just like `makeMArrayS`, but also accepts computation strategy and runs in `IO`.
499
--
500
-- @since 0.3.0
501
makeMArray
502
  :: forall r ix e m
503
   . (MonadUnliftIO m, Manifest r e, Index ix)
504
  => Comp
505
  -> Sz ix
506
  -> (ix -> m e)
507
  -> m (MArray RealWorld r ix e)
UNCOV
508
makeMArray comp sz f = makeMArrayLinear comp sz (f . fromLinearIndex sz)
×
509
{-# INLINE makeMArray #-}
510

511
-- | Just like `makeMArrayLinearS`, but also accepts computation strategy and runs in `IO`.
512
--
513
-- @since 0.3.0
514
makeMArrayLinear
515
  :: forall r ix e m
516
   . (MonadUnliftIO m, Manifest r e, Index ix)
517
  => Comp
518
  -> Sz ix
519
  -> (Int -> m e)
520
  -> m (MArray RealWorld r ix e)
521
makeMArrayLinear comp sz f = do
2✔
522
  marr <- liftIO $ unsafeNew sz
2✔
523
  withScheduler_ comp $ \scheduler ->
2✔
524
    withRunInIO $ \run ->
2✔
525
      splitLinearlyWithM_ scheduler (totalElem sz) (run . f) (unsafeLinearWrite marr)
2✔
526
  return marr
2✔
527
{-# INLINE makeMArrayLinear #-}
528

529
-- | Create a new array by supplying an action that will fill the new blank mutable array. Use
530
-- `createArray` if you'd like to keep the result of the filling function.
531
--
532
-- ====__Examples__
533
--
534
-- >>> :seti -XTypeApplications
535
-- >>> import Data.Massiv.Array
536
-- >>> createArray_ @P @_ @Int Seq (Sz1 2) (\ s marr -> scheduleWork s (writeM marr 0 10) >> scheduleWork s (writeM marr 1 11))
537
-- Array P Seq (Sz1 2)
538
--   [ 10, 11 ]
539
--
540
-- @since 0.3.0
541
createArray_
542
  :: forall r ix e a m
543
   . (Manifest r e, Index ix, MonadUnliftIO m)
544
  => Comp
545
  -- ^ Computation strategy to use after `MArray` gets frozen and onward.
546
  -> Sz ix
547
  -- ^ Size of the newly created array
548
  -> (Scheduler RealWorld () -> MArray RealWorld r ix e -> m a)
549
  -- ^ An action that should fill all elements of the brand new mutable array
550
  -> m (Array r ix e)
UNCOV
551
createArray_ comp sz action = do
×
UNCOV
552
  marr <- liftIO $ newMArray' sz
×
UNCOV
553
  withScheduler_ comp (`action` marr)
×
UNCOV
554
  liftIO $ unsafeFreeze comp marr
×
555
{-# INLINE createArray_ #-}
556

557
-- | Just like `createArray_`, but together with `Array` it returns results of scheduled filling
558
-- actions.
559
--
560
-- @since 0.3.0
561
createArray
562
  :: forall r ix e a m b
563
   . (Manifest r e, Index ix, MonadUnliftIO m)
564
  => Comp
565
  -- ^ Computation strategy to use after `MArray` gets frozen and onward.
566
  -> Sz ix
567
  -- ^ Size of the newly created array
568
  -> (Scheduler RealWorld a -> MArray RealWorld r ix e -> m b)
569
  -- ^ An action that should fill all elements of the brand new mutable array
570
  -> m ([a], Array r ix e)
UNCOV
571
createArray comp sz action = do
×
UNCOV
572
  marr <- liftIO $ newMArray' sz
×
UNCOV
573
  a <- withScheduler comp (`action` marr)
×
UNCOV
574
  arr <- liftIO $ unsafeFreeze comp marr
×
UNCOV
575
  return (a, arr)
×
576
{-# INLINE createArray #-}
577

578
-- | Create a new array by supplying an action that will fill the new blank mutable array. Use
579
-- `createArrayS` if you'd like to keep the result of the filling function.
580
--
581
-- ====__Examples__
582
--
583
-- >>> :seti -XTypeApplications
584
-- >>> import Data.Massiv.Array
585
-- >>> createArrayS_ @P @_ @Int (Sz1 2) (\ marr -> write marr 0 10 >> write marr 1 12)
586
-- Array P Seq (Sz1 2)
587
--   [ 10, 12 ]
588
--
589
-- @since 0.3.0
590
createArrayS_
591
  :: forall r ix e a m
592
   . (Manifest r e, Index ix, PrimMonad m)
593
  => Sz ix
594
  -- ^ Size of the newly created array
595
  -> (MArray (PrimState m) r ix e -> m a)
596
  -- ^ An action that should fill all elements of the brand new mutable array
597
  -> m (Array r ix e)
UNCOV
598
createArrayS_ sz action = snd <$> createArrayS sz action
×
599
{-# INLINE createArrayS_ #-}
600

601
-- | Just like `createArray_`, but together with `Array` it returns the result of the filling action.
602
--
603
-- @since 0.3.0
604
createArrayS
605
  :: forall r ix e a m
606
   . (Manifest r e, Index ix, PrimMonad m)
607
  => Sz ix
608
  -- ^ Size of the newly created array
609
  -> (MArray (PrimState m) r ix e -> m a)
610
  -- ^ An action that should fill all elements of the brand new mutable array
611
  -> m (a, Array r ix e)
UNCOV
612
createArrayS sz action = do
×
UNCOV
613
  marr <- newMArray' sz
×
UNCOV
614
  a <- action marr
×
UNCOV
615
  arr <- unsafeFreeze Seq marr
×
UNCOV
616
  return (a, arr)
×
617
{-# INLINE createArrayS #-}
618

619
-- | Just like `createArrayS_`, but restricted to `ST`.
620
--
621
-- @since 0.3.0
622
createArrayST_
623
  :: forall r ix e a
624
   . (Manifest r e, Index ix)
625
  => Sz ix
626
  -> (forall s. MArray s r ix e -> ST s a)
627
  -> Array r ix e
UNCOV
628
createArrayST_ sz action = runST $ createArrayS_ sz action
×
629
{-# INLINE createArrayST_ #-}
630

631
-- | Just like `createArrayS`, but restricted to `ST`.
632
--
633
-- @since 0.2.6
634
createArrayST
635
  :: forall r ix e a
636
   . (Manifest r e, Index ix)
637
  => Sz ix
638
  -> (forall s. MArray s r ix e -> ST s a)
639
  -> (a, Array r ix e)
UNCOV
640
createArrayST sz action = runST $ createArrayS sz action
×
641
{-# INLINE createArrayST #-}
642

643
-- | Sequentially generate a pure array. Much like `makeArray` creates a pure array this
644
-- function will use `Manifest` interface to generate a pure `Array` in the end, except that
645
-- computation strategy is set to `Seq`. Element producing function no longer has to be pure
646
-- but is a stateful action, becuase it is restricted to `PrimMonad` thus allows for sharing
647
-- the state between computation of each element.
648
--
649
-- ====__Examples__
650
--
651
-- >>> import Data.Massiv.Array
652
-- >>> import Data.IORef
653
-- >>> ref <- newIORef (0 :: Int)
654
-- >>> generateArrayS (Sz1 6) (\ i -> modifyIORef' ref (+i) >> print i >> pure i) :: IO (Array U Ix1 Int)
655
-- 0
656
-- 1
657
-- 2
658
-- 3
659
-- 4
660
-- 5
661
-- Array U Seq (Sz1 6)
662
--   [ 0, 1, 2, 3, 4, 5 ]
663
-- >>> readIORef ref
664
-- 15
665
--
666
-- @since 0.2.6
667
generateArrayS
668
  :: forall r ix e m
669
   . (Manifest r e, Index ix, PrimMonad m)
670
  => Sz ix
671
  -- ^ Size of the array
672
  -> (ix -> m e)
673
  -- ^ Element producing action
674
  -> m (Array r ix e)
675
generateArrayS sz gen = generateArrayLinearS sz (gen . fromLinearIndex sz)
2✔
676
{-# INLINE generateArrayS #-}
677

678
-- | Same as `generateArray` but with action that accepts row-major linear index.
679
--
680
-- @since 0.3.0
681
generateArrayLinearS
682
  :: forall r ix e m
683
   . (Manifest r e, Index ix, PrimMonad m)
684
  => Sz ix
685
  -- ^ Resulting size of the array
686
  -> (Int -> m e)
687
  -- ^ Element producing generator
688
  -> m (Array r ix e)
689
generateArrayLinearS sz gen = do
2✔
690
  marr <- unsafeNew sz
2✔
691
  loopA_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) $ \i -> gen i >>= unsafeLinearWrite marr i
2✔
692
  unsafeFreeze Seq marr
2✔
693
{-# INLINE generateArrayLinearS #-}
694

695
-- | Just like `generateArrayS`, except this generator __will__ respect the supplied computation
696
-- strategy, and for that reason it is restricted to `IO`.
697
--
698
-- @since 0.2.6
699
generateArray
700
  :: forall r ix e m
701
   . (MonadUnliftIO m, Manifest r e, Index ix)
702
  => Comp
703
  -> Sz ix
704
  -> (ix -> m e)
705
  -> m (Array r ix e)
706
generateArray comp sz f = generateArrayLinear comp sz (f . fromLinearIndex sz)
2✔
707
{-# INLINE generateArray #-}
708

709
-- | Just like `generateArray`, except generating action will receive a row-major linear
710
-- index.
711
--
712
-- @since 0.3.0
713
generateArrayLinear
714
  :: forall r ix e m
715
   . (MonadUnliftIO m, Manifest r e, Index ix)
716
  => Comp
717
  -> Sz ix
718
  -> (Ix1 -> m e)
719
  -> m (Array r ix e)
720
generateArrayLinear comp sz f = makeMArrayLinear comp sz f >>= liftIO . unsafeFreeze comp
2✔
721
{-# INLINE generateArrayLinear #-}
722

723
-- | Similar to `Data.Massiv.Array.makeSplitSeedArray`, except it will produce a
724
-- Manifest array and will return back the last unused seed together with all
725
-- final seeds produced by each scheduled job. This function can be thought of
726
-- as an unfolding done in parallel while iterating in a customizable manner.
727
--
728
-- @since 1.0.2
729
generateSplitSeedArray
730
  :: forall r ix e g it
731
   . (Iterator it, Manifest r e, Index ix)
732
  => it
733
  -- ^ Iterator
734
  -> g
735
  -- ^ Initial seed
736
  -> (forall s. g -> ST s (g, g))
737
  -- ^ An ST action that can split a seed into two independent seeds. It will
738
  -- be called the same number of times as the number of jobs that will get
739
  -- scheduled during parallelization. Eg. only once for the sequential case.
740
  -> Comp
741
  -- ^ Computation strategy.
742
  -> Sz ix
743
  -- ^ Resulting size of the array.
744
  -> (forall s. Ix1 -> ix -> g -> ST s (e, g))
745
  -- ^ An ST action that produces a value and the next seed. It takes both
746
  -- versions of the index, in linear and in multi-dimensional forms, as well
747
  -- as the current seeding value. Returns the element for the array cell
748
  -- together with the new seed that will be used for the next element
749
  -- generation
750
  -> (g, [g], Array r ix e)
751
  -- ^ Returned values are:
752
  --
753
  -- * The final split of the supplied seed.
754
  --
755
  -- * Results of scheduled jobs in the same order that they where scheduled
756
  --
757
  -- * Final array that was fully filled using the supplied action and iterator.
UNCOV
758
generateSplitSeedArray it seed splitSeed comp sz genFunc =
×
UNCOV
759
  unsafePerformIO $ do
×
UNCOV
760
    marr <- unsafeNew sz
×
UNCOV
761
    ref <- newIORef Nothing
×
UNCOV
762
    res <- withSchedulerR comp $ \scheduler -> do
×
UNCOV
763
      fin <- stToIO $
×
764
        iterTargetFullAccST it scheduler 0 sz seed splitSeed $ \ !i ix !g ->
×
765
          genFunc i ix g >>= \(x, g') -> g' <$ unsafeLinearWrite marr i x
×
766
      writeIORef ref $ Just fin
×
767
    mFin <- readIORef ref
×
768
    case res of
×
769
      Finished gs
770
        | Just fin <- mFin -> do
×
771
            arr <- unsafeFreeze comp marr
×
772
            pure (fin, gs, arr)
×
773
      -- This case does not make much sence for array filling and can only
774
      -- happen with a custom 'Iterator' defined outside massiv, therefore it is
775
      -- ok to not support it.
776
      _ ->
777
        error $
×
778
          "Parallelized array filling finished prematurely. "
×
UNCOV
779
            ++ "This feature is not supported by the 'generateSplitSeedArray' function."
×
780
{-# INLINE generateSplitSeedArray #-}
781

782
-- | Same as `generateArrayWS`, but use linear indexing instead.
783
--
784
-- @since 0.3.4
785
generateArrayLinearWS
786
  :: forall r ix e s m
787
   . (Manifest r e, Index ix, MonadUnliftIO m, PrimMonad m)
788
  => WorkerStates s
789
  -> Sz ix
790
  -> (Int -> s -> m e)
791
  -> m (Array r ix e)
792
generateArrayLinearWS states sz make = do
2✔
793
  marr <- unsafeNew sz
2✔
794
  withSchedulerWS_ states $ \schedulerWS ->
2✔
795
    splitLinearlyWithStatefulM_
2✔
796
      schedulerWS
2✔
797
      (totalElem sz)
2✔
798
      make
2✔
799
      (unsafeLinearWrite marr)
2✔
800
  unsafeFreeze (workerStatesComp states) marr
2✔
801
{-# INLINE generateArrayLinearWS #-}
802

803
-- | Use per worker thread state while generating elements of the array. Very useful for
804
-- things that are not thread safe.
805
--
806
-- @since 0.3.4
807
generateArrayWS
808
  :: forall r ix e s m
809
   . (Manifest r e, Index ix, MonadUnliftIO m, PrimMonad m)
810
  => WorkerStates s
811
  -> Sz ix
812
  -> (ix -> s -> m e)
813
  -> m (Array r ix e)
814
generateArrayWS states sz make = generateArrayLinearWS states sz (make . fromLinearIndex sz)
2✔
815
{-# INLINE generateArrayWS #-}
816

817
-- | Sequentially unfold an array from the left.
818
--
819
-- ====__Examples__
820
--
821
-- Create an array with Fibonacci numbers while performing an `IO` action at each iteration.
822
--
823
-- >>> import Data.Massiv.Array
824
-- >>> unfoldrPrimM_ (Sz1 10) (\(f0, f1) -> (f0, (f1, f0 + f1)) <$ print f1) (0, 1) :: IO (Array P Ix1 Int)
825
-- 1
826
-- 1
827
-- 2
828
-- 3
829
-- 5
830
-- 8
831
-- 13
832
-- 21
833
-- 34
834
-- 55
835
-- Array P Seq (Sz1 10)
836
--   [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
837
--
838
-- @since 0.3.0
839
unfoldrPrimM_
840
  :: forall r ix e a m
841
   . (Manifest r e, Index ix, PrimMonad m)
842
  => Sz ix
843
  -- ^ Size of the desired array
844
  -> (a -> m (e, a))
845
  -- ^ Unfolding action
846
  -> a
847
  -- ^ Initial accumulator
848
  -> m (Array r ix e)
849
unfoldrPrimM_ sz gen acc0 = snd <$> unfoldrPrimM sz gen acc0
2✔
850
{-# INLINE unfoldrPrimM_ #-}
851

852
-- | Same as `unfoldrPrimM_` but do the unfolding with index aware function.
853
--
854
-- @since 0.3.0
855
iunfoldrPrimM_
856
  :: forall r ix e a m
857
   . (Manifest r e, Index ix, PrimMonad m)
858
  => Sz ix
859
  -- ^ Size of the desired array
860
  -> (a -> ix -> m (e, a))
861
  -- ^ Unfolding action
862
  -> a
863
  -- ^ Initial accumulator
864
  -> m (Array r ix e)
UNCOV
865
iunfoldrPrimM_ sz gen acc0 = snd <$> iunfoldrPrimM sz gen acc0
×
866
{-# INLINE iunfoldrPrimM_ #-}
867

868
-- | Just like `iunfoldrPrimM_`, but also returns the final value of the accumulator.
869
--
870
-- @since 0.3.0
871
iunfoldrPrimM
872
  :: forall r ix e a m
873
   . (Manifest r e, Index ix, PrimMonad m)
874
  => Sz ix
875
  -- ^ Size of the desired array
876
  -> (a -> ix -> m (e, a))
877
  -- ^ Unfolding action
878
  -> a
879
  -- ^ Initial accumulator
880
  -> m (a, Array r ix e)
UNCOV
881
iunfoldrPrimM sz gen acc0 =
×
UNCOV
882
  unsafeCreateArrayS sz $ \marr ->
×
UNCOV
883
    let sz' = sizeOfMArray marr
×
UNCOV
884
     in iterLinearM sz' 0 (totalElem sz') 1 (<) acc0 $ \ !i ix !acc -> do
×
UNCOV
885
          (e, acc') <- gen acc ix
×
UNCOV
886
          unsafeLinearWrite marr i e
×
887
          pure acc'
×
888
{-# INLINE iunfoldrPrimM #-}
889

890
-- | Just like `iunfoldrPrimM`, but do the unfolding with index aware function.
891
--
892
-- @since 0.3.0
893
unfoldrPrimM
894
  :: forall r ix e a m
895
   . (Manifest r e, Index ix, PrimMonad m)
896
  => Sz ix
897
  -- ^ Size of the desired array
898
  -> (a -> m (e, a))
899
  -- ^ Unfolding action
900
  -> a
901
  -- ^ Initial accumulator
902
  -> m (a, Array r ix e)
903
unfoldrPrimM sz gen acc0 =
2✔
904
  unsafeCreateArrayS sz $ \marr ->
2✔
905
    let sz' = sizeOfMArray marr
2✔
906
     in loopM 0 (< totalElem sz') (+ 1) acc0 $ \ !i !acc -> do
2✔
907
          (e, acc') <- gen acc
2✔
908
          unsafeLinearWrite marr i e
2✔
909
          pure acc'
2✔
910
{-# INLINE unfoldrPrimM #-}
911

912
-- | Sequentially unfold an array from the left.
913
--
914
-- ====__Examples__
915
--
916
-- Create an array with Fibonacci numbers starting at the end while performing and `IO` action on
917
-- the accumulator for each element of the array.
918
--
919
-- >>> import Data.Massiv.Array
920
-- >>> unfoldlPrimM_ (Sz1 10) (\a@(f0, f1) -> let fn = f0 + f1 in print a >> return ((f1, fn), f0)) (0, 1) :: IO (Array P Ix1 Int)
921
-- (0,1)
922
-- (1,1)
923
-- (1,2)
924
-- (2,3)
925
-- (3,5)
926
-- (5,8)
927
-- (8,13)
928
-- (13,21)
929
-- (21,34)
930
-- (34,55)
931
-- Array P Seq (Sz1 10)
932
--   [ 34, 21, 13, 8, 5, 3, 2, 1, 1, 0 ]
933
--
934
-- @since 0.3.0
935
unfoldlPrimM_
936
  :: forall r ix e a m
937
   . (Manifest r e, Index ix, PrimMonad m)
938
  => Sz ix
939
  -- ^ Size of the desired array
940
  -> (a -> m (a, e))
941
  -- ^ Unfolding action
942
  -> a
943
  -- ^ Initial accumulator
944
  -> m (Array r ix e)
945
unfoldlPrimM_ sz gen acc0 = snd <$> unfoldlPrimM sz gen acc0
2✔
946
{-# INLINE unfoldlPrimM_ #-}
947

948
-- | Same as `unfoldlPrimM_` but do the unfolding with index aware function.
949
--
950
-- @since 0.3.0
951
iunfoldlPrimM_
952
  :: forall r ix e a m
953
   . (Manifest r e, Index ix, PrimMonad m)
954
  => Sz ix
955
  -- ^ Size of the desired array
956
  -> (a -> ix -> m (a, e))
957
  -- ^ Unfolding action
958
  -> a
959
  -- ^ Initial accumulator
960
  -> m (Array r ix e)
UNCOV
961
iunfoldlPrimM_ sz gen acc0 = snd <$> iunfoldlPrimM sz gen acc0
×
962
{-# INLINE iunfoldlPrimM_ #-}
963

964
-- | Just like `iunfoldlPrimM_`, but also returns the final value of the accumulator.
965
--
966
-- @since 0.3.0
967
iunfoldlPrimM
968
  :: forall r ix e a m
969
   . (Manifest r e, Index ix, PrimMonad m)
970
  => Sz ix
971
  -- ^ Size of the desired array
972
  -> (a -> ix -> m (a, e))
973
  -- ^ Unfolding action
974
  -> a
975
  -- ^ Initial accumulator
976
  -> m (a, Array r ix e)
UNCOV
977
iunfoldlPrimM sz gen acc0 =
×
UNCOV
978
  unsafeCreateArrayS sz $ \marr ->
×
UNCOV
979
    let sz' = sizeOfMArray marr
×
UNCOV
980
     in iterLinearM sz' (totalElem sz' - 1) 0 (negate 1) (>=) acc0 $ \ !i ix !acc -> do
×
UNCOV
981
          (acc', e) <- gen acc ix
×
UNCOV
982
          unsafeLinearWrite marr i e
×
983
          pure acc'
×
984
{-# INLINE iunfoldlPrimM #-}
985

986
-- | Just like `iunfoldlPrimM`, but do the unfolding with index aware function.
987
--
988
-- @since 0.3.0
989
unfoldlPrimM
990
  :: forall r ix e a m
991
   . (Manifest r e, Index ix, PrimMonad m)
992
  => Sz ix
993
  -- ^ Size of the desired array
994
  -> (a -> m (a, e))
995
  -- ^ Unfolding action
996
  -> a
997
  -- ^ Initial accumulator
998
  -> m (a, Array r ix e)
999
unfoldlPrimM sz gen acc0 =
2✔
1000
  unsafeCreateArrayS sz $ \marr ->
2✔
1001
    let sz' = sizeOfMArray marr
2✔
1002
     in loopDeepM 0 (< totalElem sz') (+ 1) acc0 $ \ !i !acc -> do
2✔
1003
          (acc', e) <- gen acc
2✔
1004
          unsafeLinearWrite marr i e
2✔
1005
          pure acc'
2✔
1006
{-# INLINE unfoldlPrimM #-}
1007

1008
-- | Sequentially loop over a mutable array while reading each element and applying an
1009
-- action to it. There is no mutation to the array, unless the action itself modifies it.
1010
--
1011
-- @since 0.4.0
1012
forPrimM_
1013
  :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (e -> m ()) -> m ()
UNCOV
1014
forPrimM_ marr f =
×
UNCOV
1015
  loopA_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (unsafeLinearRead marr >=> f)
×
1016
{-# INLINE forPrimM_ #-}
1017

1018
-- | Sequentially loop over a mutable array while modifying each element with an action.
1019
--
1020
-- @since 0.4.0
1021
forPrimM
1022
  :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (e -> m e) -> m ()
1023
forPrimM marr f =
2✔
1024
  loopA_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (unsafeLinearModify marr f)
2✔
1025
{-# INLINE forPrimM #-}
1026

1027
-- | Sequentially loop over a mutable array while reading each element and applying an
1028
-- index aware action to it. There is no mutation to the array, unless the
1029
-- action itself modifies it.
1030
--
1031
-- @since 0.4.0
1032
iforPrimM_
1033
  :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (ix -> e -> m ()) -> m ()
UNCOV
1034
iforPrimM_ marr f = iforLinearPrimM_ marr (f . fromLinearIndex (sizeOfMArray marr))
×
1035
{-# INLINE iforPrimM_ #-}
1036

1037
-- | Sequentially loop over a mutable array while modifying each element with an index aware action.
1038
--
1039
-- @since 0.4.0
1040
iforPrimM
1041
  :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (ix -> e -> m e) -> m ()
UNCOV
1042
iforPrimM marr f = iforLinearPrimM marr (f . fromLinearIndex (sizeOfMArray marr))
×
1043
{-# INLINE iforPrimM #-}
1044

1045
-- | Sequentially loop over a mutable array while reading each element and applying a
1046
-- linear index aware action to it. There is no mutation to the array, unless the action
1047
-- itself modifies it.
1048
--
1049
-- @since 0.4.0
1050
iforLinearPrimM_
1051
  :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (Int -> e -> m ()) -> m ()
UNCOV
1052
iforLinearPrimM_ marr f =
×
UNCOV
1053
  loopA_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (\i -> unsafeLinearRead marr i >>= f i)
×
1054
{-# INLINE iforLinearPrimM_ #-}
1055

1056
-- | Sequentially loop over a mutable array while modifying each element with an index aware action.
1057
--
1058
-- @since 0.4.0
1059
iforLinearPrimM
1060
  :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (Int -> e -> m e) -> m ()
UNCOV
1061
iforLinearPrimM marr f =
×
UNCOV
1062
  loopA_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (\i -> unsafeLinearModify marr (f i) i)
×
1063
{-# INLINE iforLinearPrimM #-}
1064

1065
-- | Sequentially loop over the intersection of two mutable arrays while reading
1066
-- elements from both and applying an action to it. There is no mutation to the
1067
-- actual arrays, unless the action itself modifies either one of them.
1068
--
1069
-- @since 1.0.0
1070
for2PrimM_
1071
  :: forall r1 r2 e1 e2 ix m
1072
   . (PrimMonad m, Index ix, Manifest r1 e1, Manifest r2 e2)
1073
  => MArray (PrimState m) r1 ix e1
1074
  -> MArray (PrimState m) r2 ix e2
1075
  -> (e1 -> e2 -> m ())
1076
  -> m ()
UNCOV
1077
for2PrimM_ m1 m2 f = ifor2PrimM_ m1 m2 (const f)
×
1078
{-# INLINE for2PrimM_ #-}
1079

1080
-- | Same as `for2PrimM_`, but with index aware action.
1081
--
1082
-- @since 1.0.0
1083
ifor2PrimM_
1084
  :: forall r1 r2 e1 e2 ix m
1085
   . (PrimMonad m, Index ix, Manifest r1 e1, Manifest r2 e2)
1086
  => MArray (PrimState m) r1 ix e1
1087
  -> MArray (PrimState m) r2 ix e2
1088
  -> (ix -> e1 -> e2 -> m ())
1089
  -> m ()
UNCOV
1090
ifor2PrimM_ m1 m2 f = do
×
UNCOV
1091
  let sz = liftIndex2 min (unSz (sizeOfMArray m1)) (unSz (sizeOfMArray m2))
×
UNCOV
1092
  iterA_ zeroIndex sz oneIndex (<) $ \ix -> do
×
UNCOV
1093
    e1 <- unsafeRead m1 ix
×
UNCOV
1094
    e2 <- unsafeRead m2 ix
×
UNCOV
1095
    f ix e1 e2
×
1096
{-# INLINE ifor2PrimM_ #-}
1097

1098
-- | Same as `withMArray_`, but allows to keep artifacts of scheduled tasks.
1099
--
1100
-- @since 0.5.0
1101
withMArray
1102
  :: (Manifest r e, Index ix, MonadUnliftIO m)
1103
  => Array r ix e
1104
  -> (Scheduler RealWorld a -> MArray RealWorld r ix e -> m b)
1105
  -> m ([a], Array r ix e)
UNCOV
1106
withMArray arr action = do
×
UNCOV
1107
  marr <- thaw arr
×
UNCOV
1108
  xs <- withScheduler (getComp arr) (`action` marr)
×
UNCOV
1109
  liftIO ((,) xs <$> unsafeFreeze (getComp arr) marr)
×
1110
{-# INLINE withMArray #-}
1111

1112
-- | Create a copy of a pure array, mutate it in place and return its frozen version. The big
1113
-- difference between `withMArrayS` is that it's not only gonna respect the computation strategy
1114
-- supplied to it while making a copy, but it will also pass extra argumens to the action that
1115
-- suppose to modify the mutable copy of the source array. These two extra arguments are:
1116
--
1117
-- * Number of capabilities derived from the `Comp`utation strategy of the array.
1118
--
1119
-- * An action that can be used to schedule arbitrary number of jobs that will be executed in
1120
--   parallel.
1121
--
1122
-- * And, of course, the mutable array itself.
1123
--
1124
-- @since 0.5.0
1125
withMArray_
1126
  :: (Manifest r e, Index ix, MonadUnliftIO m)
1127
  => Array r ix e
1128
  -> (Scheduler RealWorld () -> MArray RealWorld r ix e -> m a)
1129
  -> m (Array r ix e)
1130
withMArray_ arr action = do
2✔
1131
  marr <- thaw arr
2✔
1132
  withScheduler_ (getComp arr) (`action` marr)
2✔
1133
  liftIO $ unsafeFreeze (getComp arr) marr
2✔
1134
{-# INLINE withMArray_ #-}
1135

1136
-- | Same as `withMArray_`, but the array supplied to this function can be any loadable
1137
-- array. For that reason it will be faster if supplied array is delayed.
1138
--
1139
-- @since 0.6.1
1140
withLoadMArray_
1141
  :: forall r ix e r' m b
1142
   . (Load r' ix e, Manifest r e, MonadUnliftIO m)
1143
  => Array r' ix e
1144
  -> (Scheduler RealWorld () -> MArray RealWorld r ix e -> m b)
1145
  -> m (Array r ix e)
1146
withLoadMArray_ arr action = do
2✔
1147
  marr <- loadArray arr
2✔
1148
  withScheduler_ (getComp arr) (`action` marr)
2✔
1149
  liftIO $ unsafeFreeze (getComp arr) marr
2✔
1150
{-# INLINE [2] withLoadMArray_ #-}
1151

1152
{-# RULES
1153
"withLoadMArray_/withMArray_" [~2] withLoadMArray_ = withMArray_
1154
"withLoadMArrayS/withMArrayS" [~2] withLoadMArrayS = withMArrayS
1155
"withLoadMArrayS_/withMArrayS_" [~2] withLoadMArrayS_ = withMArrayS_
1156
  #-}
1157

1158
-- | Create a copy of a pure array, mutate it in place and return its frozen version. The important
1159
-- benefit over doing a manual `thawS` followed by a `freezeS` is that an array will only be copied
1160
-- once.
1161
--
1162
-- @since 0.5.0
1163
withMArrayS
1164
  :: (Manifest r e, Index ix, PrimMonad m)
1165
  => Array r ix e
1166
  -> (MArray (PrimState m) r ix e -> m a)
1167
  -> m (a, Array r ix e)
1168
withMArrayS arr action = do
2✔
1169
  marr <- thawS arr
2✔
1170
  a <- action marr
2✔
1171
  (,) a <$> unsafeFreeze (getComp arr) marr
1✔
1172
{-# INLINE withMArrayS #-}
1173

1174
-- | Same as `withMArrayS`, except it discards the value produced by the supplied action
1175
--
1176
-- @since 0.5.0
1177
withMArrayS_
1178
  :: (Manifest r e, Index ix, PrimMonad m)
1179
  => Array r ix e
1180
  -> (MArray (PrimState m) r ix e -> m a)
1181
  -> m (Array r ix e)
1182
withMArrayS_ arr action = snd <$> withMArrayS arr action
2✔
1183
{-# INLINE withMArrayS_ #-}
1184

1185
-- | Same as `withMArrayS`, but will work with any loadable array.
1186
--
1187
-- @since 0.6.1
1188
withLoadMArrayS
1189
  :: forall r ix e r' m a
1190
   . (Load r' ix e, Manifest r e, PrimMonad m)
1191
  => Array r' ix e
1192
  -> (MArray (PrimState m) r ix e -> m a)
1193
  -> m (a, Array r ix e)
1194
withLoadMArrayS arr action = do
2✔
1195
  marr <- loadArrayS arr
2✔
1196
  a <- action marr
2✔
1197
  (,) a <$> unsafeFreeze (getComp arr) marr
1✔
1198
{-# INLINE [2] withLoadMArrayS #-}
1199

1200
-- | Same as `withMArrayS_`, but will work with any loadable array.
1201
--
1202
-- @since 0.6.1
1203
withLoadMArrayS_
1204
  :: forall r ix e r' m a
1205
   . (Load r' ix e, Manifest r e, PrimMonad m)
1206
  => Array r' ix e
1207
  -> (MArray (PrimState m) r ix e -> m a)
1208
  -> m (Array r ix e)
1209
withLoadMArrayS_ arr action = snd <$> withLoadMArrayS arr action
2✔
1210
{-# INLINE [2] withLoadMArrayS_ #-}
1211

1212
-- | Same as `withMArrayS` but in `ST`. This is not only pure, but also the safest way to do
1213
-- mutation to the array.
1214
--
1215
-- @since 0.5.0
1216
withMArrayST
1217
  :: (Manifest r e, Index ix)
1218
  => Array r ix e
1219
  -> (forall s. MArray s r ix e -> ST s a)
1220
  -> (a, Array r ix e)
UNCOV
1221
withMArrayST arr f = runST $ withMArrayS arr f
×
1222
{-# INLINE withMArrayST #-}
1223

1224
-- | Same as `withMArrayS` but in `ST`. This is not only pure, but also the safest way to do
1225
-- mutation to the array.
1226
--
1227
-- @since 0.5.0
1228
withMArrayST_
1229
  :: (Manifest r e, Index ix) => Array r ix e -> (forall s. MArray s r ix e -> ST s a) -> Array r ix e
1230
withMArrayST_ arr f = runST $ withMArrayS_ arr f
2✔
1231
{-# INLINE withMArrayST_ #-}
1232

1233
-- | Same as `withMArrayST`, but works with any loadable array.
1234
--
1235
-- @since 0.6.1
1236
withLoadMArrayST
1237
  :: forall r ix e r' a
1238
   . (Load r' ix e, Manifest r e)
1239
  => Array r' ix e
1240
  -> (forall s. MArray s r ix e -> ST s a)
1241
  -> (a, Array r ix e)
UNCOV
1242
withLoadMArrayST arr f = runST $ withLoadMArrayS arr f
×
1243
{-# INLINE [2] withLoadMArrayST #-}
1244

1245
-- | Same as `withMArrayST_`, but works with any loadable array.
1246
--
1247
-- @since 0.6.1
1248
withLoadMArrayST_
1249
  :: forall r ix e r' a
1250
   . (Load r' ix e, Manifest r e)
1251
  => Array r' ix e
1252
  -> (forall s. MArray s r ix e -> ST s a)
1253
  -> Array r ix e
1254
withLoadMArrayST_ arr f = runST $ withLoadMArrayS_ arr f
2✔
1255
{-# INLINE [2] withLoadMArrayST_ #-}
1256

1257
-- | /O(1)/ - Lookup an element in the mutable array. Returns `Nothing` when index is out of bounds.
1258
--
1259
-- @since 0.1.0
1260
read
1261
  :: (Manifest r e, Index ix, PrimMonad m)
1262
  => MArray (PrimState m) r ix e
1263
  -> ix
1264
  -> m (Maybe e)
1265
read marr ix =
2✔
1266
  if isSafeIndex (sizeOfMArray marr) ix
2✔
1267
    then Just <$> unsafeRead marr ix
2✔
1268
    else return Nothing
2✔
1269
{-# INLINE read #-}
1270

1271
-- | /O(1)/ - Same as `read`, but throws `IndexOutOfBoundsException` on an invalid index.
1272
--
1273
-- @since 0.4.0
1274
readM
1275
  :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m)
1276
  => MArray (PrimState m) r ix e
1277
  -> ix
1278
  -> m e
1279
readM marr ix =
2✔
1280
  read marr ix >>= \case
2✔
1281
    Just e -> pure e
2✔
1282
    Nothing -> throwM $ IndexOutOfBoundsException (sizeOfMArray marr) ix
2✔
1283
{-# INLINE readM #-}
1284

1285
-- | /O(1)/ - Write an element into the cell of a mutable array. Returns `False` when index is out
1286
-- of bounds.
1287
--
1288
-- @since 0.1.0
1289
write :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> e -> m Bool
1290
write marr ix e =
2✔
1291
  if isSafeIndex (sizeOfMArray marr) ix
2✔
1292
    then unsafeWrite marr ix e >> pure True
2✔
1293
    else pure False
2✔
1294
{-# INLINE write #-}
1295

1296
-- | /O(1)/ - Write an element into the cell of a mutable array. Same as `write` function
1297
-- in case of an out of bounds index it is noop, but unlike `write`, there is no
1298
-- information is returned about was the writing of element successful or not.  In other
1299
-- words, just like `writeM`, but doesn't throw an exception.
1300
--
1301
-- @since 0.4.4
1302
write_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> e -> m ()
1303
write_ marr ix = when (isSafeIndex (sizeOfMArray marr) ix) . unsafeWrite marr ix
2✔
1304
{-# INLINE write_ #-}
1305

1306
-- | /O(1)/ - Same as `write`, but throws `IndexOutOfBoundsException` on an invalid index.
1307
--
1308
-- @since 0.4.0
1309
writeM
1310
  :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m)
1311
  => MArray (PrimState m) r ix e -> ix -> e -> m ()
1312
writeM marr ix e =
2✔
1313
  write marr ix e >>= (`unless` throwM (IndexOutOfBoundsException (sizeOfMArray marr) ix))
2✔
1314
{-# INLINE writeM #-}
1315

1316
-- | /O(1)/ - Modify an element in the cell of a mutable array with a supplied
1317
-- action. Returns the previous value, if index was not out of bounds.
1318
--
1319
-- @since 0.1.0
1320
modify
1321
  :: (Manifest r e, Index ix, PrimMonad m)
1322
  => MArray (PrimState m) r ix e
1323
  -- ^ Array to mutate.
1324
  -> (e -> m e)
1325
  -- ^ Monadic action that modifies the element
1326
  -> ix
1327
  -- ^ Index at which to perform modification.
1328
  -> m (Maybe e)
1329
modify marr f ix =
2✔
1330
  if isSafeIndex (sizeOfMArray marr) ix
2✔
1331
    then Just <$> unsafeModify marr f ix
2✔
1332
    else return Nothing
2✔
1333
{-# INLINE modify #-}
1334

1335
-- | /O(1)/ - Same as `modify`, except that neither the previous value, nor any
1336
-- information on whether the modification was successful are returned. In other words,
1337
-- just like `modifyM_`, but doesn't throw an exception.
1338
--
1339
-- @since 0.4.4
1340
modify_
1341
  :: (Manifest r e, Index ix, PrimMonad m)
1342
  => MArray (PrimState m) r ix e
1343
  -- ^ Array to mutate.
1344
  -> (e -> m e)
1345
  -- ^ Monadic action that modifies the element
1346
  -> ix
1347
  -- ^ Index at which to perform modification.
1348
  -> m ()
1349
modify_ marr f ix = when (isSafeIndex (sizeOfMArray marr) ix) $ void $ unsafeModify marr f ix
2✔
1350
{-# INLINE modify_ #-}
1351

1352
-- | /O(1)/ - Modify an element in the cell of a mutable array with a supplied
1353
-- action. Throws an `IndexOutOfBoundsException` exception for invalid index and returns
1354
-- the previous value otherwise.
1355
--
1356
-- @since 0.4.0
1357
modifyM
1358
  :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m)
1359
  => MArray (PrimState m) r ix e
1360
  -- ^ Array to mutate.
1361
  -> (e -> m e)
1362
  -- ^ Monadic action that modifies the element
1363
  -> ix
1364
  -- ^ Index at which to perform modification.
1365
  -> m e
1366
modifyM marr f ix
2✔
1367
  | isSafeIndex (sizeOfMArray marr) ix = unsafeModify marr f ix
2✔
1368
  | otherwise = throwM (IndexOutOfBoundsException (sizeOfMArray marr) ix)
1✔
1369
{-# INLINE modifyM #-}
1370

1371
-- | /O(1)/ - Same as `modifyM`, but discard the returned element
1372
--
1373
-- ====__Examples__
1374
--
1375
-- >>> :seti -XTypeApplications
1376
-- >>> import Control.Monad.ST
1377
-- >>> import Data.Massiv.Array
1378
-- >>> runST $ newMArray' @P @Ix1 @Int (Sz1 3) >>= (\ma -> modifyM_ ma (pure . (+10)) 1 >> freezeS ma)
1379
-- Array P Seq (Sz1 3)
1380
--   [ 0, 10, 0 ]
1381
--
1382
-- @since 0.4.0
1383
modifyM_
1384
  :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m)
1385
  => MArray (PrimState m) r ix e
1386
  -- ^ Array to mutate.
1387
  -> (e -> m e)
1388
  -- ^ Monadic action that modifies the element
1389
  -> ix
1390
  -- ^ Index at which to perform modification.
1391
  -> m ()
1392
modifyM_ marr f ix = void $ modifyM marr f ix
2✔
1393
{-# INLINE modifyM_ #-}
1394

1395
-- | /O(1)/ - Same as `swapM`, but instead of throwing an exception returns `Nothing` when
1396
-- either one of the indices is out of bounds and `Just` elements under those indices
1397
-- otherwise.
1398
--
1399
-- @since 0.1.0
1400
swap
1401
  :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> ix -> m (Maybe (e, e))
1402
swap marr ix1 ix2 =
2✔
1403
  let !sz = sizeOfMArray marr
2✔
1404
   in if isSafeIndex sz ix1 && isSafeIndex sz ix2
2✔
1405
        then Just <$> unsafeSwap marr ix1 ix2
2✔
1406
        else pure Nothing
2✔
1407
{-# INLINE swap #-}
1408

1409
-- | /O(1)/ - Same as `swap`, but instead of returning `Nothing` it does nothing. In other
1410
-- words, it is similar to `swapM_`, but does not throw any exceptions.
1411
--
1412
-- @since 0.4.4
1413
swap_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> ix -> m ()
1414
swap_ marr ix1 ix2 =
2✔
1415
  let !sz = sizeOfMArray marr
2✔
1416
   in when (isSafeIndex sz ix1 && isSafeIndex sz ix2) $ void $ unsafeSwap marr ix1 ix2
2✔
1417
{-# INLINE swap_ #-}
1418

1419
-- | /O(1)/ - Swap two elements in a mutable array under the supplied indices. Throws an
1420
-- `IndexOutOfBoundsException` when either one of the indices is out of bounds and
1421
-- elements under those indices otherwise.
1422
--
1423
-- @since 0.4.0
1424
swapM
1425
  :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m)
1426
  => MArray (PrimState m) r ix e
1427
  -> ix
1428
  -- ^ Index for the first element, which will be returned as the first element in the
1429
  -- tuple.
1430
  -> ix
1431
  -- ^ Index for the second element, which will be returned as the second element in
1432
  -- the tuple.
1433
  -> m (e, e)
1434
swapM marr ix1 ix2
2✔
1435
  | not (isSafeIndex sz ix1) = throwM $ IndexOutOfBoundsException (sizeOfMArray marr) ix1
2✔
1436
  | not (isSafeIndex sz ix2) = throwM $ IndexOutOfBoundsException (sizeOfMArray marr) ix2
2✔
1437
  | otherwise = unsafeSwap marr ix1 ix2
1✔
1438
  where
1439
    !sz = sizeOfMArray marr
2✔
1440
{-# INLINE swapM #-}
1441

1442
-- | /O(1)/ - Same as `swapM`, but discard the returned elements
1443
--
1444
-- @since 0.4.0
1445
swapM_
1446
  :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m)
1447
  => MArray (PrimState m) r ix e
1448
  -> ix
1449
  -> ix
1450
  -> m ()
1451
swapM_ marr ix1 ix2 = void $ swapM marr ix1 ix2
2✔
1452
{-# INLINE swapM_ #-}
1453

1454
-- | Swap elements in the intersection of two mutable arrays starting at the
1455
-- initial index.
1456
--
1457
-- @since 1.0.0
1458
zipSwapM_
1459
  :: forall r1 r2 ix e m s
1460
   . (MonadPrim s m, Manifest r2 e, Manifest r1 e, Index ix)
1461
  => ix
1462
  -> MArray s r1 ix e
1463
  -> MArray s r2 ix e
1464
  -> m ()
UNCOV
1465
zipSwapM_ startIx m1 m2 = do
×
UNCOV
1466
  let sz1 = sizeOfMArray m1
×
UNCOV
1467
      sz2 = sizeOfMArray m2
×
UNCOV
1468
      sz = liftIndex2 min (unSz sz1) (unSz sz2)
×
UNCOV
1469
  iterA_ startIx sz oneIndex (<) $ \ix -> do
×
UNCOV
1470
    let i1 = toLinearIndex sz1 ix
×
UNCOV
1471
        i2 = toLinearIndex sz2 ix
×
1472
    e1 <- unsafeLinearRead m1 i1
×
1473
    e2 <- unsafeLinearRead m2 i2
×
1474
    unsafeLinearWrite m2 i2 e1
×
1475
    unsafeLinearWrite m1 i1 e2
×
1476
{-# INLINE zipSwapM_ #-}
1477

1478
-- | Get the size of a mutable array.
1479
--
1480
-- @since 0.1.0
1481
msize :: (Manifest r e, Index ix) => MArray s r ix e -> Sz ix
1482
msize = sizeOfMArray
×
1483
{-# DEPRECATED msize "In favor of `sizeOfMArray`" #-}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc