/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * 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 COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 *  This example illustrates how to read/write a subset of data (a slab)
 *  from/to a dataset in an HDF5 file. It is used in the HDF5 Tutorial.
 */

#include <iostream>
using std::cout;
using std::endl;

#include <string>
#include "H5Cpp.h"
using namespace H5;

const H5std_string FILE_NAME("h5tutr_subset.h5");
const H5std_string DATASET_NAME("IntArray");

const int RANK     = 2;
const int DIM0_SUB = 3; // subset dimensions
const int DIM1_SUB = 4;
const int DIM0     = 8; // size of dataset
const int DIM1     = 10;

int
main(void)
{
    int i, j;
    int data[DIM0][DIM1], sdata[DIM0_SUB][DIM1_SUB], rdata[DIM0][DIM1];

    // Try block to detect exceptions raised by any of the calls inside it
    try {
        // Turn off the auto-printing when failure occurs so that we can
        // handle the errors appropriately
        Exception::dontPrint();

        // ---------------------------------------------------
        // Create a new file using the default property lists.
        // Then create a dataset and write data to it.
        // Close the file and dataset.
        // ---------------------------------------------------

        H5File file(FILE_NAME, H5F_ACC_TRUNC);

        hsize_t dims[2];
        dims[0]             = DIM0;
        dims[1]             = DIM1;
        DataSpace dataspace = DataSpace(RANK, dims);

        DataSet dataset(file.createDataSet(DATASET_NAME, PredType::STD_I32BE, dataspace));

        for (j = 0; j < DIM0; j++) {
            for (i = 0; i < DIM1; i++)
                if (i < (DIM1 / 2))
                    data[j][i] = 1;
                else
                    data[j][i] = 2;
        }

        dataset.write(data, PredType::NATIVE_INT);

        cout << endl << "Data Written to File:" << endl;
        for (j = 0; j < DIM0; j++) {
            for (i = 0; i < DIM1; i++)
                cout << " " << data[j][i];
            cout << endl;
        }

        dataspace.close();
        dataset.close();
        file.close();

        // ---------------------------------------------------
        // Reopen the file and dataset and write a subset of
        // values to the dataset.
        // ---------------------------------------------------

        hsize_t offset[2], count[2], stride[2], block[2];
        hsize_t dimsm[2];

        file.openFile(FILE_NAME, H5F_ACC_RDWR);
        dataset = file.openDataSet(DATASET_NAME);

        // Specify size and shape of subset to write.

        offset[0] = 1;
        offset[1] = 2;

        count[0] = DIM0_SUB;
        count[1] = DIM1_SUB;

        stride[0] = 1;
        stride[1] = 1;

        block[0] = 1;
        block[1] = 1;

        // Define Memory Dataspace. Get file dataspace and select
        // a subset from the file dataspace.

        dimsm[0] = DIM0_SUB;
        dimsm[1] = DIM1_SUB;

        DataSpace memspace(RANK, dimsm, NULL);

        dataspace = dataset.getSpace();
        dataspace.selectHyperslab(H5S_SELECT_SET, count, offset, stride, block);

        // Write a subset of data to the dataset, then read the
        // entire dataset back from the file.

        cout << endl << "Write subset to file specifying: " << endl;
        cout << "  offset=1x2 stride=1x1 count=3x4 block=1x1" << endl;
        for (j = 0; j < DIM0_SUB; j++) {
            for (i = 0; i < DIM1_SUB; i++)
                sdata[j][i] = 5;
        }

        dataset.write(sdata, PredType::NATIVE_INT, memspace, dataspace);
        dataset.read(rdata, PredType::NATIVE_INT);

        cout << endl << "Data in File after Subset is Written:" << endl;
        for (i = 0; i < DIM0; i++) {
            for (j = 0; j < DIM1; j++)
                cout << " " << rdata[i][j];
            cout << endl;
        }
        cout << endl;

        // It is not necessary to close these objects because close() will
        // be called when the object instances are going out of scope.
        dataspace.close();
        memspace.close();
        dataset.close();
        file.close();

    } // end of try block

    // catch failure caused by the H5File operations
    catch (FileIException error) {
        error.printErrorStack();
        return -1;
    }

    // catch failure caused by the DataSet operations
    catch (DataSetIException error) {
        error.printErrorStack();
        return -1;
    }

    // catch failure caused by the DataSpace operations
    catch (DataSpaceIException error) {
        error.printErrorStack();
        return -1;
    }

    return 0; // successfully terminated
}
