// bslx_instreamfunctions.h                                           -*-C++-*-
#ifndef INCLUDED_BSLX_INSTREAMFUNCTIONS
#define INCLUDED_BSLX_INSTREAMFUNCTIONS

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

//@PURPOSE: Facilitate uniform unexternalization of user and fundamental types.
//
//@CLASSES:
//  bslx::InStreamFunctions: namespace for BDEX unexternalization functions
//
//@SEE_ALSO: bslx_outstreamfunctions, bslx_versionfunctions
//
//@DESCRIPTION: This component provides a namespace, 'bslx::InStreamFunctions',
// that facilitates uniform support for BDEX unexternalization across all
// BDEX-compliant user-defined types, including template types and containers,
// as well as those fundamental types (and 'bsl::string' and 'bsl::vector') for
// which the BDEX protocol provides direct support.
//
// The namespace 'bslx::InStreamFunctions' facilitates client unexternalization
// of objects in a uniform, type-independent manner.  It contains the
// 'bdexStreamIn' function that unexternalizes objects of all BDEX-compliant
// types.  This function unexternalizes the specified 'object' in the specified
// 'version' or the 'version' read from the input stream as required by the
// BDEX protocol.  The 'bdexStreamIn' function is overloaded for fundamental
// types, enumeration types, 'bsl::string', and 'bsl::vector'.  Note that,
// excluding 'bsl::vector', version information is never read from the stream
// while unexternalizing these types.
//
// By default, objects of enumeration type are streamed in as 32-bit 'int'
// values.  Users can override this behavior by providing overloads of the
// 'InStreamFunctions::bdexStreamIn' function in the enumeration's namespace
// for their enumeration types.  The general form of this overload is:
//..
//  template <class STREAM>
//  STREAM& bdexStreamIn(STREAM& stream, MyEnum& variable, int version)
//  {
//      using bslx::InStreamFunctions::bdexStreamIn;
//
//      // Code to stream in objects of 'MyEnum' type.
//
//      return stream;
//  }
//..
// For value-semantic types that support the BDEX protocol, the free function
// 'bdexStreamIn' calls the 'bdexStreamIn' member function for that type.
//
///Component Design, Anticipated Usage, and the BDEX Contract
///----------------------------------------------------------
// 'bslx_instreamfunctions' is an integral part of the BDEX unexternalization
// contract.  The BDEX contract is at least in part "collaborative", which is
// to say that each developer of a given *kind* of component (e.g., a stream or
// a value-semantic container) must comply with the relevant portions of the
// contract to ensure that the "system as a whole" works for everybody.
// 'bslx_instreamfunctions' plays several related but different roles in
// helping various developers to produce BDEX-compliant components.  In this
// section we briefly highlight how and why 'bslx_instreamfunctions' is helpful
// (or required) for these different developers.  By discussing different
// aspects of usage, we convey the general design goals of this component, and,
// to a certain extent, the overall BDEX contract.  See the 'bslx'
// package-level documentation for a full specification of the BDEX contract.
//
///Implementing BDEX Streaming in Value-Semantic Template Classes
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The author of a non-template value-semantic type has full knowledge of the
// details of the "value" of that type, and may choose to use the appropriate
// input stream 'get' methods directly when implementing the required
// 'bdexStreamIn' method for that type.  However, if one or more aspects of the
// value are of template parameter type, then the author cannot in general know
// how to stream the value using the 'get' methods.  For example, if a type has
// as its value one 'int' data member:
//..
//  int d_value;
//..
// then the implementation of the 'bdexStreamIn' method can contain:
//..
//  stream.getInt32(d_value);
//..
// However, if the data member is of (template parameter) 'VALUE_TYPE':
//..
//  VALUE_TYPE d_value;
//..
// then the implementation of the 'bdexStreamIn' method must rely on the
// 'bslx::InStreamFunctions' implementation to input the value:
//..
//  using bslx::InStreamFunctions::bdexStreamIn;
//  bdexStreamIn(stream, d_value, 1);
//..
// This call will resolve to the correct sequence of 'get' calls no matter
// whether 'VALUE_TYPE' is a fundamental type, a BDEX-compliant 'enum', or a
// proper BDEX-compliant class.  In the latter two cases, the explicit
// specification of the version format (in this case, 1) guarantees the stable
// operation of this method whether or not 'VALUE_TYPE' is provided additional
// version formats.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Using 'bslx::InStreamFunctions' to Unexternalize Data
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example we illustrate the primary intended use of the parameterized
// methods of this component, as well as a few trivial invocations just to show
// the syntax clearly.  To accomplish this, we exhibit three separate example
// "components": an 'enum', a value-semantic point object, and an input stream.
// In all cases, the component designs are very simple, with much of the
// implied functionality omitted, in order to focus attention on the key
// aspects of the functionality of *this* component.
//
// First, consider an 'enum' 'Color' that enumerates a set of colors:
//..
//  enum Color {
//      RED   = 0,
//      GREEN = 1,
//      BLUE  = 2
//  };
//..
// Next, we consider a very special-purpose point that has as a data member its
// color.  Such a point provides an excellent opportunity for factoring, but
// since we are interested in highlighting BDEX streaming of various types, we
// will present a simple and unfactored design here.  In a real-world problem,
// the 'mypoint' component would be implemented differently.
//
// Note that the 'MyPoint' class in this example represents its coordinates as
// 'short' integer values; this is done to make the BDEX stream input byte
// pattern somewhat easier for the reader of this example to recognize when the
// input buffer is printed.
//..
//  // mypoint.h
//
//  class MyPoint {
//      // This class provides a geometric point having integer coordinates and
//      // an enumerated color property.
//
//      short d_x;      // x coordinate
//      short d_y;      // y coordinate
//      Color d_color;  // enumerated color property
//
//    public:
//      // CLASS METHODS
//      // ...
//
//      // CREATORS
//      MyPoint();
//          // Create a default point.
//
//      MyPoint(short x, short y, Color color);
//          // Create a point having the specified 'x' and 'y' coordinates
//          // and the specified 'color'.
//
//      ~MyPoint();
//          // Destroy this point.
//
//      // MANIPULATORS
//      // ...
//
//      // ACCESSORS
//      short x() const;
//          // Return the x coordinate of this point.
//
//      short y() const;
//          // Return the y coordinate of this point.
//
//      Color color() const;
//          // Return the enumerated color of this point.
//
//      template <class STREAM>
//      STREAM& bdexStreamIn(STREAM& stream, int version);
//          // 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.
//  };
//
//  // FREE OPERATORS
//  inline
//  bool operator==(const MyPoint& lhs, const MyPoint& rhs);
//      // Return 'true' if the specified 'lhs' and 'rhs' points have the same
//      // value, and 'false' otherwise.  Two points have the same value if
//      // they have the same x and y coordinates and the same color.
//..
// Representative (inline) implementations of these methods are shown below:
//..
//  // ========================================================================
//  //                      INLINE FUNCTION DEFINITIONS
//  // ========================================================================
//
//  // CREATORS
//  inline
//  MyPoint::MyPoint()
//  {
//  }
//
//  inline
//  MyPoint::MyPoint(short x, short y, Color color)
//  : d_x(x)
//  , d_y(y)
//  , d_color(color)
//  {
//  }
//
//  inline
//  MyPoint::~MyPoint()
//  {
//  }
//
//  // ...
//
//  // MANIPULATORS
//  // ...
//
//  // ACCESSORS
//  inline
//  Color MyPoint::color() const
//  {
//      return d_color;
//  }
//
//  inline
//  short MyPoint::x() const
//  {
//      return d_x;
//  }
//
//  inline
//  short MyPoint::y() const
//  {
//      return d_y;
//  }
//  // ...
//
//  template <class STREAM>
//  STREAM& MyPoint::bdexStreamIn(STREAM& stream, int version)
//  {
//      switch (version) {
//        case 1: {
//          stream.getInt16(d_x);           // input the x coordinate
//          stream.getInt16(d_y);           // input the y coordinate
//          char color;
//          stream.getInt8(color);          // input the color enum as one byte
//          d_color = static_cast<Color>(color);
//        } break;
//        default: {
//          stream.invalidate();
//        } break;
//      }
//      return stream;
//  }
//
//  // FREE OPERATORS
//  inline
//  bool operator==(const MyPoint& lhs, const MyPoint& rhs)
//  {
//      return lhs.x()     == rhs.x()
//          && lhs.y()     == rhs.y()
//          && lhs.color() == rhs.color();
//  }
//..
// Then, we will implement an extremely simple input stream that supports the
// BDEX documentation-only protocol.  For simplicity, we will use an externally
// managed buffer, and will only show a few methods needed for this example.
//..
//  // myinstream.h
//  // ...
//
// class MyInStream {
//     // This class implements a limited-size fixed-buffer input stream that
//     // partially conforms to the BDEX protocol for input streams.  This
//     // class is suitable for demonstration purposes only.
//
//     const char *d_buffer;  // input buffer, held but not owned
//     int         d_length;  // length of 'd_buffer' (bytes)
//     int         d_cursor;  // cursor (index into 'd_buffer')
//
//   public:
//     // CREATORS
//     MyInStream(const char *buffer, int length);
//         // Create an input stream using the specified 'buffer' having the
//         // specified 'length' (in bytes).
//
//     ~MyInStream();
//         // Destroy this input byte stream.
//
//     // MANIPULATORS
//     MyInStream& getVersion(int& version);
//         // Consume a version value from this input stream, store that value
//         // in the specified 'version', and return a reference to this
//         // stream.  ...
//
//     MyInStream& getInt32(int& value);
//         // Consume a 32-bit signed integer value from this input stream,
//         // store that value in the specified 'value', and return a reference
//         // to this stream.  ...
//
//     MyInStream& getInt16(short& value);
//         // Consume a 16-bit signed integer value from this input stream,
//         // store that value in the specified 'value', and return a reference
//         // to this stream.  ...
//
//     MyInStream& getInt8(char& value);
//         // Consume an 8-bit signed integer value from this input stream,
//         // store that value in the specified 'value', and return a reference
//         // to this stream.  ...
//
//     void invalidate();
//         // Put this input stream in an invalid state.  ...
//
//     // ACCESSORS
//     operator const void *() const;
//         // 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.
//
//     int cursor() const;
//         // Return the index of the next byte to be extracted from this
//         // stream.
//
//     bool isEmpty() const;
//          // Return 'true' if this stream is empty, and 'false' otherwise.
//          // Note that this function enables higher-level types to verify
//          // that, after successfully reading all expected data, no data
//          // remains.
//
//     int length() const;
//         // Return the total number of bytes stored in this stream.
// };
//
//..
// The relevant (inline) implementations are as follows.
//..
//  // ========================================================================
//  //                      INLINE FUNCTION DEFINITIONS
//  // ========================================================================
//
//  // CREATORS
//  inline
//  MyInStream::MyInStream(const char *buffer, int length)
//  : d_buffer(buffer)
//  , d_length(length)
//  , d_cursor(0)
//  {
//  }
//
//  inline
//  MyInStream::~MyInStream()
//  {
//  }
//
//  // MANIPULATORS
//
//  inline
//  MyInStream& MyInStream::getVersion(int& value)
//  {
//      value = static_cast<unsigned char>(d_buffer[d_cursor++]);
//      return *this;
//  }
//
//  inline
//  MyInStream& MyInStream::getInt32(int& value)
//  {
//      const unsigned char *buffer =
//                           reinterpret_cast<const unsigned char *>(d_buffer);
//      value = static_cast<int>((buffer[d_cursor    ] << 24U) |
//                               (buffer[d_cursor + 1] << 16U) |
//                               (buffer[d_cursor + 2] <<  8U) |
//                               (buffer[d_cursor + 3]       ));
//      d_cursor += 4;
//      return *this;
//  }
//
//  inline
//  MyInStream& MyInStream::getInt16(short& value)
//  {
//      const unsigned char *buffer =
//                           reinterpret_cast<const unsigned char *>(d_buffer);
//      value = static_cast<short>((buffer[d_cursor    ] <<  8) |
//                                 (buffer[d_cursor + 1]      ));
//      d_cursor += 2;
//      return *this;
//   }
//
//  inline
//  MyInStream& MyInStream::getInt8(char& value)
//  {
//      value = d_buffer[d_cursor];
//      d_cursor += 1;
//      return *this;
//  }
//
//  inline
//  void MyInStream::invalidate()
//  {
//      d_buffer = 0;
//  }
//
//  // ACCESSORS
//  inline
//  MyInStream::operator const void *() const
//  {
//      return d_cursor <= d_length ? d_buffer : 0;
//  }
//
//  inline
//  int MyInStream::cursor() const
//  {
//      return d_cursor;
//  }
//
//  inline
//  bool MyInStream::isEmpty() const
//  {
//      return d_cursor >= d_length;
//  }
//
//  inline
//  int MyInStream::length() const
//  {
//      return d_length;
//  }
//..
// Finally, use the above 'enum', point class, and input stream to illustrate
// 'bslx::InStreamFunctions' functionality.  This test code does not attempt to
// do anything more useful than reading values from a stream whose buffer was
// written "by hand" and confirming that the expected values were read
// correctly from the known byte pattern in the buffer.
//..
//  using bslx::InStreamFunctions::bdexStreamIn;
//
//  {
//      const int  EXP       = 0x0A0B0C0D;
//      const char buffer[4] = { 0xA, 0xB, 0xC, 0xD };  // 'int' (no version)
//      int        i         = 0;
//
//      MyInStream in1(buffer, 4);  // use the one buffer
//      bdexStreamIn(in1, i, 1);
//      assert(in1);  assert(EXP == i);
//
//      i = 0;                      // reset 'i'
//      MyInStream in2(buffer, 4);  // re-use 'buffer (no version)
//      bdexStreamIn(in2, i, 0);
//      assert(in2);  assert(EXP == i);
//  }
//
//  {
//      const MyPoint EXP(0, -1, BLUE);
//      const char buffer1[5] = { 0, 0, -1, -1, 2 };     // 'MyPoint' (no ver)
//      const char buffer2[6] = { 1, 0, 0, -1, -1, 2 };  // version, 'MyPoint'
//      MyPoint p1, p2;  // two default points
//
//      MyInStream in1(buffer1, 5);  // 'buffer1' has no version byte
//      bdexStreamIn(in1, p1, 1);
//      assert(in1);  assert(EXP == p1);
//
//      MyInStream in2(buffer2, 6);  // 'buffer2' *has* a version
//      int version;
//      in2.getVersion(version);
//      assert(1 == version);
//      bdexStreamIn(in2, p2, version);
//      assert(in2);  assert(EXP == p2);
//  }
//..

#include <bslscm_version.h>

#include <bslx_versionfunctions.h>

#include <bslmf_assert.h>
#include <bslmf_conditional.h>
#include <bslmf_isenum.h>

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

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

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bslmf_if.h>
#endif  // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

namespace BloombergLP {
namespace bslx {
                        // ===========================
                        // namespace InStreamFunctions
                        // ===========================

namespace InStreamFunctions {
    // This namespace facilitates unexternalization of all BDEX-compliant types
    // in a type-independent manner.  The unexternalization functions are
    // overloaded for fundamental types, enumeration types, 'bsl::string', and
    // 'bsl::vector'.  A compilation error will occur if the (template
    // parameter) 'VALUE_TYPE' of a non-overloaded method of
    // 'bslx::InStreamFunctions' does not support 'bdexStreamIn' (with the
    // appropriate signature).

                   // ======================================
                   // class InStreamFunctions_AccessorHelper
                   // ======================================

template <class STREAM>
struct InStreamFunctions_AccessorHelper {
    // This 'struct' provides a namespace for implementation helper functions
    // for this component.  They are not intended for use outside this
    // component.

    static STREAM& getArray(STREAM& stream, bool *result, int length);
    static STREAM& getArray(STREAM& stream, char *result, int length);
    static STREAM& getArray(STREAM& stream, signed char *result, int length);
    static STREAM& getArray(STREAM& stream, unsigned char *result, int length);
    static STREAM& getArray(STREAM& stream, short *result, int length);
    static STREAM& getArray(STREAM&         stream,
                            unsigned short *result,
                            int             length);
    static STREAM& getArray(STREAM& stream, int *result, int length);
    static STREAM& getArray(STREAM& stream, unsigned int *result, int length);
    static STREAM& getArray(STREAM&             stream,
                            bsls::Types::Int64 *result,
                            int                 length);
    static STREAM& getArray(STREAM&              stream,
                            bsls::Types::Uint64 *result,
                            int                  length);
    static STREAM& getArray(STREAM& stream, float *result, int length);
    static STREAM& getArray(STREAM& stream, double *result, int length);
        // Load into the specified 'result' the specified 'length' values read
        // from the specified 'stream', and return a reference to 'stream'.  If
        // 'stream' is initially invalid, '*result' is unchanged.  If 'stream'
        // becomes invalid during this operation, the contents of 'result' have
        // an undefined, but valid, state.

    template <class VALUE_TYPE, class ALLOC>
    static STREAM& getArray(STREAM&                         stream,
                            bsl::vector<VALUE_TYPE, ALLOC>& variable);
        // Assign to the specified 'variable' the
        // 'bsl::vector<VALUE_TYPE, ALLOC>' value read from the specified input
        // 'stream', and return a reference to 'stream'.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.
};

                             // =================
                             // struct IsEnumType
                             // =================

struct IsEnumType {
    // This 'struct', together with 'IsNotEnumType' (below), is used to
    // distinguish enumeration types from other types in function overload
    // resolution.  This 'struct' contains no interface or implementation by
    // design, and is meant for internal use only.
    };

                         // ====================
                         // struct IsNotEnumType
                         // ====================

    struct IsNotEnumType {
        // This 'struct', together with 'IsEnumType' (above), is used to
        // distinguish enumeration types from other types in function overload
        // resolution.  This 'struct' contains no interface or implementation
        // by design, and is meant for internal use only.
    };

    // PRIVATE CLASS METHODS
    template <class STREAM, class VALUE_TYPE>
    STREAM& bdexStreamInImp(STREAM&           stream,
                            VALUE_TYPE&       variable,
                            int               version,
                            const IsEnumType&);
        // Assign to the specified 'variable' the 'VALUE_TYPE' value read from
        // the specified input 'stream', and return a reference to 'stream'.
        // The specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  If 'version' is not
        // supported by 'VALUE_TYPE', 'variable' is unaltered and 'stream' is
        // invalidated, but otherwise unmodified.  If 'version' is supported
        // but 'stream' becomes invalid during this operation, 'variable' has
        // an undefined, but valid, state.  Note that this function is called
        // only for enumeration types and that this function is for internal
        // use only.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class VALUE_TYPE>
    STREAM& bdexStreamInImp(STREAM&              stream,
                            VALUE_TYPE&          variable,
                            int                  version,
                            const IsNotEnumType&);
        // Assign to the specified 'variable' the 'VALUE_TYPE' 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 by 'VALUE_TYPE', 'variable' is unaltered and 'stream' is
        // invalidated, but otherwise unmodified.  If 'version' is supported
        // but 'stream' becomes invalid during this operation, 'variable' has
        // an undefined, but valid, state.  Note that this function is for
        // internal use only.  See the 'bslx' package-level documentation for
        // more information on BDEX streaming of value-semantic types and
        // containers.

    // CLASS METHODS
    template <class STREAM, class VALUE_TYPE>
    STREAM& bdexStreamIn(STREAM& stream, VALUE_TYPE& variable);
        // Assign to the specified 'variable' the 'VALUE_TYPE' value read from
        // the specified input 'stream', and return a reference to 'stream'.
        // If 'stream' is initially invalid, this operation has no effect.  If
        // needed, first read the version information from the 'stream' and if
        // this version is not supported by 'VALUE_TYPE', 'stream' is
        // invalidated, but otherwise unmodified.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  Note that the version is only needed when the (template
        // parameter) 'VALUE_TYPE' is a 'bsl::vector' or a user-defined type.
        // See the 'bslx' package-level documentation for more information on
        // BDEX streaming of value-semantic types and containers.

    template <class STREAM, class VALUE_TYPE>
    STREAM& bdexStreamIn(STREAM& stream, VALUE_TYPE& variable, int version);
        // Assign to the specified 'variable' the 'VALUE_TYPE' 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 by 'VALUE_TYPE', 'variable' is unaltered and 'stream' is
        // invalidated, but otherwise unmodified.  If 'version' is supported
        // but 'stream' becomes invalid during this operation, 'variable' has
        // an undefined, but valid, state.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

                        /* overloads */

    template <class STREAM>
    STREAM& bdexStreamIn(STREAM& stream, bool& variable, int version = 0);
        // Assign to the specified 'variable' the 'bool' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // optionally specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  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, char& variable, int version = 0);
        // Assign to the specified 'variable' the 'char' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // optionally specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  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,
                         signed char& variable,
                         int          version = 0);
        // Assign to the specified 'variable' the 'signed char' value read from
        // the specified input 'stream', and return a reference to 'stream'.
        // The optionally specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  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,
                         unsigned char& variable,
                         int            version = 0);
        // Assign to the specified 'variable' the 'unsigned char' value read
        // from the specified input 'stream', and return a reference to
        // 'stream'.  The optionally specified 'version' is ignored.  If
        // 'stream' is initially invalid, this operation has no effect.  If
        // 'stream' becomes invalid during this operation, 'variable' has an
        // undefined, but valid, state.  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, short& variable, int version = 0);
        // Assign to the specified 'variable' the 'short' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // optionally specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  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,
                         unsigned short& variable,
                         int             version = 0);
        // Assign to the specified 'variable' the 'unsigned short' value read
        // from the specified input 'stream', and return a reference to
        // 'stream'.  The optionally specified 'version' is ignored.  If
        // 'stream' is initially invalid, this operation has no effect.  If
        // 'stream' becomes invalid during this operation, 'variable' has an
        // undefined, but valid, state.  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& variable, int version = 0);
        // Assign to the specified 'variable' the 'int' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // optionally specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  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,
                         unsigned int& variable,
                         int           version = 0);
        // Assign to the specified 'variable' the 'unsigned int' value read
        // from the specified input 'stream', and return a reference to
        // 'stream'.  The optionally specified 'version' is ignored.  If
        // 'stream' is initially invalid, this operation has no effect.  If
        // 'stream' becomes invalid during this operation, 'variable' has an
        // undefined, but valid, state.  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, long& variable, int version = 0);
        // Assign to the specified 'variable' the 32-bit 'int' value read from
        // the specified input 'stream', and return a reference to 'stream'.
        // The optionally specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  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,
                         unsigned long& variable,
                         int            version = 0);
        // Assign to the specified 'variable' the 32-bit 'unsigned int' value
        // read from the specified input 'stream', and return a reference to
        // 'stream'.  The optionally specified 'version' is ignored.  If
        // 'stream' is initially invalid, this operation has no effect.  If
        // 'stream' becomes invalid during this operation, 'variable' has an
        // undefined, but valid, state.  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,
                         bsls::Types::Int64& variable,
                         int                 version = 0);
        // Assign to the specified 'variable' the 'bsls::Types::Int64' value
        // read from the specified input 'stream', and return a reference to
        // 'stream'.  The optionally specified 'version' is ignored.  If
        // 'stream' is initially invalid, this operation has no effect.  If
        // 'stream' becomes invalid during this operation, 'variable' has an
        // undefined, but valid, state.  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,
                         bsls::Types::Uint64& variable,
                         int                  version = 0);
        // Assign to the specified 'variable' the 'bsls::Types::Uint64' value
        // read from the specified input 'stream', and return a reference to
        // 'stream'.  The optionally specified 'version' is ignored.  If
        // 'stream' is initially invalid, this operation has no effect.  If
        // 'stream' becomes invalid during this operation, 'variable' has an
        // undefined, but valid, state.  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, float& variable, int version = 0);
        // Assign to the specified 'variable' the 'float' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // optionally specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  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, double& variable, int version = 0);
        // Assign to the specified 'variable' the 'double' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // optionally specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  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,
                         bsl::string& variable,
                         int          version = 0);
        // Assign to the specified 'variable' the 'bsl::string' value read from
        // the specified input 'stream', and return a reference to 'stream'.
        // The optionally specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  See the 'bslx' package-level documentation for
        // more information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                   stream,
                         bsl::vector<char, ALLOC>& variable,
                         int                       version);
        // Assign to the specified 'variable' the 'bsl::vector<char, ALLOC>'
        // value read from the specified input 'stream', and return a reference
        // to 'stream'.  The specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  See the 'bslx' package-level documentation for
        // more information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                          stream,
                         bsl::vector<signed char, ALLOC>& variable,
                         int                              version);
        // Assign to the specified 'variable' the
        // 'bsl::vector<signed char, ALLOC>' value read from the specified
        // input 'stream', and return a reference to 'stream'.  The specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'stream' becomes invalid during this
        // operation, 'variable' has an undefined, but valid, state.  See the
        // 'bslx' package-level documentation for more information on BDEX
        // streaming of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                            stream,
                         bsl::vector<unsigned char, ALLOC>& variable,
                         int                                version);
        // Assign to the specified 'variable' the
        // 'bsl::vector<unsigned char, ALLOC>' value read from the specified
        // input 'stream', and return a reference to 'stream'.  The specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'stream' becomes invalid during this
        // operation, 'variable' has an undefined, but valid, state.  See the
        // 'bslx' package-level documentation for more information on BDEX
        // streaming of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                    stream,
                         bsl::vector<short, ALLOC>& variable,
                         int                        version);
        // Assign to the specified 'variable' the 'bsl::vector<short, ALLOC>'
        // value read from the specified input 'stream', and return a reference
        // to 'stream'.  The specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  See the 'bslx' package-level documentation for
        // more information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                             stream,
                         bsl::vector<unsigned short, ALLOC>& variable,
                         int                                 version);
        // Assign to the specified 'variable' the
        // 'bsl::vector<unsigned short, ALLOC>' value read from the specified
        // input 'stream', and return a reference to 'stream'.  The specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'stream' becomes invalid during this
        // operation, 'variable' has an undefined, but valid, state.  See the
        // 'bslx' package-level documentation for more information on BDEX
        // streaming of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                  stream,
                         bsl::vector<int, ALLOC>& variable,
                         int                      version);
        // Assign to the specified 'variable' the 'bsl::vector<int, ALLOC>'
        // value read from the specified input 'stream', and return a reference
        // to 'stream'.  The specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  See the 'bslx' package-level documentation for
        // more information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                           stream,
                         bsl::vector<unsigned int, ALLOC>& variable,
                         int                               version);
        // Assign to the specified 'variable' the
        // 'bsl::vector<unsigned int, ALLOC>' value read from the specified
        // input 'stream', and return a reference to 'stream'.  The specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'stream' becomes invalid during this
        // operation, 'variable' has an undefined, but valid, state.  See the
        // 'bslx' package-level documentation for more information on BDEX
        // streaming of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                                 stream,
                         bsl::vector<bsls::Types::Int64, ALLOC>& variable,
                         int                                     version);
        // Assign to the specified 'variable' the
        // 'bsl::vector<bsls::Types::Int64, ALLOC>' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  If 'stream' becomes invalid during
        // this operation, 'variable' has an undefined, but valid, state.  See
        // the 'bslx' package-level documentation for more information on BDEX
        // streaming of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                                  stream,
                         bsl::vector<bsls::Types::Uint64, ALLOC>& variable,
                         int                                      version);
        // Assign to the specified 'variable' the
        // 'bsl::vector<bsls::Types::Uint64, ALLOC>' value read from the
        // specified input 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  If 'stream' becomes invalid during
        // this operation, 'variable' has an undefined, but valid, state.  See
        // the 'bslx' package-level documentation for more information on BDEX
        // streaming of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                    stream,
                         bsl::vector<float, ALLOC>& variable,
                         int                        version);
        // Assign to the specified 'variable' the 'bsl::vector<float, ALLOC>'
        // value read from the specified input 'stream', and return a reference
        // to 'stream'.  The specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  See the 'bslx' package-level documentation for
        // more information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                     stream,
                         bsl::vector<double, ALLOC>& variable,
                         int                         version);
        // Assign to the specified 'variable' the 'bsl::vector<double, ALLOC>'
        // value read from the specified input 'stream', and return a reference
        // to 'stream'.  The specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  If 'stream'
        // becomes invalid during this operation, 'variable' has an undefined,
        // but valid, state.  See the 'bslx' package-level documentation for
        // more information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class VALUE_TYPE, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                         stream,
                         bsl::vector<VALUE_TYPE, ALLOC>& variable);
        // Assign to the specified 'variable' the
        // 'bsl::vector<VALUE_TYPE, ALLOC>' value read from the specified input
        // 'stream', and return a reference to 'stream'.  If 'stream' is
        // initially invalid, this operation has no effect.  First read the
        // version information from the 'stream' and if this version is not
        // supported by 'VALUE_TYPE' and the vector is not empty, 'stream' is
        // invalidated, but otherwise unmodified.  If 'stream' becomes invalid
        // during this operation, 'variable' has an undefined, but valid,
        // state.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

    template <class STREAM, class VALUE_TYPE, class ALLOC>
    STREAM& bdexStreamIn(STREAM&                         stream,
                         bsl::vector<VALUE_TYPE, ALLOC>& variable,
                         int                             version);
        // Assign to the specified 'variable' the
        // 'bsl::vector<VALUE_TYPE, ALLOC>' 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 by
        // 'VALUE_TYPE' and the vector is not empty, 'stream' is invalidated,
        // but otherwise unmodified.  If 'stream' becomes invalid during this
        // operation, 'variable' has an undefined, but valid, state.  See the
        // 'bslx' package-level documentation for more information on BDEX
        // streaming of value-semantic types and containers.

}  // close namespace InStreamFunctions

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

                   // --------------------------------------
                   // class InStreamFunctions_AccessorHelper
                   // --------------------------------------

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                               STREAM&  stream,
                                                               bool    *result,
                                                               int      length)
{
    return stream.getArrayInt8(reinterpret_cast<char*>(result), length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                               STREAM&  stream,
                                                               char    *result,
                                                               int      length)
{
    return stream.getArrayInt8(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                           STREAM&      stream,
                                                           signed char *result,
                                                           int          length)
{
    return stream.getArrayInt8(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                         STREAM&        stream,
                                                         unsigned char *result,
                                                         int            length)
{
    return stream.getArrayUint8(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                               STREAM&  stream,
                                                               short   *result,
                                                               int      length)
{
    return stream.getArrayInt16(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                        STREAM&         stream,
                                                        unsigned short *result,
                                                        int             length)
{
    return stream.getArrayUint16(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                               STREAM&  stream,
                                                               int     *result,
                                                               int      length)
{
    return stream.getArrayInt32(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                          STREAM&       stream,
                                                          unsigned int *result,
                                                          int           length)
{
    return stream.getArrayUint32(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                    STREAM&             stream,
                                                    bsls::Types::Int64 *result,
                                                    int                 length)
{
    return stream.getArrayInt64(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                   STREAM&              stream,
                                                   bsls::Types::Uint64 *result,
                                                   int                  length)
{
    return stream.getArrayUint64(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                               STREAM&  stream,
                                                               float   *result,
                                                               int      length)
{
    return stream.getArrayFloat32(result, length);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                                               STREAM&  stream,
                                                               double  *result,
                                                               int      length)
{
    return stream.getArrayFloat64(result, length);
}

template <class STREAM>
template <class VALUE_TYPE, class ALLOC>
STREAM& InStreamFunctions::InStreamFunctions_AccessorHelper<STREAM>::getArray(
                                      STREAM&                         stream,
                                      bsl::vector<VALUE_TYPE, ALLOC>& variable)
{
    int length = 0;
    stream.getLength(length);

    if (!stream) {
        return stream;                                                // RETURN
    }

    // 'length' could be corrupt or invalid, so we limit the initial
    // 'resize' to something that can accommodate the preponderance of
    // vectors that will arise in practice.  The remaining portion of a
    // vector longer than 16M is read in via a second pass.
    enum {
        k_INITIAL_ALLOCATION_COUNT = 16 * 1024 * 1024 / sizeof(VALUE_TYPE)
    };

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

    variable.resize(initialLength);

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

    STREAM& result = getArray(stream, &variable[0], initialLength);

    if (!!stream && length > initialLength) {
        variable.resize(length);
        return getArray(stream,
                        &variable[initialLength],
                        length - initialLength);                      // RETURN
    }

    return result;
}


                         // ---------------------------
                         // namespace InStreamFunctions
                         // ---------------------------

template <class STREAM, class VALUE_TYPE>
inline
STREAM& InStreamFunctions::bdexStreamInImp(STREAM&           stream,
                                           VALUE_TYPE&       variable,
                                           int /* version */,
                                           const IsEnumType&)
{
    int enumVariable = 0;
    stream.getInt32(enumVariable);

    if (stream) {
        variable = static_cast<VALUE_TYPE>(enumVariable);
    }
    return stream;
}

template <class STREAM, class VALUE_TYPE>
inline
STREAM& InStreamFunctions::bdexStreamInImp(STREAM&              stream,
                                           VALUE_TYPE&          variable,
                                           int                  version,
                                           const IsNotEnumType&)
{
    // A compilation error indicating the next line of code implies the class
    // of 'VALUE_TYPE' does not support the 'bdexStreamIn' method.

    return variable.bdexStreamIn(stream, version);
}

template <class STREAM, class VALUE_TYPE>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream, VALUE_TYPE& variable)
{
    using VersionFunctions::maxSupportedBdexVersion;

    // Determine if the 'VALUE_TYPE' requires a version to be externalized
    // using an arbitrary value for 'versionSelector'.

    int version = maxSupportedBdexVersion(&variable, 0);
    if (VersionFunctions::k_NO_VERSION != version) {
        stream.getVersion(version);

        if (!stream) {
            return stream;                                            // RETURN
        }
    }

    return bdexStreamIn(stream, variable, version);
}

template <class STREAM, class VALUE_TYPE>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&     stream,
                                        VALUE_TYPE& variable,
                                        int         version)
{
    typedef typename bsl::conditional<bslmf::IsEnum<VALUE_TYPE>::value,
                                      IsEnumType,
                                      IsNotEnumType>::type dummyType;
    return bdexStreamInImp(stream, variable, version, dummyType());
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream,
                                        bool&   variable,
                                        int  /* version */)
{
    char temp = 0;

    stream.getInt8(temp);
    variable = static_cast<bool>(temp);

    return stream;
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream,
                                        char&   variable,
                                        int  /* version */)
{
    return stream.getInt8(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&      stream,
                                        signed char& variable,
                                        int       /* version */)
{
    return stream.getInt8(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&        stream,
                                        unsigned char& variable,
                                        int         /* version */)
{
    return stream.getUint8(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream,
                                        short&  variable,
                                        int  /* version */)
{
    return stream.getInt16(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&         stream,
                                        unsigned short& variable,
                                        int          /* version */)
{
    return stream.getUint16(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream,
                                        int&    variable,
                                        int  /* version */)
{
    return stream.getInt32(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&       stream,
                                        unsigned int& variable,
                                        int        /* version */)
{
    return stream.getUint32(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream,
                                        long&   variable,
                                        int  /* version */)
{
    int temp = 0;  // 'long' and 'int' may not be the same size.
    stream.getInt32(temp);
    variable = temp;
    return stream;
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&        stream,
                                        unsigned long& variable,
                                        int         /* version */)
{
    unsigned int temp = 0;  // 'unsigned long' and 'unsigned int' may not be
                            // the same size.
    stream.getUint32(temp);
    variable = temp;
    return stream;
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&             stream,
                                        bsls::Types::Int64& variable,
                                        int              /* version */)
{
    return stream.getInt64(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&              stream,
                                        bsls::Types::Uint64& variable,
                                        int               /* version */)
{
    return stream.getUint64(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream,
                                        float&  variable,
                                        int  /* version */)
{
    return stream.getFloat32(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM& stream,
                                        double& variable,
                                        int  /* version */)
{
    return stream.getFloat64(variable);
}

template <class STREAM>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&      stream,
                                        bsl::string& variable,
                                        int       /* version */)
{
    return stream.getString(variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&                   stream,
                                        bsl::vector<char, ALLOC>& variable,
                                        int                    /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(
                                   STREAM&                          stream,
                                   bsl::vector<signed char, ALLOC>& variable,
                                   int                           /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(
                                 STREAM&                            stream,
                                 bsl::vector<unsigned char, ALLOC>& variable,
                                 int                             /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&                    stream,
                                        bsl::vector<short, ALLOC>& variable,
                                        int                     /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(
                                STREAM&                             stream,
                                bsl::vector<unsigned short, ALLOC>& variable,
                                int                              /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&                  stream,
                                        bsl::vector<int, ALLOC>& variable,
                                        int                   /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(
                                  STREAM&                           stream,
                                  bsl::vector<unsigned int, ALLOC>& variable,
                                  int                            /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(
                            STREAM&                                 stream,
                            bsl::vector<bsls::Types::Int64, ALLOC>& variable,
                            int                                  /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(
                           STREAM&                                  stream,
                           bsl::vector<bsls::Types::Uint64, ALLOC>& variable,
                           int                                   /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&                    stream,
                                        bsl::vector<float, ALLOC>& variable,
                                        int                     /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(STREAM&                     stream,
                                        bsl::vector<double, ALLOC>& variable,
                                        int                      /* version */)
{
    return InStreamFunctions_AccessorHelper<STREAM>::getArray(stream,
                                                              variable);
}

template <class STREAM, class VALUE_TYPE, class ALLOC>
inline
STREAM& InStreamFunctions::bdexStreamIn(
                                      STREAM&                         stream,
                                      bsl::vector<VALUE_TYPE, ALLOC>& variable)
{
    int version = 0;
    stream.getVersion(version);

    if (!stream) {
        return stream;                                                // RETURN
    }

    return bdexStreamIn(stream, variable, version);
}

template <class STREAM, class VALUE_TYPE, class ALLOC>
STREAM& InStreamFunctions::bdexStreamIn(
                                      STREAM&                         stream,
                                      bsl::vector<VALUE_TYPE, ALLOC>& variable,
                                      int                             version)
{
    typedef typename bsl::vector<VALUE_TYPE, ALLOC>::iterator Iterator;

    int length = 0;
    stream.getLength(length);

    if (!stream) {
        return stream;                                                // RETURN
    }

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

    enum {
        k_INITIAL_ALLOCATION_COUNT =
            16 * 1024 * 1024 / sizeof(VALUE_TYPE)
    };

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

    variable.resize(initialLength);

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

    for (Iterator it = variable.begin(); it != variable.end(); ++it) {
        bdexStreamIn(stream, *it, version);


        if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!stream)) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            return stream;                                            // RETURN
        }
    }

    if (length > initialLength) {
        variable.resize(length);

        for (Iterator it = variable.begin() + initialLength;
             it != variable.end();
             ++it) {
            bdexStreamIn(stream, *it, version);

            if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!stream)) {
                BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
                return stream;                                        // RETURN
            }
        }
    }

    return stream;
}

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