// -*- c++ -*-
//
// $Id: comm_inln.h,v 1.5 2003/09/21 20:43:49 jsquyres Exp $
//
// Copyright (c) 2001-2003 The Trustees of Indiana University.  
//                         All rights reserved.
// Copyright (c) 1998-2001 University of Notre Dame. 
//                         All rights reserved.
// Copyright (c) 1994-1998 The Ohio State University.  
//                         All rights reserved.
// 
// This file is part of the LAM/MPI software package.  For license
// information, see the LICENSE file in the top level directory of the
// LAM/MPI source distribution.
// 
// $HEADER$
//
 
//
// Point-to-Point
//

inline void
_REAL_MPI_::Comm::Send(const void *buf, int count, 
		const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  (void)MPI_Send((void *)buf, count, datatype, dest, tag, mpi_comm);
}

inline void
_REAL_MPI_::Comm::Recv(void *buf, int count, const _REAL_MPI_::Datatype & datatype,
		int source, int tag, _REAL_MPI_::Status & status) const
{
  (void)MPI_Recv(buf, count, datatype, source, tag, mpi_comm, &status.mpi_status);
}

inline void
_REAL_MPI_::Comm::Recv(void *buf, int count, const _REAL_MPI_::Datatype & datatype,
				    int source, int tag) const
{
  (void)MPI_Recv(buf, count, datatype, source, 
		 tag, mpi_comm, MPI_STATUS_IGNORE);
}

inline void
_REAL_MPI_::Comm::Bsend(const void *buf, int count,
		 const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  (void)MPI_Bsend((void *)buf, count, datatype, 
		  dest, tag, mpi_comm);
}

inline void
_REAL_MPI_::Comm::Ssend(const void *buf, int count, 
		 const _REAL_MPI_::Datatype & datatype, int dest, int tag) const 
{
  (void)MPI_Ssend((void *)buf, count,  datatype, dest, 
		  tag, mpi_comm);
}

inline void
_REAL_MPI_::Comm::Rsend(const void *buf, int count,
		 const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  (void)MPI_Rsend((void *)buf, count, datatype, 
		  dest, tag, mpi_comm);
}

inline _REAL_MPI_::Request
_REAL_MPI_::Comm::Isend(const void *buf, int count,
		 const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  MPI_Request request;
  (void)MPI_Isend((void *)buf, count, datatype, 
		  dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Request
_REAL_MPI_::Comm::Ibsend(const void *buf, int count,
		  const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  MPI_Request request;    
  (void)MPI_Ibsend((void *)buf, count, datatype, 
		   dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Request
_REAL_MPI_::Comm::Issend(const void *buf, int count,
		  const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  MPI_Request request;        
  (void)MPI_Issend((void *)buf, count, datatype,
		   dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Request
_REAL_MPI_::Comm::Irsend(const void *buf, int count,
		  const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  MPI_Request request;
  (void)MPI_Irsend((void *) buf, count, datatype, 
		   dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Request
_REAL_MPI_::Comm::Irecv(void *buf, int count,
		 const _REAL_MPI_::Datatype & datatype, int source, int tag) const
{
  MPI_Request request;
  (void)MPI_Irecv(buf, count, datatype, source, 
		  tag, mpi_comm, &request);
  return request;
}


inline bool
_REAL_MPI_::Comm::Iprobe(int source, int tag, _REAL_MPI_::Status & status) const
{
  int t;
  (void)MPI_Iprobe(source, tag, mpi_comm, &t, &status.mpi_status);
  return (bool) t;
}
  
inline bool
_REAL_MPI_::Comm::Iprobe(int source, int tag) const
{
  int t;
  (void)MPI_Iprobe(source, tag, mpi_comm, &t, MPI_STATUS_IGNORE);
  return (bool) t;
}

inline void
_REAL_MPI_::Comm::Probe(int source, int tag, _REAL_MPI_::Status & status) const
{
  (void)MPI_Probe(source, tag, mpi_comm, &status.mpi_status);
}

inline void
_REAL_MPI_::Comm::Probe(int source, int tag) const
{
  (void)MPI_Probe(source, tag, mpi_comm, MPI_STATUS_IGNORE);
}

inline _REAL_MPI_::Prequest
_REAL_MPI_::Comm::Send_init(const void *buf, int count,
		     const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{ 
  MPI_Request request;
  (void)MPI_Send_init((void *)buf, count, datatype, 
		      dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Prequest
_REAL_MPI_::Comm::Bsend_init(const void *buf, int count,
		      const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  MPI_Request request; 
  (void)MPI_Bsend_init((void *)buf, count, datatype, 
		       dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Prequest
_REAL_MPI_::Comm::Ssend_init(const void *buf, int count,
		      const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  MPI_Request request; 
  (void)MPI_Ssend_init((void *)buf, count, datatype,
		       dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Prequest
_REAL_MPI_::Comm::Rsend_init(const void *buf, int count,
		      const _REAL_MPI_::Datatype & datatype, int dest, int tag) const
{
  MPI_Request request; 
  (void)MPI_Rsend_init((void *)buf, count,  datatype,
		       dest, tag, mpi_comm, &request);
  return request;
}

inline _REAL_MPI_::Prequest
_REAL_MPI_::Comm::Recv_init(void *buf, int count,
		     const _REAL_MPI_::Datatype & datatype, int source, int tag) const
{
  MPI_Request request; 
  (void)MPI_Recv_init(buf, count, datatype, source, 
		      tag, mpi_comm, &request);
  return request;
}

inline void
_REAL_MPI_::Comm::Sendrecv(const void *sendbuf, int sendcount,
		    const _REAL_MPI_::Datatype & sendtype, int dest, int sendtag, 
		    void *recvbuf, int recvcount, 
		    const _REAL_MPI_::Datatype & recvtype, int source,
		    int recvtag, _REAL_MPI_::Status & status) const
{
  (void)MPI_Sendrecv((void *)sendbuf, sendcount, 
		     sendtype,
		     dest, sendtag, recvbuf, recvcount, 
		     recvtype, 
		     source, recvtag, mpi_comm, &status.mpi_status);
}

inline void
_REAL_MPI_::Comm::Sendrecv(const void *sendbuf, int sendcount,
		    const _REAL_MPI_::Datatype & sendtype, int dest, int sendtag, 
		    void *recvbuf, int recvcount, 
		    const _REAL_MPI_::Datatype & recvtype, int source,
		    int recvtag) const
{
  (void)MPI_Sendrecv((void *)sendbuf, sendcount, 
		     sendtype,
		     dest, sendtag, recvbuf, recvcount, 
		     recvtype, 
		     source, recvtag, mpi_comm, MPI_STATUS_IGNORE);
}

inline void
_REAL_MPI_::Comm::Sendrecv_replace(void *buf, int count,
			    const _REAL_MPI_::Datatype & datatype, int dest, 
			    int sendtag, int source,
			    int recvtag, _REAL_MPI_::Status & status) const 
{
  (void)MPI_Sendrecv_replace(buf, count, datatype, dest,
			     sendtag, source, recvtag, mpi_comm,
			     &status.mpi_status);
}

inline void
_REAL_MPI_::Comm::Sendrecv_replace(void *buf, int count,
			    const _REAL_MPI_::Datatype & datatype, int dest, 
			    int sendtag, int source,
			    int recvtag) const 
{
  (void)MPI_Sendrecv_replace(buf, count, datatype, dest,
			     sendtag, source, recvtag, mpi_comm,
			     MPI_STATUS_IGNORE);
}

//
// Groups, Contexts, and Communicators
//

inline _REAL_MPI_::Group
_REAL_MPI_::Comm::Get_group() const 
{
  MPI_Group group;
  (void)MPI_Comm_group(mpi_comm, &group);
  return group;
}
  
inline int
_REAL_MPI_::Comm::Get_size() const 
{
  int size;
  (void)MPI_Comm_size (mpi_comm, &size);
  return size;
}
  
inline int
_REAL_MPI_::Comm::Get_rank() const 
{
  int rank;
  (void)MPI_Comm_rank (mpi_comm, &rank);
  return rank;
}
  
inline int
_REAL_MPI_::Comm::Compare(const _REAL_MPI_::Comm & comm1,
		   const _REAL_MPI_::Comm & comm2)
{
  int result;
  (void)MPI_Comm_compare(comm1, comm2, &result);
  return result;
}

inline void
_REAL_MPI_::Comm::Free(void) 
{
  MPI_Comm save = mpi_comm;
  (void)MPI_Comm_free(&mpi_comm);

  if (_REAL_MPI_::Comm::mpi_comm_map[save] != 0)
    delete _REAL_MPI_::Comm::mpi_comm_map[save];
  _REAL_MPI_::Comm::mpi_comm_map.erase(save);
}
  
inline bool
_REAL_MPI_::Comm::Is_inter() const
{
  int t;
  (void)MPI_Comm_test_inter(mpi_comm, &t);
  return (bool) t;
}


//
// Process Creation and Managemnt
//

inline void
_REAL_MPI_::Comm::Disconnect()
{
  (void) MPI_Comm_disconnect(&mpi_comm);
}


inline _REAL_MPI_::Intercomm
_REAL_MPI_::Comm::Get_parent()
{
  MPI_Comm parent;
  MPI_Comm_get_parent(&parent);
  return parent;
}


inline _REAL_MPI_::Intercomm
_REAL_MPI_::Comm::Join(const int fd) 
{
  MPI_Comm newcomm;
  (void) MPI_Comm_join((int) fd, &newcomm);
  return newcomm;
}

//
// External Interfaces
//

inline void
_REAL_MPI_::Comm::Get_name(char* comm_name, int& resultlen) const
{
  (void) MPI_Comm_get_name(mpi_comm, comm_name, &resultlen);
}

inline void
_REAL_MPI_::Comm::Set_name(const char* comm_name) 
{
  (void) MPI_Comm_set_name(mpi_comm, (char *)comm_name);
}
  
//
//Process Topologies
//

inline int
_REAL_MPI_::Comm::Get_topology() const 
{
  int status;
  (void)MPI_Topo_test(mpi_comm, &status);
  return status;
}
  
//
// Environmental Inquiry
//

inline void
_REAL_MPI_::Comm::Abort(int errorcode) 
{
  (void)MPI_Abort(mpi_comm, errorcode);
}

//
//  These C++ bindings are for MPI-2.
//  The MPI-1.2 functions called below are all
//  going to be deprecated and replaced in MPI-2.
//

inline void
_REAL_MPI_::Comm::Set_errhandler(const _REAL_MPI_::Errhandler& errhandler)
{
  my_errhandler = (_REAL_MPI_::Errhandler *)&errhandler;
  _REAL_MPI_::Comm::mpi_err_map[mpi_comm] = this;
  (void)MPI_Errhandler_set(mpi_comm, errhandler);
}

inline _REAL_MPI_::Errhandler
_REAL_MPI_::Comm::Get_errhandler() const
{
  return *my_errhandler;
}

inline _REAL_MPI_::Errhandler
_REAL_MPI_::Comm::Create_errhandler(_REAL_MPI_::Comm::_MPI2CPP_ERRHANDLERFN_* function)
{
  MPI_Errhandler errhandler;
  // $%%@#%# AIX/POE 2.3.0.0 makes us put in this cast here
  (void)MPI_Errhandler_create((MPI_Handler_function*) errhandler_intercept, 
			      &errhandler);
  _REAL_MPI_::Errhandler temp(errhandler);
  temp.handler_fn = (void(*)(_REAL_MPI_::Comm&, int*, ...))function;
  return temp;
}

//JGS I took the const out because it causes problems when trying to
//call this function with the predefined NULL_COPY_FN etc.
inline int
_REAL_MPI_::Comm::Create_keyval(_REAL_MPI_::Comm::_MPI2CPP_COPYATTRFN_* comm_copy_attr_fn,
				_REAL_MPI_::Comm::_MPI2CPP_DELETEATTRFN_* comm_delete_attr_fn,
				void* extra_state)
{
  int keyval;
  (void)MPI_Keyval_create(copy_attr_intercept, delete_attr_intercept,
			  &keyval, extra_state);
  key_pair_t* copy_and_delete = 
    new key_pair_t(comm_copy_attr_fn, comm_delete_attr_fn); 
  _REAL_MPI_::Comm::key_fn_map[keyval] = copy_and_delete;
  return keyval;
}

inline void
_REAL_MPI_::Comm::Free_keyval(int& comm_keyval)
{
  int save = comm_keyval;
  (void)MPI_Keyval_free(&comm_keyval);

  if (_REAL_MPI_::Comm::key_fn_map[save] != 0)
    delete _REAL_MPI_::Comm::key_fn_map[save];
  _REAL_MPI_::Comm::key_fn_map.erase(save);
}

inline void
_REAL_MPI_::Comm::Set_attr(int comm_keyval, const void* attribute_val) const
{
  CommType type;
  int status;

  (void)MPI_Comm_test_inter(mpi_comm, &status);
  if (status) {
    type = eIntercomm;
  }
  else {
    (void)MPI_Topo_test(mpi_comm, &status);    
    if (status == MPI_CART)
      type = eCartcomm;
    else if (status == MPI_GRAPH)
      type = eGraphcomm;
    else
      type = eIntracomm;
  }
  if (_REAL_MPI_::Comm::mpi_comm_map[mpi_comm] == 0) {
    comm_pair_t* comm_type = new comm_pair_t((Comm*) this, type);
    _REAL_MPI_::Comm::mpi_comm_map[mpi_comm] = comm_type;
  }
  (void)MPI_Attr_put(mpi_comm, comm_keyval, (void*) attribute_val);
}

inline bool
_REAL_MPI_::Comm::Get_attr(int comm_keyval, void* attribute_val) const
{
  int flag;
  (void)MPI_Attr_get(mpi_comm, comm_keyval, attribute_val, &flag);
  return (bool)flag;
}

inline void
_REAL_MPI_::Comm::Delete_attr(int comm_keyval)
{
  (void)MPI_Attr_delete(mpi_comm, comm_keyval);
}

inline int
_REAL_MPI_::Comm::NULL_COPY_FN(const _REAL_MPI_::Comm& oldcomm, int comm_keyval,
			       void* extra_state, void* attribute_val_in,
			       void* attribute_val_out, bool& flag)
{
#if LAM_SIZEOF_CXX_BOOL != LAM_SIZEOF_CXX_INT
  int f = (int)flag;
  int ret;
  if (MPI_NULL_COPY_FN != 0) {

    // Portland pgCC 5.0-2 has a bug that we have to workaround here.
    // MPI_NULL_COPY_FN is actually a #define for ((MPI_Copy_function
    // *) 0).  If we try to invoke it, such as:
    //   ret = MPI_NULL_COPY_FN(...);
    // the preprocessor will resolve this to:
    //   ret = ((MPI_Copy_function *) 0)(...);
    // which should be fine.  But unfortunately, pgCC 5.0-2 makes this
    // into a real symbol that will refuse to link.  The workaround is
    // to assign this into a temp variable and then invoke through the
    // function pointer.  This shouldn't be necessary.  :-(

    MPI_Copy_function *stupid_compiler = MPI_NULL_COPY_FN;
    ret = stupid_compiler(oldcomm, comm_keyval, extra_state, attribute_val_in,
                          attribute_val_out, &f);
    flag = (bool)f;
  } else {
    ret = MPI_SUCCESS;
    flag = true;
  }
  return ret;
#else
  if (MPI_NULL_COPY_FN != 0) {

    // See note above.

    MPI_Copy_function *stupid_compiler = MPI_NULL_COPY_FN;
    return stupid_compiler(oldcomm, comm_keyval, extra_state, 
                           attribute_val_in, attribute_val_out, (int*)&flag);
  } else
    return MPI_SUCCESS;
#endif
}

inline int
_REAL_MPI_::Comm::DUP_FN(const _REAL_MPI_::Comm& oldcomm, int comm_keyval,
			 void* extra_state, void* attribute_val_in,
			 void* attribute_val_out, bool& flag)
{
#if LAM_SIZEOF_CXX_BOOL != LAM_SIZEOF_CXX_INT
  int f = (int)flag;
  int ret;
  ret = MPI_DUP_FN(oldcomm, comm_keyval, extra_state, attribute_val_in,
		   attribute_val_out, &f);
  flag = (bool) f;
  return ret;
#else
  return MPI_DUP_FN(oldcomm, comm_keyval, extra_state, attribute_val_in,
		    attribute_val_out, (int*)&flag);
#endif
}

inline int
_REAL_MPI_::Comm::NULL_DELETE_FN(_REAL_MPI_::Comm& comm, int comm_keyval, void* attribute_val,
				 void* extra_state)
{
  if (MPI_NULL_DELETE_FN != 0) {

    // See note in MPI_NULL_COPY_FN.

    MPI_Delete_function *stupid_compiler = MPI_NULL_DELETE_FN;
    return stupid_compiler(comm, comm_keyval, attribute_val, extra_state);
  } else
    return MPI_SUCCESS;
}



syntax highlighted by Code2HTML, v. 0.9.1