opal_datatype_t* test_contiguous( void )
{
    opal_datatype_t *pdt, *pdt1, *pdt2;

    printf( "test contiguous (alignement)\n" );
    opal_datatype_create_contiguous(0, &opal_datatype_empty, &pdt1);
    opal_datatype_add( pdt1, &opal_datatype_float8, 1, 0, -1 );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt1 );
    }
    opal_datatype_add( pdt1, &opal_datatype_int1, 1, 8, -1 );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt1 );
    }
    opal_datatype_create_contiguous( 4, pdt1, &pdt2 );
    OBJ_RELEASE( pdt1 ); /*assert( pdt1 == NULL );*/
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt2 );
    }
    opal_datatype_create_contiguous( 2, pdt2, &pdt );
    OBJ_RELEASE( pdt2 ); /*assert( pdt2 == NULL );*/
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt );
    }
    return pdt;
}
opal_datatype_t* create_strange_dt( void )
{
    sdata_intern v[2];
    OPAL_PTRDIFF_TYPE displ[3];
    sstrange t[2];
    int pBlock[3] = {1, 10, 1}, dispi[3];
    opal_datatype_t *pdt, *pdt1, *pdt2, *pdtTemp;

    opal_datatype_create_contiguous(0, &opal_datatype_empty, &pdt1);
    opal_datatype_add( pdt1, &opal_datatype_float8, 1, 0, -1 );
    opal_datatype_add( pdt1, &opal_datatype_int1, 1, 8, -1 );

#ifdef USE_RESIZED
    /* optional */
    displ[0] = 0;
    displ[1] = (char*)&(v[1]) - (char*)&(v[0]);
    opal_datatype_resize( pdt1, displ[0], displ[1]);
#endif  /* USE_RESIZED */

    opal_datatype_create_contiguous( SSTRANGE_CNT, pdt1, &pdt );

    OBJ_RELEASE( pdt1 );
    printf( "\nStrange datatype BEFORE COMMIT\n" );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt );
    }

    opal_datatype_commit( pdt );
    printf( "\nStrange datatype AFTER COMMIT\n" );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt );
    }
    return pdt;
}
opal_datatype_t* test_struct( void )
{
    const opal_datatype_t* types[] = { (opal_datatype_t*)&opal_datatype_float4,
                                 NULL,
                                 (opal_datatype_t*)&opal_datatype_int1 };
    int lengths[] = { 2, 1, 3 };
    OPAL_PTRDIFF_TYPE disp[] = { 0, 16, 26 };
    opal_datatype_t* pdt, *pdt1;

    printf( "test struct\n" );
    opal_datatype_create_contiguous(0, &opal_datatype_empty, &pdt1);
    opal_datatype_add( pdt1, &opal_datatype_float8, 1, 0, -1 );
    opal_datatype_add( pdt1, &opal_datatype_int1, 1, 8, -1 );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt1 );
    }

    types[1] = pdt1;

    opal_datatype_create_struct( 3, lengths, disp, types, &pdt );
    OBJ_RELEASE( pdt1 ); /*assert( pdt1 == NULL );*/
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt );
    }
    return pdt;
}
opal_datatype_t* create_contiguous_type( const opal_datatype_t* type, int length )
{
   opal_datatype_t* newtype;

   opal_datatype_create_contiguous( length, type, &newtype );
   opal_datatype_commit( newtype );

   return newtype;
}
opal_datatype_t* test_matrix_borders( unsigned int size, unsigned int width )
{
   opal_datatype_t *pdt, *pdt_line;
   int disp[2];
   int blocklen[2];

   disp[0] = 0;
   blocklen[0] = width;
   disp[1] = (size - width) * sizeof(double);
   blocklen[1] = width;

   opal_datatype_create_indexed( 2, blocklen, disp, &opal_datatype_float8,
                                 &pdt_line );
   opal_datatype_create_contiguous( size, pdt_line, &pdt );
   OBJ_RELEASE( pdt_line ); /*assert( pdt_line == NULL );*/
   return pdt;
}
int mpich_typeub2( void )
{
   int blocklen[3], err = 0;
   size_t sz1, sz2, sz3;
   OPAL_PTRDIFF_TYPE disp[3], lb, ub, ex1, ex2, ex3;
   opal_datatype_t *types[3], *dt1, *dt2, *dt3;

   blocklen[0] = 1;
   blocklen[1] = 1;
   blocklen[2] = 1;
   disp[0] = -3;
   disp[1] = 0;
   disp[2] = 6;
   types[0] = (opal_datatype_t*)&opal_datatype_lb;
   types[1] = (opal_datatype_t*)&opal_datatype_int4;
   types[2] = (opal_datatype_t*)&opal_datatype_ub;

   opal_datatype_create_struct(3, blocklen, disp, types, &dt1);
   opal_datatype_commit( dt1 );

   opal_datatype_type_lb(dt1, &lb);          opal_datatype_type_ub(dt1, &ub);
   opal_datatype_type_extent(dt1,&ex1);      opal_datatype_type_size(dt1,&sz1);

   /* Values should be lb = -3, ub = 6 extent 9; size depends on implementation */
   if (lb != -3 || ub != 6 || ex1 != 9) {
      printf("Example 3.26 type1 lb %d ub %d extent %d size %d\n", (int)lb, (int)ub, (int)ex1, (int)sz1);
      err++;
   }
   else
      printf("Example 3.26 type1 correct\n" );

   opal_datatype_create_contiguous(2, dt1, &dt2);
   opal_datatype_type_lb(dt2, &lb);          opal_datatype_type_ub(dt2, &ub);
   opal_datatype_type_extent(dt2,&ex2);      opal_datatype_type_size(dt2,&sz2);
   /* Values should be lb = -3, ub = 15, extent = 18, size depends on implementation */
   if (lb != -3 || ub != 15 || ex2 != 18) {
      printf("Example 3.26 type2 lb %d ub %d extent %d size %d\n", (int)-3, (int)15, (int)18, 8);
      printf("Example 3.26 type2 lb %d ub %d extent %d size %d\n", (int)lb, (int)ub, (int)ex2, (int)sz2);
      err++;
   }
   else
      printf("Example 3.26 type1 correct\n" );
   OBJ_RELEASE( dt2 ); assert( dt2 == NULL );
   opal_datatype_create_contiguous(2,dt1,&dt2);
   opal_datatype_type_lb(dt2, &lb);          opal_datatype_type_ub(dt2, &ub);
   opal_datatype_type_extent(dt2,&ex2);      opal_datatype_type_size(dt2,&sz2);
   /* Values should be lb = -3, ub = 15, extent = 18, size depends on implementation */
   if (lb != -3 || ub != 15 || ex2 != 18) {
      printf("Example 3.26 type2 lb %d ub %d extent %d size %d\n", (int)-3, (int)15, (int)18, 8);
      printf("Example 3.26 type2 lb %d ub %d extent %d size %d\n", (int)lb, (int)ub, (int)ex2, (int)sz2);
      err++;
   }
   else
      printf( "Example 3.26 type2 correct\n" );

   types[0]=dt1;               types[1]=dt1;
   blocklen[0]=1;              blocklen[1]=1;
   disp[0]=0;                  disp[1]=ex1;

   opal_datatype_create_struct(2, blocklen, disp, types, &dt3);
   opal_datatype_commit( dt3 );

   opal_datatype_type_lb(dt3, &lb);          opal_datatype_type_ub(dt3, &ub);
   opal_datatype_type_extent(dt3,&ex3);      opal_datatype_type_size(dt3,&sz3);
   /* Another way to express type2 */
   if (lb != -3 || ub != 15 || ex3 != 18) {
      printf("type3 lb %d ub %d extent %d size %d\n", (int)-3, (int)15, (int)18, 8);
      printf("type3 lb %d ub %d extent %d size %d\n", (int)lb, (int)ub, (int)ex3, (int)sz2);
      err++;
   }
   else
      printf( "type3 correct\n" );

   OBJ_RELEASE( dt1 ); /*assert( dt1 == NULL );*/
   OBJ_RELEASE( dt2 ); /*assert( dt2 == NULL );*/
   OBJ_RELEASE( dt3 ); assert( dt3 == NULL );
   return err;
}
/**
 * Main function. Call several tests and print-out the results. It try to stress the convertor
 * using difficult data-type constructions as well as strange segment sizes for the conversion.
 * Usually, it is able to detect most of the data-type and convertor problems. Any modifications
 * on the data-type engine should first pass all the tests from this file, before going into other
 * tests.
 */
int main( int argc, char* argv[] )
{
    opal_datatype_t *pdt, *pdt1, *pdt2, *pdt3;
    int rc, length = 500;

    opal_datatype_init();

    /**
     * By default simulate homogeneous architectures.
     */
    remote_arch = opal_local_arch;
    printf( "\n\n#\n * TEST CREATE CONTIGUOUS\n #\n\n" );
    pdt = create_contiguous_type( &opal_datatype_int1, 10 );
    if( outputFlags & CHECK_PACK_UNPACK ) {
        local_copy_ddt_count(pdt, 100);
        local_copy_with_convertor(pdt, 100, 956);
    }

    OBJ_RELEASE( pdt );
    assert( pdt == NULL );
    printf( "\n\n#\n * TEST STRANGE DATATYPE\n #\n\n" );
    pdt = create_strange_dt();
    if( outputFlags & CHECK_PACK_UNPACK ) {
        local_copy_ddt_count(pdt, 1);
        local_copy_with_convertor(pdt, 1, 956);
    }
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );


    printf( "\n\n#\n * TEST UPPER TRIANGULAR MATRIX (size 100)\n #\n\n" );
    pdt = upper_matrix(100);
    if( outputFlags & CHECK_PACK_UNPACK ) {
        local_copy_ddt_count(pdt, 1);
        local_copy_with_convertor(pdt, 1, 48);
    }
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );

    mpich_typeub();
    mpich_typeub2();
    mpich_typeub3();

    printf( "\n\n#\n * TEST UPPER MATRIX\n #\n\n" );
    rc = test_upper( length );
    if( rc == 0 )
        printf( "decode [PASSED]\n" );
    else
        printf( "decode [NOT PASSED]\n" );

    printf( "\n\n#\n * TEST MATRIX BORDERS\n #\n\n" );
    pdt = test_matrix_borders( length, 100 );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt );
    }
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );


    printf( "\n\n#\n * TEST CONTIGUOUS\n #\n\n" );
    pdt = test_contiguous();
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );
    printf( "\n\n#\n * TEST STRUCT\n #\n\n" );
    pdt = test_struct();
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );

    opal_datatype_create_contiguous(0, &opal_datatype_empty, &pdt1);
    opal_datatype_create_contiguous(0, &opal_datatype_empty, &pdt2);
    opal_datatype_create_contiguous(0, &opal_datatype_empty, &pdt3);

    opal_datatype_add( pdt3, &opal_datatype_int4, 10, 0, -1 );
    opal_datatype_add( pdt3, &opal_datatype_float4, 5, 10 * sizeof(int), -1 );

    opal_datatype_add( pdt2, &opal_datatype_float4, 1, 0, -1 );
    opal_datatype_add( pdt2, pdt3, 3, sizeof(int) * 1, -1 );

    opal_datatype_add( pdt1, &opal_datatype_int8, 5, 0, -1 );
    opal_datatype_add( pdt1, &opal_datatype_float16, 2, sizeof(long long) * 5, -1 );

    printf( ">>--------------------------------------------<<\n" );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt1 );
    }
    printf( ">>--------------------------------------------<<\n" );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt2 );
    }
    printf( ">>--------------------------------------------<<\n" );
    if( outputFlags & DUMP_DATA_AFTER_COMMIT ) {
        opal_datatype_dump( pdt3 );
    }

    OBJ_RELEASE( pdt1 );
    assert( pdt1 == NULL );
    OBJ_RELEASE( pdt2 );
    assert( pdt2 == NULL );
    OBJ_RELEASE( pdt3 );
    assert( pdt3 == NULL );

    printf( ">>--------------------------------------------<<\n" );
    printf( " Contiguous data-type (opal_datatype_float8)\n" );
    if( outputFlags & CHECK_PACK_UNPACK ) {
        const opal_datatype_t const* ddt = &opal_datatype_float8;
        local_copy_ddt_count( ddt, 4500);
        local_copy_with_convertor( ddt, 4500, 12 );
        local_copy_with_convertor_2datatypes( ddt, 4500, ddt, 4500, 12 );
    }
    printf( ">>--------------------------------------------<<\n" );

    printf( ">>--------------------------------------------<<\n" );
    if( outputFlags & CHECK_PACK_UNPACK ) {
        printf( "Contiguous multiple data-type (4500*1)\n" );
        pdt = create_contiguous_type( &opal_datatype_float8, 4500 );
        local_copy_ddt_count(pdt, 1);
        local_copy_with_convertor( pdt, 1, 12 );
        local_copy_with_convertor_2datatypes( pdt, 1, pdt, 1, 12 );
        OBJ_RELEASE( pdt );
        assert( pdt == NULL );
        printf( "Contiguous multiple data-type (450*10)\n" );
        pdt = create_contiguous_type( &opal_datatype_float8, 450 );
        local_copy_ddt_count(pdt, 10);
        local_copy_with_convertor( pdt, 10, 12 );
        local_copy_with_convertor_2datatypes( pdt, 10, pdt, 10, 12 );
        OBJ_RELEASE( pdt );
        assert( pdt == NULL );
        printf( "Contiguous multiple data-type (45*100)\n" );
        pdt = create_contiguous_type( &opal_datatype_float8, 45 );
        local_copy_ddt_count(pdt, 100);
        local_copy_with_convertor( pdt, 100, 12 );
        local_copy_with_convertor_2datatypes( pdt, 100, pdt, 100, 12 );
        OBJ_RELEASE( pdt );
        assert( pdt == NULL );
        printf( "Contiguous multiple data-type (100*45)\n" );
        pdt = create_contiguous_type( &opal_datatype_float8, 100 );
        local_copy_ddt_count(pdt, 45);
        local_copy_with_convertor( pdt, 45, 12 );
        local_copy_with_convertor_2datatypes( pdt, 45, pdt, 45, 12 );
        OBJ_RELEASE( pdt );
        assert( pdt == NULL );
        printf( "Contiguous multiple data-type (10*450)\n" );
        pdt = create_contiguous_type( &opal_datatype_float8, 10 );
        local_copy_ddt_count(pdt, 450);
        local_copy_with_convertor( pdt, 450, 12 );
        local_copy_with_convertor_2datatypes( pdt, 450, pdt, 450, 12 );
        OBJ_RELEASE( pdt );
        assert( pdt == NULL );
        printf( "Contiguous multiple data-type (1*4500)\n" );
        pdt = create_contiguous_type( &opal_datatype_float8, 1 );
        local_copy_ddt_count(pdt, 4500);
        local_copy_with_convertor( pdt, 4500, 12 );
        local_copy_with_convertor_2datatypes( pdt, 4500, pdt, 4500, 12 );
        OBJ_RELEASE( pdt );
        assert( pdt == NULL );
    }
    printf( ">>--------------------------------------------<<\n" );
    printf( ">>--------------------------------------------<<\n" );
    printf( "Vector data-type (450 times 10 double stride 11)\n" );
    pdt = create_vector_type( &opal_datatype_float8, 450, 10, 11 );
    opal_datatype_dump( pdt );
    if( outputFlags & CHECK_PACK_UNPACK ) {
        local_copy_ddt_count(pdt, 1);
        local_copy_with_convertor( pdt, 1, 12 );
        local_copy_with_convertor_2datatypes( pdt, 1, pdt, 1, 12 );
        local_copy_with_convertor( pdt, 1, 82 );
        local_copy_with_convertor_2datatypes( pdt, 1, pdt, 1, 82 );
        local_copy_with_convertor( pdt, 1, 6000 );
        local_copy_with_convertor_2datatypes( pdt, 1, pdt, 1, 6000 );
        local_copy_with_convertor( pdt, 1, 36000 );
        local_copy_with_convertor_2datatypes( pdt, 1, pdt, 1, 36000 );
    }
    printf( ">>--------------------------------------------<<\n" );
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );

    printf( ">>--------------------------------------------<<\n" );
    pdt = test_struct_char_double();
    if( outputFlags & CHECK_PACK_UNPACK ) {
        local_copy_ddt_count(pdt, 4500);
        local_copy_with_convertor( pdt, 4500, 12 );
        local_copy_with_convertor_2datatypes( pdt, 4500, pdt, 4500, 12 );
    }
    printf( ">>--------------------------------------------<<\n" );
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );

    printf( ">>--------------------------------------------<<\n" );
    pdt = test_create_twice_two_doubles();
    if( outputFlags & CHECK_PACK_UNPACK ) {
        local_copy_ddt_count(pdt, 4500);
        local_copy_with_convertor( pdt, 4500, 12 );
        local_copy_with_convertor_2datatypes( pdt, 4500, pdt, 4500, 12 );
    }
    printf( ">>--------------------------------------------<<\n" );
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );

    printf( ">>--------------------------------------------<<\n" );
    pdt = test_create_blacs_type();
    if( outputFlags & CHECK_PACK_UNPACK ) {
        opal_datatype_dump( pdt );
        local_copy_ddt_count(pdt, 4500);
        local_copy_with_convertor( pdt, 4500, 956 );
        local_copy_with_convertor_2datatypes( pdt, 4500, pdt, 4500, 956 );
        local_copy_with_convertor( pdt, 4500, 16*1024 );
        local_copy_with_convertor_2datatypes( pdt, 4500, pdt, 4500, 16*1024 );
        local_copy_with_convertor( pdt, 4500, 64*1024 );
        local_copy_with_convertor_2datatypes( pdt, 4500, pdt, 4500, 64*1024 );
    }
    printf( ">>--------------------------------------------<<\n" );
    OBJ_RELEASE( pdt );
    assert( pdt == NULL );

    printf( ">>--------------------------------------------<<\n" );
    pdt1 = test_create_blacs_type1( &opal_datatype_int4 );
    pdt2 = test_create_blacs_type2( &opal_datatype_int4 );
    if( outputFlags & CHECK_PACK_UNPACK ) {
        local_copy_with_convertor_2datatypes( pdt1, 1, pdt2, 1, 100 );
    }
    printf( ">>--------------------------------------------<<\n" );
    OBJ_RELEASE( pdt1 );
    assert( pdt1 == NULL );
    OBJ_RELEASE( pdt2 );
    assert( pdt2 == NULL );

    /* clean-ups all data allocations */
    opal_datatype_finalize();

    return OPAL_SUCCESS;
}