// bslx_marshallingutil.h                                             -*-C++-*-
#ifndef INCLUDED_BSLX_MARSHALLINGUTIL
#define INCLUDED_BSLX_MARSHALLINGUTIL

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

//@PURPOSE: Support platform-independent marshalling of fundamental types.
//
//@CLASSES:
//   bslx::MarshallingUtil: namespace for put/get marshalling functions
//
//@SEE_ALSO: bslx_byteinstream, bslx_byteoutstream
//
//@DESCRIPTION: This component provides a byte-array-based implementation,
// `bslx::MarshallingUtil`, for a suite of marshalling functions used to
// convert values (and arrays of values) of the following fundamental integer
// and floating-point types:
// ```
//     C++ TYPE          REQUIRED CONTENT OF ANY PLATFORM-NEUTRAL FORMAT
//     --------          -----------------------------------------------
//     Int64             least significant 64 bits (signed)
//     Uint64            least significant 64 bits (unsigned)
//     int               least significant 32 bits (signed)
//     unsigned int      least significant 32 bits (unsigned)
//     short             least significant 16 bits (signed)
//     unsigned short    least significant 16 bits (unsigned)
//     char              least significant  8 bits (platform-dependent)
//     signed char       least significant  8 bits (signed)
//     unsigned char     least significant  8 bits (unsigned)
//     double            IEEE standard 8-byte floating-point value
//     float             IEEE standard 4-byte floating-point value
// ```
// In addition to basic marshalling functions, where each marshalled instance
// of a fundamental type occupies the same number of bytes in the stream
// (regardless of its value), this component provides an interface for
// efficient marshalling of integer types.  In particular, 64-bit values can be
// streamed as 40-, 48-, 56-, or 64-bit values, and 32-bit values can be
// streamed as 24- or 32-bit values.  Marshalled integers are written and
// assumed to be in two's complement, big-endian format (i.e., network byte
// order).  Floating-point formats are described below.
//
///Note on Function Naming and Interface
///-------------------------------------
// The names and interfaces of the functions of `bslx::MarshallingUtil` follow
// a systematic fashion explained below.  This makes it easier to guess the
// name and signature of the intended function.  In what follows, `buffer` is
// always of type `char *` or `const char *` depending on whether it is used as
// an input or an output, and `variable` and `value` are of a type that depends
// on the name of the function and intended width, with `variable` used as an
// output, while `value` is used as an input.
//
// Here are the `get...` functions for integral and floating-point scalar
// types:
// ```
//  Name                           Type of 'variable'           Notes
//  ----                           ------------------           -----
//  getIntNN(variable, buffer)     bsls::Types::Int64 *         NN=64,56,48,40
//                                 int *                        NN=32,24
//                                 short *                      NN=16
//                                 char *                       NN=8
//                                 signed char *                NN=8
//                                 unsigned char *              NN=8
//
//  getUintNN(variable, buffer)    bsls::Types::Uint64 *        NN=64,56,48,40
//                                 unsigned int *               NN=32,24
//                                 unsigned short *             NN=16
//
//  getFloatNN(variable, buffer)   double *                     NN=64
//                                 float *                      NN=32
// ```
// Here are the `put...` functions for scalar types.  Note that there is no
// `putUintNN` since `putIntNN` applies equally to unsigned `NN`-bit values
// (through a conversion to a signed value):
// ```
//  Name                           Type of 'value'              Notes
//  ----                           ---------------              -----
//  putIntNN(buffer, value)        bsls::Types::Int64           NN=64,56,48,40
//                                 int                          NN=32,24,16,8
//
//  putFloatNN(buffer, value)      double                       NN=64
//                                 float                        NN=32
// ```
// Here are the `getArray...` functions for integral and floating-point scalar
// array types:
// ```
//  Name                           Type of 'variables'          Notes
//  ----                           ----------------             -----
//  getArrayIntNN(variables,       bsls::Types::Int64 *         NN=64,56,48,40
//                buffer,          int *                        NN=32,24
//                numVariables)    short *                      NN=16
//                                 char *                       NN=8
//                                 signed char *                NN=8
//                                 unsigned char *              NN=8
//
//  getArrayUintNN(variables,      bsls::Types::Uint64 *        NN=64,56,48,40
//                 buffer,         unsigned int *               NN=32,24
//                 numVariables)   unsigned short *             NN=16
//
//  getArrayFloatNN(variables,     double *                     NN=64
//                  buffer,        float *                      NN=32
//                  numVariables)
// ```
// Finally, the `putArray...` functions follow.  Note that this time there is
// an overload for unsigned types, but that the function name is still
// `putArrayInt...` for arrays of both signed and unsigned integrals:
// ```
//  Name                           Type of 'values'             Notes
//  ----                           ---------------              -----
//  putArrayIntNN(buffer,          const bsls::Types::Int64 *   NN=64,56,48,40
//                values,          const bsls::Types::Uint64 *  NN=64,56,48,40
//                numValues)       const int *                  NN=32,24
//                                 const unsigned int *         NN=32,24
//                                 const short *                NN=16
//                                 const unsigned short *       NN=16
//                                 const char *                 NN=8
//                                 const signed char *          NN=8
//                                 const unsigned char *        NN=8
//
//  putArrayFloatNN(buffer,        const double *               NN=64
//                  values,        const float *                NN=32
//                  numValues)
// ```
//
///IEEE 754 Double-Precision Format
///--------------------------------
// A `double` is assumed to be *at* *least* 64 bits in size.  The externalized
// byte representation of a 64-bit floating-point value is defined to conform
// to the IEEE double-precision format illustrated below.  If the native
// representation of a 64-bit floating-point value does not match this format,
// a conversion process to and from this format is performed.  This conversion
// may (of course) be lossy:
// ```
// sign bit    11-bit exponent             52-bit significand
//   /        /                           /
// +-+-----------+----------------------------------------------------+
// |s|e10......e0|m51...............................................m0|
// +-+-----------+----------------------------------------------------+
// LSB                                                              MSB
// ```
//
///IEEE 754 Single-Precision Format
///--------------------------------
// A `float` is assumed to be *at* *least* 32 bits in size.  The externalized
// byte representation of a 32-bit floating-point value is defined to conform
// to the IEEE single-precision format illustrated below.  If the native
// representation of a 32-bit floating-point value does not match this format,
// a conversion process to and from this format is performed.  This conversion
// may (of course) be lossy:
// ```
// sign bit    8-bit exponent        23-bit significand
//    /       /                     /
//   +-+--------+-----------------------+
//   |s|e7....e0|m22..................m0|
//   +-+--------+-----------------------+
//   LSB                              MSB
// ```
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Round-Trip Marshalling
///- - - - - - - - - - - - - - - - -
// The `bslx::MarshallingUtil` component can be used stand-alone to marshal a
// platform-neutral representation of fundamental data and arrays of
// fundamental data to and from a buffer.  In this example, the round-trip
// marshalling of an `int` and an array of `int` values will be demonstrated.
// First, declare the buffer and the data to be marshalled:
// ```
// char buffer[32];
// int  value = 17;
// int  values[] = { 1, 2, 3 };
// ```
// Then, marshal all data into the `buffer`:
// ```
// bslx::MarshallingUtil::putInt32(buffer + 0, value);
// bslx::MarshallingUtil::putArrayInt32(buffer + 4, values, 3);
// ```
// Next, declare variables to hold the values to be extracted from the
// `buffer`:
// ```
// int newValue = 0;
// int newValues[] = { 0, 0, 0 };
// ```
// Finally, marshal the data from the `buffer` to these variables and confirm
// the round-trip marshalling was successful:
// ```
// bslx::MarshallingUtil::getInt32(&newValue, buffer + 0);
// bslx::MarshallingUtil::getArrayInt32(newValues, buffer + 4, 3);
//
// assert(newValue     == value);
// assert(newValues[0] == values[0]);
// assert(newValues[1] == values[1]);
// assert(newValues[2] == values[2]);
// ```

#include <bslscm_version.h>

#include <bsls_assert.h>
#include <bsls_platform.h>
#include <bsls_types.h>

#include <bsl_cstring.h>           // for 'bsl::memcpy'

namespace BloombergLP {
namespace bslx {

                         // ======================
                         // struct MarshallingUtil
                         // ======================

/// This `struct` provides a namespace for a suite of functions that
/// facilitate the marshalling of values, and C-style arrays of values, of
/// the fundamental integral and floating-point types in a data-independent,
/// platform-neutral representation.
struct MarshallingUtil {

    // TYPES

    enum {
        // Enumerate the platform-independent sizes (in bytes) of data types in
        // wire format.  Note that the wire format size may differ from the
        // size in memory.

        k_SIZEOF_INT64   = 8,
        k_SIZEOF_INT56   = 7,
        k_SIZEOF_INT48   = 6,
        k_SIZEOF_INT40   = 5,
        k_SIZEOF_INT32   = 4,
        k_SIZEOF_INT24   = 3,
        k_SIZEOF_INT16   = 2,
        k_SIZEOF_INT8    = 1,
        k_SIZEOF_FLOAT64 = 8,
        k_SIZEOF_FLOAT32 = 4
    };

    // CLASS METHODS

                        // *** put scalar integral values ***

    /// Load into the specified `buffer` the eight-byte, two's complement
    /// integer (in network byte order) comprised of the least-significant
    /// eight bytes of the specified `value` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity.  Note
    /// that this function applies equally to unsigned 64-bit values.
    static void putInt64(char *buffer, bsls::Types::Int64 value);

    /// Load into the specified `buffer` the seven-byte, two's complement
    /// integer (in network byte order) comprised of the least-significant
    /// seven bytes of the specified `value` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity.  Note
    /// that this function applies equally to unsigned 64-bit values.
    static void putInt56(char *buffer, bsls::Types::Int64 value);

    /// Load into the specified `buffer` the six-byte, two's complement
    /// integer (in network byte order) comprised of the least-significant
    /// six bytes of the specified `value` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity.  Note
    /// that this function applies equally to unsigned 64-bit values.
    static void putInt48(char *buffer, bsls::Types::Int64 value);

    /// Load into the specified `buffer` the five-byte, two's complement
    /// integer (in network byte order) comprised of the least-significant
    /// five bytes of the specified `value` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity.  Note
    /// that this function applies equally to unsigned 64-bit values.
    static void putInt40(char *buffer, bsls::Types::Int64 value);

    /// Load into the specified `buffer` the four-byte, two's complement
    /// integer (in network byte order) comprised of the least-significant
    /// four bytes of the specified `value` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity.  Note
    /// that this function applies equally to unsigned 32-bit values, and
    /// signed and unsigned 16- and 8-bit values.
    static void putInt32(char *buffer, int value);

    /// Load into the specified `buffer` the three-byte, two's complement
    /// integer (in network byte order) comprised of the least-significant
    /// three bytes of the specified `value` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity.  Note
    /// that this function applies equally to unsigned 32-bit values, and
    /// signed and unsigned 16- and 8-bit values.
    static void putInt24(char *buffer, int value);

    /// Load into the specified `buffer` the two-byte, two's complement
    /// integer (in network byte order) comprised of the least-significant
    /// two bytes of the specified `value` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity.  Note
    /// that this function applies equally to unsigned 32-bit values, and
    /// signed and unsigned 16- and 8-bit values.
    static void putInt16(char *buffer, int value);

    /// Load into the specified `buffer` the one-byte, two's complement
    /// integer comprised of the least-significant one byte of the specified
    /// `value`.  The behavior is undefined unless `buffer` has sufficient
    /// capacity.  Note that this function applies equally to unsigned
    /// 32-bit values, and signed and unsigned 16- and 8-bit values.
    static void putInt8(char *buffer, int value);

                        // *** put scalar floating-point values ***

    /// Load into the specified `buffer` the eight-byte IEEE
    /// double-precision floating-point number (in network byte order)
    /// comprised of the most-significant eight bytes of the specified
    /// `value` (in host byte order).  The behavior is undefined unless
    /// `buffer` has sufficient capacity.  Note that for non-conforming
    /// platforms, this operation may be lossy.
    static void putFloat64(char *buffer, double value);

    /// Load into the specified `buffer` the four-byte IEEE single-precision
    /// floating-point number (in network byte order) comprised of the
    /// most-significant four bytes of the specified `value` (in host byte
    /// order).  The behavior is undefined unless `buffer` has sufficient
    /// capacity.  Note that for non-conforming platforms, this operation
    /// may be lossy.
    static void putFloat32(char *buffer, float value);

                        // *** get scalar integral values ***

    /// Load into the specified `variable` the eight-byte, two's complement
    /// integer (in host byte order) comprised of the initial eight bytes of
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `buffer` has sufficient contents.  Note that the
    /// value will be sign-extended.
    static void getInt64(bsls::Types::Int64 *variable,
                         const char         *buffer);

    /// Load into the specified `variable` the eight-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the initial eight
    /// bytes of the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `buffer` has sufficient contents.  Note
    /// that the value will be zero-extended.
    static void getUint64(bsls::Types::Uint64 *variable,
                          const char          *buffer);

    /// Load into the specified `variable` the seven-byte, two's complement
    /// integer (in host byte order) comprised of the initial seven bytes of
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `buffer` has sufficient contents.  Note that the
    /// value will be sign-extended.
    static void getInt56(bsls::Types::Int64 *variable,
                         const char         *buffer);

    /// Load into the specified `variable` the seven-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the initial seven
    /// bytes of the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `buffer` has sufficient contents.  Note
    /// that the value will be zero-extended.
    static void getUint56(bsls::Types::Uint64 *variable,
                          const char          *buffer);

    /// Load into the specified `variable` the six-byte, two's complement
    /// integer (in host byte order) comprised of the initial six bytes of
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `buffer` has sufficient contents.  Note that the
    /// value will be sign-extended.
    static void getInt48(bsls::Types::Int64 *variable,
                         const char         *buffer);

    /// Load into the specified `variable` the six-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the initial six
    /// bytes of the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `buffer` has sufficient contents.  Note
    /// that the value will be zero-extended.
    static void getUint48(bsls::Types::Uint64 *variable,
                          const char          *buffer);

    /// Load into the specified `variable` the five-byte, two's complement
    /// integer (in host byte order) comprised of the initial five bytes of
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `buffer` has sufficient contents.  Note that the
    /// value will be sign-extended.
    static void getInt40(bsls::Types::Int64 *variable,
                         const char         *buffer);

    /// Load into the specified `variable` the five-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the initial five
    /// bytes of the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `buffer` has sufficient contents.  Note
    /// that the value will be zero-extended.
    static void getUint40(bsls::Types::Uint64 *variable,
                          const char          *buffer);

    /// Load into the specified `variable` the four-byte, two's complement
    /// integer (in host byte order) comprised of the initial four bytes of
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `buffer` has sufficient contents.  Note that the
    /// value will be sign-extended.
    static void getInt32(int *variable, const char *buffer);

    /// Load into the specified `variable` the four-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the initial four
    /// bytes of the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `buffer` has sufficient contents.  Note
    /// that the value will be zero-extended.
    static void getUint32(unsigned int *variable, const char *buffer);

    /// Load into the specified `variable` the three-byte, two's complement
    /// integer (in host byte order) comprised of the initial three bytes of
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `buffer` has sufficient contents.  Note that the
    /// value will be sign-extended.
    static void getInt24(int *variable, const char *buffer);

    /// Load into the specified `variable` the three-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the initial three
    /// bytes of the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `buffer` has sufficient contents.  Note
    /// that the value will be zero-extended.
    static void getUint24(unsigned int *variable, const char *buffer);

    /// Load into the specified `variable` the two-byte, two's complement
    /// integer (in host byte order) comprised of the initial two bytes of
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `buffer` has sufficient contents.  Note that the
    /// value will be sign-extended.
    static void getInt16(short *variable, const char *buffer);

    /// Load into the specified `variable` the two-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the initial two
    /// bytes of the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `buffer` has sufficient contents.  Note
    /// that the value will be zero-extended.
    static void getUint16(unsigned short *variable, const char *buffer);

    /// Load into the specified `variable` the one-byte, two's complement
    /// integer comprised of the initial one byte of the specified `buffer`.
    /// The behavior is undefined unless `buffer` has sufficient contents.
    static void getInt8(char          *variable, const char *buffer);
    static void getInt8(signed char   *variable, const char *buffer);
    static void getInt8(unsigned char *variable, const char *buffer);

                        // *** get scalar floating-point values ***

    /// Load into the specified `variable` the eight-byte IEEE
    /// double-precision floating-point number (in host byte order)
    /// comprised of the initial eight bytes of the specified `buffer` (in
    /// network byte order).  The behavior is undefined unless `buffer` has
    /// sufficient contents.
    static void getFloat64(double *variable, const char *buffer);

    /// Load into the specified `variable` the four-byte IEEE
    /// single-precision floating-point number (in host byte order)
    /// comprised of the initial four bytes of the specified `buffer` (in
    /// network byte order).  The behavior is undefined unless `buffer` has
    /// sufficient contents.
    static void getFloat32(float *variable, const char *buffer);

                        // *** put arrays of integral values ***

    /// Load into the specified `buffer` the consecutive eight-byte, two's
    /// complement integers (in network byte order) comprised of the
    /// least-significant eight bytes of each of the specified `numValues`
    /// leading entries in the specified `values` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt64(char                      *buffer,
                              const bsls::Types::Int64  *values,
                              int                        numValues);
    static void putArrayInt64(char                      *buffer,
                              const bsls::Types::Uint64 *values,
                              int                        numValues);

    /// Load into the specified `buffer` the consecutive seven-byte, two's
    /// complement integers (in network byte order) comprised of the
    /// least-significant seven bytes of each of the specified `numValues`
    /// leading entries in the specified `values` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt56(char                      *buffer,
                              const bsls::Types::Int64  *values,
                              int                        numValues);
    static void putArrayInt56(char                      *buffer,
                              const bsls::Types::Uint64 *values,
                              int                        numValues);

    /// Load into the specified `buffer` the consecutive six-byte, two's
    /// complement integers (in network byte order) comprised of the
    /// least-significant six bytes of each of the specified `numValues`
    /// leading entries in the specified `values` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt48(char                      *buffer,
                              const bsls::Types::Int64  *values,
                              int                        numValues);
    static void putArrayInt48(char                      *buffer,
                              const bsls::Types::Uint64 *values,
                              int                        numValues);

    /// Load into the specified `buffer` the consecutive five-byte, two's
    /// complement integers (in network byte order) comprised of the
    /// least-significant five bytes of each of the specified `numValues`
    /// leading entries in the specified `values` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt40(char                      *buffer,
                              const bsls::Types::Int64  *values,
                              int                        numValues);
    static void putArrayInt40(char                      *buffer,
                              const bsls::Types::Uint64 *values,
                              int                        numValues);

    /// Load into the specified `buffer` the consecutive four-byte, two's
    /// complement integers (in network byte order) comprised of the
    /// least-significant four bytes of each of the specified `numValues`
    /// leading entries in the specified `values` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt32(char               *buffer,
                              const int          *values,
                              int                 numValues);
    static void putArrayInt32(char               *buffer,
                              const unsigned int *values,
                              int                 numValues);

    /// Load into the specified `buffer` the consecutive three-byte, two's
    /// complement integers (in network byte order) comprised of the
    /// least-significant three bytes of each of the specified `numValues`
    /// leading entries in the specified `values` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt24(char               *buffer,
                              const int          *values,
                              int                 numValues);
    static void putArrayInt24(char               *buffer,
                              const unsigned int *values,
                              int                 numValues);

    /// Load into the specified `buffer` the consecutive two-byte, two's
    /// complement integers (in network byte order) comprised of the
    /// least-significant two bytes of each of the specified `numValues`
    /// leading entries in the specified `values` (in host byte order).  The
    /// behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt16(char                 *buffer,
                              const short          *values,
                              int                   numValues);
    static void putArrayInt16(char                 *buffer,
                              const unsigned short *values,
                              int                   numValues);

    /// Load into the specified `buffer` the consecutive one-byte, two's
    /// complement integers comprised of the one byte of each of the
    /// specified `numValues` leading entries in the specified `values`.
    /// The behavior is undefined unless `buffer` has sufficient capacity,
    /// `values` has sufficient contents, and `0 <= numValues`.
    static void putArrayInt8(char                *buffer,
                             const char          *values,
                             int                  numValues);
    static void putArrayInt8(char                *buffer,
                             const signed char   *values,
                             int                  numValues);
    static void putArrayInt8(char                *buffer,
                             const unsigned char *values,
                             int                  numValues);

                        // *** put arrays of floating-point values ***

    /// Load into the specified `buffer` the consecutive eight-byte IEEE
    /// double-precision floating-point numbers (in network byte order)
    /// comprised of the most-significant eight bytes of each of the
    /// specified `numValues` leading entries in the specified `values` (in
    /// host byte order).  The behavior is undefined unless `buffer` has
    /// sufficient capacity, `values` has sufficient contents, and
    /// `0 <= numValues`.  Note that for non-conforming platforms, this
    /// operation may be lossy.
    static void putArrayFloat64(char         *buffer,
                                const double *values,
                                int           numValues);

    /// Load into the specified `buffer` the consecutive four-byte IEEE
    /// single-precision floating-point numbers (in network byte order)
    /// comprised of the most-significant four bytes of each of the
    /// specified `numValues` leading entries in the specified `values` (in
    /// host byte order).  The behavior is undefined unless `buffer` has
    /// sufficient capacity, `values` has sufficient contents, and
    /// `0 <= numValues`.  Note that for non-conforming platforms, this
    /// operation may be lossy.
    static void putArrayFloat32(char        *buffer,
                                const float *values,
                                int          numValues);

                        // *** get arrays of integral values ***

    /// Load into the specified `variables` the consecutive eight-byte,
    /// two's complement integers (in host byte order) comprised of each of
    /// the specified `numVariables` leading eight-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be sign-extended.
    static void getArrayInt64(bsls::Types::Int64 *variables,
                              const char         *buffer,
                              int                 numVariables);

    /// Load into the specified `variables` the consecutive eight-byte,
    /// two's complement unsigned integers (in host byte order) comprised of
    /// each of the specified `numVariables` leading eight-byte sequences in
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be zero-extended.
    static void getArrayUint64(bsls::Types::Uint64 *variables,
                               const char          *buffer,
                               int                  numVariables);

    /// Load into the specified `variables` the consecutive seven-byte,
    /// two's complement integers (in host byte order) comprised of each of
    /// the specified `numVariables` leading seven-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be sign-extended.
    static void getArrayInt56(bsls::Types::Int64 *variables,
                              const char         *buffer,
                              int                 numVariables);

    /// Load into the specified `variables` the consecutive seven-byte,
    /// two's complement unsigned integers (in host byte order) comprised of
    /// each of the specified `numVariables` leading seven-byte sequences in
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be zero-extended.
    static void getArrayUint56(bsls::Types::Uint64 *variables,
                               const char          *buffer,
                               int                  numVariables);

    /// Load into the specified `variables` the consecutive six-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` leading six-byte sequences in the specified
    /// `buffer` (in network byte order).  The behavior is undefined unless
    /// `variables` has sufficient capacity, `buffer` has sufficient
    /// contents, and `0 <= numVariables`.  Note that each of the values
    /// will be sign-extended.
    static void getArrayInt48(bsls::Types::Int64 *variables,
                              const char         *buffer,
                              int                 numVariables);

    /// Load into the specified `variables` the consecutive six-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` leading six-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be zero-extended.
    static void getArrayUint48(bsls::Types::Uint64 *variables,
                               const char          *buffer,
                               int                  numVariables);

    /// Load into the specified `variables` the consecutive five-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` leading five-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be sign-extended.
    static void getArrayInt40(bsls::Types::Int64 *variables,
                              const char         *buffer,
                              int                 numVariables);

    /// Load into the specified `variables` the consecutive five-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` leading five-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be zero-extended.
    static void getArrayUint40(bsls::Types::Uint64 *variables,
                               const char          *buffer,
                               int                  numVariables);

    /// Load into the specified `variables` the consecutive four-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` leading four-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be sign-extended.
    static void getArrayInt32(int        *variables,
                              const char *buffer,
                              int         numVariables);

    /// Load into the specified `variables` the consecutive four-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` leading four-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be zero-extended.
    static void getArrayUint32(unsigned int *variables,
                               const char   *buffer,
                               int           numVariables);

    /// Load into the specified `variables` the consecutive three-byte,
    /// two's complement integers (in host byte order) comprised of each of
    /// the specified `numVariables` leading three-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be sign-extended.
    static void getArrayInt24(int        *variables,
                              const char *buffer,
                              int         numVariables);

    /// Load into the specified `variables` the consecutive three-byte,
    /// two's complement unsigned integers (in host byte order) comprised of
    /// each of the specified `numVariables` leading three-byte sequences in
    /// the specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be zero-extended.
    static void getArrayUint24(unsigned int *variables,
                               const char   *buffer,
                               int           numVariables);

    /// Load into the specified `variables` the consecutive two-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` leading two-byte sequences in the specified
    /// `buffer` (in network byte order).  The behavior is undefined unless
    /// `variables` has sufficient capacity, `buffer` has sufficient
    /// contents, and `0 <= numVariables`.  Note that each of the values
    /// will be sign-extended.
    static void getArrayInt16(short      *variables,
                              const char *buffer,
                              int         numVariables);

    /// Load into the specified `variables` the consecutive two-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` leading two-byte sequences in the
    /// specified `buffer` (in network byte order).  The behavior is
    /// undefined unless `variables` has sufficient capacity, `buffer` has
    /// sufficient contents, and `0 <= numVariables`.  Note that each of the
    /// values will be zero-extended.
    static void getArrayUint16(unsigned short *variables,
                               const char     *buffer,
                               int             numVariables);

    /// Load into the specified `variables` the consecutive one-byte, two's
    /// complement integers comprised of each of the specified
    /// `numVariables` leading one-byte sequences in the specified `buffer`.
    /// The behavior is undefined unless `variables` has sufficient
    /// capacity, `buffer` has sufficient contents, and `0 <= numVariables`.
    static void getArrayInt8(char          *variables,
                             const char    *buffer,
                             int            numVariables);
    static void getArrayInt8(signed char   *variables,
                             const char    *buffer,
                             int            numVariables);
    static void getArrayInt8(unsigned char *variables,
                             const char    *buffer,
                             int            numVariables);

                        // *** get arrays of floating-point values ***

    /// Load into the specified `variables` the consecutive eight-byte IEEE
    /// double-precision floating-point numbers (in host byte order)
    /// comprised of each of the specified `numVariables` leading eight-byte
    /// sequences in the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `variables` has sufficient capacity,
    /// `buffer` has sufficient contents, and `0 <= numVariables`.
    static void getArrayFloat64(double     *variables,
                                const char *buffer,
                                int         numVariables);

    /// Load into the specified `variables` the consecutive four-byte IEEE
    /// single-precision floating-point numbers (in host byte order)
    /// comprised of each of the specified `numVariables` leading four-byte
    /// sequences in the specified `buffer` (in network byte order).  The
    /// behavior is undefined unless `variables` has sufficient capacity,
    /// `buffer` has sufficient contents, and `0 <= numVariables`.
    static void getArrayFloat32(float      *variables,
                                const char *buffer,
                                int         numVariables);

};

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

                         // ----------------------
                         // struct MarshallingUtil
                         // ----------------------

// CLASS METHODS

                        // *** put scalar integral values ***

inline
void MarshallingUtil::putInt64(char *buffer, bsls::Types::Int64 value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[7];
    buffer[1] = bytes[6];
    buffer[2] = bytes[5];
    buffer[3] = bytes[4];
    buffer[4] = bytes[3];
    buffer[5] = bytes[2];
    buffer[6] = bytes[1];
    buffer[7] = bytes[0];
#else
    bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT64, k_SIZEOF_INT64);
#endif
}

inline
void MarshallingUtil::putInt56(char *buffer, bsls::Types::Int64 value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[6];
    buffer[1] = bytes[5];
    buffer[2] = bytes[4];
    buffer[3] = bytes[3];
    buffer[4] = bytes[2];
    buffer[5] = bytes[1];
    buffer[6] = bytes[0];
#else
    bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT56, k_SIZEOF_INT56);
#endif
}

inline
void MarshallingUtil::putInt48(char *buffer, bsls::Types::Int64 value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[5];
    buffer[1] = bytes[4];
    buffer[2] = bytes[3];
    buffer[3] = bytes[2];
    buffer[4] = bytes[1];
    buffer[5] = bytes[0];
#else
    bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT48, k_SIZEOF_INT48);
#endif
}

inline
void MarshallingUtil::putInt40(char *buffer, bsls::Types::Int64 value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[4];
    buffer[1] = bytes[3];
    buffer[2] = bytes[2];
    buffer[3] = bytes[1];
    buffer[4] = bytes[0];
#else
    bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT40, k_SIZEOF_INT40);
#endif
}

inline
void MarshallingUtil::putInt32(char *buffer, int value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[3];
    buffer[1] = bytes[2];
    buffer[2] = bytes[1];
    buffer[3] = bytes[0];
#else
    bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT32, k_SIZEOF_INT32);
#endif
}

inline
void MarshallingUtil::putInt24(char *buffer, int value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[2];
    buffer[1] = bytes[1];
    buffer[2] = bytes[0];
#else
    bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT24, k_SIZEOF_INT24);
#endif
}

inline
void MarshallingUtil::putInt16(char *buffer, int value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[1];
    buffer[1] = bytes[0];
#else
    bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT16, k_SIZEOF_INT16);
#endif
}

inline
void MarshallingUtil::putInt8(char *buffer, int value)
{
    BSLS_ASSERT_SAFE(buffer);

    *buffer = static_cast<char>(value);
}

                        // *** put scalar floating-point values ***

inline
void MarshallingUtil::putFloat64(char *buffer, double value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[sizeof value - 1];
    buffer[1] = bytes[sizeof value - 2];
    buffer[2] = bytes[sizeof value - 3];
    buffer[3] = bytes[sizeof value - 4];
    buffer[4] = bytes[sizeof value - 5];
    buffer[5] = bytes[sizeof value - 6];
    buffer[6] = bytes[sizeof value - 7];
    buffer[7] = bytes[sizeof value - 8];
#else
    bsl::memcpy(buffer, bytes, k_SIZEOF_FLOAT64);
#endif
}

inline
void MarshallingUtil::putFloat32(char *buffer, float value)
{
    BSLS_ASSERT_SAFE(buffer);

    const char *bytes = reinterpret_cast<char *>(&value);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    buffer[0] = bytes[sizeof value - 1];
    buffer[1] = bytes[sizeof value - 2];
    buffer[2] = bytes[sizeof value - 3];
    buffer[3] = bytes[sizeof value - 4];
#else
    bsl::memcpy(buffer, bytes, k_SIZEOF_FLOAT32);
#endif
}

                        // *** get scalar integral values ***

inline
void MarshallingUtil::getInt64(bsls::Types::Int64 *variable,
                               const char         *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_INT64) {
        *variable = 0x80 & buffer[0] ? -1 : 0;  // sign extend
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[7] = buffer[0];
    bytes[6] = buffer[1];
    bytes[5] = buffer[2];
    bytes[4] = buffer[3];
    bytes[3] = buffer[4];
    bytes[2] = buffer[5];
    bytes[1] = buffer[6];
    bytes[0] = buffer[7];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT64,
                buffer,
                k_SIZEOF_INT64);
#endif
}

inline
void MarshallingUtil::getUint64(bsls::Types::Uint64 *variable,
                                const char          *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_INT64) {
        *variable = 0;  // zero-extend
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[7] = buffer[0];
    bytes[6] = buffer[1];
    bytes[5] = buffer[2];
    bytes[4] = buffer[3];
    bytes[3] = buffer[4];
    bytes[2] = buffer[5];
    bytes[1] = buffer[6];
    bytes[0] = buffer[7];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT64,
                buffer,
                k_SIZEOF_INT64);
#endif
}

inline
void MarshallingUtil::getInt56(bsls::Types::Int64 *variable,
                               const char         *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0x80 & buffer[0] ? -1 : 0;  // sign extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[6] = buffer[0];
    bytes[5] = buffer[1];
    bytes[4] = buffer[2];
    bytes[3] = buffer[3];
    bytes[2] = buffer[4];
    bytes[1] = buffer[5];
    bytes[0] = buffer[6];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT56,
                buffer,
                k_SIZEOF_INT56);
#endif
}

inline
void MarshallingUtil::getUint56(bsls::Types::Uint64 *variable,
                                const char          *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0;  // zero-extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[6] = buffer[0];
    bytes[5] = buffer[1];
    bytes[4] = buffer[2];
    bytes[3] = buffer[3];
    bytes[2] = buffer[4];
    bytes[1] = buffer[5];
    bytes[0] = buffer[6];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT56,
                buffer,
                k_SIZEOF_INT56);
#endif
}

inline
void MarshallingUtil::getInt48(bsls::Types::Int64 *variable,
                               const char         *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0x80 & buffer[0] ? -1 : 0;  // sign extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[5] = buffer[0];
    bytes[4] = buffer[1];
    bytes[3] = buffer[2];
    bytes[2] = buffer[3];
    bytes[1] = buffer[4];
    bytes[0] = buffer[5];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT48,
                buffer,
                k_SIZEOF_INT48);
#endif
}

inline
void MarshallingUtil::getUint48(bsls::Types::Uint64 *variable,
                                const char          *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0;  // zero-extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[5] = buffer[0];
    bytes[4] = buffer[1];
    bytes[3] = buffer[2];
    bytes[2] = buffer[3];
    bytes[1] = buffer[4];
    bytes[0] = buffer[5];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT48,
                buffer,
                k_SIZEOF_INT48);
#endif
}

inline
void MarshallingUtil::getInt40(bsls::Types::Int64 *variable,
                               const char         *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0x80 & buffer[0] ? -1 : 0;  // sign extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[4] = buffer[0];
    bytes[3] = buffer[1];
    bytes[2] = buffer[2];
    bytes[1] = buffer[3];
    bytes[0] = buffer[4];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT40,
                buffer,
                k_SIZEOF_INT40);
#endif
}

inline
void MarshallingUtil::getUint40(bsls::Types::Uint64 *variable,
                                const char          *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0;  // zero-extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[4] = buffer[0];
    bytes[3] = buffer[1];
    bytes[2] = buffer[2];
    bytes[1] = buffer[3];
    bytes[0] = buffer[4];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT40,
                buffer,
                k_SIZEOF_INT40);
#endif
}

inline
void MarshallingUtil::getInt32(int *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_INT32) {
        *variable = 0x80 & buffer[0] ? -1 : 0;  // sign extend
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[3] = buffer[0];
    bytes[2] = buffer[1];
    bytes[1] = buffer[2];
    bytes[0] = buffer[3];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT32,
                buffer,
                k_SIZEOF_INT32);
#endif
}

inline
void MarshallingUtil::getUint32(unsigned int *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_INT32) {
        *variable = 0;  // zero-extend
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[3] = buffer[0];
    bytes[2] = buffer[1];
    bytes[1] = buffer[2];
    bytes[0] = buffer[3];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT32,
                buffer,
                k_SIZEOF_INT32);
#endif
}

inline
void MarshallingUtil::getInt24(int *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0x80 & buffer[0] ? -1 : 0;  // sign extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[2] = buffer[0];
    bytes[1] = buffer[1];
    bytes[0] = buffer[2];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT24,
                buffer,
                k_SIZEOF_INT24);
#endif
}

inline
void MarshallingUtil::getUint24(unsigned int *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = 0;  // zero-extend

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[2] = buffer[0];
    bytes[1] = buffer[1];
    bytes[0] = buffer[2];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT24,
                buffer,
                k_SIZEOF_INT24);
#endif
}

inline
void MarshallingUtil::getInt16(short *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_INT16) {
        *variable = static_cast<short>(0x80 & buffer[0] ? -1 : 0);
                                                                 // sign extend
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[1] = buffer[0];
    bytes[0] = buffer[1];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT16,
                buffer,
                k_SIZEOF_INT16);
#endif
}

inline
void MarshallingUtil::getUint16(unsigned short *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_INT16) {
        *variable = 0;  // zero-extend
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[1] = buffer[0];
    bytes[0] = buffer[1];
#else
    bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT16,
                buffer,
                k_SIZEOF_INT16);
#endif
}

inline
void MarshallingUtil::getInt8(char *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    *variable = *buffer;
}

inline
void MarshallingUtil::getInt8(signed char *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    getInt8(reinterpret_cast<char *>(variable), buffer);
}

inline
void MarshallingUtil::getInt8(unsigned char *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    getInt8(reinterpret_cast<char *>(variable), buffer);
}

                        // *** get scalar floating-point values ***

inline
void MarshallingUtil::getFloat64(double *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_FLOAT64) {
        *variable = 0;  // zero-fill significand
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[sizeof *variable - 1] = buffer[0];
    bytes[sizeof *variable - 2] = buffer[1];
    bytes[sizeof *variable - 3] = buffer[2];
    bytes[sizeof *variable - 4] = buffer[3];
    bytes[sizeof *variable - 5] = buffer[4];
    bytes[sizeof *variable - 6] = buffer[5];
    bytes[sizeof *variable - 7] = buffer[6];
    bytes[sizeof *variable - 8] = buffer[7];
#else
    bsl::memcpy(bytes, buffer, k_SIZEOF_FLOAT64);
#endif
}

inline
void MarshallingUtil::getFloat32(float *variable, const char *buffer)
{
    BSLS_ASSERT_SAFE(variable);
    BSLS_ASSERT_SAFE(buffer);

    if (sizeof *variable > k_SIZEOF_FLOAT32) {
        *variable = 0;  // zero-fill significand
    }

    char *bytes = reinterpret_cast<char *>(variable);

#if BSLS_PLATFORM_IS_LITTLE_ENDIAN
    bytes[sizeof *variable - 1] = buffer[0];
    bytes[sizeof *variable - 2] = buffer[1];
    bytes[sizeof *variable - 3] = buffer[2];
    bytes[sizeof *variable - 4] = buffer[3];
#else
    bsl::memcpy(bytes, buffer, k_SIZEOF_FLOAT32);
#endif
}

                        // *** put arrays of integral values ***

inline
void MarshallingUtil::putArrayInt8(char       *buffer,
                                   const char *values,
                                   int         numValues)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(values);
    BSLS_ASSERT_SAFE(0 <= numValues);

    bsl::memcpy(buffer, values, numValues);
}

inline
void MarshallingUtil::putArrayInt8(char              *buffer,
                                   const signed char *values,
                                   int                numValues)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(values);
    BSLS_ASSERT_SAFE(0 <= numValues);

    putArrayInt8(buffer, reinterpret_cast<const char *>(values), numValues);
}

inline
void MarshallingUtil::putArrayInt8(char                *buffer,
                                   const unsigned char *values,
                                   int                  numValues)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(values);
    BSLS_ASSERT_SAFE(0 <= numValues);

    putArrayInt8(buffer, reinterpret_cast<const char *>(values), numValues);
}

                        // *** get arrays of integral values ***

inline
void MarshallingUtil::getArrayInt8(char       *variables,
                                   const char *buffer,
                                   int         numVariables)
{
    BSLS_ASSERT_SAFE(variables);
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= numVariables);

    bsl::memcpy(variables, buffer, numVariables);
}

inline
void MarshallingUtil::getArrayInt8(signed char *variables,
                                   const char  *buffer,
                                   int          numVariables)
{
    BSLS_ASSERT_SAFE(variables);
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= numVariables);

    getArrayInt8(reinterpret_cast<char *>(variables), buffer, numVariables);
}

inline
void MarshallingUtil::getArrayInt8(unsigned char *variables,
                                   const char    *buffer,
                                   int            numVariables)
{
    BSLS_ASSERT_SAFE(variables);
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= numVariables);

    getArrayInt8(reinterpret_cast<char *>(variables), buffer, numVariables);
}

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

#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 ----------------------------------
