// bslx_outstreamfunctions.h                                          -*-C++-*-
#ifndef INCLUDED_BSLX_OUTSTREAMFUNCTIONS
#define INCLUDED_BSLX_OUTSTREAMFUNCTIONS

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

//@PURPOSE: Facilitate uniform externalization of user and fundamental types.
//
//@CLASSES:
//  bslx::OutStreamFunctions: namespace for BDEX externalization functions
//
//@SEE_ALSO: bslx_instreamfunctions, bslx_versionfunctions
//
//@DESCRIPTION: This component provides a namespace,
// 'bslx::OutStreamFunctions', that facilitates uniform support for BDEX
// externalization 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::OutStreamFunctions' facilitates client externalization
// of objects in a uniform, type-independent manner.  It contains the
// 'bdexStreamOut' function that externalizes objects of all BDEX-compliant
// types.  This function externalizes the specified 'object' in the specified
// 'version'.  The 'bdexStreamOut' function is overloaded for fundamental
// types, enumeration types, 'bsl::string', and 'bsl::vector'.  Note that,
// excluding 'bsl::vector', version information is never written to the stream
// while externalizing these types.
//
// By default, objects of enumeration type are streamed out as 32-bit 'int'
// values.  Users can override this behavior by providing overloads of the
// 'OutStreamFunctions::bdexStreamOut' function in the enumeration's namespace
// for their enumeration types.  The general form of this overload is:
//..
//  template <class STREAM>
//  STREAM& bdexStreamOut(STREAM& stream, const MyEnum& value, int version)
//  {
//      using bslx::OutStreamFunctions::bdexStreamOut;
//
//      // Code to stream out objects of 'MyEnum' type.
//
//      return stream;
//  }
//..
// For value-semantic types that support the BDEX protocol, the free function
// 'bdexStreamOut' calls the 'bdexStreamOut' member function for that type.
//
///Component Design, Anticipated Usage, and the BDEX Contract
///----------------------------------------------------------
// 'bslx_outstreamfunctions' is an integral part of the BDEX externalization
// 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_outstreamfunctions' 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_outstreamfunctions' 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
// output stream 'put' methods directly when implementing the required
// 'bdexStreamOut' 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 'put' methods.  For example, if a
// type has as its value one 'int' data member:
//..
//  int d_value;
//..
// then the implementation of the 'bdexStreamOut' method can contain:
//..
//  stream.putInt32(d_value);
//..
// However, if the data member is of (template parameter) 'TYPE':
//..
//  TYPE d_value;
//..
// then the implementation of the 'bdexStreamOut' method must rely on the
// 'bslx::OutStreamFunctions' implementation to output the value:
//..
//  using bslx::OutStreamFunctions::bdexStreamOut;
//  bdexStreamOut(stream, d_value, 1);
//..
// This call will resolve to the correct sequence of 'put' calls no matter
// whether '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 'TYPE' is provided additional version formats.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Using 'bslx::OutStreamFunctions' to Externalize 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 two separate example
// "components": a value-semantic point object, and an 'enum'.  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 output byte
// pattern somewhat easier for the reader of this example to recognize when the
// output 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
//      static int maxSupportedBdexVersion(int versionSelector);
//          // 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.
//
//      // 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
//      int x() const;
//          // Return the x coordinate of this point.
//
//      int y() const;
//          // Return the y coordinate of this point.
//
//      Color color() const;
//          // Return the enumerated color of this point.
//
//      template <class STREAM>
//      STREAM& bdexStreamOut(STREAM& stream, int version) 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.
//  };
//
//  // 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
//  // ========================================================================
//
//  // CLASS METHODS
//  inline
//  int MyPoint::maxSupportedBdexVersion(int versionSelector)
//  {
//      if (versionSelector >= 20131201) {
//          return 2;
//      }
//      return 1;
//  }
//
//  // CREATORS
//  inline
//  MyPoint::MyPoint(short x, short y, Color color)
//  : d_x(x)
//  , d_y(y)
//  , d_color(color)
//  {
//  }
//
//  inline
//  MyPoint::~MyPoint()
//  {
//  }
//
//  // ...
//
//  // MANIPULATORS
//  // ...
//
//  // ACCESSORS
//  inline
//  int MyPoint::x() const
//  {
//      return d_x;
//  }
//
//  // ...
//
//  template <class STREAM>
//  STREAM& MyPoint::bdexStreamOut(STREAM& stream, int version) const
//  {
//      switch (version) {
//        case 1: {
//          stream.putInt16(d_x);          // output the x coordinate
//          stream.putInt16(d_y);          // output the y coordinate
//          stream.putInt8(static_cast<char>(d_color));
//                                         // output the color enum as one byte
//        } 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 output stream that supports the
// BDEX documentation-only protocol.  For simplicity, we will use a fixed-size
// buffer (usually a bad idea in any event, and more so here since the
// implementation knows the buffer size, but makes no effort to prevent
// overwriting that buffer), and will only show a few methods needed for this
// example.  See other 'bslx' stream components for examples of
// properly-designed BDEX streams.
//..
//  // myoutstream.h
//  // ...
//
//  class MyOutStream {
//      // This class implements a limited-size fixed-buffer output stream that
//      // partially conforms to the BDEX protocol for output streams.  This
//      // class is suitable for demonstration purposes only.
//
//      char d_buffer[1000]; // externalized values stored as contiguous bytes
//
//      int  d_length;       // length of data in 'd_buffer' (in bytes)
//
//      bool d_validFlag;    // stream validity flag; 'true' if stream is in
//                           // valid state, 'false' otherwise
//
//    public:
//      // CREATORS
//      MyOutStream();
//          // Create an empty output stream of limited, fixed capacity.  Note
//          // that this object is suitable for demonstration purposes only.
//
//      ~MyOutStream();
//         // Destroy this output stream.
//
//      // MANIPULATORS
//      void invalidate();
//          // 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.
//
//      MyOutStream& putVersion(int version);
//          // Write to this stream the one-byte, two's complement integer
//          // comprised of the least-significant one byte of the specified
//          // 'version', and return a reference to this stream.
//
//      MyOutStream& putInt32(int value);
//          // Write to this stream the four-byte, two's complement integer (in
//          // network byte order) comprised of the least-significant four
//          // bytes of the specified 'value' (in host byte order), and return
//          // a reference to this stream.
//
//      MyOutStream& putInt16(int value);
//          // Write to this stream the two-byte, two's complement integer
//          // (in network byte order) comprised of the least-significant two
//          // bytes of the specified 'value' (in host byte order), and return
//          // a reference to this stream.
//
//      MyOutStream& putInt8(int value);
//          // Write to this stream the one-byte, two's complement integer
//          // comprised of the least-significant one byte of the specified
//          // 'value', and return a reference to this stream.
//
//      void removeAll();
//          // Remove all content in this stream.
//
//      // ACCESSORS
//      const char *data() const;
//          // Return the address of the contiguous, non-modifiable internal
//          // memory buffer of this stream.  The address will remain valid as
//          // long as this stream is not destroyed or modified.  The behavior
//          // of accessing elements outside the range
//          // '[ data() .. data() + (length() - 1) ]' is undefined.
//
//      int length() const;
//          // Return the number of bytes in this stream.
//  };
//
//  // FREE OPERATORS
//  inline
//  bsl::ostream& operator<<(bsl::ostream&      stream,
//                           const MyOutStream& object);
//      // Write the specified 'object' to the specified output 'stream' in
//      // some reasonable (multi-line) format, and return a reference to
//      // 'stream'.
//..
// The relevant (inline) implementations are as follows.
//..
//  // ========================================================================
//  //                      INLINE FUNCTION DEFINITIONS
//  // ========================================================================
//
//  // CREATORS
//  inline
//  MyOutStream::MyOutStream()
//  : d_length(0)
//  , d_validFlag(true)
//  {
//  }
//
//  inline
//  MyOutStream::~MyOutStream()
//  {
//  }
//
//  // MANIPULATORS
//  inline
//  void MyOutStream::invalidate()
//  {
//      d_validFlag = false;
//  }
//
//  inline
//  MyOutStream& MyOutStream::putVersion(int value)
//  {
//      d_buffer[d_length] = static_cast<char>(value);
//      ++d_length;
//      return *this;
//  }
//
//  inline
//  MyOutStream& MyOutStream::putInt32(int value)
//  {
//      d_buffer[d_length + 0] = static_cast<char>((value >> 24) & 0xff);
//      d_buffer[d_length + 1] = static_cast<char>((value >> 16) & 0xff);
//      d_buffer[d_length + 2] = static_cast<char>((value >>  8) & 0xff);
//      d_buffer[d_length + 3] = static_cast<char>((value >>  0) & 0xff);
//      d_length += 4;
//      return *this;
//  }
//
//  inline
//  MyOutStream& MyOutStream::putInt16(int value)
//  {
//      d_buffer[d_length + 0] = static_cast<char>((value >> 8) & 0xff);
//      d_buffer[d_length + 1] = static_cast<char>((value >> 0) & 0xff);
//      d_length += 2;
//      return *this;
//  }
//
//  inline
//  MyOutStream& MyOutStream::putInt8(int value)
//  {
//      d_buffer[d_length] = static_cast<char>(value);
//      d_length += 1;
//      return *this;
//  }
//
//  inline
//  void MyOutStream::removeAll()
//  {
//      d_length = 0;
//  }
//
//  // ACCESSORS
//  inline
//  const char *MyOutStream::data() const
//  {
//      return static_cast<const char *>(d_buffer);
//  }
//
//  inline
//  int MyOutStream::length() const
//  {
//      return d_length;
//  }
//..
// Finally, use the above 'enum', point class, and output stream to illustrate
// 'bslx::OutStreamFunctions' functionality.  This test code does not attempt
// to do anything more useful than writing known values to a stream and
// confirming that the expected byte pattern was in fact written.
//..
//  int             i     = 168496141;  // byte pattern 0a 0b 0c 0d
//  Color           color = BLUE;       // byte pattern 02
//  MyPoint         p(0, -1, color);    // byte pattern 00 00 ff ff 02
//
//  using bslx::OutStreamFunctions::bdexStreamOut;
//
//  MyOutStream out;
//  assert(0 == out.length());
//
//  bdexStreamOut(out, i, 1);
//  assert(4 == out.length());
//  assert(0 == bsl::memcmp(out.data(), "\x0a\x0b\x0c\x0d", out.length()));
//
//  out.removeAll();
//  assert(0 == out.length());
//
//  bdexStreamOut(out, i, 0);
//  assert(4 == out.length());
//  assert(0 == bsl::memcmp(out.data(), "\x0a\x0b\x0c\x0d", out.length()));
//
//  out.removeAll();
//  assert(0 == out.length());
//
//  bdexStreamOut(out, color, 1);
//  assert(4 == out.length());
//  assert(0 == bsl::memcmp(out.data(), "\x00\x00\x00\x02", out.length()));
//
//  out.removeAll();
//  assert(0 == out.length());
//
//  bdexStreamOut(out, color, 0);
//  assert(4 == out.length());
//  assert(0 == bsl::memcmp(out.data(), "\x00\x00\x00\x02", out.length()));
//
//  out.removeAll();
//  assert(0 == out.length());
//
//  bdexStreamOut(out, p, 1);
//  assert(5 == out.length());
//  assert(0 == bsl::memcmp(out.data(), "\x00\x00\xff\xff\x02", out.length()));
//..

#include <bslscm_version.h>

#include <bslx_versionfunctions.h>

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

#include <bsls_types.h>

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

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

namespace BloombergLP {
namespace bslx {

                         // ============================
                         // namespace OutStreamFunctions
                         // ============================

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

                         // =================
                         // 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 TYPE>
    STREAM& bdexStreamOutImp(STREAM&           stream,
                             const TYPE&       value,
                             int               version,
                             const IsEnumType&);
        // Write the specified 'value' to the specified output 'stream' as a
        // 32-bit 'int', and return a reference to 'stream'.  The specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  Note that this function is called only for
        // enumeration types and that if 'value' is outside the range of an
        // 'int32_t' the externalization will be lossy.  Also 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.

    template <class STREAM, class TYPE>
    STREAM& bdexStreamOutImp(STREAM&              stream,
                             const TYPE&          value,
                             int                  version,
                             const IsNotEnumType&);
        // Write the specified 'value', 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 by 'TYPE', 'stream' is
        // invalidated, but otherwise unmodified.  Note that 'version' is not
        // written to 'stream'.  Also 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 TYPE>
    STREAM& bdexStreamOut(STREAM& stream, const TYPE& value);
        // Write the specified 'value' to the specified output 'stream', and
        // return a reference to 'stream'.  If 'stream' is initially invalid,
        // this operation has no effect.  If needed, first write the computed
        // version information to the 'stream' and if this version is not
        // supported by 'TYPE', 'stream' is invalidated.  Note that the version
        // is only needed when the (template parameter) '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 TYPE>
    STREAM& bdexStreamOut(STREAM& stream, const TYPE& value, int version);
        // Write the specified 'value', 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 by 'TYPE', '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.

                       /* overloads */

    template <class STREAM>
    STREAM& bdexStreamOut(STREAM& stream, const bool& value, int version = 0);
        // Write the specified 'bool' 'value' to the specified output 'stream',
        // and return a reference to 'stream'.  The optionally specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  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, const char& value, int version = 0);
        // Write the specified 'char' 'value' to the specified output 'stream',
        // and return a reference to 'stream'.  The optionally specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  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,
                          const signed char& value,
                          int                version = 0);
        // Write the specified 'signed char' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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,
                          const unsigned char& value,
                          int                  version = 0);
        // Write the specified 'unsigned char' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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,
                          const short& value,
                          int          version = 0);
        // Write the specified 'short' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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,
                          const unsigned short& value,
                          int                   version = 0);
        // Write the specified 'unsigned short' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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, const int& value, int version = 0);
        // Write the specified 'int' 'value' to the specified output 'stream',
        // and return a reference to 'stream'.  The optionally specified
        // 'version' is ignored.  If 'stream' is initially invalid, this
        // operation has no effect.  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,
                          const unsigned int& value,
                          int                 version = 0);
        // Write the specified 'unsigned int' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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, const long& value, int version = 0);
        // Write the specified 'long' 'value' to the specified output 'stream'
        // as a 32-bit 'int', and return a reference to 'stream'.  The
        // optionally specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  Note that for platforms
        // where 'long' is not equivalent to 'int32_t', this operation may be
        // lossy.  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,
                          const unsigned long& value,
                          int                  version = 0);
        // Write the specified 'unsigned long' 'value' to the specified output
        // 'stream' as a 32-bit 'unsigned int', and return a reference to
        // 'stream'.  The optionally specified 'version' is ignored.  If
        // 'stream' is initially invalid, this operation has no effect.  Note
        // that for platforms where 'unsigned long' is not equivalent to
        // 'uint32_t', this operation may be lossy.  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,
                          const bsls::Types::Int64& value,
                          int                       version = 0);
        // Write the specified 'bsls::Types::Int64' 'value' to the specified
        // output 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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,
                          const bsls::Types::Uint64& value,
                          int                        version = 0);
        // Write the specified 'bsls::Types::Uint64' 'value' to the specified
        // output 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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, const float& value, int version = 0);
        // Write the specified 'float' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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,
                          const double& value,
                          int           version = 0);
        // Write the specified 'double' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  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,
                          const bsl::string& value,
                          int                version = 0);
        // Write the specified 'bsl::string' 'value' to the specified output
        // 'stream', and return a reference to 'stream'.  The optionally
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                         stream,
                          const bsl::vector<char, ALLOC>& value,
                          int                             version);
        // Write the specified 'bsl::vector<char, ALLOC>' 'value' to the
        // specified output 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                                stream,
                          const bsl::vector<signed char, ALLOC>& value,
                          int                                    version);
        // Write the specified 'bsl::vector<signed char, ALLOC>' 'value' to the
        // specified output 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                                  stream,
                          const bsl::vector<unsigned char, ALLOC>& value,
                          int                                      version);
        // Write the specified 'bsl::vector<unsigned char, ALLOC>' 'value' to
        // the specified output 'stream', and return a reference to 'stream'.
        // The specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                          stream,
                          const bsl::vector<short, ALLOC>& value,
                          int                              version);
        // Write the specified 'bsl::vector<short, ALLOC>' 'value' to the
        // specified output 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                                   stream,
                          const bsl::vector<unsigned short, ALLOC>& value,
                          int                                       version);
        // Write the specified 'bsl::vector<unsigned short, ALLOC>' 'value' to
        // the specified output 'stream', and return a reference to 'stream'.
        // The specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                        stream,
                          const bsl::vector<int, ALLOC>& value,
                          int                            version);
        // Write the specified 'bsl::vector<int, ALLOC>' 'value' to the
        // specified output 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                                 stream,
                          const bsl::vector<unsigned int, ALLOC>& value,
                          int                                     version);
        // Write the specified 'bsl::vector<unsigned int, ALLOC>' 'value' to
        // the specified output 'stream', and return a reference to 'stream'.
        // The specified 'version' is ignored.  If 'stream' is initially
        // invalid, this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(
                        STREAM&                                       stream,
                        const bsl::vector<bsls::Types::Int64, ALLOC>& value,
                        int                                           version);
        // Write the specified 'bsl::vector<bsls::Types::Int64, ALLOC>' 'value'
        // to the specified output 'stream', and return a reference to
        // 'stream'.  The specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  See the 'bslx'
        // package-level documentation for more information on BDEX streaming
        // of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(
                       STREAM&                                        stream,
                       const bsl::vector<bsls::Types::Uint64, ALLOC>& value,
                       int                                            version);
        // Write the specified 'bsl::vector<bsls::Types::Uint64, ALLOC>'
        // 'value' to the specified output 'stream', and return a reference to
        // 'stream'.  The specified 'version' is ignored.  If 'stream' is
        // initially invalid, this operation has no effect.  See the 'bslx'
        // package-level documentation for more information on BDEX streaming
        // of value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                          stream,
                          const bsl::vector<float, ALLOC>& value,
                          int                              version);
        // Write the specified 'bsl::vector<float, ALLOC>' 'value' to the
        // specified output 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                           stream,
                          const bsl::vector<double, ALLOC>& value,
                          int                               version);
        // Write the specified 'bsl::vector<double, ALLOC>' 'value' to the
        // specified output 'stream', and return a reference to 'stream'.  The
        // specified 'version' is ignored.  If 'stream' is initially invalid,
        // this operation has no effect.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    template <class STREAM, class TYPE, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                         stream,
                          const bsl::vector<TYPE, ALLOC>& value);
        // Write the specified 'bsl::vector<TYPE, ALLOC>' 'value' to the
        // specified output 'stream', and return a reference to 'stream'.  If
        // 'stream' is initially invalid, this operation has no effect.  If
        // needed, first write the computed version information to the 'stream'
        // and if this version is not supported by 'TYPE' and the vector is not
        // empty, 'stream' is invalidated.  Note that the version is only
        // needed when the (template parameter) '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 TYPE, class ALLOC>
    STREAM& bdexStreamOut(STREAM&                         stream,
                          const bsl::vector<TYPE, ALLOC>& value,
                          int                             version);
        // Write the specified 'bsl::vector<TYPE, ALLOC>' 'value', 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 by
        // 'TYPE' and the vector is not empty, 'stream' is invalidated, but
        // otherwise unmodified.  Note that the specified 'TYPE' might not
        // require a 'version' to be serialized and 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.

}  // close namespace OutStreamFunctions

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

                         // ----------------------------
                         // namespace OutStreamFunctions
                         // ----------------------------

template <class STREAM, class TYPE>
inline
STREAM& OutStreamFunctions::bdexStreamOutImp(STREAM&           stream,
                                             const TYPE&       value,
                                             int            /* version */,
                                             const IsEnumType&)
{
    // A compilation error indicating the next line of code implies the 'TYPE'
    // cannot be represented as a 32-bit 'int' and an overload for the
    // 'OutStreamFunctions::bdexStreamOut' function, in the enumeration's
    // namespace, should be provided.

    BSLMF_ASSERT(sizeof(TYPE) <= sizeof(bsl::int32_t));

    // Stream the 'enum' value as a 32-bit 'int'.
    return stream.putInt32(static_cast<int>(value));
}

template <class STREAM, class TYPE>
inline
STREAM& OutStreamFunctions::bdexStreamOutImp(STREAM&              stream,
                                             const TYPE&          value,
                                             int                  version,
                                             const IsNotEnumType&)
{
    // A compilation error indicating the next line of code implies the class
    // of 'TYPE' does not support the 'bdexStreamOut' method.

    return value.bdexStreamOut(stream, version);
}

template <class STREAM, class TYPE>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM& stream, const TYPE& value)
{
    using VersionFunctions::maxSupportedBdexVersion;

    const int version = maxSupportedBdexVersion(&value,
                                                stream.bdexVersionSelector());
    if (VersionFunctions::k_NO_VERSION != version) {
        stream.putVersion(version);
    }

    return bdexStreamOut(stream, value, version);
}

template <class STREAM, class TYPE>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&     stream,
                                          const TYPE& value,
                                          int         version)
{
    typedef typename bsl::conditional<bslmf::IsEnum<TYPE>::value,
                                      IsEnumType,
                                      IsNotEnumType>::type dummyType;
    return bdexStreamOutImp(stream, value, version, dummyType());
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&     stream,
                                          const bool& value,
                                          int      /* version */)
{
    return stream.putInt8(static_cast<char>(value));
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&     stream,
                                          const char& value,
                                          int      /* version */)
{
    return stream.putInt8(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&            stream,
                                          const signed char& value,
                                          int             /* version */)
{
    return stream.putInt8(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&              stream,
                                          const unsigned char& value,
                                          int               /* version */)
{
    return stream.putUint8(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&      stream,
                                          const short& value,
                                          int       /* version */)
{
    return stream.putInt16(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&               stream,
                                          const unsigned short& value,
                                          int                /* version */)
{
    return stream.putUint16(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&    stream,
                                          const int& value,
                                          int     /* version */)
{
    return stream.putInt32(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&             stream,
                                          const unsigned int& value,
                                          int              /* version */)
{
    return stream.putUint32(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&     stream,
                                          const long& value,
                                          int      /* version */)
{
    return stream.putInt32(static_cast<int>(value));
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&              stream,
                                          const unsigned long& value,
                                          int               /* version */)
{
    return stream.putUint32(static_cast<unsigned int>(value));
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&                   stream,
                                          const bsls::Types::Int64& value,
                                          int                    /* version */)
{
    return stream.putInt64(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                                         STREAM&                    stream,
                                         const bsls::Types::Uint64& value,
                                         int                     /* version */)
{
    return stream.putUint64(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&      stream,
                                          const float& value,
                                          int       /* version */)
{
    return stream.putFloat32(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&       stream,
                                          const double& value,
                                          int        /* version */)
{
    return stream.putFloat64(value);
}

template <class STREAM>
inline
STREAM& OutStreamFunctions::bdexStreamOut(STREAM&            stream,
                                          const bsl::string& value,
                                          int             /* version */)
{
    return stream.putString(value);
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                                    STREAM&                         stream,
                                    const bsl::vector<char, ALLOC>& value,
                                    int                          /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayInt8(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                             STREAM&                                stream,
                             const bsl::vector<signed char, ALLOC>& value,
                             int                                 /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayInt8(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                           STREAM&                                  stream,
                           const bsl::vector<unsigned char, ALLOC>& value,
                           int                                   /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayUint8(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                                   STREAM&                          stream,
                                   const bsl::vector<short, ALLOC>& value,
                                   int                           /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayInt16(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                          STREAM&                                   stream,
                          const bsl::vector<unsigned short, ALLOC>& value,
                          int                                    /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayUint16(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                                     STREAM&                        stream,
                                     const bsl::vector<int, ALLOC>& value,
                                     int                         /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayInt32(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                            STREAM&                                 stream,
                            const bsl::vector<unsigned int, ALLOC>& value,
                            int                                  /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayUint32(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                      STREAM&                                       stream,
                      const bsl::vector<bsls::Types::Int64, ALLOC>& value,
                      int                                        /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayInt64(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                     STREAM&                                        stream,
                     const bsl::vector<bsls::Types::Uint64, ALLOC>& value,
                     int                                         /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayUint64(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                                   STREAM&                          stream,
                                   const bsl::vector<float, ALLOC>& value,
                                   int                           /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayFloat32(&value[0], length) : stream;
}

template <class STREAM, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                                  STREAM&                           stream,
                                  const bsl::vector<double, ALLOC>& value,
                                  int                            /* version */)
{
    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    return 0 < length ? stream.putArrayFloat64(&value[0], length) : stream;
}

template <class STREAM, class TYPE, class ALLOC>
inline
STREAM& OutStreamFunctions::bdexStreamOut(
                                        STREAM&                         stream,
                                        const bsl::vector<TYPE, ALLOC>& value)
{
    using VersionFunctions::maxSupportedBdexVersion;

    const int version = maxSupportedBdexVersion(&value,
                                                stream.bdexVersionSelector());

    stream.putVersion(version);
    return bdexStreamOut(stream, value, version);
}

template <class STREAM, class TYPE, class ALLOC>
STREAM& OutStreamFunctions::bdexStreamOut(
                                       STREAM&                         stream,
                                       const bsl::vector<TYPE, ALLOC>& value,
                                       int                             version)
{
    typedef typename bsl::vector<TYPE, ALLOC>::const_iterator Iterator;

    const int length = static_cast<int>(value.size());
    stream.putLength(length);

    for (Iterator it = value.begin(); it != value.end(); ++it) {
        bdexStreamOut(stream, *it, version);
    }

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