Rogue Wave Knowledge Base
Search:    
Browse by category:
Knowledgebase | Glossary | Ask a Question |

Use Stream Versions to Improve Efficiency or Provide Compatibility

Article ID: 1454
Last updated: 29 Aug, 2011
Revision: 1
print  Print
share  Share
Views: 1240
Posted: 29 Aug, 2011
by Rehme L.
Updated: 29 Aug, 2011
by Rehme L.

Overview
The RWvistream and RWvostream classes maintain a version number. This version number can be accessed and modified by all users of the virtual stream classes, and it affects how objects are represented on the underlying data stream. Within the Tools library, the difference between version 0 and version 1 formats is how RWCString data is stored and interpreted.
All data serialized with versions of Tools.h++ prior to 6.0.2 used version 0 of the serialization format. To enable new code to read and write data that is compatible with these legacy Tools.h++ applications, you need to set the version of the affected stream to 0 before reading or writing data.
Data serialized with versions of Tools.h++ after 6.0.2 and all versions of the SourcePro Core module can use either version 0 or version 1 of the serialization format. The version 1 format was added to make the representation of RWCString generated with RWpostream more efficient and more easily readable by humans. A side effect of this is that slightly less optimal output is generated when serializing RWCString using the other stream classes, namely RWbostream and RWeostream. Using version 0 streams eliminates this inefficiency and makes it possible to share data with legacy applications (using Tools.h++ prior to 6.0.2).
Use Case
If you are using one of RWbistream, RWbostream, RWeistream, or RWeostream and are using Tools.h++ 6.0.2 or later or the SourcePro Core module, you can explicitly specify that the virtual stream use version 0 to improve efficiency of the output.
If you are trying to ensure data compatibility with an application that is using a version of Tools.h++ prior to 6.0.2, you must set the virtual stream version to 0.
If you are using RWpistream or RWpostream and compatibility is not a concern, you should opt to use version 1 streams.
As an example--
 
// create a binary output stream from the provided stream `os'
RWbostream bos(os);
 
// set the version of the binary stream to 0 for compatibility
// with old applications or data efficiency
bos.version (0);
 
It is of utmost importance that the version of the stream used to serialize data is the same as the version of the stream used to deserialize it. Failure to use the same stream version will cause the deserialization of that data to fail.
Implementation
The following code provides a simple way to select the optimal stream version for a given virtual stream type.
inline unsigned get_optimal_stream_version(RWvistream*)
{
     return 0u;
}
 
inline unsigned get_optimal_stream_version(RWvostream*)
{
     return 0u;
}
 
inline unsigned get_optimal_stream_version(RWpistream*)
{
     return 1u;
}
 
inline unsigned get_optimal_stream_version(RWpostream*)
{
     return 1u;
}
 
template <class InputStream>
class OptimalVersionIStream : public InputStream
{
public:
     OptimalVersionIStream (std::istream& is)
          : InputStream (is)
     {
           const unsigned v = get_optimal_stream_version((InputStream*)0);
           InputStream::version (v);
     }
 
     OptimalVersionIStream (std::streambuf* sb)
          : InputStream (sb)
     {
           const unsigned v = get_optimal_stream_version((InputStream*)0);
           InputStream::version (v);
     }
};
 
template <class OutputStream>
class OptimalVersionOStream : public OutputStream
{
public:
     OptimalVersionOStream (std::ostream& os)
          : OutputStream (os)
     {
           const unsigned v = get_optimal_stream_version((OutputStream*)0);
           OutputStream::version (v);
     }
 
     OptimalVersionOStream (std::streambuf* sb)
          : OutputStream (sb)
     {
          const unsigned v = get_optimal_stream_version((OutputStream*)0);
          OutputStream::version (v);
     }
};
 
Anywhere you declare a derived virtual stream instance, you would replace that with an instance; of an appropriate optimal version stream. As an example...
// create a binary stream on top of `os'
RWbostream bos (os);
 
Instead of the above code, or explicitly specifying the version, you would write this...
// create a binary stream on top of `os', using a version number
// that is appropriate for the underlying stream type
OptimalVersionOStream<RWbostream> bos (os);

Usage of this helper class needs to be applied consistently for both input and output streams to ensure compatibility. If that is difficult to do, the technique could be extended to enable storing the version of the stream data on the actual stream. This additional information makes it trivial to ensure that the version of the stream data is read back using the appropriate stream version. As an example...
//
// exception class thrown when a stream contains data for a data format
// that cannot be properly parsed by this version of the stream code.
//
class VersionSpecificationError : public RWxmsg
{
public:
     VersionSpecificationError (const char* msg)
          : RWxmsg (msg)
     {
     }
};
 
//
// helper functions to read and write the stream version
//
void write_version_to_stream (RWvostream& output_stream);
void read_version_from_stream (RWvistream& input_stream);


template <class InputStream>
class VersionedIStream : public InputStream
{
public:
     VersionedIStream (std::istream& is)
          : InputStream (is)
     {
          read_version_from_stream (*this);
     }
 
     VersionedIStream (std::streambuf* sb)
           : InputStream (sb)
     {
          read_version_from_stream (*this);
     }
};
template <class OutputStream>
class VersionedOStream : public OutputStream
{
public:
     VersionedOStream (std::ostream& os)
          : OutputStream (os)
     {
          const unsigned v = get_optimal_stream_version((OutputStream*)0);
          OutputStream::version (v);
          write_version_to_stream (*this);
     }
     VersionedOStream (std::streambuf* sb)
          : OutputStream (sb)
     {
         // explicitly override the version on the stream
        const unsigned v = get_optimal_stream_version((OutputStream*)0);
        OutputStream::version (v);
        write_version_to_stream (*this);
     }
};
 
//
// definitions of helper functions go in a source file somewhere
//
void write_version_to_stream (RWvostream& output_stream)
{
     //
     // this code illustrates how to safely store the version number used
     // to serialize data onto the stream
     //
 
     // cache the data version used by the stream by default
     const unsigned data_version = output_stream.version ();
 
     // explicitly set the stream to a known version temporarily
     output_stream.version (0);
 
     // write the version of our data to the stream
     output_stream << data_version;
 
     // now restore the version back to the default
     output_stream.version (data_version);
}
void read_version_from_stream (RWvistream& input_stream)
{
     //
     // this code illustrates how to read the version number used
     // to serialize data onto the stream, and set our version so
     // we can read the serialized data.
     //
 
     // this is the version of the stream by default; assume this
     // is the largest legal version number.
     unsigned default_version = input_stream.version ();
 
     // explicitly set the stream to a known version
     input_stream.version (0);
 
     // read the version of the data on the stream
     unsigned data_version = 0;
     input_stream >> data_version;
 
     // verify that the version of the data is something we could possibly read
     if (default_version < data_version) {
          char buf [128];
          snprintf (buf, sizeof buf,
               "The stream version (%u) is newer than the version supported (%u)",
               data_version, default_version);
 
          throw VersionSpecificationError (buf);
     }
 
     // set the version of the stream to match the version of the data
     input_stream.version (data_version);
}
 
These wrappers help to guarantee that the version used to serialize the data is written to the stream and that the correct stream version is used to determine how the data should be read back. Other than using the stream wrapper classes, no other user intervention is necessary.

This article was:   Helpful | Not helpful Report an issue


Also listed in
folder SourcePro -> Core -> Essential Tools Module

Prev     Next
SourcePro install problem on Linux platform       On AIX 5.3, RCB only generates static libs (*.a) and not dynamic...

Others in this category
b Incorrect RCB Compiler & OS Selections in SuSE Linux Enterprise Server (SLES) 9
b SourcePro Static build looking for a shared Standard Library version
b Currency Library fails to build on AIX 5.3 with xlC 8.0.0.15
b SourcePro install problem on Linux platform
b On AIX 5.3, RCB only generates static libs (*.a) and not dynamic libs (*.so)
b What is a static initialization problem?
b How to create a single SourcePro threads rollup library?
b Display Issues during SourcePro installation
b Problem Installing SourcePro on 64bit Linux