/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <string>

#include "H5Include.h"
#include "H5Exception.h"
#include "H5IdComponent.h"
#include "H5PropList.h"
#include "H5OcreatProp.h"
#include "H5DcreatProp.h"
#include "H5DxferProp.h"
#include "H5LcreatProp.h"
#include "H5LaccProp.h"
#include "H5DaccProp.h"
#include "H5Location.h"
#include "H5Object.h"
#include "H5DataType.h"
#include "H5AbstractDs.h"
#include "H5DataSpace.h"
#include "H5AtomType.h"
#include "H5FloatType.h"
#include "H5DataSet.h"
#include "H5PredType.h"

namespace H5 {

//--------------------------------------------------------------------------
// Function:    FloatType default constructor
///\brief       Default constructor: Creates a stub floating-point datatype
//--------------------------------------------------------------------------
FloatType::FloatType()
{
}

//--------------------------------------------------------------------------
// Function:    FloatType overloaded constructor
///\brief       Creates a floating-point datatype using a predefined type.
///\param       pred_type - IN: Predefined datatype
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
FloatType::FloatType(const PredType &pred_type) : AtomType()
{
    // use DataType::copy to make a copy of this predefined type
    copy(pred_type);
}

//--------------------------------------------------------------------------
// Function:    FloatType overloaded constructor
///\brief       Creates an FloatType object using the id of an existing
///             datatype.
///\param       existing_id - IN: Id of an existing datatype
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
FloatType::FloatType(const hid_t existing_id) : AtomType(existing_id)
{
}

//--------------------------------------------------------------------------
// Function:    FloatType copy constructor
///\brief       Copy constructor: same HDF5 object as \a original
//--------------------------------------------------------------------------
FloatType::FloatType(const FloatType &original) : AtomType(original)
{
}

//--------------------------------------------------------------------------
// Function:    FloatType overloaded constructor
///\brief       Gets the floating-point datatype of the specified dataset
///\param       dataset - IN: Dataset that this floating-point datatype
///             associates with
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
FloatType::FloatType(const DataSet &dataset) : AtomType()
{
    // Calls C function H5Dget_type to get the id of the datatype
    id = H5Dget_type(dataset.getId());

    if (id < 0) {
        throw DataSetIException("FloatType constructor", "H5Dget_type failed");
    }
}

//--------------------------------------------------------------------------
// Function:    FloatType overloaded constructor
///\brief       Creates an FloatType instance by opening an HDF5 float datatype
///             given its name, provided as a C character string.
///\param       loc        - IN: Location of the type
///\param       dtype_name - IN: Float type name
///\exception   H5::DataTypeIException
// Description
//              In 1.10.1, this constructor was introduced and may replace the
//              existing function CommonFG::openFloatType(const char*)
//              to improve usability.
//              -BMR, Dec 2016
//--------------------------------------------------------------------------
FloatType::FloatType(const H5Location &loc, const char *dtype_name) : AtomType()
{
    id = p_opentype(loc, dtype_name);
}

//--------------------------------------------------------------------------
// Function:    FloatType overloaded constructor
///\brief       Creates an FloatType instance by opening an HDF5 float datatype
///             given its name, provided as an \c H5std_string.
///\param       loc        - IN: Location of the type
///\param       dtype_name - IN: Float type name
///\exception   H5::DataTypeIException
// Description
//              In 1.10.1, this constructor was introduced and may replace the
//              existing function CommonFG::openFloatType(const H5std_string&)
//              to improve usability.
//              -BMR, Dec 2016
//--------------------------------------------------------------------------
FloatType::FloatType(const H5Location &loc, const H5std_string &dtype_name) : AtomType()
{
    id = p_opentype(loc, dtype_name.c_str());
}

//--------------------------------------------------------------------------
// Function:    FloatType::decode
///\brief       Returns an FloatType object via DataType* by decoding the
///             binary object description of this type.
///
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
DataType *
FloatType::decode() const
{
    hid_t encoded_flttype_id = H5I_INVALID_HID;
    try {
        encoded_flttype_id = p_decode();
    }
    catch (DataTypeIException &err) {
        throw;
    }
    FloatType *encoded_flttype = new FloatType;
    encoded_flttype->p_setId(encoded_flttype_id);
    return (encoded_flttype);
}

//--------------------------------------------------------------------------
// Function:    FloatType::getFields
///\brief       Retrieves floating point datatype bit field information.
///\param       spos  - OUT: Retrieved floating-point sign bit
///\param       epos  - OUT: Retrieved exponent bit-position
///\param       esize - OUT: Retrieved size of exponent, in bits
///\param       mpos  - OUT: Retrieved mantissa bit-position
///\param       msize - OUT: Retrieved size of mantissa, in bits
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
void
FloatType::getFields(size_t &spos, size_t &epos, size_t &esize, size_t &mpos, size_t &msize) const
{
    herr_t ret_value = H5Tget_fields(id, &spos, &epos, &esize, &mpos, &msize);
    if (ret_value < 0) {
        throw DataTypeIException("FloatType::getFields", "H5Tget_fields failed");
    }
}

//--------------------------------------------------------------------------
// Function:    FloatType::setFields
///\brief       Sets locations and sizes of floating point bit fields.
///\param       spos  - OUT: Sign position, i.e., the bit offset of the
///             floating-point sign bit.
///\param       epos  - OUT: Exponent bit position
///\param       esize - OUT: Size of exponent, in bits
///\param       mpos  - OUT: Mantissa bit-position
///\param       msize - OUT: Size of mantissa, in bits
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
void
FloatType::setFields(size_t spos, size_t epos, size_t esize, size_t mpos, size_t msize) const
{
    herr_t ret_value = H5Tset_fields(id, spos, epos, esize, mpos, msize);
    if (ret_value < 0) {
        throw DataTypeIException("FloatType::setFields", "H5Tset_fields failed");
    }
}

//--------------------------------------------------------------------------
// Function:    FloatType::getEbias
///\brief       Retrieves the exponent bias of a floating-point type.
///\return      Exponent bias
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
size_t
FloatType::getEbias() const
{
    size_t ebias = H5Tget_ebias(id);
    // Returns the bias if successful
    if (ebias == 0) {
        throw DataTypeIException("FloatType::getEbias", "H5Tget_ebias failed - returned exponent bias as 0");
    }
    return (ebias);
}

//--------------------------------------------------------------------------
// Function:    FloatType::setEbias
///\brief       Sets the exponent bias of a floating-point type.
///\param       ebias - Exponent bias value
///\exception   H5::DataTypeIException
//--------------------------------------------------------------------------
void
FloatType::setEbias(size_t ebias) const
{
    herr_t ret_value = H5Tset_ebias(id, ebias);
    if (ret_value < 0) {
        throw DataTypeIException("FloatType::setEbias", "H5Tset_ebias failed");
    }
}

//--------------------------------------------------------------------------
// Function:    FloatType::getNorm
///\brief       Retrieves mantissa normalization of a floating-point datatype.
///\param       norm_string - OUT: Text string of the normalization type
///\return      Valid normalization type, which can be:
///             \li \c H5T_NORM_IMPLIED (0) - MSB of mantissa is not stored
///             \li \c H5T_NORM_MSBSET (1) - MSB of mantissa is always 1
///             \li \c H5T_NORM_NONE (2) - Mantissa is not normalized
///\exception   H5::DataTypeIException
///\par Description
///             For your convenience, this function also provides the text
///             string of the returned normalization type, via parameter
///             \a norm_string.
//--------------------------------------------------------------------------
H5T_norm_t
FloatType::getNorm(H5std_string &norm_string) const
{
    H5T_norm_t norm = H5Tget_norm(id); // C routine
    // Returns a valid normalization type if successful
    if (norm == H5T_NORM_ERROR) {
        throw DataTypeIException("FloatType::getNorm", "H5Tget_norm failed - returned H5T_NORM_ERROR");
    }
    if (norm == H5T_NORM_IMPLIED)
        norm_string = "H5T_NORM_IMPLIED (0)";
    else if (norm == H5T_NORM_MSBSET)
        norm_string = "H5T_NORM_MSBSET (1)";
    else if (norm == H5T_NORM_NONE)
        norm_string = "H5T_NORM_NONE (2)";
    return (norm);
}

//--------------------------------------------------------------------------
// Function:    FloatType::setNorm
///\brief       Sets the mantissa normalization of a floating-point datatype.
///\param       norm - IN: Mantissa normalization type
///\exception   H5::DataTypeIException
///\par Description
///             Valid values for normalization type include:
///             \li \c H5T_NORM_IMPLIED (0) - MSB of mantissa is not stored
///             \li \c H5T_NORM_MSBSET (1) - MSB of mantissa is always 1
///             \li \c H5T_NORM_NONE (2) - Mantissa is not normalized
//--------------------------------------------------------------------------
void
FloatType::setNorm(H5T_norm_t norm) const
{
    herr_t ret_value = H5Tset_norm(id, norm);
    if (ret_value < 0) {
        throw DataTypeIException("FloatType::setNorm", "H5Tset_norm failed");
    }
}

//--------------------------------------------------------------------------
// Function:    FloatType::getInpad
///\brief       Retrieves the internal padding type for unused bits in
///             this floating-point datatypes.
///\return      Internal padding type, which can be:
///             \li \c H5T_PAD_ZERO (0) - Set background to zeros
///             \li \c H5T_PAD_ONE (1) - Set background to ones
///             \li \c H5T_PAD_BACKGROUND (2) - Leave background alone
///\exception   H5::DataTypeIException
///\par Description
///             For your convenience, this function also provides the text
///             string of the returned internal padding type, via parameter
///             \a pad_string.
//--------------------------------------------------------------------------
H5T_pad_t
FloatType::getInpad(H5std_string &pad_string) const
{
    H5T_pad_t pad_type = H5Tget_inpad(id);
    // Returns a valid padding type if successful
    if (pad_type == H5T_PAD_ERROR) {
        throw DataTypeIException("FloatType::getInpad", "H5Tget_inpad failed - returned H5T_PAD_ERROR");
    }
    if (pad_type == H5T_PAD_ZERO)
        pad_string = "H5T_PAD_ZERO (0)";
    else if (pad_type == H5T_PAD_ONE)
        pad_string = "H5T_PAD_ONE (1)";
    else if (pad_type == H5T_PAD_BACKGROUND)
        pad_string = "H5T_PAD_BACKGROUD (2)";
    return (pad_type);
}

//--------------------------------------------------------------------------
// Function:    FloatType::setInpad
///\brief       Fills unused internal floating point bits.
///\param       inpad - IN: Internal padding type
///\exception   H5::DataTypeIException
///\par Description
///             If any internal bits of a floating point type are unused
///             (that is, those significant bits which are not part of the
///             sign, exponent, or mantissa), then they will be filled
///             according to the padding value provided by \a inpad.
///\par
///             Valid values for normalization type include:
///             \li \c H5T_PAD_ZERO (0) - Set background to zeros
///             \li \c H5T_PAD_ONE (1) - Set background to ones
///             \li \c H5T_PAD_BACKGROUND (2) - Leave background alone
//--------------------------------------------------------------------------
void
FloatType::setInpad(H5T_pad_t inpad) const
{
    herr_t ret_value = H5Tset_inpad(id, inpad);
    if (ret_value < 0) {
        throw DataTypeIException("FloatType::setInpad", "H5Tset_inpad failed");
    }
}

} // namespace H5
