// bslx_byteoutstream.h -*-C++-*- #ifndef INCLUDED_BSLX_BYTEOUTSTREAM #define INCLUDED_BSLX_BYTEOUTSTREAM #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a stream class for externalization of fundamental types. // //@CLASSES: // bslx::ByteOutStream: byte-array-based output stream for fundamental types // //@SEE_ALSO: bslx_byteinstream // //@DESCRIPTION: This component implements a byte-array-based output stream // class, 'bslx::ByteOutStream', that provides platform-independent output // methods ("externalization") on values, and arrays of values, of fundamental // types, and on 'bsl::string'. // // This component is intended to be used in conjunction with the // 'bslx_byteinstream' "unexternalization" component. Each output method of // 'bslx::ByteOutStream' 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::ByteInStream' method. In general, the user cannot rely // on any other mechanism to read data written by 'bslx::ByteOutStream' 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 (i.e., network byte order) // format. // // 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::ByteOutStream' 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::ByteOutStream', 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::ByteOutStream' with an arbitrary value for its // 'versionSelector' and externalize some values: //.. // bslx::ByteOutStream 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(15 == length); // assert( 0 == bsl::memcmp(theChars, // "\x00\x00\x00\x01\x00\x00\x00\x02""c\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): 0 // nextByte (int): 0 // nextByte (int): 0 // nextByte (int): 1 // nextByte (int): 0 // nextByte (int): 0 // nextByte (int): 0 // nextByte (int): 2 // nextByte (char): c // nextByte (int): 5 // nextByte (char): h // nextByte (char): e // nextByte (char): l // nextByte (char): l // nextByte (char): o //.. // See the 'bslx_byteinstream' component usage example for a more practical // example of using 'bslx' streams. #include <bslscm_version.h> #include <bslx_marshallingutil.h> #include <bslx_outstreamfunctions.h> #include <bslma_allocator.h> #include <bsls_assert.h> #include <bsls_performancehint.h> #include <bsls_types.h> #include <bsl_cstddef.h> #include <bsl_iosfwd.h> #include <bsl_string.h> #include <bsl_vector.h> namespace BloombergLP { namespace bslx { // =================== // class ByteOutStream // =================== class ByteOutStream { // This class provides output methods to externalize values, and C-style // arrays of values, of the fundamental integral and floating-point types, // as well as 'bsl::string' values. In particular, each 'put' method of // this class is guaranteed to write stream data that can be read by the // corresponding 'get' method of 'bslx::ByteInStream'. See the 'bslx' // package-level documentation for the definition of the BDEX 'OutStream' // protocol. // DATA bsl::vector<char> d_buffer; // byte buffer to write to int d_versionSelector; // 'versionSelector' to use with // 'operator<<' as per the 'bslx' // package-level documentation int d_validFlag; // stream validity flag; 'true' if stream // is in valid state, 'false' otherwise // FRIENDS friend bsl::ostream& operator<<(bsl::ostream&, const ByteOutStream&); // NOT IMPLEMENTED ByteOutStream(const ByteOutStream&); ByteOutStream& operator=(const ByteOutStream&); private: // PRIVATE MANIPULATORS void validate(); // Put this output stream into a valid state. This function has no // effect if this stream is already valid. public: // CREATORS explicit ByteOutStream(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. ByteOutStream(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. ~ByteOutStream(); // 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. ByteOutStream& putLength(int length); // If the specified 'length' is less than 128, write to this stream the // one-byte integer comprised of the least-significant one byte of the // 'length'; otherwise, write to this stream 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. The behavior is undefined unless '0 <= length'. ByteOutStream& putVersion(int version); // Write to this stream 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. 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 *** ByteOutStream& putInt64(bsls::Types::Int64 value); // Write to this stream 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. ByteOutStream& putUint64(bsls::Types::Uint64 value); // Write to this stream 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. ByteOutStream& putInt56(bsls::Types::Int64 value); // Write to this stream 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. ByteOutStream& putUint56(bsls::Types::Uint64 value); // Write to this stream 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. ByteOutStream& putInt48(bsls::Types::Int64 value); // Write to this stream 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. ByteOutStream& putUint48(bsls::Types::Uint64 value); // Write to this stream 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. ByteOutStream& putInt40(bsls::Types::Int64 value); // Write to this stream 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. ByteOutStream& putUint40(bsls::Types::Uint64 value); // Write to this stream 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. ByteOutStream& 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. If this stream is initially invalid, this operation // has no effect. ByteOutStream& putUint32(unsigned int value); // Write to this stream 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. ByteOutStream& putInt24(int value); // Write to this stream 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. ByteOutStream& putUint24(unsigned int value); // Write to this stream 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. ByteOutStream& 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. If this stream is initially invalid, this operation // has no effect. ByteOutStream& putUint16(unsigned int value); // Write to this stream 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. ByteOutStream& 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. If this stream is // initially invalid, this operation has no effect. ByteOutStream& putUint8(unsigned int value); // Write to this stream 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. // *** scalar floating-point values *** ByteOutStream& putFloat64(double value); // Write to this stream 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. Note that for // non-conforming platforms, this operation may be lossy. ByteOutStream& putFloat32(float value); // Write to this stream 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. Note that for // non-conforming platforms, this operation may be lossy. // *** string values *** ByteOutStream& putString(const bsl::string& value); // Write to this stream the length of the specified 'value' (see // 'putLength') 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. // *** arrays of integer values *** ByteOutStream& putArrayInt64(const bsls::Types::Int64 *values, int numValues); // Write to this stream the consecutive eight-byte, two's complement // integers (in network byte order) comprised of the least-significant // eight bytes of each of the specified 'numValues' leading entries in // the specified 'values' (in host byte order), and return a reference // to this stream. If this stream is initially invalid, this operation // has no effect. The behavior is undefined unless '0 <= numValues' // and 'values' has sufficient contents. ByteOutStream& putArrayUint64(const bsls::Types::Uint64 *values, int numValues); // Write to this stream the consecutive eight-byte, two's complement // unsigned integers (in network byte order) comprised of the // least-significant eight bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayInt56(const bsls::Types::Int64 *values, int numValues); // Write to this stream the consecutive seven-byte, two's complement // integers (in network byte order) comprised of the least-significant // seven bytes of each of the specified 'numValues' leading entries in // the specified 'values' (in host byte order), and return a reference // to this stream. If this stream is initially invalid, this operation // has no effect. The behavior is undefined unless '0 <= numValues' // and 'values' has sufficient contents. ByteOutStream& putArrayUint56(const bsls::Types::Uint64 *values, int numValues); // Write to this stream the consecutive seven-byte, two's complement // unsigned integers (in network byte order) comprised of the // least-significant seven bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayInt48(const bsls::Types::Int64 *values, int numValues); // Write to this stream the consecutive six-byte, two's complement // integers (in network byte order) comprised of the least-significant // six bytes of each of the specified 'numValues' leading entries in // the specified 'values' (in host byte order), and return a reference // to this stream. If this stream is initially invalid, this operation // has no effect. The behavior is undefined unless '0 <= numValues' // and 'values' has sufficient contents. ByteOutStream& putArrayUint48(const bsls::Types::Uint64 *values, int numValues); // Write to this stream the consecutive six-byte, two's complement // unsigned integers (in network byte order) comprised of the // least-significant six bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayInt40(const bsls::Types::Int64 *values, int numValues); // Write to this stream the consecutive five-byte, two's complement // integers (in network byte order) comprised of the least-significant // five bytes of each of the specified 'numValues' leading entries in // the specified 'values' (in host byte order), and return a reference // to this stream. If this stream is initially invalid, this operation // has no effect. The behavior is undefined unless '0 <= numValues' // and 'values' has sufficient contents. ByteOutStream& putArrayUint40(const bsls::Types::Uint64 *values, int numValues); // Write to this stream the consecutive five-byte, two's complement // unsigned integers (in network byte order) comprised of the // least-significant five bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayInt32(const int *values, int numValues); // Write to this stream the consecutive four-byte, two's complement // integers (in network byte order) comprised of the least-significant // four bytes of each of the specified 'numValues' leading entries in // the specified 'values' (in host byte order), and return a reference // to this stream. If this stream is initially invalid, this operation // has no effect. The behavior is undefined unless '0 <= numValues' // and 'values' has sufficient contents. ByteOutStream& putArrayUint32(const unsigned int *values, int numValues); // Write to this stream the consecutive four-byte, two's complement // unsigned integers (in network byte order) comprised of the // least-significant four bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayInt24(const int *values, int numValues); // Write to this stream the consecutive three-byte, two's complement // integers (in network byte order) comprised of the least-significant // three bytes of each of the specified 'numValues' leading entries in // the specified 'values' (in host byte order), and return a reference // to this stream. If this stream is initially invalid, this operation // has no effect. The behavior is undefined unless '0 <= numValues' // and 'values' has sufficient contents. ByteOutStream& putArrayUint24(const unsigned int *values, int numValues); // Write to this stream the consecutive three-byte, two's complement // unsigned integers (in network byte order) comprised of the // least-significant three bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayInt16(const short *values, int numValues); // Write to this stream the consecutive two-byte, two's complement // integers (in network byte order) comprised of the least-significant // two bytes of each of the specified 'numValues' leading entries in // the specified 'values' (in host byte order), and return a reference // to this stream. If this stream is initially invalid, this operation // has no effect. The behavior is undefined unless '0 <= numValues' // and 'values' has sufficient contents. ByteOutStream& putArrayUint16(const unsigned short *values, int numValues); // Write to this stream the consecutive two-byte, two's complement // unsigned integers (in network byte order) comprised of the // least-significant two bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayInt8(const char *values, int numValues); ByteOutStream& putArrayInt8(const signed char *values, int numValues); // Write to this stream the consecutive one-byte, two's complement // integers comprised of the least-significant one byte of each of the // specified '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. The behavior is undefined // unless '0 <= numValues' and 'values' has sufficient contents. ByteOutStream& putArrayUint8(const char *values, int numValues); ByteOutStream& putArrayUint8(const unsigned char *values, int numValues); // Write to this stream the consecutive one-byte, two's complement // unsigned integers comprised of the least-significant one byte of // each of the specified '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. The behavior is // undefined unless '0 <= numValues' and 'values' has sufficient // contents. // *** arrays of floating-point values *** ByteOutStream& putArrayFloat64(const double *values, int numValues); // Write to this stream the consecutive eight-byte IEEE // double-precision floating-point numbers (in network byte order) // comprised of the most-significant eight bytes of each of the // specified 'numValues' leading entries in the specified 'values' (in // host byte order), and return a reference to this stream. If this // stream is initially invalid, this operation has no effect. The // behavior is undefined unless '0 <= numValues' and 'values' has // sufficient contents. Note that for non-conforming platforms, this // operation may be lossy. ByteOutStream& putArrayFloat32(const float *values, int numValues); // Write to this stream the consecutive four-byte IEEE single-precision // floating-point numbers (in network byte order) comprised of the // most-significant four bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order), and // return a reference to this stream. If this stream is initially // invalid, this operation has no effect. 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 stream is not destroyed or modified. 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 ByteOutStream& 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> ByteOutStream& operator<<(ByteOutStream& 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 ByteOutStream // ------------------- // PRIVATE MANIPULATORS inline void ByteOutStream::validate() { d_validFlag = true; } // CREATORS inline ByteOutStream::ByteOutStream(int versionSelector, bslma::Allocator *basicAllocator) : d_buffer(basicAllocator) , d_versionSelector(versionSelector) , d_validFlag(true) { } inline ByteOutStream::ByteOutStream(int versionSelector, bsl::size_t initialCapacity, bslma::Allocator *basicAllocator) : d_buffer(basicAllocator) , d_versionSelector(versionSelector) , d_validFlag(true) { d_buffer.reserve(initialCapacity); } inline ByteOutStream::~ByteOutStream() { } // MANIPULATORS inline void ByteOutStream::invalidate() { d_validFlag = false; } inline ByteOutStream& ByteOutStream::putLength(int length) { BSLS_ASSERT_SAFE(0 <= length); if (length > 127) { putInt32(length | (1 << 31)); } else { putInt8(length); } return *this; } inline ByteOutStream& ByteOutStream::putVersion(int version) { return putUint8(version); } inline void ByteOutStream::reserveCapacity(bsl::size_t newCapacity) { d_buffer.reserve(newCapacity); } inline void ByteOutStream::reset() { d_buffer.clear(); validate(); } // *** scalar integer values *** inline ByteOutStream& ByteOutStream::putInt64(bsls::Types::Int64 value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT64); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt64(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint64(bsls::Types::Uint64 value) { return putInt64(static_cast<bsls::Types::Int64>(value)); } inline ByteOutStream& ByteOutStream::putInt56(bsls::Types::Int64 value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT56); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt56(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint56(bsls::Types::Uint64 value) { return putInt56(static_cast<bsls::Types::Int64>(value)); } inline ByteOutStream& ByteOutStream::putInt48(bsls::Types::Int64 value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT48); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt48(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint48(bsls::Types::Uint64 value) { return putInt48(static_cast<bsls::Types::Int64>(value)); } inline ByteOutStream& ByteOutStream::putInt40(bsls::Types::Int64 value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT40); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt40(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint40(bsls::Types::Uint64 value) { return putInt40(static_cast<bsls::Types::Int64>(value)); } inline ByteOutStream& ByteOutStream::putInt32(int value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT32); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt32(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint32(unsigned int value) { return putInt32(static_cast<int>(value)); } inline ByteOutStream& ByteOutStream::putInt24(int value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT24); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt24(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint24(unsigned int value) { return putInt24(static_cast<int>(value)); } inline ByteOutStream& ByteOutStream::putInt16(int value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT16); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt16(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint16(unsigned int value) { return putInt16(static_cast<int>(value)); } inline ByteOutStream& ByteOutStream::putInt8(int value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_INT8); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putInt8(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putUint8(unsigned int value) { return putInt8(static_cast<int>(value)); } // *** scalar floating-point values *** inline ByteOutStream& ByteOutStream::putFloat64(double value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_FLOAT64); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putFloat64(d_buffer.data() + n, value); return *this; } inline ByteOutStream& ByteOutStream::putFloat32(float value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + MarshallingUtil::k_SIZEOF_FLOAT32); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putFloat32(d_buffer.data() + n, value); return *this; } // *** arrays of integer values *** inline ByteOutStream& ByteOutStream::putArrayInt64( const bsls::Types::Int64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT64); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt64(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint64( const bsls::Types::Uint64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT64); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt64(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt56( const bsls::Types::Int64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT56); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt56(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint56( const bsls::Types::Uint64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT56); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt56(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt48( const bsls::Types::Int64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT48); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt48(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint48( const bsls::Types::Uint64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT48); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt48(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt40( const bsls::Types::Int64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT40); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt40(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint40( const bsls::Types::Uint64 *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT40); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt40(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt32(const int *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT32); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt32(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint32(const unsigned int *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT32); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt32(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt24(const int *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT24); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt24(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint24(const unsigned int *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT24); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt24(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt16(const short *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT16); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt16(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint16(const unsigned short *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT16); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt16(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt8(const char *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT8); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt8(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayInt8(const signed char *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT8); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt8(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint8(const char *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT8); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt8(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayUint8(const unsigned char *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_INT8); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayInt8(d_buffer.data() + n, values, numValues); return *this; } // *** arrays of floating-point values *** inline ByteOutStream& ByteOutStream::putArrayFloat64(const double *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_FLOAT64); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayFloat64(d_buffer.data() + n, values, numValues); return *this; } inline ByteOutStream& ByteOutStream::putArrayFloat32(const float *values, int numValues) { BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValid() || 0 == numValues)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return *this; // RETURN } // Resize the buffer to have sufficient capacity with care to ensure this // stream is invalidated if an exception is thrown. const bsl::size_t n = d_buffer.size(); invalidate(); d_buffer.resize(n + numValues * MarshallingUtil::k_SIZEOF_FLOAT32); validate(); // Write to the buffer the specified 'value'. MarshallingUtil::putArrayFloat32(d_buffer.data() + n, values, numValues); return *this; } // ACCESSORS inline ByteOutStream::operator const void *() const { return isValid() ? this : 0; } inline int ByteOutStream::bdexVersionSelector() const { return d_versionSelector; } inline const char *ByteOutStream::data() const { return d_buffer.begin(); } inline bool ByteOutStream::isValid() const { return d_validFlag; } inline bsl::size_t ByteOutStream::length() const { return d_buffer.size(); } // FREE OPERATORS template <class TYPE> inline ByteOutStream& operator<<(ByteOutStream& stream, const TYPE& value) { return OutStreamFunctions::bdexStreamOut(stream, value); } } // close package namespace } // close enterprise namespace // TRAITS namespace BloombergLP { namespace bslma { template <> struct UsesBslmaAllocator<bslx::ByteOutStream> : 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 ----------------------------------