/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the LICENSE file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*****************************************************************************
   FILE
   tcompound.cpp - HDF5 C++ testing the compound data type functionality

 ***************************************************************************/
#include <iostream>
using std::cerr;
using std::endl;

#include <string>
#include "H5Cpp.h" // C++ API header file
using namespace H5;

#include "h5test.h"
#include "h5cpputil.h" // C++ utilility header file

/* Number of elements in each test */
#define NTESTELEM 100000

typedef struct complex_t {
    double re;
    double im;
} complex_t;

/*-------------------------------------------------------------------------
 * Function:    test_compound_1
 *
 * Purpose      Tests various things about compound data types.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
static void
test_compound_1()
{
    // Output message about test being performed
    SUBTEST("Compound Data Types");
    try {
        // Create an empty compound datatype
        CompType complex_type(sizeof(complex_t));

        // Add a couple of fields
        complex_type.insertMember("real", HOFFSET(complex_t, re), PredType::NATIVE_DOUBLE);
        complex_type.insertMember("imaginary", HOFFSET(complex_t, im), PredType::NATIVE_DOUBLE);
        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }
} // test_compound_1()

/*-------------------------------------------------------------------------
 * Function:    test_compound_2
 *
 * Purpose      Tests a compound type conversion where the source and
 *              destination are the same except for the order of the
 *              elements.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
static void
test_compound_2()
{
    typedef struct {
        int a, b, c[4], d, e;
    } src_typ_t;
    typedef struct {
        int e, d, c[4], b, a;
    } dst_typ_t;

    src_typ_t     *s_ptr;
    dst_typ_t     *d_ptr;
    const int      nelmts = NTESTELEM;
    const hsize_t  four   = 4;
    int            i;
    unsigned char *buf = NULL, *orig = NULL, *bkg = NULL;
    ArrayType     *array_dt = NULL;

    // Output message about test being performed
    SUBTEST("Compound Element Reordering");
    try {
        // Sizes should be the same, but be careful just in case
        buf  = static_cast<unsigned char *>(malloc(nelmts * MAX(sizeof(src_typ_t), sizeof(dst_typ_t))));
        bkg  = static_cast<unsigned char *>(malloc(nelmts * sizeof(dst_typ_t)));
        orig = static_cast<unsigned char *>(malloc(nelmts * sizeof(src_typ_t)));
        for (i = 0; i < nelmts; i++) {
            s_ptr       = (reinterpret_cast<src_typ_t *>(orig)) + i;
            s_ptr->a    = i * 8 + 0;
            s_ptr->b    = i * 8 + 1;
            s_ptr->c[0] = i * 8 + 2;
            s_ptr->c[1] = i * 8 + 3;
            s_ptr->c[2] = i * 8 + 4;
            s_ptr->c[3] = i * 8 + 5;
            s_ptr->d    = i * 8 + 6;
            s_ptr->e    = i * 8 + 7;
        }
        memcpy(buf, orig, nelmts * sizeof(src_typ_t));

        // Build hdf5 datatypes
        array_dt = new ArrayType(PredType::NATIVE_INT, 1, &four);

        // Create an empty compound datatype
        CompType st(sizeof(src_typ_t));
        st.insertMember("a", HOFFSET(src_typ_t, a), PredType::NATIVE_INT);
        st.insertMember("b", HOFFSET(src_typ_t, b), PredType::NATIVE_INT);
        st.insertMember("c", HOFFSET(src_typ_t, c), *array_dt);
        st.insertMember("d", HOFFSET(src_typ_t, d), PredType::NATIVE_INT);
        st.insertMember("e", HOFFSET(src_typ_t, e), PredType::NATIVE_INT);
        array_dt->close();
        delete array_dt;

        array_dt = new ArrayType(PredType::NATIVE_INT, 1, &four);

        // Create an empty compound datatype
        CompType dt(sizeof(dst_typ_t));
        dt.insertMember("a", HOFFSET(dst_typ_t, a), PredType::NATIVE_INT);
        dt.insertMember("b", HOFFSET(dst_typ_t, b), PredType::NATIVE_INT);
        dt.insertMember("c", HOFFSET(dst_typ_t, c), *array_dt);
        dt.insertMember("d", HOFFSET(dst_typ_t, d), PredType::NATIVE_INT);
        dt.insertMember("e", HOFFSET(dst_typ_t, e), PredType::NATIVE_INT);
        array_dt->close();

        // Perform the conversion
        st.convert(dt, static_cast<size_t>(nelmts), buf, bkg);

        // Compare results
        for (i = 0; i < nelmts; i++) {
            s_ptr = (reinterpret_cast<src_typ_t *>(orig)) + i;
            d_ptr = (reinterpret_cast<dst_typ_t *>(buf)) + i;
            if (s_ptr->a != d_ptr->a || s_ptr->b != d_ptr->b || s_ptr->c[0] != d_ptr->c[0] ||
                s_ptr->c[1] != d_ptr->c[1] || s_ptr->c[2] != d_ptr->c[2] || s_ptr->c[3] != d_ptr->c[3] ||
                s_ptr->d != d_ptr->d || s_ptr->e != d_ptr->e) {
                H5_FAILED();
                cerr << "    i=" << i << endl;
                cerr << "    src={a=" << s_ptr->a << ", b=" << s_ptr->b << "c=[" << s_ptr->c[0] << ","
                     << s_ptr->c[1] << "," << s_ptr->c[2] << "," << s_ptr->c[3] << ", d=" << s_ptr->d
                     << ", e=" << s_ptr->e << "}" << endl;
                cerr << "    dst={a=" << s_ptr->a << ", b=" << s_ptr->b << "c=[" << s_ptr->c[0] << ","
                     << s_ptr->c[1] << "," << s_ptr->c[2] << "," << s_ptr->c[3] << ", d=" << s_ptr->d
                     << ", e=" << s_ptr->e << "}" << endl;
            }
        }
        // Release resources
        free(buf);
        free(bkg);
        free(orig);
        s_ptr = NULL;
        d_ptr = NULL;
        st.close();
        dt.close();
        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }

    delete array_dt;
} // test_compound_2()

/*-------------------------------------------------------------------------
 * Function:    test_compound_3
 *
 * Purpose      Tests compound conversions where the source and destination
 *              are the same except the destination is missing a couple
 *              members which appear in the source.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
static void
test_compound_3()
{
    typedef struct {
        int a, b, c[4], d, e;
    } src_typ_t;
    typedef struct {
        int a, c[4], e;
    } dst_typ_t;

    src_typ_t     *s_ptr;
    dst_typ_t     *d_ptr;
    int            i;
    const int      nelmts = NTESTELEM;
    const hsize_t  four   = 4;
    unsigned char *buf = NULL, *orig = NULL, *bkg = NULL;
    ArrayType     *array_dt = NULL;

    // Output message about test being performed
    SUBTEST("Compound Datatype Subset Conversions");
    try {
        /* Initialize */
        buf  = static_cast<unsigned char *>(malloc(nelmts * MAX(sizeof(src_typ_t), sizeof(dst_typ_t))));
        bkg  = static_cast<unsigned char *>(malloc(nelmts * sizeof(dst_typ_t)));
        orig = static_cast<unsigned char *>(malloc(nelmts * sizeof(src_typ_t)));
        for (i = 0; i < nelmts; i++) {
            s_ptr       = (reinterpret_cast<src_typ_t *>(orig)) + i;
            s_ptr->a    = i * 8 + 0;
            s_ptr->b    = i * 8 + 1;
            s_ptr->c[0] = i * 8 + 2;
            s_ptr->c[1] = i * 8 + 3;
            s_ptr->c[2] = i * 8 + 4;
            s_ptr->c[3] = i * 8 + 5;
            s_ptr->d    = i * 8 + 6;
            s_ptr->e    = i * 8 + 7;
        }
        memcpy(buf, orig, nelmts * sizeof(src_typ_t));

        /* Build hdf5 datatypes */
        array_dt = new ArrayType(PredType::NATIVE_INT, 1, &four);

        // Create an empty compound datatype
        CompType st(sizeof(src_typ_t));
        st.insertMember("a", HOFFSET(src_typ_t, a), PredType::NATIVE_INT);
        st.insertMember("b", HOFFSET(src_typ_t, b), PredType::NATIVE_INT);
        st.insertMember("c", HOFFSET(src_typ_t, c), *array_dt);
        st.insertMember("d", HOFFSET(src_typ_t, d), PredType::NATIVE_INT);
        st.insertMember("e", HOFFSET(src_typ_t, e), PredType::NATIVE_INT);
        array_dt->close();
        delete array_dt;

        array_dt = new ArrayType(PredType::NATIVE_INT, 1, &four);

        // Create an empty compound datatype
        CompType dt(sizeof(dst_typ_t));
        dt.insertMember("a", HOFFSET(dst_typ_t, a), PredType::NATIVE_INT);
        dt.insertMember("c", HOFFSET(dst_typ_t, c), *array_dt);
        dt.insertMember("e", HOFFSET(dst_typ_t, e), PredType::NATIVE_INT);
        array_dt->close();

        /* Perform the conversion */
        st.convert(dt, static_cast<size_t>(nelmts), buf, bkg);

        /* Compare results */
        for (i = 0; i < nelmts; i++) {
            s_ptr = (reinterpret_cast<src_typ_t *>(orig)) + i;
            d_ptr = (reinterpret_cast<dst_typ_t *>(buf)) + i;
            if (s_ptr->a != d_ptr->a || s_ptr->c[0] != d_ptr->c[0] || s_ptr->c[1] != d_ptr->c[1] ||
                s_ptr->c[2] != d_ptr->c[2] || s_ptr->c[3] != d_ptr->c[3] || s_ptr->e != d_ptr->e) {
                H5_FAILED();
                cerr << "    i=" << i << endl;
                cerr << "    src={a=" << s_ptr->a << ", b=" << s_ptr->b << ", c=[" << s_ptr->c[0] << ","
                     << s_ptr->c[1] << "," << s_ptr->c[2] << "," << s_ptr->c[3] << "], d=" << s_ptr->d
                     << ", e=" << s_ptr->e << "}" << endl;
                cerr << "    dst={a=" << d_ptr->a << ", c=[" << d_ptr->c[0] << "," << d_ptr->c[1] << ","
                     << d_ptr->c[2] << "," << d_ptr->c[3] << "], e=" << d_ptr->e << "}" << endl;
            }
        }

        /* Release resources */
        free(buf);
        free(bkg);
        free(orig);
        s_ptr = NULL;
        d_ptr = NULL;
        st.close();
        dt.close();
        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }

    delete array_dt;
} // test_compound_3()

/*-------------------------------------------------------------------------
 * Function:    test_compound_4
 *
 * Purpose      Tests compound conversions when the destination has the same
 *              fields as the source but one or more of the fields are
 *              smaller.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
static void
test_compound_4()
{

    typedef struct {
        int a, b, c[4], d, e;
    } src_typ_t;

    typedef struct {
        short b;
        int   a, c[4];
        short d;
        int   e;
    } dst_typ_t;

    src_typ_t     *s_ptr;
    dst_typ_t     *d_ptr;
    int            i;
    const int      nelmts = NTESTELEM;
    const hsize_t  four   = 4;
    unsigned char *buf = NULL, *orig = NULL, *bkg = NULL;
    ArrayType     *array_dt = NULL;

    // Output message about test being performed
    SUBTEST("Compound Element Shrinking & Reordering");
    try {
        /* Sizes should be the same, but be careful just in case */
        buf  = static_cast<unsigned char *>(malloc(nelmts * MAX(sizeof(src_typ_t), sizeof(dst_typ_t))));
        bkg  = static_cast<unsigned char *>(malloc(nelmts * sizeof(dst_typ_t)));
        orig = static_cast<unsigned char *>(malloc(nelmts * sizeof(src_typ_t)));
        for (i = 0; i < nelmts; i++) {
            s_ptr       = (reinterpret_cast<src_typ_t *>(orig)) + i;
            s_ptr->a    = i * 8 + 0;
            s_ptr->b    = (i * 8 + 1) & 0x7fff;
            s_ptr->c[0] = i * 8 + 2;
            s_ptr->c[1] = i * 8 + 3;
            s_ptr->c[2] = i * 8 + 4;
            s_ptr->c[3] = i * 8 + 5;
            s_ptr->d    = (i * 8 + 6) & 0x7fff;
            s_ptr->e    = i * 8 + 7;
        }
        memcpy(buf, orig, nelmts * sizeof(src_typ_t));

        /* Build hdf5 datatypes */
        array_dt = new ArrayType(PredType::NATIVE_INT, 1, &four);

        // Create an empty compound datatype
        CompType st(sizeof(src_typ_t));
        st.insertMember("a", HOFFSET(src_typ_t, a), PredType::NATIVE_INT);
        st.insertMember("b", HOFFSET(src_typ_t, b), PredType::NATIVE_INT);
        st.insertMember("c", HOFFSET(src_typ_t, c), *array_dt);
        st.insertMember("d", HOFFSET(src_typ_t, d), PredType::NATIVE_INT);
        st.insertMember("e", HOFFSET(src_typ_t, e), PredType::NATIVE_INT);
        array_dt->close();
        delete array_dt;

        array_dt = new ArrayType(PredType::NATIVE_INT, 1, &four);

        // Create an empty compound datatype
        CompType dt(sizeof(dst_typ_t));
        dt.insertMember("a", HOFFSET(dst_typ_t, a), PredType::NATIVE_INT);
        dt.insertMember("b", HOFFSET(dst_typ_t, b), PredType::NATIVE_SHORT);
        dt.insertMember("c", HOFFSET(dst_typ_t, c), *array_dt);
        dt.insertMember("d", HOFFSET(dst_typ_t, d), PredType::NATIVE_SHORT);
        dt.insertMember("e", HOFFSET(dst_typ_t, e), PredType::NATIVE_INT);
        array_dt->close();

        /* Perform the conversion */
        st.convert(dt, static_cast<size_t>(nelmts), buf, bkg);

        /* Compare results */
        for (i = 0; i < nelmts; i++) {
            s_ptr = (reinterpret_cast<src_typ_t *>(orig)) + i;
            d_ptr = (reinterpret_cast<dst_typ_t *>(buf)) + i;
            if (s_ptr->a != d_ptr->a || s_ptr->b != d_ptr->b || s_ptr->c[0] != d_ptr->c[0] ||
                s_ptr->c[1] != d_ptr->c[1] || s_ptr->c[2] != d_ptr->c[2] || s_ptr->c[3] != d_ptr->c[3] ||
                s_ptr->d != d_ptr->d || s_ptr->e != d_ptr->e) {
                H5_FAILED();
                cerr << "    i=" << i << endl;
                cerr << "    src={a=" << s_ptr->a << ", b=" << s_ptr->b << "c=[" << s_ptr->c[0] << ","
                     << s_ptr->c[1] << "," << s_ptr->c[2] << "," << s_ptr->c[3] << ", d=" << s_ptr->d
                     << ", e=" << s_ptr->e << "}" << endl;
                cerr << "    dst={a=" << d_ptr->a << ", b=" << d_ptr->b << "c=[" << d_ptr->c[0] << ","
                     << d_ptr->c[1] << "," << d_ptr->c[2] << "," << d_ptr->c[3] << ", d=" << d_ptr->d
                     << ", e=" << d_ptr->e << "}" << endl;
            } // if
        }     // for

        /* Release resources */
        free(buf);
        free(bkg);
        free(orig);
        s_ptr = NULL;
        d_ptr = NULL;
        st.close();
        dt.close();
        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }

    delete array_dt;
} // test_compound_4()

/*-------------------------------------------------------------------------
 * Function:    test_compound_5
 *
 * Purpose      Many versions of HDF5 have a bug in the optimized compound
 *              datatype conversion function, H5T_conv_struct_opt(), which
 *              is triggered when the top-level type contains a struct
 *              which must undergo a conversion.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
static void
test_compound_5()
{
    typedef struct {
        char  name[16];
        short tdim;
        short coll_ids[4];
    } src_typ_t;

    typedef struct {
        char  name[16];
        short tdim;
        int   coll_ids[4];
    } dst_typ_t;

    hsize_t    dims[1] = {4};
    src_typ_t  src[2]  = {{"one", 102, {104, 105, 106, 107}}, {"two", 202, {204, 205, 206, 207}}};
    dst_typ_t *dst;
    void      *buf      = calloc(2, sizeof(dst_typ_t));
    void      *bkg      = calloc(2, sizeof(dst_typ_t));
    ArrayType *array_dt = NULL;

    // Output message about test being performed
    SUBTEST("Optimized Struct Converter");
    try {

        /* Build datatypes */
        array_dt = new ArrayType(PredType::NATIVE_SHORT, 1, dims);
        CompType short_array(4 * sizeof(short));
        short_array.insertMember("_", 0, *array_dt);
        array_dt->close();
        delete array_dt;

        CompType int_array(4 * sizeof(int));
        array_dt = new ArrayType(PredType::NATIVE_INT, 1, dims);
        int_array.insertMember("_", 0, *array_dt);
        array_dt->close();

        StrType  strg(PredType::C_S1, 16);
        CompType src_type(sizeof(src_typ_t));
        src_type.insertMember("name", HOFFSET(src_typ_t, name), strg);
        src_type.insertMember("tdim", HOFFSET(src_typ_t, tdim), PredType::NATIVE_SHORT);
        src_type.insertMember("coll_ids", HOFFSET(src_typ_t, coll_ids), short_array);

        CompType dst_type(sizeof(dst_typ_t));
        dst_type.insertMember("name", HOFFSET(dst_typ_t, name), strg);
        dst_type.insertMember("tdim", HOFFSET(dst_typ_t, tdim), PredType::NATIVE_SHORT);
        dst_type.insertMember("coll_ids", HOFFSET(dst_typ_t, coll_ids), int_array);

        /* Convert data */
        memcpy(buf, src, sizeof(src));
        src_type.convert(dst_type, 2, buf, bkg);
        dst = static_cast<dst_typ_t *>(buf);

        /* Cleanup */
        src_type.close();
        dst_type.close();
        strg.close();
        short_array.close();
        int_array.close();

        /* Check results */
        if (memcmp(src[1].name, dst[1].name, sizeof(src[1].name)) != 0 || src[1].tdim != dst[1].tdim ||
            src[1].coll_ids[0] != dst[1].coll_ids[0] || src[1].coll_ids[1] != dst[1].coll_ids[1] ||
            src[1].coll_ids[2] != dst[1].coll_ids[2] || src[1].coll_ids[3] != dst[1].coll_ids[3]) {
            H5_FAILED();
        }

        /* Free memory buffers */
        free(buf);
        free(bkg);
        dst = NULL;
        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }

    delete array_dt;
} // test_compound_5()

/*-------------------------------------------------------------------------
 * Function:    test_compound_6
 *
 * Purpose      Tests compound conversions when the destination has the same
 *              fields as the source but one or more of the fields are
 *              larger.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
static void
test_compound_6()
{
    typedef struct {
        short b;
        short d;
    } src_typ_t;

    typedef struct {
        long b;
        long d;
    } dst_typ_t;

    src_typ_t     *s_ptr;
    dst_typ_t     *d_ptr;
    int            i;
    const int      nelmts = NTESTELEM;
    unsigned char *buf = NULL, *orig = NULL, *bkg = NULL;

    // Output message about test being performed
    SUBTEST("Compound Element Growing");
    try {
        /* Sizes should be the same, but be careful just in case */
        buf  = static_cast<unsigned char *>(malloc(nelmts * MAX(sizeof(src_typ_t), sizeof(dst_typ_t))));
        bkg  = static_cast<unsigned char *>(malloc(nelmts * sizeof(dst_typ_t)));
        orig = static_cast<unsigned char *>(malloc(nelmts * sizeof(src_typ_t)));
        for (i = 0; i < nelmts; i++) {
            s_ptr    = (reinterpret_cast<src_typ_t *>(orig)) + i;
            s_ptr->b = (i * 8 + 1) & 0x7fff;
            s_ptr->d = (i * 8 + 6) & 0x7fff;
        }
        memcpy(buf, orig, nelmts * sizeof(src_typ_t));

        /* Build hdf5 datatypes */
        CompType st(sizeof(src_typ_t));
        st.insertMember("b", HOFFSET(src_typ_t, b), PredType::NATIVE_SHORT);
        st.insertMember("d", HOFFSET(src_typ_t, d), PredType::NATIVE_SHORT);

        CompType dt(sizeof(dst_typ_t));
        dt.insertMember("b", HOFFSET(dst_typ_t, b), PredType::NATIVE_LONG);
        dt.insertMember("d", HOFFSET(dst_typ_t, d), PredType::NATIVE_LONG);

        /* Perform the conversion */
        st.convert(dt, static_cast<size_t>(nelmts), buf, bkg);

        /* Compare results */
        for (i = 0; i < nelmts; i++) {
            s_ptr = (reinterpret_cast<src_typ_t *>(orig)) + i;
            d_ptr = (reinterpret_cast<dst_typ_t *>(buf)) + i;
            if (s_ptr->b != d_ptr->b || s_ptr->d != d_ptr->d) {
                H5_FAILED();
                cerr << "    i=" << i << endl;
                cerr << "    src={b=" << s_ptr->b << ", d=" << s_ptr->d << "}" << endl;
                cerr << "    dst={b=" << d_ptr->b << ", d=" << d_ptr->d << "}" << endl;
            }
        }

        /* Release resources */
        free(buf);
        free(bkg);
        free(orig);
        s_ptr = NULL;
        d_ptr = NULL;
        st.close();
        dt.close();
        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }
} // test_compound_6()

/*-------------------------------------------------------------------------
 * Function:    test_compound_7
 *
 * Purpose      Tests inserting fields into compound datatypes when the field
 *              overlaps the end of the compound datatype.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
static void
test_compound_7()
{
    typedef struct {
        int   a;
        float b;
        long  c;
    } s1_typ_t;

    typedef struct {
        int    a;
        float  b;
        long   c;
        double d;
    } s2_typ_t;

    // Output message about test being performed
    SUBTEST("Compound Element Insertion");
    try {
        CompType tid1(sizeof(s1_typ_t));

        tid1.insertMember("a", HOFFSET(s1_typ_t, a), PredType::NATIVE_INT);
        tid1.insertMember("b", HOFFSET(s1_typ_t, b), PredType::NATIVE_FLOAT);
        tid1.insertMember("c", HOFFSET(s1_typ_t, c), PredType::NATIVE_LONG);

        size_t type_size = tid1.getSize();
        verify_val(type_size, sizeof(s1_typ_t), "DataType::getSize", __LINE__, __FILE__);

        CompType tid2;
        tid2.copy(tid1);

        type_size = tid2.getSize();
        verify_val_noteq(type_size, sizeof(s2_typ_t), "DataType::getSize", __LINE__, __FILE__);

        /* Should not be able to insert field past end of compound datatype */
        try {
            tid2.insertMember("d", HOFFSET(s2_typ_t, d), PredType::NATIVE_DOUBLE);
            // Should FAIL but didn't, so throw an invalid action exception
            throw InvalidActionException("CompType::insertMember",
                                         "Attempted to insert field past end of compound data type.");
        }
        catch (DataTypeIException &err) {
        }

        /* Release resources */
        tid1.close();
        tid2.close();
        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }
} // test_compound_7()

/*-------------------------------------------------------------------------
 * Function:    test_compound_set_size
 *
 * Purpose      Tests member function setSize() on compound datatype
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
const H5std_string COMPFILE("tcompound_types.h5");

static void
test_compound_set_size()
{
    typedef struct {
        int a, b, c[4], d, e;
    } src_typ_t;

    // Output message about test being performed
    SUBTEST("Setting Size on Compound Datatype");
    try {
        // Create File
        H5File file(COMPFILE, H5F_ACC_TRUNC);

        // Create a compound datatype
        CompType dtype(sizeof(src_typ_t));

        dtype.insertMember("a", HOFFSET(src_typ_t, a), PredType::NATIVE_INT);
        dtype.insertMember("b", HOFFSET(src_typ_t, b), PredType::NATIVE_FLOAT);
        dtype.insertMember("c", HOFFSET(src_typ_t, c), PredType::NATIVE_LONG);
        dtype.insertMember("d", HOFFSET(src_typ_t, d), PredType::NATIVE_DOUBLE);

        // Verify that the compound is not packed
        // bool packed = dtype.packed(); // not until C library provides API
        // verify_val(packed, FALSE, "DataType::packed", __LINE__, __FILE__);

        dtype.commit(file, "dtype");

        // Close the type and file
        dtype.close();
        file.close();

        // Open the file for read/write
        file.openFile(COMPFILE, H5F_ACC_RDWR);

        // Open the data type "dtype"
        CompType dtype_tmp = file.openCompType("dtype");

        // Make a copy of the data type
        dtype.copy(dtype_tmp);

        // Verify that the compound is not packed
        // packed = dtype_tmp.packed(); // not until C library provides API
        // verify_val(packed, FALSE, "DataType::packed", __LINE__, __FILE__);

        // Expand the type, and verify that it became unpacked
        dtype.setSize(33);
        // packed = dtype.packed(); // not until C library provides API
        // verify_val(packed, FALSE, "DataType::packed", __LINE__, __FILE__);

        // Verify setSize() actually set size
        size_t new_size = dtype.getSize();
        verify_val(static_cast<long>(new_size), 33, "DataType::getSize", __LINE__, __FILE__);

        // Shrink the type, and verify that it became packed
        dtype.setSize(32);
        // packed = dtype.packed(); // not until C library provides API
        // verify_val(packed, TRUE, "DataType::packed", __LINE__, __FILE__);

        // Verify setSize() actually set size again
        new_size = dtype.getSize();
        verify_val(static_cast<long>(new_size), 32, "DataType::getSize", __LINE__, __FILE__);

        /* Close types and file */
        dtype_tmp.close();
        dtype.close();
        file.close();

        PASSED();
    } // end of try block

    catch (Exception &E) {
        issue_fail_msg(E.getCFuncName(), __LINE__, __FILE__, E.getCDetailMsg());
    }
} // test_compound_set_size()

/*-------------------------------------------------------------------------
 * Function:    test_compound
 *
 * Purpose      Main compound datatype testing routine
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
extern "C" void
test_compound(const void *params)
{
    // Output message about test being performed
    MESSAGE(5, ("Testing Compound Data Type operations\n"));

    test_compound_1();        // various things about compound data types
    test_compound_2();        // compound element reordering
    test_compound_3();        // compound datatype subset conversions
    test_compound_4();        // compound element shrinking & reordering
    test_compound_5();        // optimized struct converter
    test_compound_6();        // compound element growing
    test_compound_7();        // compound element insertion
    test_compound_set_size(); // set size on compound data types
} // test_compound()

/*-------------------------------------------------------------------------
 * Function:    cleanup_compound
 *
 * Purpose      Cleanup temporary test files - nothing at this time.
 *
 * Return       None
 *-------------------------------------------------------------------------
 */
extern "C" void
cleanup_compound(void *params)
{
    if (GetTestCleanup()) {
        HDremove(COMPFILE.c_str());
    }
} // cleanup_file
