-- | A variation of 'alltoall' that allows to use data segments of
--   different length.
alltoallv :: (SendFrom v1, RecvInto v2) => Comm
             -> v1 -- ^ Send buffer
             -> StorableArray Int CInt -- ^ Lengths of segments in the send buffer
             -> StorableArray Int CInt -- ^ Displacements of the segments in the send buffer
             -> StorableArray Int CInt -- ^ Lengths of segments in the receive buffer
             -> StorableArray Int CInt -- ^ Displacements of the segments in the receive buffer
             -> v2 -- ^ Receive buffer
             -> IO ()
alltoallv comm sendVal sendCounts sendDisplacements recvCounts recvDisplacements recvVal = do
  sendFrom sendVal $ \sendPtr _ sendType ->
    recvInto recvVal $ \recvPtr _ recvType ->
      withStorableArray sendCounts $ \sendCountsPtr ->
        withStorableArray sendDisplacements $ \sendDisplPtr ->
          withStorableArray recvCounts $ \recvCountsPtr ->
            withStorableArray recvDisplacements $ \recvDisplPtr ->
              Internal.alltoallv (castPtr sendPtr) sendCountsPtr sendDisplPtr sendType
                                 (castPtr recvPtr) recvCountsPtr recvDisplPtr recvType comm

{-| Reduce values from a group of processes into single value, which is delivered to single (so-called root) process.
See 'reduceRecv' for function that should be called by root process.

If the value is scalar, then reduction is similar to 'fold1'. For example, if the opreration is 'sumOp', then
@reduceSend@ would compute sum of values supplied by all processes.
-}
alltoallv :: (SendFrom v1, RecvInto v2) => Comm
             -> v1 -- ^ Send buffer
             -> StorableArray Int CInt -- ^ Lengths of segments in the send buffer
             -> StorableArray Int CInt -- ^ Displacements of the segments in the send buffer
             -> StorableArray Int CInt -- ^ Lengths of segments in the receive buffer
             -> StorableArray Int CInt -- ^ Displacements of the segments in the receive buffer
             -> v2 -- ^ Receive buffer
             -> IO ()
alltoallv comm sendVal sendCounts sendDisplacements recvCounts recvDisplacements recvVal = do
  sendFrom sendVal $ \sendPtr _ sendType ->
    recvInto recvVal $ \recvPtr _ recvType ->
      withStorableArray sendCounts $ \sendCountsPtr ->
        withStorableArray sendDisplacements $ \sendDisplPtr ->
          withStorableArray recvCounts $ \recvCountsPtr ->
            withStorableArray recvDisplacements $ \recvDisplPtr ->
              Internal.alltoallv (castPtr sendPtr) sendCountsPtr sendDisplPtr sendType
                                 (castPtr recvPtr) recvCountsPtr recvDisplPtr recvType comm

{-| Reduce values from a group of processes into single value, which is delivered to single (so-called root) process.
See 'reduceRecv' for function that should be called by root process.

If the value is scalar, then reduction is similar to 'fold1'. For example, if the opreration is 'sumOp', then
@reduceSend@ would compute sum of values supplied by all processes.
-}
alltoallv comm sendVal sendCounts sendDisplacements recvCounts recvDisplacements recvVal = do
  sendFrom sendVal $ \sendPtr _ sendType ->
    recvInto recvVal $ \recvPtr _ recvType ->
      withStorableArray sendCounts $ \sendCountsPtr ->
        withStorableArray sendDisplacements $ \sendDisplPtr ->
          withStorableArray recvCounts $ \recvCountsPtr ->
            withStorableArray recvDisplacements $ \recvDisplPtr ->
              Internal.alltoallv (castPtr sendPtr) sendCountsPtr sendDisplPtr sendType
                                 (castPtr recvPtr) recvCountsPtr recvDisplPtr recvType comm

{-| Reduce values from a group of processes into single value, which is delivered to single (so-called root) process.
See 'reduceRecv' for function that should be called by root process.

If the value is scalar, then reduction is similar to 'fold1'. For example, if the opreration is 'sumOp', then
@reduceSend@ would compute sum of values supplied by all processes.
-}