/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 */

#include "mpi.h"
#include <stdio.h>
#include <assert.h>
#include "mpitest.h"

#define CAS_CHECK_TYPE(c_type, mpi_type, expected_err)  \
do {                                                    \
    int            err, err_class, i;                   \
    c_type         val, cmp_val;                        \
    c_type         buf, res;                            \
    MPI_Win        win;                                 \
                                                        \
    val = cmp_val = buf = 0;                            \
                                                        \
    MPI_Win_create(&buf, sizeof(c_type), sizeof(c_type),       \
                    MPI_INFO_NULL, MPI_COMM_WORLD, &win);      \
                                                        \
    MPI_Win_set_errhandler(win, MPI_ERRORS_RETURN);   \
                                                        \
    MPI_Win_fence(MPI_MODE_NOPRECEDE, win);           \
    for (i = 0; i < 10000; i++) {                       \
    err = MPI_Compare_and_swap(&val, &cmp_val, &res,  \
                                 mpi_type, 0, 0, win); \
    MPI_Error_class(err, &err_class);                 \
    assert(err_class == expected_err);                \
    }                                                   \
    MPI_Win_fence(MPI_MODE_NOSUCCEED, win);            \
                                                        \
    MPI_Win_free(&win);                               \
} while (0);


int main(int argc, char *argv[])
{
    int rank;
    MPI_Datatype my_int;

    MTest_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    /* C Integer */
    CAS_CHECK_TYPE(signed char, MPI_SIGNED_CHAR, MPI_SUCCESS);
    CAS_CHECK_TYPE(short, MPI_SHORT, MPI_SUCCESS);
    CAS_CHECK_TYPE(int, MPI_INT, MPI_SUCCESS);
    CAS_CHECK_TYPE(long, MPI_LONG, MPI_SUCCESS);
    CAS_CHECK_TYPE(long long, MPI_LONG_LONG, MPI_SUCCESS);
    CAS_CHECK_TYPE(unsigned char, MPI_UNSIGNED_CHAR, MPI_SUCCESS);
    CAS_CHECK_TYPE(unsigned short, MPI_UNSIGNED_SHORT, MPI_SUCCESS);
    CAS_CHECK_TYPE(unsigned, MPI_UNSIGNED, MPI_SUCCESS);
    CAS_CHECK_TYPE(unsigned long, MPI_UNSIGNED_LONG, MPI_SUCCESS);
    CAS_CHECK_TYPE(unsigned long long, MPI_UNSIGNED_LONG_LONG, MPI_SUCCESS);

    /* Multilanguage Types */
    CAS_CHECK_TYPE(MPI_Aint, MPI_AINT, MPI_SUCCESS);
    CAS_CHECK_TYPE(MPI_Offset, MPI_OFFSET, MPI_SUCCESS);
    CAS_CHECK_TYPE(MPI_Count, MPI_COUNT, MPI_SUCCESS);

    /* Byte */
    CAS_CHECK_TYPE(char, MPI_BYTE, MPI_SUCCESS);

    /* Logical */
    CAS_CHECK_TYPE(char, MPI_C_BOOL, MPI_SUCCESS);

    /* ERR: Derived datatypes */
    MPI_Type_contiguous(sizeof(int), MPI_BYTE, &my_int);
    MPI_Type_commit(&my_int);
    CAS_CHECK_TYPE(int, my_int, MPI_ERR_TYPE);
    MPI_Type_free(&my_int);

    /* ERR: Character types */
    CAS_CHECK_TYPE(char, MPI_CHAR, MPI_SUCCESS);

    /* ERR: Floating point */
    CAS_CHECK_TYPE(float, MPI_FLOAT, MPI_ERR_TYPE);
    CAS_CHECK_TYPE(double, MPI_DOUBLE, MPI_ERR_TYPE);
#ifdef HAVE_LONG_DOUBLE
    if (MPI_LONG_DOUBLE != MPI_DATATYPE_NULL) {
        CAS_CHECK_TYPE(long double, MPI_LONG_DOUBLE, MPI_ERR_TYPE);
    }
#endif

    MTest_Finalize(0);

    return 0;
}
