// bdldfp_decimalconvertutil_inteldfp.h                               -*-C++-*-
#ifndef INCLUDED_BDLDFP_DECIMALCONVERTUTIL_INTELDFP
#define INCLUDED_BDLDFP_DECIMALCONVERTUTIL_INTELDFP

#include <bsls_ident.h>
BSLS_IDENT("$Id$")

//@PURPOSE: Provide decimal floating-point conversion functions for Intel DFP.
//
//@CLASSES:
//  bdldfp::DecimalConvertUtil_IntelDfp: Intel DFP conversion functions
//
//@SEE_ALSO: bdldfp_decimal, bdldfp_decimalplatform
//
//@DESCRIPTION: This component provides conversion operations between the
// decimal types supplied in this package (`Decimal32`, `Decimal64`,
// `Decimal128`) and various alternative representations.  Some of the
// alternative representations that this component provides conversions for are
// IEEE-754 binary floating point (i.e., `float` and `double`) and a network
// format (big-endian, Densely Packed Decimal encoding).
//
///Usage
///-----
// This section shows the intended use of this component.
//
///Example 1: TBD
/// - - - - - - -

#include <bdlscm_version.h>

#include <bdldfp_decimalplatform.h>

#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
#include <bdldfp_decimal.h>
#include <bdldfp_decimalimputil.h>
#include <bdldfp_decimalimputil_inteldfp.h>
#include <bdldfp_intelimpwrapper.h>

#include <bsls_assert.h>

#include <bsl_cstring.h>

namespace BloombergLP {
namespace bdldfp {
                        // =================================
                        // class DecimalConvertUtil_IntelDfp
                        // =================================

/// This `struct` provides a namespace for utility functions that convert
/// between the decimal floating-point types of `bdldfp_decimal` and various
/// other formats.
struct DecimalConvertUtil_IntelDfp {

    // Convert to Binary Floating-Point from C++ Decimal TR

    // CLASS METHODS

                        // decimalToDouble functions

    static double decimal32ToDouble (Decimal32  decimal);
    static double decimal64ToDouble (Decimal64  decimal);
    static double decimal128ToDouble(Decimal128 decimal);

    /// Return a `double` object having the value closest to the value of
    /// the specified `decimal` object following the conversion rules
    /// defined by IEEE-754:
    ///
    /// * If the `decimal` object is a NaN, return a NaN.
    /// * Otherwise if `decimal` is positive or negative infinity, return
    ///   infinity of the same sign.
    /// * Otherwise if `decimal` is positive or negative zero, return zero
    ///   of the same sign.
    /// * Otherwise if `decimal` object has an absolute value that is
    ///   larger than `std::numeric_limits<double>::max()`, raise the
    ///   "overflow" floating-point exception and return infinity of the
    ///   same sign as `decimal`.
    /// * Otherwise if `decimal` has an absolute value that is smaller than
    ///   `std::numeric_limits<double>::min()`, raise the "underflow"
    ///   floating-point exception and return zero of the same sign as
    ///   `decimal`.
    /// * Otherwise if `decimal` has a value that has more significant
    ///   base-10 digits than `std::numeric_limits<double>::digits10`,
    ///   raise the "inexact" floating-point exception, round that value
    ///   according to the *binary* rounding direction setting of the
    ///   floating-point environment, and return the result of that.
    /// * Otherwise if `decimal` has a significand that cannot be exactly
    ///   represented using binary floating-point, raise the "inexact"
    ///   floating-point exception, roundthat value according to the
    ///   *binary* rounding direction setting of the environment, and
    ///   return the result of that.
    /// * Otherwise use the exact value of the `other` object for the
    ///   initialization if this object.
    static double decimalToDouble   (Decimal32  decimal);
    static double decimalToDouble   (Decimal64  decimal);
    static double decimalToDouble   (Decimal128 decimal);

                        // decimalToFloat functions

    static float decimal32ToFloat (Decimal32  decimal);
    static float decimal64ToFloat (Decimal64  decimal);
    static float decimal128ToFloat(Decimal128 decimal);

    /// Return a `float` object having the value closest to the value of the
    /// specified `decimal` object following the conversion rules defined
    /// by IEEE-754:
    ///
    /// * If the `decimal` object is a NaN, return a NaN.
    /// * Otherwise if `decimal` is positive or negative infinity, return
    ///   infinity of the same sign.
    /// * Otherwise if `decimal` is positive or negative zero, return zero
    ///   of the same sign.
    /// * Otherwise if `decimal` object has an absolute value that is
    ///   larger than `std::numeric_limits<long double>::max()`, raise the
    ///   "overflow" floating-point exception and return infinity of the
    ///   same sign as `decimal`.
    /// * Otherwise if `decimal` has an absolute value that is smaller than
    ///   `std::numeric_limits<float>::min()`, raise the "underflow"
    ///   floating-point exception and return zero of the same sign as
    ///   `decimal`.
    /// * Otherwise if `decimal` has a value that has more significant
    ///   base-10 digits than `std::numeric_limits<float>::digits10`,
    ///   raise the "inexact" floating-point exception, round that value
    ///   according to the *binary* rounding direction setting of the
    ///   floating-point environment, and return the result of that.
    /// * Otherwise if `decimal` has a significand that cannot be exactly
    ///   represented using binary floating-point, raise the "inexact"
    ///   floating-point exception, roundthat value according to the
    ///   *binary* rounding direction setting of the environment, and
    ///   return the result of that.
    /// * Otherwise use the exact value of the `other` object for the
    ///   initialization if this object.
    static float decimalToFloat   (Decimal32  decimal);
    static float decimalToFloat   (Decimal64  decimal);
    static float decimalToFloat   (Decimal128 decimal);


                        // decimalToDPD functions

    static void decimal32ToDPD( unsigned char *buffer,
                                Decimal32      decimal);
    static void decimal64ToDPD( unsigned char *buffer,
                                Decimal64      decimal);
    static void decimal128ToDPD(unsigned char *buffer,
                                Decimal128     decimal);

    /// Populate the specified `buffer` with the Densely Packed Decimal
    /// (DPD) representation of the specified `decimal` value.  The DPD
    /// representations of `Decimal32`, `Decimal64`, and `Decimal128`
    /// require 4, 8, and 16 bytes respectively.  The behavior is undefined
    /// unless `buffer` points to a contiguous sequence of at least
    /// `sizeof(decimal)` bytes.  Note that the DPD representation is
    /// defined in section 3.5 of IEEE 754-2008.
    static void decimalToDPD(   unsigned char *buffer,
                                Decimal32      decimal);
    static void decimalToDPD(   unsigned char *buffer,
                                Decimal64      decimal);
    static void decimalToDPD(   unsigned char *buffer,
                                Decimal128     decimal);

                        // decimalFromDPD functions

    static Decimal32  decimal32FromDPD( const unsigned char *buffer);
    static Decimal64  decimal64FromDPD( const unsigned char *buffer);

    /// Return the native implementation representation of the value of the
    /// same size base-10 floating-point value stored in Densely Packed
    /// Decimal format at the specified `buffer` address.  The behavior is
    /// undefined unless `buffer` points to a memory area at least
    /// `sizeof(decimal)` in size containing a value in DPD format.
    static Decimal128 decimal128FromDPD(const unsigned char *buffer);

    /// Store, into the specified `decimal`, the native implementation
    /// representation of the value of the same size base-10 floating point
    /// value represented in Densely Packed Decimal format, at the specified
    /// `buffer` address.  The behavior is undefined unless `buffer` points
    /// to a memory area at least `sizeof(decimal)` in size containing a
    /// value in DPD format.
    static void decimalFromDPD(Decimal32           *decimal,
                               const unsigned char *buffer);
    static void decimalFromDPD(Decimal64           *decimal,
                               const unsigned char *buffer);
    static void decimalFromDPD(Decimal128          *decimal,
                               const unsigned char *buffer);

                        // decimalToBID functions

    static void decimal32ToBID( unsigned char *buffer,
                                Decimal32      decimal);
    static void decimal64ToBID( unsigned char *buffer,
                                Decimal64      decimal);
    static void decimal128ToBID(unsigned char *buffer,
                                Decimal128     decimal);

    /// Populate the specified `buffer` with the Binary Integer Decimal
    /// (BID) representation of the specified `decimal` value.  The BID
    /// representations of `Decimal32`, `Decimal64`, and `Decimal128`
    /// require 4, 8, and 16 bytes respectively.  The behavior is undefined
    /// unless `buffer` points to a contiguous sequence of at least
    /// `sizeof(decimal)` bytes.  Note that the BID representation is
    /// defined in section 3.5 of IEEE 754-2008.
    static void decimalToBID(   unsigned char *buffer,
                                Decimal32      decimal);
    static void decimalToBID(   unsigned char *buffer,
                                Decimal64      decimal);
    static void decimalToBID(   unsigned char *buffer,
                                Decimal128     decimal);

                        // decimalFromBID functions

    static Decimal32  decimal32FromBID( const unsigned char *buffer);
    static Decimal64  decimal64FromBID( const unsigned char *buffer);

    /// Return the native implementation representation of the value of the
    /// same size base-10 floating-point value stored in Binary Integer
    /// Decimal format at the specified `buffer` address.  The behavior is
    /// undefined unless `buffer` points to a memory area at least
    /// `sizeof(decimal)` in size containing a value in BID format.
    static Decimal128 decimal128FromBID(const unsigned char *buffer);

    /// Store, into the specified `decimal`, the native implementation
    /// representation of the value of the same size base-10 floating point
    /// value represented in Binary Integer Decimal format, at the specified
    /// `buffer` address.  The behavior is undefined unless `buffer` points
    /// to a memory area at least `sizeof(decimal)` in size containing a
    /// value in BID format.
    static void decimalFromBID(Decimal32           *decimal,
                               const unsigned char *buffer);
    static void decimalFromBID(Decimal64           *decimal,
                               const unsigned char *buffer);
    static void decimalFromBID(Decimal128          *decimal,
                               const unsigned char *buffer);
};

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================

                        // decimalToDouble functions

inline
double
DecimalConvertUtil_IntelDfp::decimal32ToDouble(Decimal32 decimal)
{
    return decimalToDouble(decimal);
}

inline
double
DecimalConvertUtil_IntelDfp::decimal64ToDouble(Decimal64 decimal)
{
    return decimalToDouble(decimal);
}

inline
double
DecimalConvertUtil_IntelDfp::decimal128ToDouble(Decimal128 decimal)
{
    return decimalToDouble(decimal);
}

inline
double
DecimalConvertUtil_IntelDfp::decimalToDouble(Decimal32 decimal)
{
    _IDEC_flags flags;
    return __bid32_to_binary64(decimal.data()->d_raw, &flags);
}

inline
double
DecimalConvertUtil_IntelDfp::decimalToDouble(Decimal64 decimal)
{
    _IDEC_flags flags;
    return __bid64_to_binary64(decimal.data()->d_raw, &flags);
}

inline
double
DecimalConvertUtil_IntelDfp::decimalToDouble(Decimal128 decimal)
{
    _IDEC_flags flags;
    return __bid128_to_binary64(decimal.data()->d_raw, &flags);
}

                        // decimalToFloat functions

inline
float
DecimalConvertUtil_IntelDfp::decimal32ToFloat(Decimal32 decimal)
{
    return decimalToFloat(decimal);
}

inline float
DecimalConvertUtil_IntelDfp::decimal64ToFloat(Decimal64 decimal)
{
    return decimalToFloat(decimal);
}

inline float
DecimalConvertUtil_IntelDfp::decimal128ToFloat(Decimal128 decimal)
{
    return decimalToFloat(decimal);
}

inline
float
DecimalConvertUtil_IntelDfp::decimalToFloat(Decimal32 decimal)
{
    _IDEC_flags flags;
    return __bid32_to_binary32(decimal.data()->d_raw, &flags);
}

inline
float
DecimalConvertUtil_IntelDfp::decimalToFloat(Decimal64 decimal)
{
    _IDEC_flags flags;
    return __bid64_to_binary32(decimal.data()->d_raw, &flags);
}

inline
float
DecimalConvertUtil_IntelDfp::decimalToFloat(Decimal128 decimal)
{
    _IDEC_flags flags;
    return __bid128_to_binary32(decimal.data()->d_raw, &flags);
}

                        // decimalToDPD functions

inline
void DecimalConvertUtil_IntelDfp::decimal32ToDPD(unsigned char *buffer,
                                                 Decimal32      decimal)
{
    decimalToDPD(buffer, decimal);
}

inline
void DecimalConvertUtil_IntelDfp::decimal64ToDPD(unsigned char *buffer,
                                                 Decimal64      decimal)
{
    decimalToDPD(buffer, decimal);
}

inline
void DecimalConvertUtil_IntelDfp::decimal128ToDPD(unsigned char *buffer,
                                                  Decimal128     decimal)
{
    decimalToDPD(buffer, decimal);
}

inline
void DecimalConvertUtil_IntelDfp::decimalToDPD(unsigned char *buffer,
                                               Decimal32      decimal)
{
    decimal.data()->d_raw = __bid_to_dpd32(decimal.data()->d_raw);
    bsl::memcpy(buffer, &decimal, sizeof(decimal));
}

inline
void DecimalConvertUtil_IntelDfp::decimalToDPD(unsigned char *buffer,
                                               Decimal64      decimal)
{
    decimal.data()->d_raw = __bid_to_dpd64(decimal.data()->d_raw);
    bsl::memcpy(buffer, &decimal, sizeof(decimal));
}

inline
void DecimalConvertUtil_IntelDfp::decimalToDPD(unsigned char *buffer,
                                               Decimal128     decimal)
{
    decimal.data()->d_raw = __bid_to_dpd128(decimal.data()->d_raw);
    bsl::memcpy(buffer, &decimal, sizeof(decimal));
}

                       // decimalFromDPD functions

inline
Decimal32 DecimalConvertUtil_IntelDfp::decimal32FromDPD(
                                                   const unsigned char *buffer)
{
    BSLS_ASSERT(buffer);

    DecimalImpUtil::ValueType32 value;
    bsl::memcpy(&value, buffer, sizeof(value));
    value.d_raw = __bid_dpd_to_bid32(value.d_raw);

    return Decimal32(value);
}

inline
Decimal64 DecimalConvertUtil_IntelDfp::decimal64FromDPD(
                                                   const unsigned char *buffer)
{
    BSLS_ASSERT(buffer);

    DecimalImpUtil::ValueType64 value;
    bsl::memcpy(&value, buffer, sizeof(value));
    value.d_raw = __bid_dpd_to_bid64(value.d_raw);

    return Decimal64(value);
}

inline
Decimal128 DecimalConvertUtil_IntelDfp::decimal128FromDPD(
                                                   const unsigned char *buffer)
{
    BSLS_ASSERT(buffer);

    DecimalImpUtil::ValueType128 value;
    bsl::memcpy(&value, buffer, sizeof(value));
    value.d_raw = __bid_dpd_to_bid128(value.d_raw);

    return Decimal128(value);
}

inline
void DecimalConvertUtil_IntelDfp::decimalFromDPD(Decimal32           *decimal,
                                                 const unsigned char *buffer)
{
    BSLS_ASSERT(decimal);
    BSLS_ASSERT(buffer);

    *decimal = decimal32FromDPD(buffer);
}

inline
void DecimalConvertUtil_IntelDfp::decimalFromDPD(Decimal64           *decimal,
                                                 const unsigned char *buffer)
{
    BSLS_ASSERT(decimal);
    BSLS_ASSERT(buffer);

    *decimal = decimal64FromDPD(buffer);
}

inline
void DecimalConvertUtil_IntelDfp::decimalFromDPD(Decimal128          *decimal,
                                                 const unsigned char *buffer)
{
    BSLS_ASSERT(decimal);
    BSLS_ASSERT(buffer);

    *decimal = decimal128FromDPD(buffer);
}

                        // decimalToBID functions

inline
void
DecimalConvertUtil_IntelDfp::decimal32ToBID(unsigned char *buffer,
                                            Decimal32      decimal)
{
    decimalToBID(buffer, decimal);
}

inline
void
DecimalConvertUtil_IntelDfp::decimal64ToBID(unsigned char *buffer,
                                            Decimal64      decimal)
{
    decimalToBID(buffer, decimal);
}

inline
void DecimalConvertUtil_IntelDfp::decimal128ToBID(unsigned char *buffer,
                                                  Decimal128     decimal)
{
    decimalToBID(buffer, decimal);
}

inline
void DecimalConvertUtil_IntelDfp::decimalToBID(unsigned char *buffer,
                                               Decimal32      decimal)
{
    bsl::memcpy(buffer, &decimal, sizeof(decimal));
}

inline
void DecimalConvertUtil_IntelDfp::decimalToBID(unsigned char *buffer,
                                               Decimal64      decimal)
{
    bsl::memcpy(buffer, &decimal, sizeof(decimal));
}

inline
void DecimalConvertUtil_IntelDfp::decimalToBID(unsigned char *buffer,
                                               Decimal128     decimal)
{
    bsl::memcpy(buffer, &decimal, sizeof(decimal));
}

                          // decimalFromBID functions

inline
Decimal32 DecimalConvertUtil_IntelDfp::decimal32FromBID(
                                                   const unsigned char *buffer)
{
    BSLS_ASSERT(buffer);

    DecimalImpUtil::ValueType32 value;
    bsl::memcpy(&value, buffer, sizeof(value));

    return Decimal32(value);
}

inline
Decimal64 DecimalConvertUtil_IntelDfp::decimal64FromBID(
                                                   const unsigned char *buffer)
{
    BSLS_ASSERT(buffer);

    DecimalImpUtil::ValueType64 value;
    bsl::memcpy(&value, buffer, sizeof(value));

    return Decimal64(value);
}

inline
Decimal128 DecimalConvertUtil_IntelDfp::decimal128FromBID(
                                                   const unsigned char *buffer)
{
    BSLS_ASSERT(buffer);

    DecimalImpUtil::ValueType128 value;
    bsl::memcpy(&value, buffer, sizeof(value));

    return Decimal128(value);
}

inline
void DecimalConvertUtil_IntelDfp::decimalFromBID(Decimal32           *decimal,
                                                 const unsigned char *buffer)
{
    BSLS_ASSERT(decimal);
    BSLS_ASSERT(buffer);

    *decimal = decimal32FromBID(buffer);
}

inline
void DecimalConvertUtil_IntelDfp::decimalFromBID(Decimal64           *decimal,
                                                 const unsigned char *buffer)
{
    BSLS_ASSERT(decimal);
    BSLS_ASSERT(buffer);

    *decimal = decimal64FromBID(buffer);
}

inline
void DecimalConvertUtil_IntelDfp::decimalFromBID(Decimal128          *decimal,
                                                 const unsigned char *buffer)
{
    BSLS_ASSERT(decimal);
    BSLS_ASSERT(buffer);

    *decimal = decimal128FromBID(buffer);
}

}  // close package namespace
}  // close enterprise namespace

#endif

#endif

// ----------------------------------------------------------------------------
// Copyright 2014 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
