{-

In-place receive vs new array allocation for Storable Array
-----------------------------------------------------------
When using StorableArray API in tight numeric loops, it is best to
reuse existing arrays and avoid penalties incurred by
allocation/deallocation of memory. Which is why destinations/receive
buffers in StorableArray API are specified exclusively as
(StorableArray i e).

If you'd rather allocate new array for a particular operation, you
could use withNewArray/withNewArray_:

Instead of (recv comm rank tag arr) you would write
(arr <- withNewArray bounds $ recv comm rank tag), and new array would
be allocated, supplied as the target of the (recv) operation and
returned to you.

You could easily write your own convenience wrappers similar to
withNewArray. For example, you could create wrapper that would take an
array size as a simple number instead of range.

-}


{- | Helper wrapper function that would allocate array of the given size and use it as receive buffer, without the need to
preallocate it explicitly.

Most of the functions in this API could reuse receive buffer (like 'StorableArray') over and over again.
If you do not have preallocated buffer you could use this wrapper to get yourself one.

Consider the following code that uses preallocated buffer:

@
scattervRecv root comm arr
@

Same code with buffer allocation:

@
(arr,status) <- intoNewArray range $ scattervRecv root comm
@
-}
intoNewArray :: (Ix i, MArray a e m, RecvInto (a i e)) => (i, i) -> (a i e -> m r) -> m (a i e, r)
intoNewArray range f = do
  arr <- unsafeNewArray_ range -- New, uninitialized array, According to http://hackage.haskell.org/trac/ghc/ticket/3586
                               -- should be faster than newArray_
  res <- f arr
  return (arr, res)

-- | Variant of 'intoNewArray' that discards the result of the wrapped function.
-- Useful for discarding @()@ from functions like 'scatterSend' that return @IO ()@
intoNewArray :: (Ix i, MArray a e m, RecvInto (a i e)) => (i, i) -> (a i e -> m r) -> m (a i e, r)
intoNewArray range f = do
  arr <- unsafeNewArray_ range -- New, uninitialized array, According to http://hackage.haskell.org/trac/ghc/ticket/3586
                               -- should be faster than newArray_
  res <- f arr
  return (arr, res)

-- | Variant of 'intoNewArray' that discards the result of the wrapped function.
-- Useful for discarding @()@ from functions like 'scatterSend' that return @IO ()@
intoNewArray range f = do
  arr <- unsafeNewArray_ range -- New, uninitialized array, According to http://hackage.haskell.org/trac/ghc/ticket/3586
                               -- should be faster than newArray_
  res <- f arr
  return (arr, res)

-- | Variant of 'intoNewArray' that discards the result of the wrapped function.
-- Useful for discarding @()@ from functions like 'scatterSend' that return @IO ()@