BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslx_genericoutstream

Detailed Description

Outline

Purpose

Externalization of fundamental types to a parameterized stream.

Classes

See also
bslx_streambufoutstream, bslx_genericinstream

Description

This component implements a parameterized output stream class, bslx::GenericOutStream, 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 unexternalization component. Each output method of bslx::GenericOutStream writes either a value or a homogeneous array of values of a fundamental type, in a format that is readable by the corresponding bslx::GenericInStream method. In general, the user cannot rely on any other mechanism to read data written by bslx::GenericOutStream 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.

Generic Byte-Format Generator

The class bslx::GenericOutStream is parameterized by a buffered stream class, STREAMBUF, which, given the declarations:

char c;
int len;
const char *s;
STREAMBUF *sb;

must make the following expressions syntactically valid, with the assert statements highlighting the expected return values:

STREAMBUF::traits_type::int_type eof = STREAMBUF::traits_type::eof();
assert(eof != sb->sputc(c));
assert(len == sb->sputn(s, len));
assert( 0 == sb->pubsync());

Suitable choices for STREAMBUF include any class that implements the bsl::basic_streambuf protocol.

The class bslx::StreambufOutStream is a typedef of bslx::GenericOutStream<bsl::streambuf>.

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. The first example depicts usage with a bsl::stringbuf. The second example replaces the bsl::stringbuf with a user-defined STREAMBUF.

Example 1: Basic Externalization

A bslx::GenericOutStream 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::GenericOutStream, 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::GenericOutStream, with an arbitrary value for its versionSelector, and externalize some values:

bslx::GenericOutStream<bsl::stringbuf> outStream1(&buffer1, 20131127);
outStream1.putInt32(1);
outStream1.putInt32(2);
outStream1.putInt8('c');
outStream1.putString(bsl::string("hello"));
Definition bslstl_string.h:1281
Definition bslstl_stringbuf.h:245
Definition bslx_genericoutstream.h:363

Then, we compare the contents of the buffer to the expected value:

bsl::string theChars = buffer1.str();
assert(15 == theChars.size());
assert( 0 == bsl::memcmp(theChars.data(),
"\x00\x00\x00\x01\x00\x00\x00\x02""c\x05""hello",
15));
size_type size() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6592
CHAR_TYPE * data() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6477
void str(const StringType &value)
Definition bslstl_stringbuf.h:1538

Finally, we print the buffer's contents to bsl::cout.

for (bsl::size_t i = 0; i < theChars.size(); ++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_genericinstream component usage example for a more practical example of using bslx streams.

Example 2: Sample STREAMBUF Implementation

For this example, we will implement MyOutStreamBuf, a minimal STREAMBUF to be used with bslx::GenericOutStream. The implementation will consist of only what is required of the type and two accessors to verify correct functionality (data and length).

First, we implement MyOutStreamBuf (which, for brevity, simply uses the default allocator):

class MyOutStreamBuf {
// This class implements a very basic stream buffer suitable for use in
// 'bslx::GenericOutStream'.
// DATA
bsl::string d_buffer; // output buffer
private:
// NOT IMPLEMENTED
MyOutStreamBuf(const MyOutStreamBuf&);
MyOutStreamBuf& operator=(const MyOutStreamBuf&);
public:
// TYPES
struct traits_type {
static int eof() { return -1; }
};
// CREATORS
MyOutStreamBuf();
// Create an empty stream buffer.
~MyOutStreamBuf();
// Destroy this stream buffer.
// MANIPULATORS
int pubsync();
// Return 0.
int sputc(char c);
// Write the specified character 'c' to this buffer. Return 'c' on
// success, and 'traits_type::eof()' otherwise.
bsl::streamsize sputn(const char *s, bsl::streamsize length);
// Write the specified 'length' characters at the specified address
// 's' to this buffer, and return the number of characters written.
// ACCESSORS
const char *data() const;
// Return the address of the non-modifiable character buffer held
// by this stream buffer.
bsl::streamsize size() const;
// Return the number of characters from the beginning of the buffer
// to the current write position.
};
// ========================================================================
// INLINE FUNCTION DEFINITIONS
// ========================================================================
// CREATORS
MyOutStreamBuf::MyOutStreamBuf()
: d_buffer()
{
}
MyOutStreamBuf::~MyOutStreamBuf()
{
}
// MANIPULATORS
int MyOutStreamBuf::pubsync()
{
// In this implementation, there is nothing to be done except return
// success.
return 0;
}
int MyOutStreamBuf::sputc(char c)
{
d_buffer += c;
return static_cast<int>(c);
}
bsl::streamsize MyOutStreamBuf::sputn(const char *s,
bsl::streamsize length)
{
d_buffer.append(s, length);
return length;
}
// ACCESSORS
const char *MyOutStreamBuf::data() const
{
return d_buffer.data();
}
bsl::streamsize MyOutStreamBuf::size() const
{
return d_buffer.size();
}
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
BSLS_KEYWORD_CONSTEXPR CONTAINER::value_type * data(CONTAINER &container)
Definition bslstl_iterator.h:1231

Then, we create buffer2, an instance of MyOutStreamBuf, and a bslx::GenericOutStream using buffer2, with an arbitrary value for its versionSelector, and externalize some values:

MyOutStreamBuf buffer2;
bslx::GenericOutStream<MyOutStreamBuf> outStream2(&buffer2, 20131127);
outStream2.putInt32(1);
outStream2.putInt32(2);
outStream2.putInt8('c');
outStream2.putString(bsl::string("hello"));

Finally, we compare the contents of the buffer to the expected value:

assert(15 == buffer2.size());
assert( 0 == bsl::memcmp(buffer2.data(),
"\x00\x00\x00\x01\x00\x00\x00\x02""c\x05""hello",
15));