// bslx_testoutstream.h                                               -*-C++-*-
#ifndef INCLUDED_BSLX_TESTOUTSTREAM
#define INCLUDED_BSLX_TESTOUTSTREAM

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

//@PURPOSE: Enable externalization of fundamental types with identification.
//
//@CLASSES:
//  bslx::TestOutStream: byte-array-based output stream for fundamental types
//
//@SEE_ALSO: bslx_testinstream, bslx_byteoutstream
//
//@DESCRIPTION: This component implements a byte-array-based output stream
// class, 'bslx::TestOutStream', that provides platform-independent output
// methods ("externalization") on values, and arrays of values, of fundamental
// types, and on 'bsl::string'.  This component also externalizes information
// to the stream that can be used by the reader of the stream to verify, for
// these types, that the type of data requested from the input stream matches
// what was written by this output stream.  This component is meant for testing
// only.
//
// This component is intended to be used in conjunction with the
// 'bslx_testinstream' "unexternalization" component.  Each output method of
// 'bslx::TestOutStream' writes a value or a homogeneous array of values to an
// internally managed buffer.  The values are formatted to be readable by the
// corresponding 'bslx::TestInStream' method.  In general, the user cannot rely
// on any other mechanism to read data written by 'bslx::TestOutStream' unless
// that mechanism explicitly states its ability to do so.
//
// The supported types and required content are listed in the 'bslx'
// package-level documentation under "Supported Types".
//
// Note that the values are stored in big-endian format (i.e., network byte
// order).
//
// Note that output streams can be *invalidated* explicitly and queried for
// *validity*.  Writing to an initially invalid stream has no effect.  Whenever
// an output operation fails, the stream should be invalidated explicitly.
//
///Versioning
///----------
// BDEX provides two concepts that support versioning the BDEX serialization
// format of a type: 'version' and 'versionSelector'.  A 'version' is a 1-based
// integer indicating one of the supported formats (e.g., format 1, format 2,
// etc.).  A 'versionSelector' is a value that is mapped to a 'version' for a
// type by the type's implementation of 'maxSupportedBdexVersion'.
//
// Selecting a value for a 'versionSelector' is required at two different
// points: (1) when implementing a new 'version' format within the
// 'bdexStreamIn' and 'bdexStreamOut' methods of a type, and (2) when
// implementing code that constructs a BDEX 'OutStream'.  In both cases, the
// value should be a *compile*-time-selected value.
//
// When a new 'version' format is implemented within the 'bdexStreamIn' and
// 'bdexStreamOut' methods of a type, a new mapping in
// 'maxSupportedBdexVersion' should be created to expose this new 'version'
// with a 'versionSelector'.  A simple - and the recommended - approach is to
// use a value having the pattern "YYYYMMDD", where "YYYYMMDD" corresponds to
// the "go-live" date of the corresponding 'version' format.
//
// When constructing an 'OutStream', a simple approach is to use the current
// date as a *compile*-time constant value.  In combination with the
// recommended selection of 'versionSelector' values for
// 'maxSupportedBdexVersion', this will result in consistent and predictable
// behavior while externalizing types.  Note that this recommendation is chosen
// for its simplicity: to ensure the largest possible audience for an
// externalized representation, clients can select the minimum date value that
// will result in the desired version of all types externalized with
// 'operator<<' being selected.
//
// See the 'bslx' package-level documentation for more detailed information
// about versioning.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Externalization
/// - - - - - - - - - - - - - - - -
// A 'bslx::TestOutStream' can be used to externalize values in a
// platform-neutral way.  Writing out fundamental C++ types and 'bsl::string'
// requires no additional work on the part of the client; the client can simply
// use the stream directly.  The following code serializes a few representative
// values using a 'bslx::TestOutStream', compares the contents of this stream
// to the expected value, and then writes the contents of this stream's buffer
// to 'stdout'.
//
// First, we create a 'bslx::TestOutStream' with an arbitrary value for its
// 'versionSelector' and externalize some values:
//..
//  bslx::TestOutStream outStream(20131127);
//  outStream.putInt32(1);
//  outStream.putInt32(2);
//  outStream.putInt8('c');
//  outStream.putString(bsl::string("hello"));
//..
// Then, we compare the contents of the stream to the expected value:
//..
//  const char  *theChars = outStream.data();
//  bsl::size_t  length   = outStream.length();
//  assert(24 == length);
//  assert( 0 == bsl::memcmp(theChars,
//                           "\xE6\x00\x00\x00\x01\xE6\x00\x00\x00\x02\xE0"
//                                      "c\xE0\x05\xE1\x00\x00\x00\x05""hello",
//                           length));
//..
// Finally, we print the stream's contents to 'bsl::cout'.
//..
//  for (bsl::size_t i = 0; i < length; ++i) {
//      if(bsl::isalnum(static_cast<unsigned char>(theChars[i]))) {
//          bsl::cout << "nextByte (char): " << theChars[i] << bsl::endl;
//      }
//      else {
//          bsl::cout << "nextByte (int): "
//                    << static_cast<int>(theChars[i])
//                    << bsl::endl;
//      }
//  }
//..
// Executing the above code results in the following output:
//..
//  nextByte (int): -26
//  nextByte (int): 0
//  nextByte (int): 0
//  nextByte (int): 0
//  nextByte (int): 1
//  nextByte (int): -26
//  nextByte (int): 0
//  nextByte (int): 0
//  nextByte (int): 0
//  nextByte (int): 2
//  nextByte (int): -32
//  nextByte (char): c
//  nextByte (int): -32
//  nextByte (int): 5
//  nextByte (int): -31
//  nextByte (char): h
//  nextByte (char): e
//  nextByte (char): l
//  nextByte (char): l
//  nextByte (char): o
//..
// Note the negative numeric values indicate the "type" of the data that
// follows (see 'bslx_typecode').
//
// See the 'bslx_testinstream' component usage example for a more practical
// example of using this test output stream.

#include <bslscm_version.h>

#include <bslx_byteoutstream.h>
#include <bslx_outstreamfunctions.h>

#include <bsls_types.h>

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

namespace BloombergLP {

namespace bslma { class Allocator; }

namespace bslx {

                         // ===================
                         // class TestOutStream
                         // ===================

class TestOutStream {
    // This class implements output methods to externalize fundamental types
    // and their associated type identification data.  It stores the
    // accumulated result in network byte order.  See the 'bslx' package-level
    // documentation for the definition of the BDEX 'OutStream' protocol.

    // DATA
    ByteOutStream d_imp;                  // byte out stream implementation

    bool          d_makeNextInvalidFlag;  // if 'true', next "put" operation
                                          // outputs the invalid data indicator
                                          // and resets this flag to 'false'

    // FRIENDS
    friend bsl::ostream& operator<<(bsl::ostream&, const TestOutStream&);

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

  public:
    // CREATORS
    explicit TestOutStream(int               versionSelector,
                           bslma::Allocator *basicAllocator = 0);
        // Create an empty output byte stream that will use the specified
        // (*compile*-time-defined) 'versionSelector' as needed (see
        // {Versioning}).  Optionally specify a 'basicAllocator' used to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  Note that the 'versionSelector' is expected to
        // be formatted as "YYYYMMDD", a date representation.

    TestOutStream(int               versionSelector,
                  bsl::size_t       initialCapacity,
                  bslma::Allocator *basicAllocator = 0);
        // Create an empty output byte stream having an initial buffer capacity
        // of at least the specified 'initialCapacity' (in bytes) and that will
        // use the specified (*compile*-time-defined) 'versionSelector' as
        // needed (see {Versioning}).  Optionally specify a 'basicAllocator'
        // used to supply memory.  If 'basicAllocator' is 0, the currently
        // installed default allocator is used.  Note that the
        // 'versionSelector' is expected to be formatted as "YYYYMMDD", a date
        // representation.

    ~TestOutStream();
        // Destroy this object.

    // MANIPULATORS
    void invalidate();
        // Put this output stream in an invalid state.  This function has no
        // effect if this stream is already invalid.

    void makeNextInvalid();
        // Make the next output operation externalize the invalid data
        // indicator, as opposed to the actual type indicator, to this output
        // stream; the data associated with the next output operation is still
        // externalized.  Note that the invalid data indicator can be detected
        // by a corresponding 'TestInStream' object.

    TestOutStream& putLength(int length);
        // If the specified 'length' is less than 128, write to this stream the
        // one-byte type indicator for a one-byte integer and the one-byte
        // integer comprised of the least-significant one byte of the 'length';
        // otherwise, write to this stream the one-byte type indicator for a
        // four-byte integer and the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the 'length' (in host byte order) with the most-significant bit set.
        // Return a reference to this stream.  If this stream is initially
        // invalid, this operation has no effect.  If the next output operation
        // has been set to be marked invalid (see 'makeNextInvalid'), reset
        // this marking and emit the invalid indicator instead of the type
        // indicator.  The behavior is undefined unless '0 <= length'.

    TestOutStream& putVersion(int version);
        // Write to this stream the one-byte type indicator for a one-byte
        // unsigned integer and the one-byte, two's complement unsigned integer
        // comprised of the least-significant one byte of the specified
        // 'version', and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.

    void reserveCapacity(bsl::size_t newCapacity);
        // Set the internal buffer size of this stream to be at least the
        // specified 'newCapacity' (in bytes).

    void reset();
        // Remove all content in this stream and validate this stream if it is
        // currently invalid.

                      // *** scalar integer values ***

    TestOutStream& putInt64(bsls::Types::Int64 value);
        // Write to this stream the one-byte type indicator for an eight-byte
        // integer and the eight-byte, two's complement integer (in network
        // byte order) comprised of the least-significant eight bytes of the
        // specified 'value' (in host byte order), and return a reference to
        // this stream.  If this stream is initially invalid, this operation
        // has no effect.  If the next output operation has been set to be
        // marked invalid (see 'makeNextInvalid'), reset this marking and emit
        // the invalid indicator instead of the type indicator.

    TestOutStream& putUint64(bsls::Types::Uint64 value);
        // Write to this stream the one-byte type indicator for an eight-byte
        // unsigned integer and the eight-byte, two's complement unsigned
        // integer (in network byte order) comprised of the least-significant
        // eight bytes of the specified 'value' (in host byte order), and
        // return a reference to this stream.  If this stream is initially
        // invalid, this operation has no effect.  If the next output operation
        // has been set to be marked invalid (see 'makeNextInvalid'), reset
        // this marking and emit the invalid indicator instead of the type
        // indicator.

    TestOutStream& putInt56(bsls::Types::Int64 value);
        // Write to this stream the one-byte type indicator for a seven-byte
        // integer and the seven-byte, two's complement integer (in network
        // byte order) comprised of the least-significant seven bytes of the
        // specified 'value' (in host byte order), and return a reference to
        // this stream.  If this stream is initially invalid, this operation
        // has no effect.  If the next output operation has been set to be
        // marked invalid (see 'makeNextInvalid'), reset this marking and emit
        // the invalid indicator instead of the type indicator.

    TestOutStream& putUint56(bsls::Types::Uint64 value);
        // Write to this stream the one-byte type indicator for a seven-byte
        // unsigned integer and the seven-byte, two's complement unsigned
        // integer (in network byte order) comprised of the least-significant
        // seven bytes of the specified 'value' (in host byte order), and
        // return a reference to this stream.  If this stream is initially
        // invalid, this operation has no effect.  If the next output operation
        // has been set to be marked invalid (see 'makeNextInvalid'), reset
        // this marking and emit the invalid indicator instead of the type
        // indicator.

    TestOutStream& putInt48(bsls::Types::Int64 value);
        // Write to this stream the one-byte type indicator for a six-byte
        // integer and the six-byte, two's complement integer (in network byte
        // order) comprised of the least-significant six bytes of the specified
        // 'value' (in host byte order), and return a reference to this stream.
        // If this stream is initially invalid, this operation has no effect.
        // If the next output operation has been set to be marked invalid (see
        // 'makeNextInvalid'), reset this marking and emit the invalid
        // indicator instead of the type indicator.

    TestOutStream& putUint48(bsls::Types::Uint64 value);
        // Write to this stream the one-byte type indicator for a six-byte
        // unsigned integer and the six-byte, two's complement unsigned integer
        // (in network byte order) comprised of the least-significant six bytes
        // of the specified 'value' (in host byte order), and return a
        // reference to this stream.  If this stream is initially invalid, this
        // operation has no effect.  If the next output operation has been set
        // to be marked invalid (see 'makeNextInvalid'), reset this marking and
        // emit the invalid indicator instead of the type indicator.

    TestOutStream& putInt40(bsls::Types::Int64 value);
        // Write to this stream the one-byte type indicator for a five-byte
        // integer and the five-byte, two's complement integer (in network byte
        // order) comprised of the least-significant five bytes of the
        // specified 'value' (in host byte order), and return a reference to
        // this stream.  If this stream is initially invalid, this operation
        // has no effect.  If the next output operation has been set to be
        // marked invalid (see 'makeNextInvalid'), reset this marking and emit
        // the invalid indicator instead of the type indicator.

    TestOutStream& putUint40(bsls::Types::Uint64 value);
        // Write to this stream the one-byte type indicator for a five-byte
        // unsigned integer and the five-byte, two's complement unsigned
        // integer (in network byte order) comprised of the least-significant
        // five bytes of the specified 'value' (in host byte order), and return
        // a reference to this stream.  If this stream is initially invalid,
        // this operation has no effect.  If the next output operation has been
        // set to be marked invalid (see 'makeNextInvalid'), reset this marking
        // and emit the invalid indicator instead of the type indicator.

    TestOutStream& putInt32(int value);
        // Write to this stream the one-byte type indicator for a four-byte
        // integer and 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.  If this stream is initially invalid, this operation
        // has no effect.  If the next output operation has been set to be
        // marked invalid (see 'makeNextInvalid'), reset this marking and emit
        // the invalid indicator instead of the type indicator.

    TestOutStream& putUint32(unsigned int value);
        // Write to this stream the one-byte type indicator for a four-byte
        // unsigned integer and the four-byte, two's complement unsigned
        // 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.  If this stream is initially invalid,
        // this operation has no effect.  If the next output operation has been
        // set to be marked invalid (see 'makeNextInvalid'), reset this marking
        // and emit the invalid indicator instead of the type indicator.

    TestOutStream& putInt24(int value);
        // Write to this stream the one-byte type indicator for a three-byte
        // integer and the three-byte, two's complement integer (in network
        // byte order) comprised of the least-significant three bytes of the
        // specified 'value' (in host byte order), and return a reference to
        // this stream.  If this stream is initially invalid, this operation
        // has no effect.  If the next output operation has been set to be
        // marked invalid (see 'makeNextInvalid'), reset this marking and emit
        // the invalid indicator instead of the type indicator.

    TestOutStream& putUint24(unsigned int value);
        // Write to this stream the one-byte type indicator for a three-byte
        // unsigned integer and the three-byte, two's complement unsigned
        // integer (in network byte order) comprised of the least-significant
        // three bytes of the specified 'value' (in host byte order), and
        // return a reference to this stream.  If this stream is initially
        // invalid, this operation has no effect.  If the next output operation
        // has been set to be marked invalid (see 'makeNextInvalid'), reset
        // this marking and emit the invalid indicator instead of the type
        // indicator.

    TestOutStream& putInt16(int value);
        // Write to this stream the one-byte type indicator for a two-byte
        // integer and 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.
        // If this stream is initially invalid, this operation has no effect.
        // If the next output operation has been set to be marked invalid (see
        // 'makeNextInvalid'), reset this marking and emit the invalid
        // indicator instead of the type indicator.

    TestOutStream& putUint16(unsigned int value);
        // Write to this stream the one-byte type indicator for a two-byte
        // unsigned integer and the two-byte, two's complement unsigned 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.  If this stream is initially invalid, this
        // operation has no effect.  If the next output operation has been set
        // to be marked invalid (see 'makeNextInvalid'), reset this marking and
        // emit the invalid indicator instead of the type indicator.

    TestOutStream& putInt8(int value);
        // Write to this stream the one-byte type indicator for a one-byte
        // integer and 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.  If this stream is initially invalid, this
        // operation has no effect.  If the next output operation has been set
        // to be marked invalid (see 'makeNextInvalid'), reset this marking and
        // emit the invalid indicator instead of the type indicator.

    TestOutStream& putUint8(unsigned int value);
        // Write to this stream the one-byte type indicator for a one-byte
        // unsigned integer and the one-byte, two's complement unsigned integer
        // comprised of the least-significant one byte of the specified
        // 'value', and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.

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

    TestOutStream& putFloat64(double value);
        // Write to this stream the one-byte type indicator for an eight-byte
        // double-precision floating-point number and the eight-byte IEEE
        // double-precision floating-point number (in network byte order)
        // comprised of the most-significant eight bytes of the specified
        // 'value' (in host byte order), and return a reference to this stream.
        // If this stream is initially invalid, this operation has no effect.
        // If the next output operation has been set to be marked invalid (see
        // 'makeNextInvalid'), reset this marking and emit the invalid
        // indicator instead of the type indicator.  Note that for
        // non-conforming platforms, this operation may be lossy.

    TestOutStream& putFloat32(float value);
        // Write to this stream the one-byte type indicator for a four-byte
        // single-precision floating-point number and the four-byte IEEE
        // single-precision floating-point number (in network byte order)
        // comprised of the most-significant four bytes of the specified
        // 'value' (in host byte order), and return a reference to this stream.
        // If this stream is initially invalid, this operation has no effect.
        // If the next output operation has been set to be marked invalid (see
        // 'makeNextInvalid'), reset this marking and emit the invalid
        // indicator instead of the type indicator.  Note that for
        // non-conforming platforms, this operation may be lossy.

                      // *** string values ***

    TestOutStream& putString(const bsl::string& value);
        // Write to this stream the one-byte type indicator for a length (see
        // 'putLength'), the length of the specified 'value' (see 'putLength'),
        // the one-byte type indicator for an array of one-byte unsigned
        // integers, and an array of one-byte, two's complement unsigned
        // integers comprised of the least-significant one byte of each
        // character in the 'value', and return a reference to this stream.  If
        // this stream is initially invalid, this operation has no effect.  If
        // the next output operation has been set to be marked invalid (see
        // 'makeNextInvalid'), reset this marking and emit the invalid
        // indicator instead of the type indicator.

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

    TestOutStream& putArrayInt64(const bsls::Types::Int64 *values,
                                 int                       numValues);
        // Write to this stream the one-byte type indicator for an eight-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // eight-byte, two's complement integers (in network byte order)
        // comprised of the least-significant eight bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayUint64(const bsls::Types::Uint64 *values,
                                  int                        numValues);
        // Write to this stream the one-byte type indicator for an eight-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // eight-byte, two's complement unsigned integers (in network byte
        // order) comprised of the least-significant eight bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayInt56(const bsls::Types::Int64 *values,
                                 int                       numValues);
        // Write to this stream the one-byte type indicator for a seven-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // seven-byte, two's complement integers (in network byte order)
        // comprised of the least-significant seven bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayUint56(const bsls::Types::Uint64 *values,
                                  int                        numValues);
        // Write to this stream the one-byte type indicator for a seven-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // seven-byte, two's complement unsigned integers (in network byte
        // order) comprised of the least-significant seven bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayInt48(const bsls::Types::Int64 *values,
                                 int                       numValues);
        // Write to this stream the one-byte type indicator for a six-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // six-byte, two's complement integers (in network byte order)
        // comprised of the least-significant six bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayUint48(const bsls::Types::Uint64 *values,
                                  int                        numValues);
        // Write to this stream the one-byte type indicator for a six-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // six-byte, two's complement unsigned integers (in network byte order)
        // comprised of the least-significant six bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayInt40(const bsls::Types::Int64 *values,
                                 int                       numValues);
        // Write to this stream the one-byte type indicator for a five-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // five-byte, two's complement integers (in network byte order)
        // comprised of the least-significant five bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayUint40(const bsls::Types::Uint64 *values,
                                  int                        numValues);
        // Write to this stream the one-byte type indicator for a five-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // five-byte, two's complement unsigned integers (in network byte
        // order) comprised of the least-significant five bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayInt32(const int *values, int numValues);
        // Write to this stream the one-byte type indicator for a four-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // four-byte, two's complement integers (in network byte order)
        // comprised of the least-significant four bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayUint32(const unsigned int *values, int numValues);
        // Write to this stream the one-byte type indicator for a four-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // four-byte, two's complement unsigned integers (in network byte
        // order) comprised of the least-significant four bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayInt24(const int *values, int numValues);
        // Write to this stream the one-byte type indicator for a three-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // three-byte, two's complement integers (in network byte order)
        // comprised of the least-significant three bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayUint24(const unsigned int *values, int numValues);
        // Write to this stream the one-byte type indicator for a three-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // three-byte, two's complement unsigned integers (in network byte
        // order) comprised of the least-significant three bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayInt16(const short *values, int numValues);
        // Write to this stream the one-byte type indicator for a two-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // two-byte, two's complement integers (in network byte order)
        // comprised of the least-significant two bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayUint16(const unsigned short *values, int numValues);
        // Write to this stream the one-byte type indicator for a two-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // two-byte, two's complement unsigned integers (in network byte order)
        // comprised of the least-significant two bytes of each of the
        // 'numValues' leading entries in the specified 'values' (in host byte
        // order), and return a reference to this stream.  If this stream is
        // initially invalid, this operation has no effect.  If the next output
        // operation has been set to be marked invalid (see 'makeNextInvalid'),
        // reset this marking and emit the invalid indicator instead of the
        // type indicator.  The behavior is undefined unless '0 <= numValues'
        // and 'values' has sufficient contents.

    TestOutStream& putArrayInt8(const char        *values, int numValues);
    TestOutStream& putArrayInt8(const signed char *values, int numValues);
        // Write to this stream the one-byte type indicator for a one-byte
        // integer, the four-byte, two's complement integer (in network byte
        // order) comprised of the least-significant four bytes of the
        // specified 'numValues' (in host byte order), and the consecutive
        // one-byte, two's complement integers comprised of the
        // least-significant one byte of each of the 'numValues' leading
        // entries in the specified 'values', and return a reference to this
        // stream.  If this stream is initially invalid, this operation has no
        // effect.  If the next output operation has been set to be marked
        // invalid (see 'makeNextInvalid'), reset this marking and emit the
        // invalid indicator instead of the type indicator.  The behavior is
        // undefined unless '0 <= numValues' and 'values' has sufficient
        // contents.

    TestOutStream& putArrayUint8(const char          *values, int numValues);
    TestOutStream& putArrayUint8(const unsigned char *values, int numValues);
        // Write to this stream the one-byte type indicator for a one-byte
        // unsigned integer, the four-byte, two's complement integer (in
        // network byte order) comprised of the least-significant four bytes of
        // the specified 'numValues' (in host byte order), and the consecutive
        // one-byte, two's complement unsigned integers comprised of the
        // least-significant one byte of each of the 'numValues' leading
        // entries in the specified 'values', and return a reference to this
        // stream.  If this stream is initially invalid, this operation has no
        // effect.  If the next output operation has been set to be marked
        // invalid (see 'makeNextInvalid'), reset this marking and emit the
        // invalid indicator instead of the type indicator.  The behavior is
        // undefined unless '0 <= numValues' and 'values' has sufficient
        // contents.

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

    TestOutStream& putArrayFloat64(const double *values, int numValues);
        // Write to this stream the one-byte type indicator for an eight-byte
        // double-precision floating-point number, the four-byte, two's
        // complement integer (in network byte order) comprised of the
        // least-significant four bytes of the specified 'numValues' (in host
        // byte order), and the consecutive eight-byte IEEE double-precision
        // floating-point numbers (in network byte order) comprised of the
        // most-significant eight bytes of each of the 'numValues' leading
        // entries in the specified 'values' (in host byte order), and return a
        // reference to this stream.  If this stream is initially invalid, this
        // operation has no effect.  If the next output operation has been set
        // to be marked invalid (see 'makeNextInvalid'), reset this marking and
        // emit the invalid indicator instead of the type indicator.  The
        // behavior is undefined unless '0 <= numValues' and 'values' has
        // sufficient contents.  Note that for non-conforming platforms, this
        // operation may be lossy.

    TestOutStream& putArrayFloat32(const float *values, int numValues);
        // Write to this stream the one-byte type indicator for a four-byte
        // single-precision floating-point number, the four-byte, two's
        // complement integer (in network byte order) comprised of the
        // least-significant four bytes of the specified 'numValues' (in host
        // byte order), and the consecutive four-byte IEEE single-precision
        // floating-point numbers (in network byte order) comprised of the
        // most-significant four bytes of each of the 'numValues' leading
        // entries in the specified 'values' (in host byte order), and return a
        // reference to this stream.  If this stream is initially invalid, this
        // operation has no effect.  If the next output operation has been set
        // to be marked invalid (see 'makeNextInvalid'), reset this marking and
        // emit the invalid indicator instead of the type indicator.  The
        // behavior is undefined unless '0 <= numValues' and 'values' has
        // sufficient contents.  Note that for non-conforming platforms, this
        // operation may be lossy.

    // ACCESSORS
    operator const void *() const;
        // Return a non-zero value if this stream is valid, and 0 otherwise.
        // An invalid stream is a stream for which an output operation was
        // detected to have failed or 'invalidate' was called.

    int bdexVersionSelector() const;
        // Return the 'versionSelector' to be used with 'operator<<' for BDEX
        // streaming as per the 'bslx' package-level documentation.

    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 array is not destroyed or modified (i.e., the current capacity
        // is not exceeded).  The behavior of accessing elements outside the
        // range '[ data() .. data() + (length() - 1) ]' is undefined.

    bool isValid() const;
        // Return 'true' if this stream is valid, and 'false' otherwise.  An
        // invalid stream is a stream for which an output operation was
        // detected to have failed or 'invalidate' was called.

    bsl::size_t length() const;
        // Return the number of bytes in this stream.
};

// FREE OPERATORS
bsl::ostream& operator<<(bsl::ostream&        stream,
                         const TestOutStream& object);
    // Write the specified 'object' to the specified output 'stream' in some
    // reasonable (multi-line) format, and return a reference to 'stream'.

template <class TYPE>
TestOutStream& operator<<(TestOutStream& stream, const TYPE& value);
    // Write the specified 'value' to the specified output 'stream' following
    // the requirements of the BDEX protocol (see the 'bslx' package-level
    // documentation), and return a reference to 'stream'.  The behavior is
    // undefined unless 'TYPE' is BDEX-compliant.

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

                         // -------------------
                         // class TestOutStream
                         // -------------------

// MANIPULATORS
inline
void TestOutStream::invalidate()
{
    d_imp.invalidate();
}

inline
void TestOutStream::makeNextInvalid()
{
    d_makeNextInvalidFlag = true;
}

inline
void TestOutStream::reserveCapacity(bsl::size_t newCapacity)
{
    d_imp.reserveCapacity(newCapacity);
}

inline
void TestOutStream::reset()
{
    d_imp.reset();
}

                      // *** string values ***

inline
TestOutStream& TestOutStream::putString(const bsl::string& value)
{
    putLength(static_cast<int>(value.length()));
    return putArrayUint8(value.data(), static_cast<int>(value.length()));
}

// ACCESSORS
inline
TestOutStream::operator const void *() const
{
    return d_imp;
}

inline
int TestOutStream::bdexVersionSelector() const
{
    return d_imp.bdexVersionSelector();
}

inline
const char *TestOutStream::data() const
{
    return d_imp.data();
}

inline
bool TestOutStream::isValid() const
{
    return d_imp.isValid();
}

inline
bsl::size_t TestOutStream::length() const
{
    return d_imp.length();
}

// FREE OPERATORS
template <class TYPE>
inline
TestOutStream& operator<<(TestOutStream& stream, const TYPE& value)
{
    return OutStreamFunctions::bdexStreamOut(stream, value);
}

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

// TRAITS
namespace BloombergLP {
namespace bslma {

template <>
struct UsesBslmaAllocator<bslx::TestOutStream> : bsl::true_type {};

}  // close namespace bslma
}  // 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 ----------------------------------