Unexternalization of fundamental types from a bsl::streambuf
.
More...
Namespaces |
namespace | bslx |
Detailed Description
- Outline
-
-
- Purpose:
- Unexternalization of fundamental types from a
bsl::streambuf
.
-
- Classes:
-
- See also:
- Component bslx_streambufoutstream, Component bslx_genericinstream
-
- Description:
- This component implements a
bsl::streambuf
input stream class, bslx::StreambufInStream
, that provides platform-independent input methods ("unexternalization") on values, and arrays of values, of fundamental types, and on bsl::string
.
- The
bslx::StreambufInStream
type reads from a user-supplied bsl::streambuf
directly, with no data copying or assumption of ownership. The user must therefore make sure that the lifetime and visibility of the buffer is sufficient to satisfy the needs of the input stream.
- This component is intended to be used in conjunction with the
bslx_streambufoutstream
"externalization" component. Each input method of bslx::StreambufInStream
reads either a value or a homogeneous array of values of a fundamental type, in a format that was written by the corresponding bslx::StreambufOutStream
method. In general, the user of this component cannot rely on being able to read data that was written by any mechanism other than bslx::StreambufOutStream
.
- The supported types and required content are listed in the
bslx
package-level documentation under "Supported Types".
- Note that input streams can be invalidated explicitly and queried for validity. Reading from an initially invalid stream has no effect. Attempting to read beyond the end of a stream will automatically invalidate the stream. Whenever an inconsistent value is detected, the stream should be invalidated explicitly.
-
- Usage:
- This section illustrates intended use of this component.
-
- Example 1: Basic Unexternalization:
- Suppose we wish to implement a (deliberately simple)
MyPerson
class as a value-semantic object that supports BDEX externalization and unexternalization. In addition to whatever data and methods that we choose to put into our design, we must supply three methods having specific names and signatures in order to comply with the BDEX protocol: a class method maxSupportedBdexVersion
, an accessor (i.e., a const
method) bdexStreamOut
, and a manipulator (i.e., a non-'const' method) bdexStreamIn
. This example shows how to implement those three methods.
- In this example we will not worry overly about "good design" of the
MyPerson
component, and we will declare but not implement illustrative methods and free operators, except for the three required BDEX methods, which are implemented in full. In particular, we will not make explicit use of bslma
allocators; a more complete design would do so:
- First, we implement
MyPerson
: class MyPerson {
bsl::string d_firstName;
bsl::string d_lastName;
int d_age;
friend bool operator==(const MyPerson&, const MyPerson&);
public:
static int maxSupportedBdexVersion(int versionSelector);
MyPerson();
MyPerson(const char *firstName, const char *lastName, int age);
MyPerson(const MyPerson& original);
~MyPerson();
MyPerson& operator=(const MyPerson& rhs);
template <class STREAM>
STREAM& bdexStreamIn(STREAM& stream, int version);
int age() const;
template <class STREAM>
STREAM& bdexStreamOut(STREAM& stream, int version) const;
const bsl::string& firstName() const;
const bsl::string& lastName() const;
};
bool operator==(const MyPerson& lhs, const MyPerson& rhs);
bool operator!=(const MyPerson& lhs, const MyPerson& rhs);
inline
int MyPerson::maxSupportedBdexVersion(int ) {
return 1;
}
inline
MyPerson::MyPerson()
: d_firstName("")
, d_lastName("")
, d_age(0)
{
}
inline
MyPerson::MyPerson(const char *firstName, const char *lastName, int age)
: d_firstName(firstName)
, d_lastName(lastName)
, d_age(age)
{
}
inline
MyPerson::~MyPerson()
{
}
template <class STREAM>
STREAM& MyPerson::bdexStreamIn(STREAM& stream, int version)
{
if (stream) {
switch (version) {
case 1: {
stream.getString(d_firstName);
if (!stream) {
d_firstName = "stream error";
return stream;
}
stream.getString(d_lastName);
if (!stream) {
d_lastName = "stream error";
return stream;
}
stream.getInt32(d_age);
if (!stream) {
d_age = 999;
return stream;
}
} break;
default: {
stream.invalidate();
}
}
}
return stream;
}
inline
int MyPerson::age() const
{
return d_age;
}
template <class STREAM>
STREAM& MyPerson::bdexStreamOut(STREAM& stream, int version) const
{
switch (version) {
case 1: {
stream.putString(d_firstName);
stream.putString(d_lastName);
stream.putInt32(d_age);
} break;
default: {
stream.invalidate();
} break;
}
return stream;
}
inline
const bsl::string& MyPerson::firstName() const
{
return d_firstName;
}
inline
const bsl::string& MyPerson::lastName() const
{
return d_lastName;
}
inline
bool operator==(const MyPerson& lhs, const MyPerson& rhs)
{
return lhs.d_firstName == rhs.d_firstName &&
lhs.d_lastName == rhs.d_lastName &&
lhs.d_age == rhs.d_age;
}
inline
bool operator!=(const MyPerson& lhs, const MyPerson& rhs)
{
return !(lhs == rhs);
}
Then, we can exercise the new MyPerson
value-semantic class by externalizing and reconstituting an object. First, create a MyPerson
janeSmith
and a bslx::StreambufOutStream
outStream
: MyPerson janeSmith("Jane", "Smith", 42);
bsl::stringbuf buffer;
bslx::StreambufOutStream outStream(&buffer, 20131127);
const int VERSION = 1;
outStream.putVersion(VERSION);
janeSmith.bdexStreamOut(outStream, VERSION);
assert(outStream.isValid());
Next, create a MyPerson
janeCopy
initialized to the default value, and assert that janeCopy
is different from janeSmith
: MyPerson janeCopy;
assert(janeCopy != janeSmith);
Then, create a bslx::StreambufInStream
inStream
initialized with the buffer from the bslx::StreambufOutStream
object outStream
and unexternalize this data into janeCopy
: bslx::StreambufInStream inStream(&buffer);
int version;
inStream.getVersion(version);
janeCopy.bdexStreamIn(inStream, version);
assert(inStream.isValid());
Finally, assert
the obtained values are as expected and display the results to bsl::stdout
: assert(version == VERSION);
assert(janeCopy == janeSmith);
if (janeCopy == janeSmith) {
bsl::cout << "Successfully serialized and de-serialized Jane Smith:"
<< "\n\tFirstName: " << janeCopy.firstName()
<< "\n\tLastName : " << janeCopy.lastName()
<< "\n\tAge : " << janeCopy.age() << bsl::endl;
}
else {
bsl::cout << "Serialization unsuccessful. 'janeCopy' holds:"
<< "\n\tFirstName: " << janeCopy.firstName()
<< "\n\tLastName : " << janeCopy.lastName()
<< "\n\tAge : " << janeCopy.age() << bsl::endl;
}