// bslx_genericinstream.h                                             -*-C++-*-
#ifndef INCLUDED_BSLX_GENERICINSTREAM
#define INCLUDED_BSLX_GENERICINSTREAM

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

//@PURPOSE: Unexternalization of fundamental types from a parameterized stream.
//
//@CLASSES:
//  bslx::GenericInStream: parameterized input stream for fundamental types
//
//@SEE_ALSO: bslx_streambufinstream, bslx_genericoutstream
//
//@DESCRIPTION: This component implements a parameterized input stream
// class, `bslx::GenericInStream`, that provides platform-independent input
// methods ("unexternalization") on values, and arrays of values, of
// fundamental types, and on `bsl::string`.
//
// The `bslx::GenericInStream` type reads from a compliant user-supplied buffer
// (see [](#Generic Byte-Format Parser)) directly, with no data copying or
// assumption of ownership.  The user must therefore make sure that the
// lifetime and visibility of the buffer is sufficient to satisfy the needs of
// the input stream.
//
// This component is intended to be used in conjunction with the
// `bslx_genericoutstream` "externalization" component.  Each input method of
// `bslx::GenericInStream` reads either a value or a homogeneous array of
// values of a fundamental type, in a format that was written by the
// corresponding `bslx::GenericOutStream` method.  In general, the user of
// this component cannot rely on being able to read data that was written by
// any mechanism other than `bslx::GenericOutStream`.
//
// The supported types and required content are listed in the `bslx`
// package-level documentation under "Supported Types".
//
// Note that input streams can be *invalidated* explicitly and queried for
// *validity*.  Reading from an initially invalid stream has no effect.
// Attempting to read beyond the end of a stream will automatically invalidate
// the stream.  Whenever an inconsistent value is detected, the stream should
// be invalidated explicitly.
//
///Generic Byte-Format Parser
///--------------------------
// The class `bslx::GenericInStream` is parameterized by a buffered stream
// class, `STREAMBUF`, which, given the declarations:
// ```
// char        c;
// int         len;
// const char *s;
// STREAMBUF  *sb;
// ```
// must make the following expressions syntactically valid, with the assert
// statements highlighting the expected return values:
// ```
// STREAMBUF::traits_type::int_type eof = STREAMBUF::traits_type::eof();
// assert(eof != sb->sbumpc());
// assert(eof != sb->sgetc());
// assert(len == sb->sgetn(s, len));
// ```
// Suitable choices for `STREAMBUF` include any class that implements the
// `bsl::basic_streambuf` protocol.
//
// The class `bslx::StreambufInStream` is a `typedef` for
// `bslx::GenericInStream<bsl::streambuf>`.
//
///Usage
///-----
// This section illustrates intended use of this component.  The first example
// depicts usage with a `bsl::stringbuf`.  The second example replaces the
// `bsl::stringbuf` with a user-defined `STREAMBUF`.
//
///Example 1: Basic Unexternalization
/// - - - - - - - - - - - - - - - - -
// Suppose we wish to implement a (deliberately simple) `MyPerson` class as a
// value-semantic object that supports BDEX externalization and
// unexternalization.  In addition to whatever data and methods that we choose
// to put into our design, we must supply three methods having specific names
// and signatures in order to comply with the BDEX protocol: a class method
// `maxSupportedBdexVersion`, an accessor (i.e., a `const` method)
// `bdexStreamOut`, and a manipulator (i.e., a non-`const` method)
// `bdexStreamIn`.  This example shows how to implement those three methods.
//
// In this example we will not worry overly about "good design" of the
// `MyPerson` component, and we will declare but not implement illustrative
// methods and free operators, except for the three required BDEX methods,
// which are implemented in full.  In particular, we will not make explicit use
// of `bslma` allocators; a more complete design would do so:
//
// First, we implement `MyPerson`:
// ```
// class MyPerson {
//     bsl::string d_firstName;
//     bsl::string d_lastName;
//     int         d_age;
//
//     friend bool operator==(const MyPerson&, const MyPerson&);
//
//   public:
//     // CLASS METHODS
//
//     /// Return the maximum valid BDEX format version, as indicated by
//     /// the specified `versionSelector`, to be passed to the
//     /// `bdexStreamOut` method.  Note that it is highly recommended that
//     /// `versionSelector` be formatted as "YYYYMMDD", a date
//     /// representation.  Also note that `versionSelector` should be a
//     /// *compile*-time-chosen value that selects a format version
//     /// supported by both externalizer and unexternalizer.  See the
//     /// `bslx` package-level documentation for more information on BDEX
//     /// streaming of value-semantic types and containers.
//     static int maxSupportedBdexVersion(int versionSelector);
//
//     // CREATORS
//
//     /// Create a default person.
//     MyPerson();
//
//     /// Create a person having the specified `firstName`, `lastName`,
//     /// and `age`.
//     MyPerson(const char *firstName, const char *lastName, int age);
//
//     /// Create a person having the value of the specified `original`
//     /// person.
//     MyPerson(const MyPerson& original);
//
//     /// Destroy this object.
//     ~MyPerson();
//
//     // MANIPULATORS
//
//     /// Assign to this person the value of the specified `rhs` person,
//     /// and return a reference to this person.
//     MyPerson& operator=(const MyPerson& rhs);
//
//     /// Assign to this object the value read from the specified input
//     /// `stream` using the specified `version` format, and return a
//     /// reference to `stream`.  If `stream` is initially invalid, this
//     /// operation has no effect.  If `version` is not supported, this
//     /// object is unaltered and `stream` is invalidated, but otherwise
//     /// unmodified.  If `version` is supported but `stream` becomes
//     /// invalid during this operation, this object has an undefined, but
//     /// valid, state.  Note that no version is read from `stream`.  See
//     /// the `bslx` package-level documentation for more information on
//     /// BDEX streaming of value-semantic types and containers.
//     template <class STREAM>
//     STREAM& bdexStreamIn(STREAM& stream, int version);
//
//     //...
//
//     // ACCESSORS
//
//     /// Return the age of this person.
//     int age() const;
//
//     /// Write the value of this object, using the specified `version`
//     /// format, to the specified output `stream`, and return a reference
//     /// to `stream`.  If `stream` is initially invalid, this operation
//     /// has no effect.  If `version` is not supported, `stream` is
//     /// invalidated, but otherwise unmodified.  Note that `version` is
//     /// not written to `stream`.  See the `bslx` package-level
//     /// documentation for more information on BDEX streaming of
//     /// value-semantic types and containers.
//     template <class STREAM>
//     STREAM& bdexStreamOut(STREAM& stream, int version) const;
//
//     /// Return the first name of this person.
//     const bsl::string& firstName() const;
//
//     /// Return the last name of this person.
//     const bsl::string& lastName() const;
//
//     //...
//
// };
//
// // FREE OPERATORS
//
// /// Return `true` if the specified `lhs` and `rhs` person objects have
// /// the same value, and `false` otherwise.  Two person objects have the
// /// same value if they have the same first name, last name, and age.
// bool operator==(const MyPerson& lhs, const MyPerson& rhs);
//
// /// Return `true` if the specified `lhs` and `rhs` person objects do not
// /// have the same value, and `false` otherwise.  Two person objects
// /// differ in value if they differ in first name, last name, or age.
// bool operator!=(const MyPerson& lhs, const MyPerson& rhs);
//
// // ========================================================================
// //                  INLINE FUNCTION DEFINITIONS
// // ========================================================================
//
// // CLASS METHODS
// inline
// int MyPerson::maxSupportedBdexVersion(int /* versionSelector */) {
//     return 1;
// }
//
// // CREATORS
// inline
// MyPerson::MyPerson()
// : d_firstName("")
// , d_lastName("")
// , d_age(0)
// {
// }
//
// inline
// MyPerson::MyPerson(const char *firstName, const char *lastName, int age)
// : d_firstName(firstName)
// , d_lastName(lastName)
// , d_age(age)
// {
// }
//
// inline
// MyPerson::~MyPerson()
// {
// }
//
// template <class STREAM>
// STREAM& MyPerson::bdexStreamIn(STREAM& stream, int version)
// {
//     if (stream) {
//         switch (version) {  // switch on the 'bslx' version
//           case 1: {
//             stream.getString(d_firstName);
//             if (!stream) {
//                 d_firstName = "stream error";  // *might* be corrupted;
//                                                //  value for testing
//                 return stream;                                    // RETURN
//             }
//             stream.getString(d_lastName);
//             if (!stream) {
//                 d_lastName = "stream error";  // *might* be corrupted;
//                                               //  value for testing
//                 return stream;                                    // RETURN
//             }
//             stream.getInt32(d_age);
//             if (!stream) {
//                 d_age = 999;     // *might* be corrupted; value for testing
//                 return stream;                                    // RETURN
//             }
//           } break;
//           default: {
//             stream.invalidate();
//           }
//         }
//     }
//     return stream;
// }
//
// // ACCESSORS
// inline
// int MyPerson::age() const
// {
//     return d_age;
// }
//
// template <class STREAM>
// STREAM& MyPerson::bdexStreamOut(STREAM& stream, int version) const
// {
//     switch (version) {
//       case 1: {
//         stream.putString(d_firstName);
//         stream.putString(d_lastName);
//         stream.putInt32(d_age);
//       } break;
//       default: {
//         stream.invalidate();
//       } break;
//     }
//     return stream;
// }
//
// inline
// const bsl::string& MyPerson::firstName() const
// {
//     return d_firstName;
// }
//
// inline
// const bsl::string& MyPerson::lastName() const
// {
//     return d_lastName;
// }
//
// // FREE OPERATORS
// inline
// bool operator==(const MyPerson& lhs, const MyPerson& rhs)
// {
//     return lhs.d_firstName == rhs.d_firstName &&
//            lhs.d_lastName  == rhs.d_lastName  &&
//            lhs.d_age       == rhs.d_age;
// }
//
// inline
// bool operator!=(const MyPerson& lhs, const MyPerson& rhs)
// {
//     return !(lhs == rhs);
// }
// ```
// Then, we can exercise the new `MyPerson` value-semantic class by
// externalizing and reconstituting an object.  First, create a `MyPerson`
// `janeSmith1` and a `bslx::GenericOutStream` `outStream1`:
// ```
// MyPerson                               janeSmith1("Jane", "Smith", 42);
// bsl::stringbuf                         buffer1;
// bslx::GenericOutStream<bsl::stringbuf> outStream1(&buffer1, 20131127);
// const int                              VERSION1 = 1;
// outStream1.putVersion(VERSION1);
// janeSmith1.bdexStreamOut(outStream1, VERSION1);
// assert(outStream1.isValid());
// ```
// Next, create a `MyPerson` `janeCopy1` initialized to the default value, and
// assert that `janeCopy1` is different from `janeSmith1`:
// ```
// MyPerson janeCopy1;
// assert(janeCopy1 != janeSmith1);
// ```
// Then, create a `bslx::GenericInStream` `inStream1` initialized with the
// buffer from the `bslx::GenericOutStream` object `outStream1` and
// unexternalize this data into `janeCopy1`:
// ```
// bslx::GenericInStream<bsl::stringbuf> inStream1(&buffer1);
// int                                   version1;
// inStream1.getVersion(version1);
// janeCopy1.bdexStreamIn(inStream1, version1);
// assert(inStream1.isValid());
// ```
// Finally, `assert` the obtained values are as expected and display the
// results to `bsl::stdout`:
// ```
// assert(version1  == VERSION1);
// assert(janeCopy1 == janeSmith1);
//
// if (janeCopy1 == janeSmith1) {
//     bsl::cout << "Successfully serialized and de-serialized Jane Smith:"
//               << "\n\tFirstName: " << janeCopy1.firstName()
//               << "\n\tLastName : " << janeCopy1.lastName()
//               << "\n\tAge      : " << janeCopy1.age() << bsl::endl;
// }
// else {
//     bsl::cout << "Serialization unsuccessful.  'janeCopy1' holds:"
//               << "\n\tFirstName: " << janeCopy1.firstName()
//               << "\n\tLastName : " << janeCopy1.lastName()
//               << "\n\tAge      : " << janeCopy1.age() << bsl::endl;
// }
// ```
//
///Example 2: Sample `STREAMBUF` Implementation
/// - - - - - - - - - - - - - - - - - - - - - -
// For this example, we will implement `MyStreamBuf`, a minimal `STREAMBUF` to
// to be used with `bslx::GenericInStream` and `bslx::GenericOutStream`.  The
// implementation will consist of only what is required of the type.  For
// comparison, we will reuse `MyPerson` and repeat part of {Example 1} to
// demonstrate how to use `bslx::GenericInStream`.
//
// First, we implement `MyStreamBuf` (which, for brevity, simply uses the
// default allocator):
// ```
// /// This class implements a very basic stream buffer suitable for use in
// /// 'bslx::GenericOutStream' and 'bslx::GenericInStream'.
// class MyStreamBuf {
//
//     // DATA
//     bsl::deque<char> d_buffer;  // the input and output buffer
//
//   private:
//     // NOT IMPLEMENTED
//     MyStreamBuf(const MyStreamBuf&);
//     MyStreamBuf& operator=(const MyStreamBuf&);
//
//   public:
//     // TYPES
//     struct traits_type {
//         static int eof() { return -1; }
//     };
//
//     // CREATORS
//
//     /// Create an empty stream buffer.
//     MyStreamBuf();
//
//     /// Destroy this object.
//     ~MyStreamBuf();
//
//     // MANIPULATORS
//
//     /// Return 0.
//     int pubsync();
//
//     /// Read the next character in this buffer.  Return the value of the
//     // character on success, and `traits_type::eof()` otherwise.
//     int sbumpc();
//
//     /// Peek at the next character in this buffer.  Return the value of
//     /// the character on success, and `traits_type::eof()` otherwise.
//     int sgetc();
//
//     /// Load the specified `length` characters into the specified
//     /// address `s`, and return the number of characters read.
//     bsl::streamsize sgetn(char *s, bsl::streamsize length);
//
//     /// Write the specified character `c` to this buffer.  Return `c` on
//     /// success, and `traits_type::eof()` otherwise.
//     int sputc(char c);
//
//     /// Write the specified `length` characters at the specified address
//     /// `s` to this buffer, and return the number of characters written.
//     bsl::streamsize sputn(const char *s, bsl::streamsize length);
// };
//
// // ========================================================================
// //                  INLINE FUNCTION DEFINITIONS
// // ========================================================================
//
// // CREATORS
// MyStreamBuf::MyStreamBuf()
// : d_buffer()
// {
// }
//
// MyStreamBuf::~MyStreamBuf()
// {
// }
//
// // MANIPULATORS
// int MyStreamBuf::pubsync()
// {
//     // In this implementation, there is nothing to be done except return
//     // success.
//
//     return 0;
// }
//
// int MyStreamBuf::sbumpc()
// {
//     if (!d_buffer.empty()) {
//         const int rv = static_cast<int>(d_buffer.front());
//         d_buffer.pop_front();
//         return rv;                                                // RETURN
//     }
//     return traits_type::eof();
// }
//
// int MyStreamBuf::sgetc()
// {
//     if (!d_buffer.empty()) {
//         return static_cast<int>(d_buffer.front());                // RETURN
//     }
//     return traits_type::eof();
// }
//
// bsl::streamsize MyStreamBuf::sgetn(char *s, bsl::streamsize length)
// {
//     for (bsl::streamsize i = 0; i < length; ++i) {
//         if (d_buffer.empty()) {
//             return i;                                             // RETURN
//         }
//         s[i] = d_buffer.front();
//         d_buffer.pop_front();
//     }
//     return length;
// }
//
// int MyStreamBuf::sputc(char c)
// {
//     d_buffer.push_back(c);
//     return static_cast<int>(c);
// }
//
// bsl::streamsize MyStreamBuf::sputn(const char      *s,
//                                    bsl::streamsize  length)
// {
//     for (bsl::streamsize i = 0; i < length; ++i) {
//         d_buffer.push_back(s[i]);
//     }
//     return length;
// }
// ```
// Then, we create a `MyPerson` `janeSmith2` and a `bslx::GenericOutStream`
// `outStream2`:
// ```
// MyPerson                               janeSmith2("Jane", "Smith", 42);
// MyStreamBuf                            buffer2;
// bslx::GenericOutStream<MyStreamBuf>    outStream2(&buffer2, 20131127);
// const int                              VERSION2 = 1;
// outStream2.putVersion(VERSION2);
// janeSmith2.bdexStreamOut(outStream2, VERSION2);
// assert(outStream2.isValid());
// ```
// Next, create a `MyPerson` `janeCopy2` initialized to the default value, and
// assert that `janeCopy2` is different from `janeSmith2`:
// ```
// MyPerson janeCopy2;
// assert(janeCopy2 != janeSmith2);
// ```
// Then, create a `bslx::GenericInStream` `inStream2` initialized with the
// buffer from the `bslx::GenericOutStream` object `outStream2` and
// unexternalize this data into `janeCopy2`:
// ```
// bslx::GenericInStream<MyStreamBuf>    inStream2(&buffer2);
// int                                   version2;
// inStream2.getVersion(version2);
// janeCopy2.bdexStreamIn(inStream2, version2);
// assert(inStream2.isValid());
// ```
// Finally, `assert` the obtained values are as expected:
// ```
// assert(version2  == VERSION2);
// assert(janeCopy2 == janeSmith2);
// ```

#include <bslscm_version.h>

#include <bslx_instreamfunctions.h>

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

#include <bsl_cstddef.h>
#include <bsl_string.h>
#include <bsl_vector.h>

namespace BloombergLP {
namespace bslx {

                        // =====================
                        // class GenericInStream
                        // =====================

/// This class provides input methods to unexternalize values, and C-style
/// arrays of values, of the fundamental integral and floating-point types,
/// as well as `bsl::string` values, using a byte format documented in the
/// `bslx_byteoutstream` component.  In particular, each `get` method of
/// this class is guaranteed to read stream data written by the
/// corresponding `put` method of `bslx::GenericOutStream`.  Note that
/// attempting to read beyond the end of a stream will automatically
/// invalidate the stream.  See the `bslx` package-level documentation for
/// the definition of the BDEX `InStream` protocol.
template <class STREAMBUF>
class GenericInStream {

    // PRIVATE 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
    };

    // DATA
    STREAMBUF *d_streamBuf;  // held stream to read from

    bool       d_validFlag;  // stream validity flag; 'true' if stream is in
                             // valid state, 'false' otherwise

    // NOT IMPLEMENTED
    GenericInStream(const GenericInStream&);
    GenericInStream& operator=(const GenericInStream&);

  private:
    // PRIVATE MANIPULATORS

    /// Put this output stream into a valid state.  This function has no
    /// effect if this stream is already valid.
    void validate();

  public:
    // CREATORS

    /// Create an input byte stream that reads its input from the specified
    /// `streamBuf`.
    GenericInStream(STREAMBUF *streamBuf);

    /// Destroy this object.
    ~GenericInStream();

    // MANIPULATORS

    /// If the most-significant bit of the one byte of this stream at the
    /// current cursor location is set, assign to the specified `length` the
    /// four-byte, two's complement integer (in host byte order) comprised
    /// of the four bytes of this stream at the current cursor location (in
    /// network byte order) with the most-significant bit unset; otherwise,
    /// assign to `length` the one-byte, two's complement integer comprised
    /// of the one byte of this stream at the current cursor location.
    /// Update the cursor location and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `length` is undefined.
    /// Note that the value will be zero-extended.
    GenericInStream& getLength(int& length);

    /// Assign to the specified `version` the one-byte, two's complement
    /// unsigned integer comprised of the one byte of this stream at the
    /// current cursor location, update the cursor location, and return a
    /// reference to this stream.  If this stream is initially invalid, this
    /// operation has no effect.  If this function otherwise fails to
    /// extract a valid value, this stream is marked invalid and the value
    /// of `version` is undefined.  Note that the value will be
    /// zero-extended.
    GenericInStream& getVersion(int& version);

    /// Put this input stream in an invalid state.  This function has no
    /// effect if this stream is already invalid.  Note that this function
    /// should be called whenever a value extracted from this stream is
    /// determined to be invalid, inconsistent, or otherwise incorrect.
    void invalidate();

                      // *** scalar integer values ***

    /// Assign to the specified `variable` the eight-byte, two's complement
    /// integer (in host byte order) comprised of the eight bytes of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be sign-extended.
    GenericInStream& getInt64(bsls::Types::Int64& variable);

    /// Assign to the specified `variable` the eight-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the eight bytes
    /// of this stream at the current cursor location (in network byte
    /// order), update the cursor location, and return a reference to this
    /// stream.  If this stream is initially invalid, this operation has no
    /// effect.  If this function otherwise fails to extract a valid value,
    /// this stream is marked invalid and the value of `variable` is
    /// undefined.  Note that the value will be zero-extended.
    GenericInStream& getUint64(bsls::Types::Uint64& variable);

    /// Assign to the specified `variable` the seven-byte, two's complement
    /// integer (in host byte order) comprised of the seven bytes of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be sign-extended.
    GenericInStream& getInt56(bsls::Types::Int64& variable);

    /// Assign to the specified `variable` the seven-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the seven bytes
    /// of this stream at the current cursor location (in network byte
    /// order), update the cursor location, and return a reference to this
    /// stream.  If this stream is initially invalid, this operation has no
    /// effect.  If this function otherwise fails to extract a valid value,
    /// this stream is marked invalid and the value of `variable` is
    /// undefined.  Note that the value will be zero-extended.
    GenericInStream& getUint56(bsls::Types::Uint64& variable);

    /// Assign to the specified `variable` the six-byte, two's complement
    /// integer (in host byte order) comprised of the six bytes of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be sign-extended.
    GenericInStream& getInt48(bsls::Types::Int64& variable);

    /// Assign to the specified `variable` the six-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the six bytes of
    /// this stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be zero-extended.
    GenericInStream& getUint48(bsls::Types::Uint64& variable);

    /// Assign to the specified `variable` the five-byte, two's complement
    /// integer (in host byte order) comprised of the five bytes of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be sign-extended.
    GenericInStream& getInt40(bsls::Types::Int64& variable);

    /// Assign to the specified `variable` the five-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the five bytes of
    /// this stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be zero-extended.
    GenericInStream& getUint40(bsls::Types::Uint64& variable);

    /// Assign to the specified `variable` the four-byte, two's complement
    /// integer (in host byte order) comprised of the four bytes of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be sign-extended.
    GenericInStream& getInt32(int& variable);

    /// Assign to the specified `variable` the four-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the four bytes of
    /// this stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be zero-extended.
    GenericInStream& getUint32(unsigned int& variable);

    /// Assign to the specified `variable` the three-byte, two's complement
    /// integer (in host byte order) comprised of the three bytes of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be sign-extended.
    GenericInStream& getInt24(int& variable);

    /// Assign to the specified `variable` the three-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the three bytes
    /// of this stream at the current cursor location (in network byte
    /// order), update the cursor location, and return a reference to this
    /// stream.  If this stream is initially invalid, this operation has no
    /// effect.  If this function otherwise fails to extract a valid value,
    /// this stream is marked invalid and the value of `variable` is
    /// undefined.  Note that the value will be zero-extended.
    GenericInStream& getUint24(unsigned int& variable);

    /// Assign to the specified `variable` the two-byte, two's complement
    /// integer (in host byte order) comprised of the two bytes of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be sign-extended.
    GenericInStream& getInt16(short& variable);

    /// Assign to the specified `variable` the two-byte, two's complement
    /// unsigned integer (in host byte order) comprised of the two bytes of
    /// this stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variable` is undefined.
    /// Note that the value will be zero-extended.
    GenericInStream& getUint16(unsigned short& variable);

    /// Assign to the specified `variable` the one-byte, two's complement
    /// integer comprised of the one byte of this stream at the current
    /// cursor location, update the cursor location, and return a reference
    /// to this stream.  If this stream is initially invalid, this operation
    /// has no effect.  If this function otherwise fails to extract a valid
    /// value, this stream is marked invalid and the value of `variable` is
    /// undefined.  Note that the value will be sign-extended.
    GenericInStream& getInt8(char&        variable);
    GenericInStream& getInt8(signed char& variable);

    /// Assign to the specified `variable` the one-byte, two's complement
    /// unsigned integer comprised of the one byte of this stream at the
    /// current cursor location, update the cursor location, and return a
    /// reference to this stream.  If this stream is initially invalid, this
    /// operation has no effect.  If this function otherwise fails to
    /// extract a valid value, this stream is marked invalid and the value
    /// of `variable` is undefined.  Note that the value will be
    /// zero-extended.
    GenericInStream& getUint8(char&          variable);
    GenericInStream& getUint8(unsigned char& variable);

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

    /// Assign to the specified `variable` the eight-byte IEEE
    /// double-precision floating-point number (in host byte order)
    /// comprised of the eight bytes of this stream at the current cursor
    /// location (in network byte order), update the cursor location, and
    /// return a reference to this stream.  If this stream is initially
    /// invalid, this operation has no effect.  If this function otherwise
    /// fails to extract a valid value, this stream is marked invalid and
    /// the value of `variable` is undefined.
    GenericInStream& getFloat64(double& variable);

    /// Assign to the specified `variable` the four-byte IEEE
    /// single-precision floating-point number (in host byte order)
    /// comprised of the four bytes of this stream at the current cursor
    /// location (in network byte order), update the cursor location, and
    /// return a reference to this stream.  If this stream is initially
    /// invalid, this operation has no effect.  If this function otherwise
    /// fails to extract a valid value, this stream is marked invalid and
    /// the value of `variable` is undefined.
    GenericInStream& getFloat32(float& variable);

                      // *** string values ***

    /// Assign to the specified `variable` the string comprised of the
    /// length of the string (see `getLength`) and the string data (see
    /// `getUint8`), update the cursor location, and return a reference to
    /// this stream.  If this stream is initially invalid, this operation
    /// has no effect.  If this function otherwise fails to extract a valid
    /// value, this stream is marked invalid and the value of `variable` is
    /// undefined.
    GenericInStream& getString(bsl::string& variable);

                      // *** arrays of integer values ***

    /// Assign to the specified `variables` the consecutive eight-byte,
    /// two's complement integers (in host byte order) comprised of each of
    /// the specified `numVariables` eight-byte sequences of this stream at
    /// the current cursor location (in network byte order), update the
    /// cursor location, and return a reference to this stream.  If this
    /// stream is initially invalid, this operation has no effect.  If this
    /// function otherwise fails to extract a valid value, this stream is
    /// marked invalid and the value of `variables` is undefined.  The
    /// behavior is undefined unless `0 <= numVariables` and `variables` has
    /// sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be sign-extended.
    GenericInStream& getArrayInt64(bsls::Types::Int64 *variables,
                                   int                 numVariables);

    /// Assign to the specified `variables` the consecutive eight-byte,
    /// two's complement unsigned integers (in host byte order) comprised of
    /// each of the specified `numVariables` eight-byte sequences of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variables` is undefined.
    /// The behavior is undefined unless `0 <= numVariables` and `variables`
    /// has sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be zero-extended.
    GenericInStream& getArrayUint64(bsls::Types::Uint64 *variables,
                                    int                  numVariables);

    /// Assign to the specified `variables` the consecutive seven-byte,
    /// two's complement integers (in host byte order) comprised of each of
    /// the specified `numVariables` seven-byte sequences of this stream at
    /// the current cursor location (in network byte order), update the
    /// cursor location, and return a reference to this stream.  If this
    /// stream is initially invalid, this operation has no effect.  If this
    /// function otherwise fails to extract a valid value, this stream is
    /// marked invalid and the value of `variables` is undefined.  The
    /// behavior is undefined unless `0 <= numVariables` and `variables` has
    /// sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be sign-extended.
    GenericInStream& getArrayInt56(bsls::Types::Int64 *variables,
                                   int                 numVariables);

    /// Assign to the specified `variables` the consecutive seven-byte,
    /// two's complement unsigned integers (in host byte order) comprised of
    /// each of the specified `numVariables` seven-byte sequences of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variables` is undefined.
    /// The behavior is undefined unless `0 <= numVariables` and `variables`
    /// has sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// zero-extended.
    GenericInStream& getArrayUint56(bsls::Types::Uint64 *variables,
                                    int                  numVariables);

    /// Assign to the specified `variables` the consecutive six-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` six-byte sequences of this stream at the
    /// current cursor location (in network byte order), update the cursor
    /// location, and return a reference to this stream.  If this stream is
    /// initially invalid, this operation has no effect.  If this function
    /// otherwise fails to extract a valid value, this stream is marked
    /// invalid and the value of `variables` is undefined.  The behavior is
    /// undefined unless `0 <= numVariables` and `variables` has sufficient
    /// capacity, or `0 == numVariables && nullptr == variables`.  Note that
    /// each of the values will be sign-extended.
    GenericInStream& getArrayInt48(bsls::Types::Int64 *variables,
                                   int                 numVariables);

    /// Assign to the specified `variables` the consecutive six-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` six-byte sequences of this stream at
    /// the current cursor location (in network byte order), update the
    /// cursor location, and return a reference to this stream.  If this
    /// stream is initially invalid, this operation has no effect.  If this
    /// function otherwise fails to extract a valid value, this stream is
    /// marked invalid and the value of `variables` is undefined.  The
    /// behavior is undefined unless `0 <= numVariables` and `variables` has
    /// sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be zero-extended.
    GenericInStream& getArrayUint48(bsls::Types::Uint64 *variables,
                                    int                  numVariables);

    /// Assign to the specified `variables` the consecutive five-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` five-byte sequences of this stream at the
    /// current cursor location (in network byte order), update the cursor
    /// location, and return a reference to this stream.  If this stream is
    /// initially invalid, this operation has no effect.  If this function
    /// otherwise fails to extract a valid value, this stream is marked
    /// invalid and the value of `variables` is undefined.  The behavior is
    /// undefined unless `0 <= numVariables` and `variables` has sufficient
    /// capacity, or `0 == numVariables && nullptr == variables`.  Note that
    /// each of the values will be sign-extended.
    GenericInStream& getArrayInt40(bsls::Types::Int64 *variables,
                                   int                 numVariables);

    /// Assign to the specified `variables` the consecutive five-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` five-byte sequences of this stream
    /// at the current cursor location (in network byte order), update the
    /// cursor location, and return a reference to this stream.  If this
    /// stream is initially invalid, this operation has no effect.  If this
    /// function otherwise fails to extract a valid value, this stream is
    /// marked invalid and the value of `variables` is undefined.  The
    /// behavior is undefined unless `0 <= numVariables` and `variables` has
    /// sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be zero-extended.
    GenericInStream& getArrayUint40(bsls::Types::Uint64 *variables,
                                    int                  numVariables);

    /// Assign to the specified `variables` the consecutive four-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` four-byte sequences of this stream at the
    /// current cursor location (in network byte order), update the cursor
    /// location, and return a reference to this stream.  If this stream is
    /// initially invalid, this operation has no effect.  If this function
    /// otherwise fails to extract a valid value, this stream is marked
    /// invalid and the value of `variables` is undefined.  The behavior is
    /// undefined unless `0 <= numVariables` and `variables` has sufficient
    /// capacity, or `0 == numVariables && nullptr == variables`.  Note that
    /// each of the values will be sign-extended.
    GenericInStream& getArrayInt32(int *variables, int numVariables);

    /// Assign to the specified `variables` the consecutive four-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` four-byte sequences of this stream
    /// at the current cursor location (in network byte order), update the
    /// cursor location, and return a reference to this stream.  If this
    /// stream is initially invalid, this operation has no effect.  If this
    /// function otherwise fails to extract a valid value, this stream is
    /// marked invalid and the value of `variables` is undefined.  The
    /// behavior is undefined unless `0 <= numVariables` and `variables` has
    /// sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be zero-extended.
    GenericInStream& getArrayUint32(unsigned int *variables, int numVariables);

    /// Assign to the specified `variables` the consecutive three-byte,
    /// two's complement integers (in host byte order) comprised of each of
    /// the specified `numVariables` three-byte sequences of this stream at
    /// the current cursor location (in network byte order), update the
    /// cursor location, and return a reference to this stream.  If this
    /// stream is initially invalid, this operation has no effect.  If this
    /// function otherwise fails to extract a valid value, this stream is
    /// marked invalid and the value of `variables` is undefined.  The
    /// behavior is undefined unless `0 <= numValues` and `variables` has
    /// sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be sign-extended.
    GenericInStream& getArrayInt24(int *variables, int numVariables);

    /// Assign to the specified `variables` the consecutive three-byte,
    /// two's complement unsigned integers (in host byte order) comprised of
    /// each of the specified `numVariables` three-byte sequences of this
    /// stream at the current cursor location (in network byte order),
    /// update the cursor location, and return a reference to this stream.
    /// If this stream is initially invalid, this operation has no effect.
    /// If this function otherwise fails to extract a valid value, this
    /// stream is marked invalid and the value of `variables` is undefined.
    /// The behavior is undefined unless `0 <= numVariables` and `variables`
    /// has sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be zero-extended.
    GenericInStream& getArrayUint24(unsigned int *variables, int numVariables);

    /// Assign to the specified `variables` the consecutive two-byte, two's
    /// complement integers (in host byte order) comprised of each of the
    /// specified `numVariables` two-byte sequences of this stream at the
    /// current cursor location (in network byte order), update the cursor
    /// location, and return a reference to this stream.  If this stream is
    /// initially invalid, this operation has no effect.  If this function
    /// otherwise fails to extract a valid value, this stream is marked
    /// invalid and the value of `variables` is undefined.  The behavior is
    /// undefined unless `0 <= numVariables` and `variables` has sufficient
    /// capacity, or `0 == numVariables && nullptr == variables`.  Note that
    /// each of the values will be sign-extended.
    GenericInStream& getArrayInt16(short *variables, int numVariables);

    /// Assign to the specified `variables` the consecutive two-byte, two's
    /// complement unsigned integers (in host byte order) comprised of each
    /// of the specified `numVariables` two-byte sequences of this stream at
    /// the current cursor location (in network byte order), update the
    /// cursor location, and return a reference to this stream.  If this
    /// stream is initially invalid, this operation has no effect.  If this
    /// function otherwise fails to extract a valid value, this stream is
    /// marked invalid and the value of `variables` is undefined.  The
    /// behavior is undefined unless `0 <= numVariables` and `variables` has
    /// sufficient capacity, or `0 == numVariables && nullptr == variables`.
    /// Note that each of the values will be zero-extended.
    GenericInStream& getArrayUint16(unsigned short *variables,
                                    int             numVariables);

    /// Assign to the specified `variables` the consecutive one-byte, two's
    /// complement integers comprised of each of the specified
    /// `numVariables` one-byte sequences of this stream at the current
    /// cursor location, update the cursor location, and return a reference
    /// to this stream.  If this stream is initially invalid, this operation
    /// has no effect.  If this function otherwise fails to extract a valid
    /// value, this stream is marked invalid and the value of `variables` is
    /// undefined.  The behavior is undefined unless `0 <= numVariables` and
    /// `variables` has sufficient capacity, or `0 == numVariables && nullptr ==
    /// variables`.  Note that each of the values will be sign-extended.
    GenericInStream& getArrayInt8(char *variables, int numVariables);
    GenericInStream& getArrayInt8(signed char *variables, int numVariables);

    /// Assign to the specified `variables` the consecutive one-byte, two's
    /// complement unsigned integers comprised of each of the specified
    /// `numVariables` one-byte sequences of this stream at the current
    /// cursor location, update the cursor location, and return a reference
    /// to this stream.  If this stream is initially invalid, this operation
    /// has no effect.  If this function otherwise fails to extract a valid
    /// value, this stream is marked invalid and the value of `variables` is
    /// undefined.  The behavior is undefined unless `0 <= numVariables` and
    /// `variables` has sufficient capacity, or `0 == numVariables && nullptr ==
    /// variables`.  Note that each of the values will be zero-extended.
    GenericInStream& getArrayUint8(char *variables, int numVariables);
    GenericInStream& getArrayUint8(unsigned char *variables, int numVariables);

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

    /// Assign to the specified `variables` the consecutive eight-byte IEEE
    /// double-precision floating-point numbers (in host byte order)
    /// comprised of each of the specified `numVariables` eight-byte
    /// sequences of this stream at the current cursor location (in network
    /// byte order), update the cursor location, and return a reference to
    /// this stream.  If this stream is initially invalid, this operation
    /// has no effect.  If this function otherwise fails to extract a valid
    /// value, this stream is marked invalid and the value of `variables` is
    /// undefined.  The behavior is undefined unless `0 <= numVariables` and
    /// `variables` has sufficient capacity.
    GenericInStream& getArrayFloat64(double *variables, int numVariables);

    /// Assign to the specified `variables` the consecutive four-byte IEEE
    /// single-precision floating-point numbers (in host byte order)
    /// comprised of each of the specified `numVariables` four-byte
    /// sequences of this stream at the current cursor location (in network
    /// byte order), update the cursor location, and return a reference to
    /// this stream.  If this stream is initially invalid, this operation
    /// has no effect.  If this function otherwise fails to extract a valid
    /// value, this stream is marked invalid and the value of `variables` is
    /// undefined.  The behavior is undefined unless `0 <= numVariables` and
    /// `variables` has sufficient capacity.
    GenericInStream& getArrayFloat32(float *variables, int numVariables);

    // ACCESSORS

    /// Return a non-zero value if this stream is valid, and 0 otherwise.
    /// An invalid stream is a stream in which insufficient or invalid data
    /// was detected during an extraction operation.  Note that an empty
    /// stream will be valid unless an extraction attempt or explicit
    /// invalidation causes it to be otherwise.
    operator const void *() const;

    /// Return `true` if this stream is valid, and `false` otherwise.  An
    /// invalid stream is a stream in which insufficient or invalid data was
    /// detected during an extraction operation.  Note that an empty stream
    /// will be valid unless an extraction attempt or explicit invalidation
    /// causes it to be otherwise.
    bool isValid() const;
};

// FREE OPERATORS

/// Read the specified `value` from the specified input `stream` following
/// the requirements of the BDEX protocol (see the `bslx` package-level
/// documentation), and return a reference to `stream`.  The behavior is
/// undefined unless `TYPE` is BDEX-compliant.
template <class STREAMBUF, class TYPE>
GenericInStream<STREAMBUF>&
                   operator>>(GenericInStream<STREAMBUF>& stream, TYPE& value);

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

                        // ---------------------
                        // class GenericInStream
                        // ---------------------

// PRIVATE MANIPULATORS
template <class STREAMBUF>
inline
void GenericInStream<STREAMBUF>::validate()
{
    d_validFlag = true;
}

// CREATORS
template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>::GenericInStream(STREAMBUF *streamBuf)
: d_streamBuf(streamBuf)
, d_validFlag(true)
{
    BSLS_ASSERT_SAFE(streamBuf);
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>::~GenericInStream()
{
}

// MANIPULATORS
template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>& GenericInStream<STREAMBUF>::getLength(int& length)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    const int current = d_streamBuf->sgetc();
    if (STREAMBUF::traits_type::eof() != current) {
        validate();
        if (127 < current) {
            // If 'length > 127', 'length' is stored as 4 bytes with top bit
            // set.

            getInt32(length);
            length &= 0x7fffffff;  // Clear top bit.
        }
        else {
            // If 'length <= 127', 'length' is stored as one byte.

            char tmp = 0;
            getInt8(tmp);
            length = tmp;
        }
    }

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getVersion(int& version)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    unsigned char tmp = 0;
    getUint8(tmp);
    version = tmp;

    return *this;
}

template <class STREAMBUF>
inline
void GenericInStream<STREAMBUF>::invalidate()
{
    d_validFlag = false;
}

                      // *** scalar integer values ***

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt64(bsls::Types::Int64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    if (sizeof variable > k_SIZEOF_INT64) {
        const int current = d_streamBuf->sgetc();
        if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                   STREAMBUF::traits_type::eof() == current)) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            return *this;                                             // RETURN
        }
        variable = 0x80 & current ? -1 : 0;  // sign extend
    }

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT64];
    if (k_SIZEOF_INT64 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT64)) {
        validate();
        bytes[7] = rawBytes[0];
        bytes[6] = rawBytes[1];
        bytes[5] = rawBytes[2];
        bytes[4] = rawBytes[3];
        bytes[3] = rawBytes[4];
        bytes[2] = rawBytes[5];
        bytes[1] = rawBytes[6];
        bytes[0] = rawBytes[7];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT64;
    if (k_SIZEOF_INT64 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT64)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint64(bsls::Types::Uint64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

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

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT64];
    if (k_SIZEOF_INT64 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT64)) {
        validate();
        bytes[7] = rawBytes[0];
        bytes[6] = rawBytes[1];
        bytes[5] = rawBytes[2];
        bytes[4] = rawBytes[3];
        bytes[3] = rawBytes[4];
        bytes[2] = rawBytes[5];
        bytes[1] = rawBytes[6];
        bytes[0] = rawBytes[7];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT64;
    if (k_SIZEOF_INT64 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT64)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt56(bsls::Types::Int64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    const int current = d_streamBuf->sgetc();
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                   STREAMBUF::traits_type::eof() == current)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }
    variable = 0x80 & current ? -1 : 0;  // sign extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT56];
    if (k_SIZEOF_INT56 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT56)) {
        validate();
        bytes[6] = rawBytes[0];
        bytes[5] = rawBytes[1];
        bytes[4] = rawBytes[2];
        bytes[3] = rawBytes[3];
        bytes[2] = rawBytes[4];
        bytes[1] = rawBytes[5];
        bytes[0] = rawBytes[6];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT56;
    if (k_SIZEOF_INT56 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT56)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint56(bsls::Types::Uint64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    variable = 0;  // zero-extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT56];
    if (k_SIZEOF_INT56 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT56)) {
        validate();
        bytes[6] = rawBytes[0];
        bytes[5] = rawBytes[1];
        bytes[4] = rawBytes[2];
        bytes[3] = rawBytes[3];
        bytes[2] = rawBytes[4];
        bytes[1] = rawBytes[5];
        bytes[0] = rawBytes[6];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT56;
    if (k_SIZEOF_INT56 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT56)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt48(bsls::Types::Int64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    const int current = d_streamBuf->sgetc();
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                   STREAMBUF::traits_type::eof() == current)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }
    variable = 0x80 & current ? -1 : 0;  // sign extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT48];
    if (k_SIZEOF_INT48 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT48)) {
        validate();
        bytes[5] = rawBytes[0];
        bytes[4] = rawBytes[1];
        bytes[3] = rawBytes[2];
        bytes[2] = rawBytes[3];
        bytes[1] = rawBytes[4];
        bytes[0] = rawBytes[5];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT48;
    if (k_SIZEOF_INT48 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT48)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint48(bsls::Types::Uint64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    variable = 0;  // zero-extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT48];
    if (k_SIZEOF_INT48 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT48)) {
        validate();
        bytes[5] = rawBytes[0];
        bytes[4] = rawBytes[1];
        bytes[3] = rawBytes[2];
        bytes[2] = rawBytes[3];
        bytes[1] = rawBytes[4];
        bytes[0] = rawBytes[5];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT48;
    if (k_SIZEOF_INT48 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT48)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt40(bsls::Types::Int64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    const int current = d_streamBuf->sgetc();
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                   STREAMBUF::traits_type::eof() == current)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }
    variable = 0x80 & current ? -1 : 0;  // sign extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT40];
    if (k_SIZEOF_INT40 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT40)) {
        validate();
        bytes[4] = rawBytes[0];
        bytes[3] = rawBytes[1];
        bytes[2] = rawBytes[2];
        bytes[1] = rawBytes[3];
        bytes[0] = rawBytes[4];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT40;
    if (k_SIZEOF_INT40 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT40)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint40(bsls::Types::Uint64& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    variable = 0;  // zero-extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT40];
    if (k_SIZEOF_INT40 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT40)) {
        validate();
        bytes[4] = rawBytes[0];
        bytes[3] = rawBytes[1];
        bytes[2] = rawBytes[2];
        bytes[1] = rawBytes[3];
        bytes[0] = rawBytes[4];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT40;
    if (k_SIZEOF_INT40 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT40)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt32(int& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    if (sizeof variable > k_SIZEOF_INT32) {
        const int current = d_streamBuf->sgetc();
        if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                   STREAMBUF::traits_type::eof() == current)) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            return *this;                                             // RETURN
        }
        variable = 0x80 & current ? -1 : 0;  // sign extend
    }

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT32];
    if (k_SIZEOF_INT32 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT32)) {
        validate();
        bytes[3] = rawBytes[0];
        bytes[2] = rawBytes[1];
        bytes[1] = rawBytes[2];
        bytes[0] = rawBytes[3];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT32;
    if (k_SIZEOF_INT32 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT32)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint32(unsigned int& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

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

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT32];
    if (k_SIZEOF_INT32 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT32)) {
        validate();
        bytes[3] = rawBytes[0];
        bytes[2] = rawBytes[1];
        bytes[1] = rawBytes[2];
        bytes[0] = rawBytes[3];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT32;
    if (k_SIZEOF_INT32 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT32)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt24(int& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    const int current = d_streamBuf->sgetc();
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                   STREAMBUF::traits_type::eof() == current)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }
    variable = 0x80 & current ? -1 : 0;  // sign extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT24];
    if (k_SIZEOF_INT24 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT24)) {
        validate();
        bytes[2] = rawBytes[0];
        bytes[1] = rawBytes[1];
        bytes[0] = rawBytes[2];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT24;
    if (k_SIZEOF_INT24 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT24)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint24(unsigned int& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    variable = 0;  // zero-extend

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT24];
    if (k_SIZEOF_INT24 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT24)) {
        validate();
        bytes[2] = rawBytes[0];
        bytes[1] = rawBytes[1];
        bytes[0] = rawBytes[2];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT24;
    if (k_SIZEOF_INT24 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT24)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt16(short& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    if (sizeof variable > k_SIZEOF_INT16) {
        const int current = d_streamBuf->sgetc();
        if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                   STREAMBUF::traits_type::eof() == current)) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            return *this;                                             // RETURN
        }
        variable = 0x80 & current ? -1 : 0;  // sign extend
    }

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT16];
    if (k_SIZEOF_INT16 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT16)) {
        validate();
        bytes[1] = rawBytes[0];
        bytes[0] = rawBytes[1];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT16;
    if (k_SIZEOF_INT16 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT16)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint16(unsigned short& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

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

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_INT16];
    if (k_SIZEOF_INT16 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_INT16)) {
        validate();
        bytes[1] = rawBytes[0];
        bytes[0] = rawBytes[1];
    }
#else
    char *bytes =
        reinterpret_cast<char *>(&variable) + sizeof variable - k_SIZEOF_INT16;
    if (k_SIZEOF_INT16 == d_streamBuf->sgetn(bytes, k_SIZEOF_INT16)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt8(char& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

    const int current = d_streamBuf->sbumpc();
    if (STREAMBUF::traits_type::eof() != current) {
        validate();
        variable = static_cast<char>(current);
    }

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getInt8(signed char& variable)
{
    return getInt8(reinterpret_cast<char&>(variable));
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint8(char& variable)
{
    return getInt8(variable);
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getUint8(unsigned char& variable)
{
    return getInt8(reinterpret_cast<char&>(variable));
}

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

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getFloat64(double& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

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

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_FLOAT64];
    if (k_SIZEOF_FLOAT64 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_FLOAT64)) {
        validate();
        bytes[sizeof variable - 1] = rawBytes[0];
        bytes[sizeof variable - 2] = rawBytes[1];
        bytes[sizeof variable - 3] = rawBytes[2];
        bytes[sizeof variable - 4] = rawBytes[3];
        bytes[sizeof variable - 5] = rawBytes[4];
        bytes[sizeof variable - 6] = rawBytes[5];
        bytes[sizeof variable - 7] = rawBytes[6];
        bytes[sizeof variable - 8] = rawBytes[7];
    }
#else
    char *bytes = reinterpret_cast<char *>(&variable);
    if (k_SIZEOF_FLOAT64 == d_streamBuf->sgetn(bytes, k_SIZEOF_FLOAT64)) {
        validate();
    }
#endif

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getFloat32(float& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    invalidate();

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

#ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN
    char *bytes = reinterpret_cast<char *>(&variable);
    char  rawBytes[k_SIZEOF_FLOAT32];
    if (k_SIZEOF_FLOAT32 == d_streamBuf->sgetn(rawBytes, k_SIZEOF_FLOAT32)) {
        validate();
        bytes[sizeof variable - 1] = rawBytes[0];
        bytes[sizeof variable - 2] = rawBytes[1];
        bytes[sizeof variable - 3] = rawBytes[2];
        bytes[sizeof variable - 4] = rawBytes[3];
    }
#else
    char *bytes = reinterpret_cast<char *>(&variable);
    if (k_SIZEOF_FLOAT32 == d_streamBuf->sgetn(bytes, k_SIZEOF_FLOAT32)) {
        validate();
    }
#endif

    return *this;
}

                      // *** string values ***

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getString(bsl::string& variable)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    int length = 0;
    getLength(length);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    // 'length' could be corrupt or invalid, so we limit the initial 'resize'
    // to something that can accommodate the preponderance of strings that will
    // arise in practice.  The remaining portion of a string longer than 16M is
    // read in via a second pass.

    enum { k_INITIAL_ALLOCATION_SIZE = 16 * 1024 * 1024 };

    const int initialLength = length < k_INITIAL_ALLOCATION_SIZE
                              ? length
                              : k_INITIAL_ALLOCATION_SIZE;

    variable.resize(initialLength);

    if (0 == length) {
        return *this;                                                 // RETURN
    }

    getArrayUint8(&variable.front(), initialLength);
    if (isValid() && length > initialLength) {
        variable.resize(length);
        getArrayUint8(&variable[initialLength], length - initialLength);
    }

    return *this;
}

                      // *** arrays of integer values ***

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt64(bsls::Types::Int64 *variables,
                                          int                 numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Int64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt64(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint64(bsls::Types::Uint64 *variables,
                                           int                  numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Uint64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getUint64(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt56(bsls::Types::Int64 *variables,
                                          int                 numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Int64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt56(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint56(bsls::Types::Uint64 *variables,
                                           int                  numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Uint64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getUint56(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt48(bsls::Types::Int64 *variables,
                                          int                 numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Int64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt48(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint48(bsls::Types::Uint64 *variables,
                                           int                  numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Uint64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getUint48(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt40(bsls::Types::Int64 *variables,
                                          int                 numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Int64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt40(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint40(bsls::Types::Uint64 *variables,
                                           int                  numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const bsls::Types::Uint64 *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getUint40(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt32(int *variables, int numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const int *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt32(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint32(unsigned int *variables,
                                           int           numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const unsigned int *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getUint32(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt24(int *variables, int numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const int *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt24(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint24(unsigned int *variables,
                                           int           numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const unsigned int *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getUint24(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt16(short *variables,
                                          int    numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const short *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt16(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint16(unsigned short *variables,
                                           int             numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const unsigned short *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getUint16(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt8(char *variables,
                                         int   numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const char *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getInt8(*variables);
    }

    return *this;
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayInt8(signed char *variables,
                                         int          numVariables)
{
    BSLS_ASSERT_SAFE(variables || 0 == numVariables);
    BSLS_ASSERT_SAFE(0 <= numVariables);

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

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint8(char *variables,
                                          int   numVariables)
{
    BSLS_ASSERT_SAFE(variables || 0 == numVariables);
    BSLS_ASSERT_SAFE(0 <= numVariables);

    return getArrayInt8(variables, numVariables);
}

template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayUint8(unsigned char *variables,
                                          int            numVariables)
{
    BSLS_ASSERT_SAFE(variables || 0 == numVariables);
    BSLS_ASSERT_SAFE(0 <= numVariables);

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

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

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayFloat64(double *variables,
                                            int     numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const double *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getFloat64(*variables);
    }

    return *this;
}

template <class STREAMBUF>
GenericInStream<STREAMBUF>&
GenericInStream<STREAMBUF>::getArrayFloat32(float *variables,
                                            int    numVariables)
{
    BSLS_ASSERT(variables || 0 == numVariables);
    BSLS_ASSERT(0 <= numVariables);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(   !isValid()
                                              || 0 == numVariables)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return *this;                                                 // RETURN
    }

    const float *end = variables + numVariables;
    for (; variables != end; ++variables) {
        getFloat32(*variables);
    }

    return *this;
}

// ACCESSORS
template <class STREAMBUF>
inline
GenericInStream<STREAMBUF>::operator const void *() const
{
    return isValid() ? this : 0;
}

template <class STREAMBUF>
inline
bool GenericInStream<STREAMBUF>::isValid() const
{
    return d_validFlag;
}

template <class STREAMBUF, class TYPE>
inline
GenericInStream<STREAMBUF>&
                operator>>(GenericInStream<STREAMBUF>& stream, TYPE& value)
{
    return InStreamFunctions::bdexStreamIn(stream, value);
}

}  // 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 ----------------------------------
